UNPKG

@interopio/cli

Version:

Interop.io CLI - a command line for creating Interop.io applications

144 lines (143 loc) 8.82 kB
/* eslint-disable import/default */ /* eslint-disable @typescript-eslint/no-explicit-any */ import { ux } from "@oclif/core"; import decompress from "decompress"; import fs from "fs-extra/esm"; import log4js from "log4js"; import { existsSync } from "node:fs"; import { copyFile, mkdir, rm, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { PLATFORM_TEMPLATE, TEMP_ZIP_NAME } from "../../shared/constants.js"; import { obfuscateLicense } from "../../utils/license-obfuscate.js"; import locatorService from "../locator.service.js"; export class BrowserPlatformService { currentDir = process.cwd(); logger = log4js.getLogger("NewBrowserPlatformService"); async build(config) { const { appName, template, version } = config; this.logger.info(`Creating new ${appName} app with io.CB version ${version} and template ${template}`); ux.info(`Creating new ${appName} app with io.CB version ${version} and template ${template}`); const cliConfig = await locatorService.configurationService.getCliConfig(); const appDir = join(this.currentDir, appName); this.logger.info(`Making new app directory at ${appDir}`); await mkdir(appDir); this.logger.info(`New app directory created at ${appDir}, proceeding with fetching ${template} template`); const resolvedMode = await this.getZipTemplate(config, cliConfig); this.logger.info(`Fetched ${template} template with mode ${resolvedMode}, proceeding with unpacking`); ux.info(`Proceeding with ${resolvedMode} template`); await this.unpackZipTemplate(appDir, template, join(appDir, TEMP_ZIP_NAME)); this.logger.info(`Unpacked ${template} template, proceeding with ${template} configuration`); if (template === "vanilla-js") { await this.configureVanillaJsTemplate(config, cliConfig); } if (template === "home-react-wsp") { await this.configureHomeWspReactTemplate(config, cliConfig); } if (template === "dev-react-seed") { await this.configureDevReactSeedTemplate(config, cliConfig); } if (template === "wsp-frame") { await this.configureWspFrameTemplate(config, cliConfig); } this.logger.info(`New ${appName} app creation complete.`); ux.info(`New Browser Platform Creation Complete. Please run "cd ./${appName}" and "npm install" to install dependencies${template === PLATFORM_TEMPLATE.DEV_REACT_SEED ? `, "npm run bootstrap" to install all dependencies for all apps` : ""} and "npm start" to start the app.`); } async clean(config) { const appDir = join(this.currentDir, config.appName); this.logger.info(`Cleaning up the app directory at ${appDir}`); await rm(appDir, { force: true, recursive: true }); ux.action.stop("New Browser Platform Creation Failed. Cleaned up the app directory."); this.logger.info(`Cleaned up the app directory at ${appDir}`); } async configureDevReactSeedTemplate(config, cliConfig) { const appDir = join(this.currentDir, config.appName); const configExampleLocation = join(appDir, "workspace-platform", "src", "config.example.json"); const configLocation = join(appDir, "workspace-platform", "src", "config.json"); await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "dev-react-seed"); } async configureHomeWspReactTemplate(config, cliConfig) { const appDir = join(this.currentDir, config.appName); const configExampleLocation = join(appDir, "src", "config.example.json"); const configLocation = join(appDir, "src", "config.json"); await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "home-react-wsp"); } async configureVanillaJsTemplate(config, cliConfig) { const appDir = join(this.currentDir, config.appName); const configExampleLocation = join(appDir, "public", "config.example.json"); const configLocation = join(appDir, "public", "config.json"); await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "vanilla-js"); } async configureWspFrameTemplate(config, cliConfig) { const appDir = join(this.currentDir, config.appName); const configExampleLocation = join(appDir, "src", "config.example.json"); const configLocation = join(appDir, "src", "config.json"); await this.setPlatformConfig(cliConfig, configExampleLocation, configLocation, "wsp-frame"); } async getZipTemplate(config, cliConfig) { const { appName, version } = config; const appDir = join(this.currentDir, appName); const zipLocation = join(appDir, TEMP_ZIP_NAME); if (cliConfig.mode === "remote") { this.logger.info(`Fetching remote template ${version}, to zip location ${zipLocation}`); await this.resolveRemoteZip(version, zipLocation); this.logger.info(`Completed remote template fetch`); return "remote"; } if (cliConfig.mode === "offline") { this.logger.info(`Fetching offline template ${version}, to zip location ${zipLocation}`); await this.resolveLocalZip(version, zipLocation); this.logger.info(`Completed local template fetch`); return "offline"; } try { this.logger.info(`Fetching remote template ${version}, to zip location ${zipLocation}, with auto mode`); await this.resolveRemoteZip(version, zipLocation); this.logger.info(`Completed remote template fetch with auto mode`); return "remote"; } catch (error) { this.logger.warn(`Could not get the remote template, falling back to the offline template. Reason: ${error.message}`); ux.warn(`Could not get the remote template, falling back to the offline template. Reason: ${error.message}`); await this.resolveLocalZip(version, zipLocation, `Unable to get the remote template, resolved to the offline template ${version}`); this.logger.info(`Completed local fallback template fetch with auto mode`); return "offline"; } } async resolveLocalZip(version, zipLocation, stopMessage) { ux.action.start(`Fetching offline template ${version}`); const verifiedVersion = await locatorService.validationService.transformVersion(version, "ioCb", "offline"); const { root } = locatorService.configurationService.directoryConfig; const templateLocation = join(root, "templates", verifiedVersion ? `${verifiedVersion}.zip` : "latest.zip"); existsSync(templateLocation) || ux.error(`Could not find the offline template ${version}`); await copyFile(templateLocation, zipLocation); ux.action.stop(stopMessage); } async resolveRemoteZip(version, zipLocation, stopMessage) { ux.action.start(`Downloading remote template ${version}`); const verifiedVersion = await locatorService.validationService.transformVersion(version, "ioCb", "remote"); await locatorService.downloaderService.downloadRemoteZip(verifiedVersion, zipLocation); ux.action.stop(stopMessage); } async setPlatformConfig(cliConfig, configExampleLocation, configLocation, template) { this.logger.info(`Setting the config.json file with license key ${cliConfig.licenseKey ? obfuscateLicense(cliConfig.licenseKey) : "no license key"}, using example file at ${configExampleLocation}`); existsSync(configExampleLocation) || ux.error(`Could not find the config.example.json file at ${configExampleLocation}`); const configFile = await fs.readJSON(configExampleLocation, { throws: false }); if (template === "dev-react-seed" || template === "wsp-frame") { configFile.browserPlatform.licenseKey = cliConfig.licenseKey; } else { configFile.licenseKey = cliConfig.licenseKey; } await writeFile(configLocation, JSON.stringify(configFile, null, 4)); this.logger.info(`Set the config.json file at location ${configLocation}`); } async unpackZipTemplate(appDir, template, zipLocation) { await mkdir(join(appDir, "temp")); await decompress(zipLocation, join(appDir, "temp"), { strip: 1 }); const source = join(appDir, "temp", `browser-platform-${template}`); existsSync(source) || ux.error(`Could not find the template ${join(appDir, "temp", `browser-platform-${template}`)}`); fs.copySync(source, appDir, { overwrite: true }); await rm(zipLocation, { force: true, recursive: true }); await rm(join(appDir, "temp"), { force: true, recursive: true }); } }