@dagger.io/dagger 0.9.3 → 0.9.5
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/dist/api/client.gen.d.ts +323 -280
- package/dist/api/client.gen.d.ts.map +1 -1
- package/dist/api/client.gen.js +1725 -1879
- package/dist/api/utils.js +73 -90
- package/dist/common/errors/DaggerSDKError.js +5 -1
- package/dist/common/errors/DockerImageRefValidationError.js +7 -3
- package/dist/common/errors/EngineSessionConnectParamsParseError.js +6 -2
- package/dist/common/errors/EngineSessionConnectionTimeoutError.js +6 -2
- package/dist/common/errors/EngineSessionErrorOptions.js +2 -2
- package/dist/common/errors/ExecError.js +18 -2
- package/dist/common/errors/GraphQLRequestError.js +10 -2
- package/dist/common/errors/InitEngineSessionBinaryError.js +2 -2
- package/dist/common/errors/NotAwaitedRequestError.js +2 -2
- package/dist/common/errors/TooManyNestedObjectsError.js +6 -2
- package/dist/common/errors/UnknownDaggerError.js +2 -2
- package/dist/common/errors/errors-codes.js +1 -1
- package/dist/common/utils.d.ts +4 -4
- package/dist/connect.d.ts +22 -27
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +43 -49
- package/dist/connectOpts.d.ts +25 -0
- package/dist/connectOpts.d.ts.map +1 -0
- package/dist/connectOpts.js +1 -0
- package/dist/context/builder.d.ts +9 -0
- package/dist/context/builder.d.ts.map +1 -0
- package/dist/context/builder.js +34 -0
- package/dist/context/context.d.ts +39 -0
- package/dist/context/context.d.ts.map +1 -0
- package/dist/context/context.js +51 -0
- package/dist/entrypoint/entrypoint.d.ts +2 -0
- package/dist/entrypoint/entrypoint.d.ts.map +1 -0
- package/dist/entrypoint/entrypoint.js +70 -0
- package/dist/entrypoint/invoke.d.ts +11 -0
- package/dist/entrypoint/invoke.d.ts.map +1 -0
- package/dist/entrypoint/invoke.js +14 -0
- package/dist/entrypoint/load.d.ts +16 -0
- package/dist/entrypoint/load.d.ts.map +1 -0
- package/dist/entrypoint/load.js +44 -0
- package/dist/entrypoint/register.d.ts +6 -0
- package/dist/entrypoint/register.d.ts.map +1 -0
- package/dist/entrypoint/register.js +93 -0
- package/dist/graphql/client.d.ts +3 -0
- package/dist/graphql/client.d.ts.map +1 -0
- package/dist/graphql/client.js +8 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/introspector/decorators/decorators.d.ts +4 -0
- package/dist/introspector/decorators/decorators.d.ts.map +1 -0
- package/dist/introspector/decorators/decorators.js +7 -0
- package/dist/introspector/registry/registry.d.ts +65 -0
- package/dist/introspector/registry/registry.d.ts.map +1 -0
- package/dist/introspector/registry/registry.js +125 -0
- package/dist/introspector/scanner/metadata.d.ts +23 -0
- package/dist/introspector/scanner/metadata.d.ts.map +1 -0
- package/dist/introspector/scanner/metadata.js +1 -0
- package/dist/introspector/scanner/scan.d.ts +17 -0
- package/dist/introspector/scanner/scan.d.ts.map +1 -0
- package/dist/introspector/scanner/scan.js +158 -0
- package/dist/introspector/scanner/serialize.d.ts +34 -0
- package/dist/introspector/scanner/serialize.d.ts.map +1 -0
- package/dist/introspector/scanner/serialize.js +62 -0
- package/dist/introspector/scanner/typeDefs.d.ts +70 -0
- package/dist/introspector/scanner/typeDefs.d.ts.map +1 -0
- package/dist/introspector/scanner/typeDefs.js +1 -0
- package/dist/introspector/scanner/utils.d.ts +62 -0
- package/dist/introspector/scanner/utils.d.ts.map +1 -0
- package/dist/introspector/scanner/utils.js +124 -0
- package/dist/introspector/utils/files.d.ts +5 -0
- package/dist/introspector/utils/files.d.ts.map +1 -0
- package/dist/introspector/utils/files.js +28 -0
- package/dist/provisioning/bin.d.ts +5 -3
- package/dist/provisioning/bin.d.ts.map +1 -1
- package/dist/provisioning/bin.js +185 -233
- package/dist/provisioning/default.d.ts +1 -1
- package/dist/provisioning/default.js +1 -1
- package/dist/provisioning/engineconn.d.ts +6 -2
- package/dist/provisioning/engineconn.d.ts.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
import { TypeDefKind } from "../../api/client.gen.js";
|
|
3
|
+
/**
|
|
4
|
+
* Return true if the given class declaration has the decorator @obj on
|
|
5
|
+
* top of its declaration.
|
|
6
|
+
* @param object
|
|
7
|
+
*/
|
|
8
|
+
export function isObject(object) {
|
|
9
|
+
return (ts
|
|
10
|
+
.getDecorators(object)
|
|
11
|
+
?.find((d) => d.expression.getText() === "object") !== undefined);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Return true if the given method has the decorator @fct on top
|
|
15
|
+
* of its declaration.
|
|
16
|
+
*
|
|
17
|
+
* @param method The method to check
|
|
18
|
+
*/
|
|
19
|
+
export function isFunction(method) {
|
|
20
|
+
return (ts.getDecorators(method)?.find((d) => d.expression.getText() === "func") !==
|
|
21
|
+
undefined);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Return true if the given property is public.
|
|
25
|
+
*
|
|
26
|
+
* This function actually in work the reverse, it checks if the property
|
|
27
|
+
* isn't private nor protected.
|
|
28
|
+
*
|
|
29
|
+
* It returns true if the property has no modifiers since no keyword
|
|
30
|
+
* has been set on the property.
|
|
31
|
+
*
|
|
32
|
+
* Example
|
|
33
|
+
* ```
|
|
34
|
+
* class Human {
|
|
35
|
+
* private age = 22 // Return false
|
|
36
|
+
* protected familyName = "Doe" // Return false
|
|
37
|
+
*
|
|
38
|
+
* @field
|
|
39
|
+
* name = "John" // Return true
|
|
40
|
+
*
|
|
41
|
+
* city = "Paris" // Return false because there's no decorator
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @param property The property to check on.
|
|
46
|
+
*/
|
|
47
|
+
export function isPublicProperty(property) {
|
|
48
|
+
const decorators = ts.getDecorators(property);
|
|
49
|
+
if (!decorators) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
if (decorators.find((d) => d.expression.getText() === "field") === undefined) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const modifiers = ts.getModifiers(property);
|
|
56
|
+
if (!modifiers) {
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
return !modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.PrivateKeyword ||
|
|
60
|
+
modifier.kind === ts.SyntaxKind.ProtectedKeyword);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Return true if the parameter is optional.
|
|
64
|
+
*
|
|
65
|
+
* This includes both optional value defines with `?` and value that
|
|
66
|
+
* have a default value.
|
|
67
|
+
*
|
|
68
|
+
* If there's a default value, its expression is returned in the result.
|
|
69
|
+
*
|
|
70
|
+
* @param param The param to check.
|
|
71
|
+
*/
|
|
72
|
+
export function isOptional(param) {
|
|
73
|
+
const result = { optional: false };
|
|
74
|
+
const declarations = param.getDeclarations();
|
|
75
|
+
// Only check if the parameters actually have declarations
|
|
76
|
+
if (declarations && declarations.length > 0) {
|
|
77
|
+
const parameterDeclaration = declarations[0];
|
|
78
|
+
// Convert the symbol declaration into Parameter
|
|
79
|
+
if (ts.isParameter(parameterDeclaration)) {
|
|
80
|
+
result.optional =
|
|
81
|
+
parameterDeclaration.questionToken !== undefined ||
|
|
82
|
+
parameterDeclaration.initializer !== undefined;
|
|
83
|
+
if (parameterDeclaration.initializer !== undefined) {
|
|
84
|
+
result.defaultValue = formatDefaultValue(parameterDeclaration.initializer.getText());
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
function formatDefaultValue(value) {
|
|
91
|
+
const isSingleQuoteString = () => value.startsWith("'") && value.endsWith("'");
|
|
92
|
+
if (isSingleQuoteString()) {
|
|
93
|
+
return `"${value.slice(1, value.length - 1)}"`;
|
|
94
|
+
}
|
|
95
|
+
return value;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Convert a typename into a Dagger Typedef using dynamic typing.
|
|
99
|
+
*/
|
|
100
|
+
export function typeNameToTypedef(typeName) {
|
|
101
|
+
// If it's a list, remove the '[]' and recall the function to get
|
|
102
|
+
// the type of list
|
|
103
|
+
if (typeName.endsWith("[]")) {
|
|
104
|
+
return {
|
|
105
|
+
kind: TypeDefKind.Listkind,
|
|
106
|
+
typeDef: typeNameToTypedef(typeName.slice(0, typeName.length - 2)),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
switch (typeName) {
|
|
110
|
+
case "string":
|
|
111
|
+
return { kind: TypeDefKind.Stringkind };
|
|
112
|
+
case "number":
|
|
113
|
+
return { kind: TypeDefKind.Integerkind };
|
|
114
|
+
case "boolean":
|
|
115
|
+
return { kind: TypeDefKind.Booleankind };
|
|
116
|
+
case "void":
|
|
117
|
+
return { kind: TypeDefKind.Voidkind };
|
|
118
|
+
default:
|
|
119
|
+
return {
|
|
120
|
+
kind: TypeDefKind.Objectkind,
|
|
121
|
+
name: typeName,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../../introspector/utils/files.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,SAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0B5D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Extensions supported by the loader.
|
|
5
|
+
*/
|
|
6
|
+
const allowedExtensions = [".ts", ".mts"];
|
|
7
|
+
/**
|
|
8
|
+
* Returns a list of path of all files in the given directory
|
|
9
|
+
*/
|
|
10
|
+
export async function listFiles(dir = ".") {
|
|
11
|
+
const res = await Promise.all(fs.readdirSync(dir).map(async (file) => {
|
|
12
|
+
const filepath = path.join(dir, file);
|
|
13
|
+
// Ignore node_modules and transpiled typescript
|
|
14
|
+
if (filepath.includes("node_modules") || filepath.includes("dist")) {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
const stat = fs.statSync(filepath);
|
|
18
|
+
if (stat.isDirectory()) {
|
|
19
|
+
return await listFiles(filepath);
|
|
20
|
+
}
|
|
21
|
+
const ext = path.extname(filepath);
|
|
22
|
+
if (allowedExtensions.find((allowedExt) => allowedExt === ext)) {
|
|
23
|
+
return [`${dir}/${file}`];
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}));
|
|
27
|
+
return res.reduce((p, c) => [...c, ...p], []);
|
|
28
|
+
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExecaChildProcess } from "execa";
|
|
2
|
+
import { GraphQLClient } from "graphql-request";
|
|
2
3
|
import { ConnectOpts, EngineConn } from "./engineconn.js";
|
|
3
4
|
/**
|
|
4
5
|
* Bin runs an engine session from a specified binary
|
|
5
6
|
*/
|
|
6
7
|
export declare class Bin implements EngineConn {
|
|
7
|
-
private
|
|
8
|
+
private _subProcess?;
|
|
8
9
|
private binPath?;
|
|
9
10
|
private cliVersion?;
|
|
10
11
|
private readonly cacheDir;
|
|
11
12
|
private readonly DAGGER_CLI_BIN_PREFIX;
|
|
12
13
|
constructor(binPath?: string, cliVersion?: string);
|
|
13
14
|
Addr(): string;
|
|
14
|
-
|
|
15
|
+
get subProcess(): ExecaChildProcess | undefined;
|
|
16
|
+
Connect(opts: ConnectOpts): Promise<GraphQLClient>;
|
|
15
17
|
private downloadCLI;
|
|
16
18
|
/**
|
|
17
19
|
* Traverse up the directory tree to find the package.json file and return the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../provisioning/bin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../../provisioning/bin.ts"],"names":[],"mappings":"AAGA,OAAO,EAAgB,iBAAiB,EAAE,MAAM,OAAO,CAAA;AAEvD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAgB/C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAA;AAMxE;;GAEG;AACH,qBAAa,GAAI,YAAW,UAAU;IACpC,OAAO,CAAC,WAAW,CAAC,CAAmB;IAEvC,OAAO,CAAC,OAAO,CAAC,CAAQ;IACxB,OAAO,CAAC,UAAU,CAAC,CAAQ;IAE3B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAKxB;IAED,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAW;gBAErC,OAAO,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;IAKjD,IAAI,IAAI,MAAM;IAId,IAAI,UAAU,IAAI,iBAAiB,GAAG,SAAS,CAE9C;IAEK,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;YAgB1C,WAAW;IAgEzB;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAqBrB;;;OAGG;YACW,gBAAgB;YAqEhB,iBAAiB;IA2BzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAU5B;;;;;;;OAOG;IACH,OAAO,CAAC,cAAc;IAItB;;;;;OAKG;IACH,OAAO,CAAC,YAAY;IAOpB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAStB;;OAEG;IACH,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;YAOR,WAAW;YAkBX,gBAAgB;YAWhB,cAAc;IA4C5B;;OAEG;IACH,OAAO,CAAC,WAAW;CAGpB;AAGD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEjD;AAGD,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAE1D"}
|
package/dist/provisioning/bin.js
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
11
|
-
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
12
|
-
var m = o[Symbol.asyncIterator], i;
|
|
13
|
-
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
14
|
-
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
15
|
-
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
16
|
-
};
|
|
17
1
|
import AdmZip from "adm-zip";
|
|
18
2
|
import * as crypto from "crypto";
|
|
19
3
|
import envPaths from "env-paths";
|
|
@@ -26,8 +10,8 @@ import * as process from "process";
|
|
|
26
10
|
import readline from "readline";
|
|
27
11
|
import * as tar from "tar";
|
|
28
12
|
import { fileURLToPath } from "url";
|
|
29
|
-
import { Client } from "../api/client.gen.js";
|
|
30
13
|
import { EngineSessionConnectionTimeoutError, EngineSessionConnectParamsParseError, EngineSessionError, InitEngineSessionBinaryError, } from "../common/errors/index.js";
|
|
14
|
+
import { createGQLClient } from "../graphql/client.js";
|
|
31
15
|
const CLI_HOST = "dl.dagger.io";
|
|
32
16
|
let OVERRIDE_CLI_URL;
|
|
33
17
|
let OVERRIDE_CHECKSUMS_URL;
|
|
@@ -35,75 +19,76 @@ let OVERRIDE_CHECKSUMS_URL;
|
|
|
35
19
|
* Bin runs an engine session from a specified binary
|
|
36
20
|
*/
|
|
37
21
|
export class Bin {
|
|
22
|
+
_subProcess;
|
|
23
|
+
binPath;
|
|
24
|
+
cliVersion;
|
|
25
|
+
cacheDir = path.join(`${process.env.XDG_CACHE_HOME?.trim() || envPaths("", { suffix: "" }).cache}`, "dagger");
|
|
26
|
+
DAGGER_CLI_BIN_PREFIX = "dagger";
|
|
38
27
|
constructor(binPath, cliVersion) {
|
|
39
|
-
var _a;
|
|
40
|
-
this.cacheDir = path.join(`${((_a = process.env.XDG_CACHE_HOME) === null || _a === void 0 ? void 0 : _a.trim()) || envPaths("", { suffix: "" }).cache}`, "dagger");
|
|
41
|
-
this.DAGGER_CLI_BIN_PREFIX = "dagger";
|
|
42
28
|
this.binPath = binPath;
|
|
43
29
|
this.cliVersion = cliVersion;
|
|
44
30
|
}
|
|
45
31
|
Addr() {
|
|
46
32
|
return "http://dagger";
|
|
47
33
|
}
|
|
48
|
-
|
|
49
|
-
return
|
|
50
|
-
if (!this.binPath) {
|
|
51
|
-
if (opts.LogOutput) {
|
|
52
|
-
opts.LogOutput.write("Downloading CLI... ");
|
|
53
|
-
}
|
|
54
|
-
this.binPath = yield this.downloadCLI();
|
|
55
|
-
if (opts.LogOutput) {
|
|
56
|
-
opts.LogOutput.write("OK!\n");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return this.runEngineSession(this.binPath, opts);
|
|
60
|
-
});
|
|
34
|
+
get subProcess() {
|
|
35
|
+
return this._subProcess;
|
|
61
36
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
if (
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
const binPath = this.buildBinPath();
|
|
68
|
-
// Create a temporary bin file path
|
|
69
|
-
this.createCacheDir();
|
|
70
|
-
const tmpBinDownloadDir = fs.mkdtempSync(path.join(this.cacheDir, `temp-${this.getRandomId()}`));
|
|
71
|
-
const tmpBinPath = this.buildOsExePath(tmpBinDownloadDir, this.DAGGER_CLI_BIN_PREFIX);
|
|
72
|
-
try {
|
|
73
|
-
// download an archive and use appropriate extraction depending on platforms (zip on windows, tar.gz on other platforms)
|
|
74
|
-
const actualChecksum = yield this.extractArchive(tmpBinDownloadDir, this.normalizedOS());
|
|
75
|
-
const expectedChecksum = yield this.expectedChecksum();
|
|
76
|
-
if (actualChecksum !== expectedChecksum) {
|
|
77
|
-
throw new Error(`checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`);
|
|
78
|
-
}
|
|
79
|
-
fs.chmodSync(tmpBinPath, 0o700);
|
|
80
|
-
fs.renameSync(tmpBinPath, binPath);
|
|
81
|
-
fs.rmSync(tmpBinDownloadDir, { recursive: true });
|
|
82
|
-
}
|
|
83
|
-
catch (e) {
|
|
84
|
-
fs.rmSync(tmpBinDownloadDir, { recursive: true });
|
|
85
|
-
throw new InitEngineSessionBinaryError(`failed to download dagger cli binary: ${e}`, { cause: e });
|
|
37
|
+
async Connect(opts) {
|
|
38
|
+
if (!this.binPath) {
|
|
39
|
+
if (opts.LogOutput) {
|
|
40
|
+
opts.LogOutput.write("Downloading CLI... ");
|
|
86
41
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
const files = fs.readdirSync(this.cacheDir);
|
|
92
|
-
files.forEach((file) => {
|
|
93
|
-
const filePath = path.join(this.cacheDir, file);
|
|
94
|
-
if (filePath === binPath ||
|
|
95
|
-
!file.startsWith(this.DAGGER_CLI_BIN_PREFIX)) {
|
|
96
|
-
return;
|
|
97
|
-
}
|
|
98
|
-
fs.unlinkSync(filePath);
|
|
99
|
-
});
|
|
42
|
+
this.binPath = await this.downloadCLI();
|
|
43
|
+
if (opts.LogOutput) {
|
|
44
|
+
opts.LogOutput.write("OK!\n");
|
|
100
45
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
46
|
+
}
|
|
47
|
+
return this.runEngineSession(this.binPath, opts);
|
|
48
|
+
}
|
|
49
|
+
async downloadCLI() {
|
|
50
|
+
if (!this.cliVersion) {
|
|
51
|
+
throw new Error("cliVersion is not set");
|
|
52
|
+
}
|
|
53
|
+
const binPath = this.buildBinPath();
|
|
54
|
+
// Create a temporary bin file path
|
|
55
|
+
this.createCacheDir();
|
|
56
|
+
const tmpBinDownloadDir = fs.mkdtempSync(path.join(this.cacheDir, `temp-${this.getRandomId()}`));
|
|
57
|
+
const tmpBinPath = this.buildOsExePath(tmpBinDownloadDir, this.DAGGER_CLI_BIN_PREFIX);
|
|
58
|
+
try {
|
|
59
|
+
// download an archive and use appropriate extraction depending on platforms (zip on windows, tar.gz on other platforms)
|
|
60
|
+
const actualChecksum = await this.extractArchive(tmpBinDownloadDir, this.normalizedOS());
|
|
61
|
+
const expectedChecksum = await this.expectedChecksum();
|
|
62
|
+
if (actualChecksum !== expectedChecksum) {
|
|
63
|
+
throw new Error(`checksum mismatch: expected ${expectedChecksum}, got ${actualChecksum}`);
|
|
104
64
|
}
|
|
105
|
-
|
|
106
|
-
|
|
65
|
+
fs.chmodSync(tmpBinPath, 0o700);
|
|
66
|
+
fs.renameSync(tmpBinPath, binPath);
|
|
67
|
+
fs.rmSync(tmpBinDownloadDir, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
fs.rmSync(tmpBinDownloadDir, { recursive: true });
|
|
71
|
+
throw new InitEngineSessionBinaryError(`failed to download dagger cli binary: ${e}`, { cause: e });
|
|
72
|
+
}
|
|
73
|
+
// Remove all temporary binary files
|
|
74
|
+
// Ignore current dagger cli or other files that have not be
|
|
75
|
+
// created by this SDK.
|
|
76
|
+
try {
|
|
77
|
+
const files = fs.readdirSync(this.cacheDir);
|
|
78
|
+
files.forEach((file) => {
|
|
79
|
+
const filePath = path.join(this.cacheDir, file);
|
|
80
|
+
if (filePath === binPath ||
|
|
81
|
+
!file.startsWith(this.DAGGER_CLI_BIN_PREFIX)) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
fs.unlinkSync(filePath);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
// Log the error but do not interrupt program.
|
|
89
|
+
console.error("could not clean up temporary binary files");
|
|
90
|
+
}
|
|
91
|
+
return binPath;
|
|
107
92
|
}
|
|
108
93
|
/**
|
|
109
94
|
* Traverse up the directory tree to find the package.json file and return the
|
|
@@ -135,108 +120,82 @@ export class Bin {
|
|
|
135
120
|
* runEngineSession execute the engine binary and set up a GraphQL client that
|
|
136
121
|
* target this engine.
|
|
137
122
|
*/
|
|
138
|
-
runEngineSession(binPath, opts) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
if (pair.value) {
|
|
151
|
-
args.push(pair.flag, pair.value);
|
|
152
|
-
}
|
|
153
|
-
});
|
|
154
|
-
if (opts.LogOutput) {
|
|
155
|
-
opts.LogOutput.write("Creating new Engine session... ");
|
|
156
|
-
}
|
|
157
|
-
this.subProcess = execaCommand(args.join(" "), {
|
|
158
|
-
stdio: "pipe",
|
|
159
|
-
reject: true,
|
|
160
|
-
// Kill the process if parent exit.
|
|
161
|
-
cleanup: true,
|
|
162
|
-
});
|
|
163
|
-
// Log the output if the user wants to.
|
|
164
|
-
if (opts.LogOutput) {
|
|
165
|
-
(_a = this.subProcess.stderr) === null || _a === void 0 ? void 0 : _a.pipe(opts.LogOutput);
|
|
166
|
-
}
|
|
167
|
-
const stdoutReader = readline.createInterface({
|
|
168
|
-
input: (_b = this.subProcess) === null || _b === void 0 ? void 0 : _b.stdout,
|
|
169
|
-
});
|
|
170
|
-
const timeOutDuration = 300000;
|
|
171
|
-
if (opts.LogOutput) {
|
|
172
|
-
opts.LogOutput.write("OK!\nEstablishing connection to Engine... ");
|
|
123
|
+
async runEngineSession(binPath, opts) {
|
|
124
|
+
const args = [binPath, "session"];
|
|
125
|
+
const sdkVersion = this.getSDKVersion();
|
|
126
|
+
const flagsAndValues = [
|
|
127
|
+
{ flag: "--workdir", value: opts.Workdir },
|
|
128
|
+
{ flag: "--project", value: opts.Project },
|
|
129
|
+
{ flag: "--label", value: "dagger.io/sdk.name:nodejs" },
|
|
130
|
+
{ flag: "--label", value: `dagger.io/sdk.version:${sdkVersion}` },
|
|
131
|
+
];
|
|
132
|
+
flagsAndValues.forEach((pair) => {
|
|
133
|
+
if (pair.value) {
|
|
134
|
+
args.push(pair.flag, pair.value);
|
|
173
135
|
}
|
|
174
|
-
const connectParams = (yield Promise.race([
|
|
175
|
-
this.readConnectParams(stdoutReader),
|
|
176
|
-
new Promise((_, reject) => {
|
|
177
|
-
setTimeout(() => {
|
|
178
|
-
reject(new EngineSessionConnectionTimeoutError("Engine connection timeout", { timeOutDuration }));
|
|
179
|
-
}, timeOutDuration).unref(); // long timeout to account for extensions, though that should be optimized in future
|
|
180
|
-
}),
|
|
181
|
-
]));
|
|
182
|
-
if (opts.LogOutput) {
|
|
183
|
-
opts.LogOutput.write("OK!\n");
|
|
184
|
-
}
|
|
185
|
-
return new Client({
|
|
186
|
-
host: `127.0.0.1:${connectParams.port}`,
|
|
187
|
-
sessionToken: connectParams.session_token,
|
|
188
|
-
});
|
|
189
136
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
_d = stdoutReader_1_1.value;
|
|
199
|
-
_a = false;
|
|
200
|
-
const line = _d;
|
|
201
|
-
// parse the the line as json-encoded connect params
|
|
202
|
-
const connectParams = JSON.parse(line);
|
|
203
|
-
if (connectParams.port && connectParams.session_token) {
|
|
204
|
-
return connectParams;
|
|
205
|
-
}
|
|
206
|
-
throw new EngineSessionConnectParamsParseError(`invalid connect params: ${line}`, { parsedLine: line });
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
210
|
-
finally {
|
|
211
|
-
try {
|
|
212
|
-
if (!_a && !_b && (_c = stdoutReader_1.return)) yield _c.call(stdoutReader_1);
|
|
213
|
-
}
|
|
214
|
-
finally { if (e_1) throw e_1.error; }
|
|
215
|
-
}
|
|
216
|
-
// Need to find a better way to handle this part
|
|
217
|
-
// At this stage something wrong happened, `for await` didn't return anything
|
|
218
|
-
// await the subprocess to catch the error
|
|
219
|
-
try {
|
|
220
|
-
yield this.subProcess;
|
|
221
|
-
}
|
|
222
|
-
catch (_f) {
|
|
223
|
-
(_e = this.subProcess) === null || _e === void 0 ? void 0 : _e.catch((e) => {
|
|
224
|
-
throw new EngineSessionError(e.stderr);
|
|
225
|
-
});
|
|
226
|
-
}
|
|
137
|
+
if (opts.LogOutput) {
|
|
138
|
+
opts.LogOutput.write("Creating new Engine session... ");
|
|
139
|
+
}
|
|
140
|
+
this._subProcess = execaCommand(args.join(" "), {
|
|
141
|
+
stdio: "pipe",
|
|
142
|
+
reject: true,
|
|
143
|
+
// Kill the process if parent exit.
|
|
144
|
+
cleanup: true,
|
|
227
145
|
});
|
|
146
|
+
// Log the output if the user wants to.
|
|
147
|
+
if (opts.LogOutput) {
|
|
148
|
+
this._subProcess.stderr?.pipe(opts.LogOutput);
|
|
149
|
+
}
|
|
150
|
+
const stdoutReader = readline.createInterface({
|
|
151
|
+
input: this._subProcess?.stdout,
|
|
152
|
+
});
|
|
153
|
+
const timeOutDuration = 300000;
|
|
154
|
+
if (opts.LogOutput) {
|
|
155
|
+
opts.LogOutput.write("OK!\nEstablishing connection to Engine... ");
|
|
156
|
+
}
|
|
157
|
+
const connectParams = (await Promise.race([
|
|
158
|
+
this.readConnectParams(stdoutReader),
|
|
159
|
+
new Promise((_, reject) => {
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
reject(new EngineSessionConnectionTimeoutError("Engine connection timeout", { timeOutDuration }));
|
|
162
|
+
}, timeOutDuration).unref(); // long timeout to account for extensions, though that should be optimized in future
|
|
163
|
+
}),
|
|
164
|
+
]));
|
|
165
|
+
if (opts.LogOutput) {
|
|
166
|
+
opts.LogOutput.write("OK!\n");
|
|
167
|
+
}
|
|
168
|
+
return createGQLClient(connectParams.port, connectParams.session_token);
|
|
228
169
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// which currently has to happen synchronously with the session.
|
|
236
|
-
forceKillAfterTimeout: 300000, // 5 mins
|
|
237
|
-
});
|
|
170
|
+
async readConnectParams(stdoutReader) {
|
|
171
|
+
for await (const line of stdoutReader) {
|
|
172
|
+
// parse the the line as json-encoded connect params
|
|
173
|
+
const connectParams = JSON.parse(line);
|
|
174
|
+
if (connectParams.port && connectParams.session_token) {
|
|
175
|
+
return connectParams;
|
|
238
176
|
}
|
|
239
|
-
|
|
177
|
+
throw new EngineSessionConnectParamsParseError(`invalid connect params: ${line}`, { parsedLine: line });
|
|
178
|
+
}
|
|
179
|
+
// Need to find a better way to handle this part
|
|
180
|
+
// At this stage something wrong happened, `for await` didn't return anything
|
|
181
|
+
// await the subprocess to catch the error
|
|
182
|
+
try {
|
|
183
|
+
await this.subProcess;
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
this.subProcess?.catch((e) => {
|
|
187
|
+
throw new EngineSessionError(e.stderr);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
async Close() {
|
|
192
|
+
if (this.subProcess?.pid) {
|
|
193
|
+
this.subProcess.kill("SIGTERM", {
|
|
194
|
+
// Set a long timeout to give time for any cache exports to pack layers up
|
|
195
|
+
// which currently has to happen synchronously with the session.
|
|
196
|
+
forceKillAfterTimeout: 300000, // 5 mins
|
|
197
|
+
});
|
|
198
|
+
}
|
|
240
199
|
}
|
|
241
200
|
/**
|
|
242
201
|
* createCacheDir will create a cache directory on user
|
|
@@ -314,70 +273,63 @@ export class Bin {
|
|
|
314
273
|
}
|
|
315
274
|
return `https://${CLI_HOST}/dagger/releases/${this.cliVersion}/checksums.txt`;
|
|
316
275
|
}
|
|
317
|
-
checksumMap() {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
return checksumMap;
|
|
332
|
-
});
|
|
276
|
+
async checksumMap() {
|
|
277
|
+
// download checksums.txt
|
|
278
|
+
const checksums = await fetch(this.cliChecksumURL());
|
|
279
|
+
if (!checksums.ok) {
|
|
280
|
+
throw new Error(`failed to download checksums.txt from ${this.cliChecksumURL()}`);
|
|
281
|
+
}
|
|
282
|
+
const checksumsText = await checksums.text();
|
|
283
|
+
// iterate over lines filling in map of filename -> checksum
|
|
284
|
+
const checksumMap = new Map();
|
|
285
|
+
for (const line of checksumsText.split("\n")) {
|
|
286
|
+
const [checksum, filename] = line.split(/\s+/);
|
|
287
|
+
checksumMap.set(filename, checksum);
|
|
288
|
+
}
|
|
289
|
+
return checksumMap;
|
|
333
290
|
}
|
|
334
|
-
expectedChecksum() {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return expectedChecksum;
|
|
342
|
-
});
|
|
291
|
+
async expectedChecksum() {
|
|
292
|
+
const checksumMap = await this.checksumMap();
|
|
293
|
+
const expectedChecksum = checksumMap.get(this.cliArchiveName());
|
|
294
|
+
if (!expectedChecksum) {
|
|
295
|
+
throw new Error(`failed to find checksum for ${this.cliArchiveName()} in checksums.txt`);
|
|
296
|
+
}
|
|
297
|
+
return expectedChecksum;
|
|
343
298
|
}
|
|
344
|
-
extractArchive(destDir, os) {
|
|
345
|
-
return
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
(_b = archiveResp.body) === null || _b === void 0 ? void 0 : _b.on("error", reject);
|
|
361
|
-
archiveFile.on("finish", resolve);
|
|
362
|
-
});
|
|
363
|
-
const actualChecksum = crypto
|
|
364
|
-
.createHash("sha256")
|
|
365
|
-
.update(fs.readFileSync(archivePath))
|
|
366
|
-
.digest("hex");
|
|
367
|
-
if (os === "windows") {
|
|
368
|
-
const zip = new AdmZip(archivePath);
|
|
369
|
-
// extract just dagger.exe to the destdir
|
|
370
|
-
zip.extractEntryTo("dagger.exe", destDir, false, true);
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
tar.extract({
|
|
374
|
-
cwd: destDir,
|
|
375
|
-
file: archivePath,
|
|
376
|
-
sync: true,
|
|
377
|
-
});
|
|
378
|
-
}
|
|
379
|
-
return actualChecksum;
|
|
299
|
+
async extractArchive(destDir, os) {
|
|
300
|
+
// extract the dagger binary in the cli archive and return the archive of the .zip for windows and .tar.gz for other plateforms
|
|
301
|
+
const archiveResp = await fetch(this.cliArchiveURL());
|
|
302
|
+
if (!archiveResp.ok) {
|
|
303
|
+
throw new Error(`failed to download dagger cli archive from ${this.cliArchiveURL()}`);
|
|
304
|
+
}
|
|
305
|
+
if (!archiveResp.body) {
|
|
306
|
+
throw new Error("archive response body is null");
|
|
307
|
+
}
|
|
308
|
+
// create a temporary file to store the archive
|
|
309
|
+
const archivePath = path.join(destDir, os === "windows" ? "dagger.zip" : "dagger.tar.gz");
|
|
310
|
+
const archiveFile = fs.createWriteStream(archivePath);
|
|
311
|
+
await new Promise((resolve, reject) => {
|
|
312
|
+
archiveResp.body?.pipe(archiveFile);
|
|
313
|
+
archiveResp.body?.on("error", reject);
|
|
314
|
+
archiveFile.on("finish", resolve);
|
|
380
315
|
});
|
|
316
|
+
const actualChecksum = crypto
|
|
317
|
+
.createHash("sha256")
|
|
318
|
+
.update(fs.readFileSync(archivePath))
|
|
319
|
+
.digest("hex");
|
|
320
|
+
if (os === "windows") {
|
|
321
|
+
const zip = new AdmZip(archivePath);
|
|
322
|
+
// extract just dagger.exe to the destdir
|
|
323
|
+
zip.extractEntryTo("dagger.exe", destDir, false, true);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
tar.extract({
|
|
327
|
+
cwd: destDir,
|
|
328
|
+
file: archivePath,
|
|
329
|
+
sync: true,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
return actualChecksum;
|
|
381
333
|
}
|
|
382
334
|
/**
|
|
383
335
|
* Generate a unix timestamp in nanosecond
|