UNPKG

@kumologica/builder

Version:
244 lines (210 loc) 6.43 kB
const fs = require('fs-extra'); const path = require('path'); const util = require('util'); const exec = util.promisify(require('child_process').exec); const AdmZip = require('adm-zip'); const codegen = require('./codegen'); /** * sample events: * https://docs.aws.amazon.com/lambda/latest/dg/lambda-services.html */ class AzureBuilder { constructor(log) { if (log) { this.logger = log; } } log(text, calog = true) { if (this.logger) { this.logger(text, calog); } else { console.log(text); } } async buildFunction(buildDir, zipFileName) { this.log(`Building Azure function... ${buildDir}/${zipFileName}`); const npmCmd = `npm install --production --prefix "${buildDir}"`; const response = await exec(npmCmd, { cwd: buildDir }); if (response) { this.log('', false); const lines = response.stdout.split('\n'); for (var i = 0; i < lines.length; i++) { if (lines[i]) { this.log(lines[i], false); } } this.log('', false); } // for npm 8 on windows is creating symlink that causes recursions and zip to fail const splitdir = path.dirname(buildDir).split(path.sep); const linkname = splitdir[splitdir.length-1]; try { fs.unlinkSync(path.join(buildDir, 'node_modules', linkname)); } catch (e) { // ignore ENOENT if (e.code !== "ENOENT") { throw e; } } this.log('Zipping Function ...'); const zip = new AdmZip(); zip.addLocalFolder(buildDir); zip.writeZip(path.join(buildDir, zipFileName)); this.log('Function has been succesfully built:'); this.log(` zip file: ${path.join(buildDir, zipFileName)}`); } prepare(projectDir, flowFileName) { const buildDir = path.join(projectDir, 'build'); const flowName = flowFileName.replace('.json', ''); const webappDir = path.join(buildDir, flowName); // setup deployment directory fs.ensureDirSync(buildDir); fs.emptyDirSync(buildDir); fs.ensureDirSync(webappDir); fs.ensureDirSync(path.join(buildDir, 'node_modules')); // copy project files codegen.generateAzureProjectCode( buildDir, flowFileName, flowName ); this.generateBindings(webappDir, flowName); this.generateHost(buildDir); fs.copySync( path.join(projectDir, flowFileName), path.join(buildDir, flowFileName) ); this.processPackageJson(projectDir, buildDir); } processPackageJson(projectDir, buildDir) { const pckg = codegen.loadJsonFile(path.join(projectDir, 'package.json')); if (!pckg.dependencies["@kumologica/runtime"]) { pckg.dependencies["@kumologica/runtime"] = `^${pckg.version.substr(0, 1)}`; } if (!pckg.dependencies["@aws-sdk/client-cloudwatch-events"]) { pckg.dependencies["@aws-sdk/client-cloudwatch-events"] = `^3.549.0`; } if (!pckg.dependencies["aws-sdk/client-dynamodb"]) { pckg.dependencies["aws-sdk/client-dynamodb"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-lambda"]) { pckg.dependencies["@aws-sdk/client-lambda"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-rekognition"]) { pckg.dependencies["@aws-sdk/client-rekognition"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-s3"]) { pckg.dependencies["@aws-sdk/client-s3"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-ses"]) { pckg.dependencies["@aws-sdk/client-ses"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-sns"]) { pckg.dependencies["@aws-sdk/client-sns"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-sqs"]) { pckg.dependencies["@aws-sdk/client-sqs"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-ssm"]) { pckg.dependencies["@aws-sdk/client-ssm"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/client-sts"]) { pckg.dependencies["@aws-sdk/client-sts"] = `^3.549.0`; } if (!pckg.dependencies["@aws-sdk/lib-dynamodb"]) { pckg.dependencies["@aws-sdk/lib-dynamodb"] = `^3.549.0`; } // ensure dependencies contain runtime if (!pckg.dependencies["@kumologica/runtime"]) { pckg.dependencies["@kumologica/runtime"] = `^${pckg.version.substr(0, 1)}`; } codegen.createFile(buildDir, 'package.json', JSON.stringify(pckg)); if (pckg.files) { pckg.files.forEach(f => { if (!["node_modules/**/*", "lambda.js", "src/**/*"].includes(f)) { fs.copySync( path.join(projectDir, f), path.join(buildDir, f) ); } }); } } generateBindings(directory, functionName) { let bindings = { "bindings": [ { "authLevel": "anonymous", "type": "httpTrigger", "direction": "in", "name": "req", "methods": [ "get", "post", "delete", "put", "patch" ], "route": `${functionName}/{*restOfPath}` }, { "type": "http", "direction": "out", "name": "res" } ], "entryPoint": "handler", "scriptFile": "../index.js" } codegen.createFile(directory, 'function.json', JSON.stringify(bindings)); } generateHost(directory) { let host = { "version": "2.0", "logging": { "applicationInsights": { "samplingSettings": { "isEnabled": true, "excludedTypes": "Request" } } }, "extensionBundle": { "id": "Microsoft.Azure.Functions.ExtensionBundle", "version": "[1.*, 2.0.0)" }, "extensions": { "http": { "routePrefix": "" } } } codegen.createFile(directory, 'host.json', JSON.stringify(host)); } validate(flow, provider) { const FlowValidator = require('../validator'); const validator = new FlowValidator(this.logger); validator.validate(flow, provider); } async build(argv) { let projectDir = argv["project-directory"] || process.cwd(); let buildDir = path.join(projectDir, 'build'); let projectFlowName = argv["flow-file-name"] || codegen.findFlowFile(projectDir); if (!projectFlowName) { throw new Error(`Unable to find flow file in project directory: ${projectDir}`); } const flow = codegen.loadJsonFile(path.join(projectDir, projectFlowName)); this.validate(flow, "azure"); console.log(`project directory: ${projectDir}`); console.log(`flow file name: ${projectFlowName}`); console.log(`zip file name: ${argv["zip-file-name"] || 'azure.zip'}`); this.prepare( projectDir, projectFlowName ); const zipFileName = argv["zip-file-name"] || "azure.zip"; await this.buildFunction(buildDir, zipFileName); return zipFileName; } } module.exports = AzureBuilder;