UNPKG

bicep-assets

Version:
172 lines (169 loc) 7.34 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BuildCommand = void 0; const clipanion_1 = require("clipanion"); const folder_hash_1 = require("folder-hash"); const promises_1 = require("fs/promises"); const fs_1 = require("fs"); const path_1 = require("path"); const copy_1 = require("../build-plugins/copy"); const nodejs_1 = require("../build-plugins/nodejs"); const vite_1 = require("../build-plugins/vite"); const configuration_1 = require("../configuration"); const plugin_manager_1 = require("../utils/plugin-manager"); class BuildCommand extends clipanion_1.Command { constructor() { super(...arguments); this.outFolder = clipanion_1.Option.String('--output,-o', '.bicep-assets', { description: 'The output folder for the assets. Defaults to .bicep-assets', }); } execute() { return __awaiter(this, void 0, void 0, function* () { const configuration = yield configuration_1.Configuration.load(false); const pluginManager = new plugin_manager_1.PluginManager(); pluginManager.register('nodejs', new nodejs_1.NodeJsBuildPlugin()); pluginManager.register('vite', new vite_1.ViteBuildPlugin()); pluginManager.register('copy', new copy_1.CopyBuildPlugin()); const commands = yield pluginManager.load(configuration.assets); const manifestContent = { // resourceProviderId: configuration.customResourceProviderId, storageAccountName: configuration.storageAccountName, subscription: configuration.subscription, resourceGroup: configuration.resourceGroup, assets: {}, }; for (const command of commands) { const hash = yield this.execBuild(command, this.outFolder); manifestContent.assets[command.name] = hash !== null && hash !== void 0 ? hash : 'ERROR'; } yield (0, promises_1.mkdir)(this.outFolder, { recursive: true, }); yield (0, promises_1.writeFile)((0, path_1.join)(this.outFolder, 'manifest.json'), JSON.stringify(manifestContent, null, 2), 'utf-8'); const bicepContent = this.generateBicep(manifestContent, this.outFolder); yield (0, promises_1.writeFile)((0, path_1.join)('bicep-assets.bicep'), bicepContent, 'utf-8'); }); } execBuild(command, outputFolder) { return __awaiter(this, void 0, void 0, function* () { console.log(`➤ Building ${command.name}`); yield this.retry((0, promises_1.mkdir)(outputFolder, { recursive: true, })); const tempFolder = yield (0, promises_1.mkdtemp)((0, path_1.resolve)((0, path_1.join)(outputFolder, 'tmp-asset-'))); try { const result = yield command.buildInFolder(tempFolder); const hash = (yield (0, folder_hash_1.hashElement)('.', tempFolder, { encoding: 'hex', })).hash; let filename = hash; if (typeof result === 'string') { const extension = (0, path_1.extname)(result); if (extension.length > 1) { filename = filename + extension; } } const output = (0, path_1.join)(outputFolder, filename); if ((0, fs_1.existsSync)(output)) { yield this.retry((0, promises_1.rm)(output, { recursive: true, })); } if (typeof result === 'string') { yield this.retry((0, promises_1.rename)(result, (0, path_1.join)(outputFolder, filename))); yield this.retry((0, promises_1.rm)(tempFolder, { recursive: true, })); } else { yield this.retry((0, promises_1.rename)(tempFolder, (0, path_1.join)(outputFolder, filename))); } console.log(`➤ Finished building ${command.name}`); return filename; } catch (error) { yield this.retry((0, promises_1.rm)(tempFolder, { recursive: true, })); throw error; } }); } retry(command) { return __awaiter(this, void 0, void 0, function* () { const backOffInterval = 1000; // 1 second const maxRetries = 10; let retry = 0; let lastError = undefined; while (retry < maxRetries) { try { return yield command; } catch (error) { retry++; yield new Promise(resolve => setTimeout(resolve, backOffInterval * retry)); if (retry >= maxRetries) { lastError = error; break; } } } throw lastError; }); } generateBicep(manifestContent, outFolder) { if (Object.keys(manifestContent.assets).length === 0) { return ''; } const assets = Object.entries(manifestContent.assets).map(([k, v]) => { const stats = (0, fs_1.statSync)((0, path_1.join)(outFolder, v)); const filename = stats.isDirectory() ? `${v}.zip` : v; // return `${k.replace(/[-.]/g, '_')}: { // resourceProviderId: '${manifestContent.resourceProviderId}' // filename: '${filename}' // }`; return `${k.replace(/[-.]/g, '_')}: { subscription: '${manifestContent.subscription}' resourceGroup: '${manifestContent.resourceGroup}' storageAccountName: '${manifestContent.storageAccountName}' containerName: 'assets' filename: '${filename}' }`; }); return ` @export() type Asset = { storageAccountName: string subscription: string resourceGroup: string containerName: string filename: string } @export() var assets = { ${assets.join('\n ')} } `; } } exports.BuildCommand = BuildCommand; BuildCommand.paths = [ ['build'], ]; BuildCommand.usage = clipanion_1.Command.Usage({ description: 'Build the assets for the bicep template', details: ` This command will build the assets for the bicep template. It will generate a distribution folder with all assets. `, });