UNPKG

genezio

Version:

Command line utility to interact with Genezio infrastructure.

146 lines (145 loc) 7.93 kB
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _KotlinBundler_instances, _KotlinBundler_compile, _KotlinBundler_castParameterToPropertyType, _KotlinBundler_getProperCast, _KotlinBundler_createRouterFileForClass; // Libs import path from "path"; import Mustache from "mustache"; import { default as fsExtra } from "fs-extra"; import { log } from "../../utils/logging.js"; import { spawnSync } from "child_process"; // Kotlin stuff import { checkIfKotlinReqsAreInstalled } from "../../utils/kotlin.js"; import { template } from "./kotlinMain.js"; import { castArrayRecursivelyInitial, castMapRecursivelyInitial, } from "../../utils/kotlinAstCasting.js"; // Utils import { createTemporaryFolder, writeToFile } from "../../utils/file.js"; import { debugLogger } from "../../utils/logging.js"; import { TriggerType } from "../../projectConfiguration/yaml/models.js"; import { AstNodeType, } from "../../models/genezioModels.js"; import { UserError } from "../../errors.js"; import fs from "fs"; export class KotlinBundler { constructor() { _KotlinBundler_instances.add(this); } async bundle(input) { // Create a temporary folder were we copy user code to prepare everything. const folderPath = input.projectConfiguration.workspace?.backend ?? input.genezioConfigurationFilePath; const inputTemporaryFolder = await createTemporaryFolder(); await fsExtra.copy(folderPath, inputTemporaryFolder); debugLogger.debug(`Copy files in temp folder ${inputTemporaryFolder}`); // Create the router class const userClass = input.projectConfiguration.classes.find((c) => c.path == input.path); // If workspace.backend is defined we need to subtract it from the userClass.path if (input.projectConfiguration.workspace?.backend) { userClass.path = userClass.path.replace(input.projectConfiguration.workspace.backend, ""); } await __classPrivateFieldGet(this, _KotlinBundler_instances, "m", _KotlinBundler_createRouterFileForClass).call(this, userClass, input.ast, inputTemporaryFolder); checkIfKotlinReqsAreInstalled(); // Compile the Kotlin code locally debugLogger.debug("Compiling Kotlin..."); await __classPrivateFieldGet(this, _KotlinBundler_instances, "m", _KotlinBundler_compile).call(this, inputTemporaryFolder); debugLogger.debug("Compiling Kotlin finished."); return { ...input, path: path.join(inputTemporaryFolder, "final_build"), }; } } _KotlinBundler_instances = new WeakSet(), _KotlinBundler_compile = async function _KotlinBundler_compile(folderPath) { // Compile the Kotlin code locally const gradlew = "." + path.sep + "gradlew" + (process.platform === "win32" ? ".bat" : ""); fs.chmod(`${folderPath}${path.sep}${"gradlew" + (process.platform === "win32" ? ".bat" : "")}`, 0o755, (err) => { if (err) { throw Error("Error while changing gradlew permissions"); } }); const result = spawnSync(gradlew, ["--quiet", "fatJar"], { cwd: folderPath, }); if (result.status == null) { log.info("There was an error while running the " + gradlew + " script, make sure you have the correct permissions."); throw new UserError("Compilation error! Please check your code and try again."); } else if (result.status != 0) { log.info(result.stderr.toString()); log.info(result.stdout.toString()); throw new UserError("Compilation error! Please check your code and try again."); } // Move the stand alone jar to its own folder fsExtra.mkdirSync(path.join(folderPath, "final_build")); const result_path = path.join(folderPath, "app", "build", "libs", "app-standalone.jar"); const destination_path = path.join(folderPath, "final_build", "app-standalone.jar"); fsExtra.moveSync(result_path, destination_path); }, _KotlinBundler_castParameterToPropertyType = function _KotlinBundler_castParameterToPropertyType(node, variableName) { let implementation = ""; switch (node.type) { case AstNodeType.StringLiteral: implementation += `${variableName}.jsonPrimitive.content`; break; case AstNodeType.DoubleLiteral: implementation += `${variableName}.toDouble()`; break; case AstNodeType.BooleanLiteral: implementation += `${variableName}.jsonPrimitive.content.toBoolean()`; break; case AstNodeType.IntegerLiteral: implementation += `Integer.parseInt(${variableName}.jsonPrimitive.content)`; break; case AstNodeType.CustomNodeLiteral: implementation += `Json.decodeFromJsonElement<${node.rawValue}>(${variableName})`; break; case AstNodeType.ArrayType: implementation += castArrayRecursivelyInitial(node, variableName); break; case AstNodeType.MapType: implementation += castMapRecursivelyInitial(node, variableName); } return implementation; }, _KotlinBundler_getProperCast = function _KotlinBundler_getProperCast(mainClass, method, parameterType, index) { const type = mainClass.methods .find((m) => m.name == method.name) .params.find((p) => p.name == parameterType.name); return `${__classPrivateFieldGet(this, _KotlinBundler_instances, "m", _KotlinBundler_castParameterToPropertyType).call(this, type.paramType, `params!![${index}]`)}`; }, _KotlinBundler_createRouterFileForClass = async function _KotlinBundler_createRouterFileForClass(classConfiguration, ast, folderPath) { const mainClass = ast.body?.find((element) => { return (element.type === AstNodeType.ClassDefinition && element.name === classConfiguration.name); }); const classConfigPath = path.dirname(classConfiguration.path); // Error check: User is using Windows but paths are unix style (possible when cloning projects from git) if (process.platform === "win32" && classConfigPath.includes("/")) { throw new UserError("Error: You are using Windows but your project contains unix style paths. Please use Windows style paths in genezio.yaml instead."); } const moustacheViewForMain = { packageName: classConfigPath.substring(classConfigPath.lastIndexOf(path.sep) + 1), classFileName: path.basename(classConfiguration.path, path.extname(classConfiguration.path)), className: classConfiguration.name, jsonRpcMethods: classConfiguration.methods .filter((m) => m.type === TriggerType.jsonrpc) .map((m) => ({ name: m.name, parameters: m.parameters.map((p, index) => ({ index, cast: __classPrivateFieldGet(this, _KotlinBundler_instances, "m", _KotlinBundler_getProperCast).call(this, mainClass, m, p, index), })), })), cronMethods: classConfiguration.methods .filter((m) => m.type === TriggerType.cron) .map((m) => ({ name: m.name, })), httpMethods: classConfiguration.methods .filter((m) => m.type === TriggerType.http) .map((m) => ({ name: m.name, })), }; const routerFileContent = Mustache.render(template, moustacheViewForMain); await writeToFile(folderPath, path.join(classConfigPath, "GeneratedCaller.kt"), routerFileContent); };