import { Scope, type VmRecord, type VmValue } from '@cloudpss/expression'; import { fillArgumentMap, type ArgumentMap } from '@cloudpss/expression/definitions'; import type { ResourceRevisionVersion } from '../../revision.js'; import type { ResourceContextVersion } from '../../context.js'; import type { Func, FuncConfiguration } from '../../function/index.js'; import { V5Migrator } from '../v5.js'; /** 升级算例 */ class Migrator extends V5Migrator { constructor(readonly func: Func) { super(); for (const additionalEnv of this.revision.implement?.additionalEnv ?? []) { if (String(additionalEnv.key).toUpperCase().startsWith('CLOUDPSS')) { continue; } // 环境变量的实际值不重要 this.env[additionalEnv.key] = typeof additionalEnv.value == 'string' ? additionalEnv.value : ''; } } readonly revision = this.func.revision; /** 默认配置 */ get defaultConfig(): ArgumentMap { return fillArgumentMap(this.revision.parameters); } // 参考 @private/job-executor-utils/utils 设置的虚拟求值环境 /** 任务信息 */ readonly job = { id: 'job-id', machine: 'executor-id', function: this.func as Func & VmRecord, args: this.defaultConfig, debug: {}, jobToken: 'job-token', functionToken: 'function-token', input: 'input-stream-id', output: 'output-stream-token', } satisfies VmRecord; /** 环境变量 */ readonly env: Record = { HOME: '~', USERPROFILE: '~', TMP: '/tmp', TEMP: '/tmp', TMPDIR: '/tmp', CLOUDPSS_API_URL: 'https://cloudpss.net/api', CLOUDPSS_GQL_URL: 'https://cloudpss.net/graphql', CLOUDPSS_HOME_URL: 'https://cloudpss.net', CLOUDPSS_EXECUTOR_ID: 'executor-id', CLOUDPSS_EXECUTOR_NAME: 'executor-name', CLOUDPSS_EXECUTOR_TYPE: (this.revision.implementType ?? 'local:basic').split(':')[0]!, CLOUDPSS_EXECUTOR_VERSION: '0.0.0', CLOUDPSS_TOKEN: 'x.y.z', CLOUDPSS_JOB_TOKEN: 'x.y.z', CLOUDPSS_FUNCTION_TOKEN: 'x.y.z', CLOUDPSS_JOB_ID: this.job.id, CLOUDPSS_JOB_INPUT: this.job.input, CLOUDPSS_JOB_OUTPUT: this.job.output, CLOUDPSS_FUNCTION_ID: this.func.rid, // 省略 CLOUDPSS_JOB_ARGS 相关参数,在求值环境中推荐直接使用变量而非环境变量 }; /** 上下文 */ context(inner: boolean): Scope { if (inner) { return new Scope((key: string) => { if (key.startsWith('$')) { const prop = key.slice(1); const { defaultConfig } = this; if (prop in defaultConfig) { return defaultConfig[prop]; } } if (key === 'env') { return this.env; } if (key === 'job') { return this.job; } return undefined; }); } return new Scope((key: string) => { if (key === '$$') return this.func as Func & VmValue; if (key === '$') return { args: this.defaultConfig } satisfies FuncConfiguration; const { defaultConfig } = this; if (key in defaultConfig) { return defaultConfig[key]; } return undefined; }); } /** * 升级算例 */ migrate(): void { const outerContext = this.context(false); if (this.revision.version < 5) { this.migrateParameters(this.revision.parameters, outerContext); } if (this.func.context.version < 5) { for (const config of this.func.configs) { this.migrateConfig(config, outerContext); } this.func.context.version = 5 as ResourceContextVersion; } if (this.revision.version < 5) { const { implement } = this.revision; if (implement) { const innerContext = this.context(true); this.migrateExpression('command', implement, innerContext); this.migrateExpression('workingDirectory', implement, innerContext); this.migrateVariables(implement.additionalEnv, innerContext); } this.func.revision.version = 5 as ResourceRevisionVersion; } } } /** * 升级算例 */ export function migrate(func: Func): void { const m = new Migrator(func); m.migrate(); }