@platforma-sdk/package-builder-lib 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/conda-dockerfile.template +45 -0
- package/assets/python-dockerfile.template +22 -0
- package/dist/_virtual/_rolldown/runtime.cjs +33 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/core/archive.cjs +52 -0
- package/dist/core/archive.cjs.map +1 -0
- package/dist/core/archive.js +47 -0
- package/dist/core/archive.js.map +1 -0
- package/dist/core/conda/builder.cjs +226 -0
- package/dist/core/conda/builder.cjs.map +1 -0
- package/dist/core/conda/builder.js +220 -0
- package/dist/core/conda/builder.js.map +1 -0
- package/dist/core/conda/validate-spec.cjs +76 -0
- package/dist/core/conda/validate-spec.cjs.map +1 -0
- package/dist/core/conda/validate-spec.js +73 -0
- package/dist/core/conda/validate-spec.js.map +1 -0
- package/dist/core/core.cjs +403 -0
- package/dist/core/core.cjs.map +1 -0
- package/dist/core/core.d.ts +82 -0
- package/dist/core/core.d.ts.map +1 -0
- package/dist/core/core.js +397 -0
- package/dist/core/core.js.map +1 -0
- package/dist/core/docker-conda.cjs +75 -0
- package/dist/core/docker-conda.cjs.map +1 -0
- package/dist/core/docker-conda.js +71 -0
- package/dist/core/docker-conda.js.map +1 -0
- package/dist/core/docker-python.cjs +147 -0
- package/dist/core/docker-python.cjs.map +1 -0
- package/dist/core/docker-python.js +144 -0
- package/dist/core/docker-python.js.map +1 -0
- package/dist/core/docker.cjs +223 -0
- package/dist/core/docker.cjs.map +1 -0
- package/dist/core/docker.js +207 -0
- package/dist/core/docker.js.map +1 -0
- package/dist/core/envs.cjs +58 -0
- package/dist/core/envs.cjs.map +1 -0
- package/dist/core/envs.d.ts +26 -0
- package/dist/core/envs.d.ts.map +1 -0
- package/dist/core/envs.js +51 -0
- package/dist/core/envs.js.map +1 -0
- package/dist/core/package-info.cjs +450 -0
- package/dist/core/package-info.cjs.map +1 -0
- package/dist/core/package-info.d.ts +57 -0
- package/dist/core/package-info.d.ts.map +1 -0
- package/dist/core/package-info.js +447 -0
- package/dist/core/package-info.js.map +1 -0
- package/dist/core/paths.cjs +15 -0
- package/dist/core/paths.cjs.map +1 -0
- package/dist/core/paths.js +14 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/resolver.cjs +99 -0
- package/dist/core/resolver.cjs.map +1 -0
- package/dist/core/resolver.js +95 -0
- package/dist/core/resolver.js.map +1 -0
- package/dist/core/schemas/artifacts.cjs +136 -0
- package/dist/core/schemas/artifacts.cjs.map +1 -0
- package/dist/core/schemas/artifacts.d.ts +280 -0
- package/dist/core/schemas/artifacts.d.ts.map +1 -0
- package/dist/core/schemas/artifacts.js +122 -0
- package/dist/core/schemas/artifacts.js.map +1 -0
- package/dist/core/schemas/entrypoints.cjs +43 -0
- package/dist/core/schemas/entrypoints.cjs.map +1 -0
- package/dist/core/schemas/entrypoints.d.ts +32 -0
- package/dist/core/schemas/entrypoints.d.ts.map +1 -0
- package/dist/core/schemas/entrypoints.js +41 -0
- package/dist/core/schemas/entrypoints.js.map +1 -0
- package/dist/core/schemas/sw-json.cjs +111 -0
- package/dist/core/schemas/sw-json.cjs.map +1 -0
- package/dist/core/schemas/sw-json.js +110 -0
- package/dist/core/schemas/sw-json.js.map +1 -0
- package/dist/core/storage.cjs +86 -0
- package/dist/core/storage.cjs.map +1 -0
- package/dist/core/storage.js +83 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/sw-json-render.cjs +327 -0
- package/dist/core/sw-json-render.cjs.map +1 -0
- package/dist/core/sw-json-render.js +322 -0
- package/dist/core/sw-json-render.js.map +1 -0
- package/dist/core/util.cjs +313 -0
- package/dist/core/util.cjs.map +1 -0
- package/dist/core/util.d.ts +66 -0
- package/dist/core/util.d.ts.map +1 -0
- package/dist/core/util.js +281 -0
- package/dist/core/util.js.map +1 -0
- package/dist/defaults.cjs +54 -0
- package/dist/defaults.cjs.map +1 -0
- package/dist/defaults.d.ts +21 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +37 -0
- package/dist/defaults.js.map +1 -0
- package/dist/index.cjs +31 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
- package/src/__test__/Dockerfile +1 -0
- package/src/__test__/docker.test.ts +67 -0
- package/src/__test__/package.json +39 -0
- package/src/__test__/python-example/main.py +1 -0
- package/src/__test__/python-example/requirements.txt +0 -0
- package/src/__test__/vite.config.mts +7 -0
- package/src/core/__tests__/docker-conda.test.ts +145 -0
- package/src/core/__tests__/docker-entrypoint-generation.test.ts +119 -0
- package/src/core/__tests__/docker-python.test.ts +374 -0
- package/src/core/__tests__/publish-docker-images.test.ts +309 -0
- package/src/core/archive.ts +102 -0
- package/src/core/conda/builder.test.ts +71 -0
- package/src/core/conda/builder.ts +384 -0
- package/src/core/conda/validate-spec.test.ts +213 -0
- package/src/core/conda/validate-spec.ts +107 -0
- package/src/core/core.ts +835 -0
- package/src/core/docker-conda.ts +149 -0
- package/src/core/docker-python.ts +283 -0
- package/src/core/docker.ts +300 -0
- package/src/core/envs.ts +31 -0
- package/src/core/package-info.test.ts +82 -0
- package/src/core/package-info.ts +843 -0
- package/src/core/paths.ts +16 -0
- package/src/core/resolver.ts +195 -0
- package/src/core/schemas/artifacts.test.ts +72 -0
- package/src/core/schemas/artifacts.ts +279 -0
- package/src/core/schemas/entrypoints.test.ts +171 -0
- package/src/core/schemas/entrypoints.ts +150 -0
- package/src/core/schemas/sw-json.ts +216 -0
- package/src/core/schemas/test-artifacts.ts +362 -0
- package/src/core/storage.ts +125 -0
- package/src/core/sw-json-render.test.ts +215 -0
- package/src/core/sw-json-render.ts +682 -0
- package/src/core/util.ts +390 -0
- package/src/defaults.ts +38 -0
- package/src/index.ts +31 -0
- package/src/requirements.txt +1 -0
package/src/core/util.ts
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import type { Hash } from "node:crypto";
|
|
5
|
+
import { createHash } from "node:crypto";
|
|
6
|
+
import winston from "winston";
|
|
7
|
+
import type { z } from "zod/v4";
|
|
8
|
+
import * as envs from "./envs";
|
|
9
|
+
|
|
10
|
+
export const packageJsonName = "package.json";
|
|
11
|
+
export const softwareConfigName = "package.json";
|
|
12
|
+
|
|
13
|
+
export function assertNever(_a: never) {
|
|
14
|
+
throw new Error(`code logic error: assertNever() call for ${JSON.stringify(_a)}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function trimPrefix(str: string, prefix: string): string {
|
|
18
|
+
if (str.startsWith(prefix)) {
|
|
19
|
+
return str.slice(prefix.length);
|
|
20
|
+
}
|
|
21
|
+
return str;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function trimSuffix(str: string, suffix: string): string {
|
|
25
|
+
if (str.endsWith(suffix)) {
|
|
26
|
+
return str.slice(0, -suffix.length);
|
|
27
|
+
}
|
|
28
|
+
return str;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function hashDirMetaSync(folder: string, hasher?: Hash): Hash {
|
|
32
|
+
const hash = hasher ? hasher : createHash("sha256");
|
|
33
|
+
const info = fs.readdirSync(folder, { withFileTypes: true });
|
|
34
|
+
|
|
35
|
+
for (const item of info) {
|
|
36
|
+
const fullPath = path.join(folder, item.name);
|
|
37
|
+
|
|
38
|
+
if (item.isFile()) {
|
|
39
|
+
const statInfo = fs.statSync(fullPath);
|
|
40
|
+
const fileInfo = `${fullPath}:${statInfo.size}:${statInfo.mtimeMs}`;
|
|
41
|
+
hash.update(fileInfo);
|
|
42
|
+
} else if (item.isDirectory()) {
|
|
43
|
+
hashDirMetaSync(fullPath, hash);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return hash;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function hashDirSync(rootDir: string, hasher?: Hash, subdir?: string): Hash {
|
|
51
|
+
const hash = hasher ? hasher : createHash("sha256");
|
|
52
|
+
const folder = path.join(rootDir, subdir ?? ".");
|
|
53
|
+
|
|
54
|
+
const info = fs.readdirSync(folder, { withFileTypes: true });
|
|
55
|
+
|
|
56
|
+
for (const item of info) {
|
|
57
|
+
const relPath = path.join(subdir ?? ".", item.name);
|
|
58
|
+
const fullPath = path.join(folder, item.name);
|
|
59
|
+
|
|
60
|
+
hash.update(relPath);
|
|
61
|
+
|
|
62
|
+
if (item.isFile()) {
|
|
63
|
+
const fileDescriptor = fs.openSync(fullPath, "r");
|
|
64
|
+
const buffer = Buffer.alloc(65536);
|
|
65
|
+
let bytesRead: number;
|
|
66
|
+
|
|
67
|
+
while ((bytesRead = fs.readSync(fileDescriptor, buffer, 0, buffer.length, null)) !== 0) {
|
|
68
|
+
hash.update(buffer.subarray(0, bytesRead));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fs.closeSync(fileDescriptor);
|
|
72
|
+
} else if (item.isDirectory()) {
|
|
73
|
+
hashDirSync(fullPath, hash);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return hash;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//
|
|
81
|
+
// Creates all intermediate directories down to given <dirPath>.
|
|
82
|
+
//
|
|
83
|
+
export function ensureDirsExist(dirPath: string) {
|
|
84
|
+
if (fs.existsSync(dirPath)) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const parentDir = path.dirname(dirPath);
|
|
88
|
+
ensureDirsExist(parentDir);
|
|
89
|
+
fs.mkdirSync(dirPath);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function findPackageRoot(logger: winston.Logger, startPath?: string): string {
|
|
93
|
+
if (!startPath) {
|
|
94
|
+
startPath = process.cwd();
|
|
95
|
+
}
|
|
96
|
+
logger.debug(`Detecting package root...`);
|
|
97
|
+
const pkgRoot = searchPathUp(startPath, startPath, packageJsonName);
|
|
98
|
+
logger.debug(` package root found at '${pkgRoot}'`);
|
|
99
|
+
|
|
100
|
+
return pkgRoot;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function findNodeModules(logger: winston.Logger, startPath?: string): string {
|
|
104
|
+
if (!startPath) {
|
|
105
|
+
startPath = process.cwd();
|
|
106
|
+
}
|
|
107
|
+
logger.debug(`Detecting 'node_modules' directory...`);
|
|
108
|
+
const nodeModules = searchPathUp(startPath, startPath, "node_modules");
|
|
109
|
+
logger.debug(` 'node_modules' found at '${nodeModules}'`);
|
|
110
|
+
|
|
111
|
+
return path.join(nodeModules, "node_modules");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function findInstalledModule(
|
|
115
|
+
logger: winston.Logger,
|
|
116
|
+
packageName: string,
|
|
117
|
+
startPath?: string,
|
|
118
|
+
): string {
|
|
119
|
+
const nodeModules = findNodeModules(logger, startPath);
|
|
120
|
+
const packagePath = path.resolve(nodeModules, packageName);
|
|
121
|
+
|
|
122
|
+
if (!fs.existsSync(packagePath)) {
|
|
123
|
+
throw CLIError(
|
|
124
|
+
`package '${packageName}' not found in '${nodeModules}'. Did you forget to add it as a dependency?`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return packagePath;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function searchPathUp(startPath: string, pathToCheck: string, itemToCheck: string): string {
|
|
132
|
+
const itemPath = path.resolve(pathToCheck, itemToCheck);
|
|
133
|
+
|
|
134
|
+
if (fs.existsSync(itemPath)) {
|
|
135
|
+
return pathToCheck;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const parentDir = path.dirname(pathToCheck);
|
|
139
|
+
if (parentDir === pathToCheck || pathToCheck === "") {
|
|
140
|
+
throw CLIError(
|
|
141
|
+
`failed to find '${itemToCheck}' file in any of parent directories starting from '${startPath}'`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return searchPathUp(startPath, parentDir, itemToCheck);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function createLogger(level: string = "debug"): winston.Logger {
|
|
149
|
+
if (envs.isCI() && envs.isRunnerDebug()) {
|
|
150
|
+
level = "debug";
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return winston.createLogger({
|
|
154
|
+
level: level,
|
|
155
|
+
|
|
156
|
+
format: winston.format.printf(({ level, message }) => {
|
|
157
|
+
const indent = " ".repeat(level.length + 2); // For ': ' after the level
|
|
158
|
+
if (typeof message !== "string") {
|
|
159
|
+
const messageJson = JSON.stringify(message);
|
|
160
|
+
throw new Error(`logger message ${messageJson} is not a string`);
|
|
161
|
+
}
|
|
162
|
+
const indentedMessage = message
|
|
163
|
+
.split("\n")
|
|
164
|
+
.map((line: string, index: number) => (index === 0 ? line : indent + line))
|
|
165
|
+
.join("\n");
|
|
166
|
+
|
|
167
|
+
const colorize = (l: string) => winston.format.colorize().colorize(l, l);
|
|
168
|
+
|
|
169
|
+
return `${colorize(level)}: ${indentedMessage}`;
|
|
170
|
+
}),
|
|
171
|
+
|
|
172
|
+
transports: [
|
|
173
|
+
new winston.transports.Console({
|
|
174
|
+
stderrLevels: ["error", "warn", "info", "debug"],
|
|
175
|
+
handleExceptions: true,
|
|
176
|
+
}),
|
|
177
|
+
],
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function rSplit(input: string, delimiter: string, limit?: number): string[] {
|
|
182
|
+
const parts = input.split(delimiter);
|
|
183
|
+
if (!limit || parts.length <= limit) {
|
|
184
|
+
return parts;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return [parts.slice(0, -limit + 1).join(delimiter), ...parts.slice(-limit + 1)];
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const replaceDuplicateSlashes = new RegExp("//+", "g");
|
|
191
|
+
export function urlJoin(url: string, appendPath: string): string {
|
|
192
|
+
const u = new URL(url, "file:/nonexistent-9672674c/");
|
|
193
|
+
if (u.protocol === "file:" && u.pathname.startsWith("/nonexistent-9672674c/")) {
|
|
194
|
+
throw new Error(`string '${url}' is not valid URL`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
u.pathname = u.pathname + "/" + appendPath;
|
|
198
|
+
u.pathname = u.pathname.replaceAll(replaceDuplicateSlashes, "/");
|
|
199
|
+
return u.toString();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function wrapErr(e: any, msg: string): any {
|
|
203
|
+
if (!(e instanceof Error)) {
|
|
204
|
+
return e;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const wrappedError = new Error(`${msg}: ${e.message}`);
|
|
208
|
+
wrappedError.name = e.name;
|
|
209
|
+
wrappedError.stack = e.stack;
|
|
210
|
+
// Copy any additional custom properties
|
|
211
|
+
Object.assign(wrappedError, e);
|
|
212
|
+
return wrappedError;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Converts any value to integer number 1 if value is truthful and 0 otherwice.
|
|
217
|
+
* Provides simple way to count values that are defined in an object:
|
|
218
|
+
* toInt(options.a) + toInt(options.b) + toInt(options.c) === 1
|
|
219
|
+
* @param input: any
|
|
220
|
+
* @returns number - '1' or '0'
|
|
221
|
+
*/
|
|
222
|
+
export function toInt(input: any): number {
|
|
223
|
+
return input ? 1 : 0;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const OSes = ["linux", "macosx", "windows"] as const;
|
|
227
|
+
export type OSType = (typeof OSes)[number];
|
|
228
|
+
|
|
229
|
+
export function currentOS(): OSType {
|
|
230
|
+
const platform = os.platform();
|
|
231
|
+
switch (platform) {
|
|
232
|
+
case "darwin":
|
|
233
|
+
return "macosx";
|
|
234
|
+
case "linux":
|
|
235
|
+
return "linux";
|
|
236
|
+
case "win32":
|
|
237
|
+
return "windows";
|
|
238
|
+
default:
|
|
239
|
+
throw CLIError(
|
|
240
|
+
`operating system '${platform}' is not currently supported by Platforma ecosystem. The list of OSes supported: ` +
|
|
241
|
+
JSON.stringify(OSes),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export const Arches = ["x64", "aarch64"] as const;
|
|
247
|
+
export type ArchType = (typeof Arches)[number];
|
|
248
|
+
|
|
249
|
+
export function currentArch(): ArchType {
|
|
250
|
+
const arch = os.arch();
|
|
251
|
+
switch (arch) {
|
|
252
|
+
case "arm64":
|
|
253
|
+
return "aarch64";
|
|
254
|
+
case "x64":
|
|
255
|
+
return "x64";
|
|
256
|
+
default:
|
|
257
|
+
throw CLIError(
|
|
258
|
+
`processor architecture '${arch}' is not currently supported by Platforma ecosystem. The list of architectures supported: ` +
|
|
259
|
+
JSON.stringify(Arches),
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Combinartions of OS and architecture, Platforma supports.
|
|
265
|
+
export const AllPlatforms: `${OSType}-${ArchType}`[] = [
|
|
266
|
+
"linux-x64",
|
|
267
|
+
"linux-aarch64",
|
|
268
|
+
"macosx-x64",
|
|
269
|
+
"macosx-aarch64",
|
|
270
|
+
"windows-x64",
|
|
271
|
+
] as const;
|
|
272
|
+
export type PlatformType = (typeof AllPlatforms)[number];
|
|
273
|
+
|
|
274
|
+
export function splitPlatform(platform: PlatformType): { os: OSType; arch: ArchType } {
|
|
275
|
+
const parts = platform.split("-");
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
os: parts[0] as OSType,
|
|
279
|
+
arch: parts[1] as ArchType,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export function joinPlatform(os: OSType, arch: ArchType): PlatformType {
|
|
284
|
+
return `${os}-${arch}`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function isPlatformSupported(os: OSType, arch: ArchType): boolean {
|
|
288
|
+
return AllPlatforms.includes(`${os}-${arch}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function currentPlatform(): PlatformType {
|
|
292
|
+
return `${currentOS()}-${currentArch()}`;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export const AllSoftwareSources = ["archive", "docker"] as const; // add 'image', '<whatever>' here when supported
|
|
296
|
+
export type SoftwareSource = (typeof AllSoftwareSources)[number];
|
|
297
|
+
|
|
298
|
+
export type BuildMode = "dev-local" | "release";
|
|
299
|
+
|
|
300
|
+
/** True for dev-local build mode. */
|
|
301
|
+
export function isDevLocalMode(mode: BuildMode): mode is "dev-local" {
|
|
302
|
+
return mode === "dev-local";
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
export type artifactID = {
|
|
306
|
+
package: string;
|
|
307
|
+
name: string;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
export function artifactIDFromString(s: string): artifactID {
|
|
311
|
+
const parts = s.split(":", 2);
|
|
312
|
+
if (parts.length < 2) {
|
|
313
|
+
throw CLIError(
|
|
314
|
+
`string '${s}' is not an artifact ID (artifact ID format is <packageName>:<artifactName>)`,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
package: parts[0],
|
|
319
|
+
name: parts[1],
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export function artifactIDToString(a: artifactID): string {
|
|
324
|
+
return `${a.package}:${a.name}`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function indentText(txt: string, indent: string | number, skipFirstLine: boolean = false) {
|
|
328
|
+
indent = typeof indent === "number" ? " ".repeat(indent) : indent;
|
|
329
|
+
|
|
330
|
+
return txt
|
|
331
|
+
.split("\n")
|
|
332
|
+
.map((line, index) => (index === 0 && skipFirstLine ? line : `${indent}${line}`))
|
|
333
|
+
.join("\n");
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export const formatZodIssues = (
|
|
337
|
+
issues: z.core.$ZodIssue[],
|
|
338
|
+
i: string = "",
|
|
339
|
+
p: PropertyKey[] = [],
|
|
340
|
+
): string => {
|
|
341
|
+
const _errors: string[] = [];
|
|
342
|
+
|
|
343
|
+
const formatSubpath = (path: PropertyKey[], prefix: string = "") => {
|
|
344
|
+
let pp = path.join(".");
|
|
345
|
+
if (pp != "" && p.length > 0) pp = `.${pp}`;
|
|
346
|
+
if (pp != "") pp = `${prefix}${pp}`;
|
|
347
|
+
return pp;
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const addItem = (item: string) => _errors.push(indentText(item, i));
|
|
351
|
+
|
|
352
|
+
for (const issue of issues) {
|
|
353
|
+
if (issue.code === "invalid_union") {
|
|
354
|
+
addItem(`✖ Expected one of several possible values`);
|
|
355
|
+
const path = formatSubpath(issue.path, "");
|
|
356
|
+
addItem(` → at '${path}':`);
|
|
357
|
+
for (const errGrp of issue.errors) {
|
|
358
|
+
_errors.push(formatZodIssues(errGrp, `${i} `, [...p, ...issue.path]));
|
|
359
|
+
}
|
|
360
|
+
} else if (issue.code === "invalid_element" || issue.code === "invalid_key") {
|
|
361
|
+
addItem(`✖ ${issue.code.replaceAll("_", " ")}:`);
|
|
362
|
+
_errors.push(formatZodIssues(issue.issues, `${i} `, [...p, ...issue.path]));
|
|
363
|
+
} else if (issue.code === "invalid_type") {
|
|
364
|
+
const path = formatSubpath(issue.path, " ");
|
|
365
|
+
const prefix = `✖ (${issue.expected})${path}: `;
|
|
366
|
+
const msg = indentText(issue.message, Math.min(prefix.length, 20), true);
|
|
367
|
+
addItem(`${prefix}${msg}`);
|
|
368
|
+
} else {
|
|
369
|
+
const path = formatSubpath(issue.path, " ");
|
|
370
|
+
const prefix = `✖ (${issue.code.replaceAll("_", " ")})${path}: `;
|
|
371
|
+
const msg = indentText(issue.message, Math.min(prefix.length, 20), true);
|
|
372
|
+
addItem(`${prefix}${msg}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return _errors.join("\n");
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// User-facing CLI error. The top-level handler (bin/run.mjs) prints its
|
|
380
|
+
// message without a stack trace and exits non-zero.
|
|
381
|
+
export class CLIErrorClass extends Error {
|
|
382
|
+
constructor(msg: string | Error) {
|
|
383
|
+
super(typeof msg === "string" ? msg : msg.message);
|
|
384
|
+
this.name = "CLIError";
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export function CLIError(msg: string | Error): CLIErrorClass {
|
|
389
|
+
return new CLIErrorClass(msg);
|
|
390
|
+
}
|
package/src/defaults.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// This file contains default values that are part of external contract from the package-builder prospective.
|
|
2
|
+
//
|
|
3
|
+
// DO NOT CHANGE THEIR VALUES UNLESS YOU KNOW WHAT YOU ARE DOING,
|
|
4
|
+
//
|
|
5
|
+
// as these values could be used in different parts of the system (i.e. tengo code, go code of backend and so on).
|
|
6
|
+
|
|
7
|
+
// Global
|
|
8
|
+
export const BIN_REGISTRY_NAME = "platforma-open";
|
|
9
|
+
export const BIN_REGISTRY_DOWNLOAD_URL = "https://bin.pl-open.science/";
|
|
10
|
+
|
|
11
|
+
// Python
|
|
12
|
+
export const PYTHON_TOOLSET = "pip";
|
|
13
|
+
export const PYTHON_REQUIREMENTS_FILE = "requirements.txt";
|
|
14
|
+
|
|
15
|
+
export const PYTHON_DOCKER_BASE_IMAGE = "python:3.12-slim";
|
|
16
|
+
|
|
17
|
+
// Conda
|
|
18
|
+
export const CONDA_MICROMAMBA_VERSION = "2.3.2-0";
|
|
19
|
+
export const CONDA_SOURCE_ENV_SPEC_FILE = "conda-spec.yaml"; // inside git repo: what env to build in CI
|
|
20
|
+
export const CONDA_FROZEN_ENV_SPEC_FILE = "frozen-spec.yaml"; // inside built package: how to restore env on backend side
|
|
21
|
+
export const CONDA_DATA_LOCATION = "conda-env-data"; // inside built package: where MICROMAMBA_ROOT_PREFIX should point on backend side
|
|
22
|
+
|
|
23
|
+
export const CONDA_DOCKER_BASE_IMAGE = "ubuntu:22.04";
|
|
24
|
+
|
|
25
|
+
// Docker
|
|
26
|
+
export const DOCKER_REGISTRY = "containers.pl-open.science/milaboratories/pl-containers";
|
|
27
|
+
export const DOCKER_DOCKERFILE = "Dockerfile"; // inside git repo: path to Dockerfile to build by default
|
|
28
|
+
export const DOCKER_PLACEHOLDER_PKG = "/app"; // {pkg} placeholder value to by used in 'cmd' (for autogenerated docker images)
|
|
29
|
+
|
|
30
|
+
// Block-software dev pushes (pl-pkg build --dev=local) target this ECR by default.
|
|
31
|
+
// Override per-run with --docker-registry / PL_DOCKER_REGISTRY.
|
|
32
|
+
export const DEV_DOCKER_REGISTRY = "public.ecr.aws/u5p1x5q2/pl-containers";
|
|
33
|
+
|
|
34
|
+
// All docker images are built for and pushed as linux/amd64, regardless of host arch.
|
|
35
|
+
// Platforma's K8s nodes are linux/amd64; building for any other platform produces
|
|
36
|
+
// a non-runnable artifact. On non-x64 hosts the build cross-compiles via the
|
|
37
|
+
// Docker daemon's qemu emulation.
|
|
38
|
+
export const DOCKER_BUILD_PLATFORM = "linux/amd64";
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type winston from "winston";
|
|
2
|
+
import { Core } from "./core/core";
|
|
3
|
+
|
|
4
|
+
export * as util from "./core/util";
|
|
5
|
+
export * as envs from "./core/envs";
|
|
6
|
+
export * as defaults from "./defaults";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Public surface of the build engine. Derived from `Core` so signatures never
|
|
10
|
+
* drift, while the `Core` class itself stays internal (per A-0023: the engine is
|
|
11
|
+
* a library, not a half-binary with an exported orchestrator class). Consumers
|
|
12
|
+
* (`pl-pkg`, and later `block-tools software`) wrap this, they do not subclass it.
|
|
13
|
+
*/
|
|
14
|
+
export type Builder = Pick<
|
|
15
|
+
Core,
|
|
16
|
+
| "buildMode"
|
|
17
|
+
| "targetPlatform"
|
|
18
|
+
| "allPlatforms"
|
|
19
|
+
| "fullDirHash"
|
|
20
|
+
| "version"
|
|
21
|
+
| "isPrivate"
|
|
22
|
+
| "buildDockerImages"
|
|
23
|
+
| "buildSoftwareArchives"
|
|
24
|
+
| "buildSwJsonFiles"
|
|
25
|
+
| "publishPackages"
|
|
26
|
+
| "publishDockerImages"
|
|
27
|
+
>;
|
|
28
|
+
|
|
29
|
+
export function createBuilder(logger: winston.Logger, opts?: { packageRoot?: string }): Builder {
|
|
30
|
+
return new Core(logger, opts);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# No dependencies specified
|