containerify 3.2.1 → 3.3.2
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/lib/appLayerCreator.d.ts +2 -2
- package/lib/appLayerCreator.js +27 -34
- package/lib/cli.js +7 -3
- package/lib/httpRequest.js +9 -5
- package/lib/registry.js +10 -5
- package/lib/types.d.ts +2 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +3 -3
package/lib/appLayerCreator.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Options } from "./types";
|
|
2
|
-
declare function addLayers(tmpdir: string, fromdir: string, todir: string, options: Options): Promise<
|
|
1
|
+
import { ManifestDescriptor, Options } from "./types";
|
|
2
|
+
declare function addLayers(tmpdir: string, fromdir: string, todir: string, options: Options): Promise<ManifestDescriptor>;
|
|
3
3
|
declare const _default: {
|
|
4
4
|
addLayers: typeof addLayers;
|
|
5
5
|
};
|
package/lib/appLayerCreator.js
CHANGED
|
@@ -22,39 +22,25 @@ const utils_1 = require("./utils");
|
|
|
22
22
|
const version_1 = require("./version");
|
|
23
23
|
const depLayerPossibles = ["package.json", "package-lock.json", "node_modules"];
|
|
24
24
|
const ignore = [".git", ".gitignore", ".npmrc", ".DS_Store", "npm-debug.log", ".svn", ".hg", "CVS"];
|
|
25
|
-
function
|
|
25
|
+
function createOnWriteEntry(layerOwner) {
|
|
26
26
|
if (!layerOwner)
|
|
27
|
-
return
|
|
28
|
-
// We use
|
|
29
|
-
//
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
stat.birthtime = new Date(0);
|
|
45
|
-
stat.atimeMs = 0;
|
|
46
|
-
stat.mtimeMs = 0;
|
|
47
|
-
stat.ctimeMs = 0;
|
|
48
|
-
stat.birthtimeMs = 0;
|
|
49
|
-
statCacheMap.set(name, stat);
|
|
50
|
-
return stat;
|
|
51
|
-
},
|
|
52
|
-
set: function (name, stat) {
|
|
53
|
-
statCacheMap.set(name, stat);
|
|
54
|
-
},
|
|
55
|
-
has: function () {
|
|
56
|
-
return true;
|
|
57
|
-
},
|
|
27
|
+
return undefined;
|
|
28
|
+
// We use onWriteEntry to overwrite uid and gid in the tar archive
|
|
29
|
+
// Format is already validated in cli.ts to be "gid:uid"
|
|
30
|
+
const parts = layerOwner.split(":");
|
|
31
|
+
const gid = parseInt(parts[0], 10);
|
|
32
|
+
const uid = parseInt(parts[1], 10);
|
|
33
|
+
return (entry) => {
|
|
34
|
+
if (entry.header) {
|
|
35
|
+
entry.header.uid = uid;
|
|
36
|
+
entry.header.gid = gid;
|
|
37
|
+
entry.header.uname = "";
|
|
38
|
+
entry.header.gname = "";
|
|
39
|
+
// Set all timestamps to epoch to match original behavior
|
|
40
|
+
entry.header.atime = new Date(0);
|
|
41
|
+
entry.header.mtime = new Date(0);
|
|
42
|
+
entry.header.ctime = new Date(0);
|
|
43
|
+
}
|
|
58
44
|
};
|
|
59
45
|
}
|
|
60
46
|
const tarDefaultConfig = {
|
|
@@ -127,7 +113,7 @@ function addDataLayer(tmpdir, todir, options, config, manifest, files, comment)
|
|
|
127
113
|
comment +
|
|
128
114
|
(comment == "dependencies" ? ". Did you forget to run npm install?" : ""));
|
|
129
115
|
}
|
|
130
|
-
yield tar.create(Object.assign(Object.assign({}, tarDefaultConfig), Object.assign({
|
|
116
|
+
yield tar.create(Object.assign(Object.assign({}, tarDefaultConfig), Object.assign({ onWriteEntry: createOnWriteEntry(options.layerOwner), portable: !options.layerOwner, prefix: "/", cwd: buildDir, file: layerFile, gzip: true, noMtime: !(options.setTimeStamp || options.preserveTimeStamp) }, (options.setTimeStamp ? { mtime: new Date(options.setTimeStamp) } : {}))), filesToTar);
|
|
131
117
|
const fhash = yield calculateHash(layerFile);
|
|
132
118
|
const finalName = path.join(todir, fhash + ".tar.gz");
|
|
133
119
|
yield fse.move(layerFile, finalName);
|
|
@@ -253,7 +239,14 @@ function addLayers(tmpdir, fromdir, todir, options) {
|
|
|
253
239
|
yield fs_1.promises.writeFile(configFile, configContent);
|
|
254
240
|
manifest.config.digest = "sha256:" + configHash;
|
|
255
241
|
manifest.config.size = yield fileutil.sizeOf(configFile);
|
|
256
|
-
|
|
242
|
+
const manifestJson = JSON.stringify(manifest);
|
|
243
|
+
yield fs_1.promises.writeFile(path.join(todir, "manifest.json"), manifestJson);
|
|
244
|
+
const manifestBuffer = Buffer.from(manifestJson, "utf-8");
|
|
245
|
+
return {
|
|
246
|
+
mediaType: manifest.mediaType,
|
|
247
|
+
digest: calculateHashOfBuffer(manifestBuffer),
|
|
248
|
+
size: manifestBuffer.byteLength,
|
|
249
|
+
};
|
|
257
250
|
});
|
|
258
251
|
}
|
|
259
252
|
exports.default = {
|
package/lib/cli.js
CHANGED
|
@@ -61,6 +61,7 @@ program
|
|
|
61
61
|
.option("--layerOwner <gid:uid>", "Optional: Set specific gid and uid on files in the added layers")
|
|
62
62
|
.option("--buildFolder <path>", "Optional: Use a specific build folder when creating the image")
|
|
63
63
|
.option("--layerCacheFolder <path>", "Optional: Folder to cache base layers between builds")
|
|
64
|
+
.option("--writeDigestTo <path>", "Optional: Write the resulting image digest to the file path provided")
|
|
64
65
|
.version(version_1.VERSION, "--version", "Get containerify version");
|
|
65
66
|
program.parse(process.argv);
|
|
66
67
|
function setKeyValue(target, keyValue, separator = "=", defaultValue) {
|
|
@@ -96,7 +97,6 @@ const labels = Object.assign(Object.assign({}, configFromFile.labels), labelsOpt
|
|
|
96
97
|
const envOpt = {};
|
|
97
98
|
(_b = cliOptions.envs) === null || _b === void 0 ? void 0 : _b.forEach((envs) => envs.split(",").forEach((env) => setKeyValue(envOpt, env)));
|
|
98
99
|
const envs = Object.assign(Object.assign({}, configFromFile.envs), envOpt); //Let cli arguments override file
|
|
99
|
-
console.log(envs);
|
|
100
100
|
const customContent = {};
|
|
101
101
|
(_c = configFromFile.customContent) === null || _c === void 0 ? void 0 : _c.forEach((c) => setKeyValue(customContent, c, ":", c));
|
|
102
102
|
(_d = cliOptions.customContent) === null || _d === void 0 ? void 0 : _d.forEach((contents) => contents.split(",").forEach((content) => setKeyValue(customContent, content, ":", content)));
|
|
@@ -118,7 +118,7 @@ const options = Object.assign(Object.assign(Object.assign({}, defaultOptions), s
|
|
|
118
118
|
user: setOptions.user,
|
|
119
119
|
workdir: setOptions.workdir,
|
|
120
120
|
entrypoint: setOptions.entrypoint,
|
|
121
|
-
} });
|
|
121
|
+
}, writeDigestTo: cliOptions.writeDigestTo });
|
|
122
122
|
function exitWithErrorIf(check, error) {
|
|
123
123
|
if (check) {
|
|
124
124
|
logger_1.default.error("ERROR: " + error);
|
|
@@ -214,7 +214,7 @@ function run(options) {
|
|
|
214
214
|
const fromRegistryUrl = (_a = options.fromRegistry) !== null && _a !== void 0 ? _a : registry_1.DEFAULT_DOCKER_REGISTRY;
|
|
215
215
|
const fromRegistry = yield (0, registry_1.createRegistry)(fromRegistryUrl, options.fromImage, allowInsecure, options.fromToken);
|
|
216
216
|
const originalManifest = yield fromRegistry.download(options.fromImage, fromdir, (0, utils_1.getPreferredPlatform)(options.platform), options.layerCacheFolder);
|
|
217
|
-
yield appLayerCreator_1.default.addLayers(tmpdir, fromdir, todir, options);
|
|
217
|
+
const manifestDescriptor = yield appLayerCreator_1.default.addLayers(tmpdir, fromdir, todir, options);
|
|
218
218
|
if (options.toDocker) {
|
|
219
219
|
if (!(yield dockerExporter_1.default.isAvailable())) {
|
|
220
220
|
throw new Error("Docker executable not found on path. Unable to export to local docker registry.");
|
|
@@ -233,6 +233,10 @@ function run(options) {
|
|
|
233
233
|
logger_1.default.debug(`Deleting ${tmpdir} ...`);
|
|
234
234
|
yield fse.remove(tmpdir);
|
|
235
235
|
logger_1.default.debug("Done");
|
|
236
|
+
if (options.writeDigestTo) {
|
|
237
|
+
logger_1.default.debug(`Writing digest ${manifestDescriptor.digest} to ${options.writeDigestTo}`);
|
|
238
|
+
fs.writeFileSync(options.writeDigestTo, manifestDescriptor.digest);
|
|
239
|
+
}
|
|
236
240
|
});
|
|
237
241
|
}
|
|
238
242
|
logger_1.default.debug("Running with config:", options);
|
package/lib/httpRequest.js
CHANGED
|
@@ -20,7 +20,6 @@ exports.dlJson = dlJson;
|
|
|
20
20
|
exports.followRedirects = followRedirects;
|
|
21
21
|
const https = require("https");
|
|
22
22
|
const http = require("http");
|
|
23
|
-
const URL = require("url");
|
|
24
23
|
const logger_1 = require("./logger");
|
|
25
24
|
const types_1 = require("./types");
|
|
26
25
|
exports.redirectCodes = [308, 307, 303, 302, 301];
|
|
@@ -28,9 +27,15 @@ function isOk(httpStatus) {
|
|
|
28
27
|
return httpStatus >= 200 && httpStatus < 300;
|
|
29
28
|
}
|
|
30
29
|
function createHttpOptions(method, url, headers) {
|
|
31
|
-
const
|
|
32
|
-
options
|
|
33
|
-
|
|
30
|
+
const parsedUrl = new URL(url);
|
|
31
|
+
const options = {
|
|
32
|
+
protocol: parsedUrl.protocol,
|
|
33
|
+
hostname: parsedUrl.hostname,
|
|
34
|
+
port: parsedUrl.port,
|
|
35
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
36
|
+
headers: headers,
|
|
37
|
+
method: method,
|
|
38
|
+
};
|
|
34
39
|
if (url.includes("X-Amz-Algorithm") && method == "GET") {
|
|
35
40
|
//We are using a pre-signed URL, so we don't need to send the Authorization header
|
|
36
41
|
options.headers["Authorization"] = "";
|
|
@@ -101,7 +106,6 @@ function followRedirects(uri, headers, allowInsecure, cb, count = 0) {
|
|
|
101
106
|
if (count > 10)
|
|
102
107
|
return cb({ error: "Too many redirects for " + uri });
|
|
103
108
|
const location = res.headers.location;
|
|
104
|
-
console.log(res.headers);
|
|
105
109
|
if (!location)
|
|
106
110
|
return cb({ error: "Redirect, but missing location header" });
|
|
107
111
|
return followRedirects(location, headers, allowInsecure, cb, count + 1);
|
package/lib/registry.js
CHANGED
|
@@ -12,7 +12,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.DEFAULT_DOCKER_REGISTRY = void 0;
|
|
13
13
|
exports.createRegistry = createRegistry;
|
|
14
14
|
exports.parseFullImageUrl = parseFullImageUrl;
|
|
15
|
-
const URL = require("url");
|
|
16
15
|
const fss = require("fs");
|
|
17
16
|
const fs_1 = require("fs");
|
|
18
17
|
const path = require("path");
|
|
@@ -130,7 +129,7 @@ function uploadContent(uploadUrl, file, fileConfig, allowInsecure, auth, content
|
|
|
130
129
|
}
|
|
131
130
|
function processToken(registryBaseUrl, allowInsecure, imagePath, token) {
|
|
132
131
|
return __awaiter(this, void 0, void 0, function* () {
|
|
133
|
-
const { hostname } = new URL
|
|
132
|
+
const { hostname } = new URL(registryBaseUrl);
|
|
134
133
|
const image = (0, utils_1.parseImage)(imagePath);
|
|
135
134
|
if ((hostname === null || hostname === void 0 ? void 0 : hostname.endsWith(".docker.io")) && !token)
|
|
136
135
|
return getDockerToken(image.path, allowInsecure);
|
|
@@ -182,8 +181,14 @@ function createRegistry(registryBaseUrl_1, imagePath_1, allowInsecure_1, auth_1)
|
|
|
182
181
|
return new Promise((resolve, reject) => {
|
|
183
182
|
const parameters = new URLSearchParams(mountParameters);
|
|
184
183
|
const url = `${registryBaseUrl}${image.path}/blobs/uploads/${parameters.size > 0 ? "?" + parameters : ""}`;
|
|
185
|
-
const
|
|
186
|
-
options
|
|
184
|
+
const parsedUrl = new URL(url);
|
|
185
|
+
const options = {
|
|
186
|
+
protocol: parsedUrl.protocol,
|
|
187
|
+
hostname: parsedUrl.hostname,
|
|
188
|
+
port: parsedUrl.port,
|
|
189
|
+
path: parsedUrl.pathname + parsedUrl.search,
|
|
190
|
+
method: "POST",
|
|
191
|
+
};
|
|
187
192
|
if (token)
|
|
188
193
|
options.headers = { authorization: token };
|
|
189
194
|
(0, httpRequest_1.request)(options, allowInsecure, (res) => {
|
|
@@ -195,7 +200,7 @@ function createRegistry(registryBaseUrl_1, imagePath_1, allowInsecure_1, auth_1)
|
|
|
195
200
|
resolve({ uploadUrl: location });
|
|
196
201
|
}
|
|
197
202
|
else {
|
|
198
|
-
const regURL = URL
|
|
203
|
+
const regURL = new URL(registryBaseUrl);
|
|
199
204
|
resolve({
|
|
200
205
|
uploadUrl: `${regURL.protocol}//${regURL.hostname}${regURL.port ? ":" + regURL.port : ""}${location}`,
|
|
201
206
|
});
|
package/lib/types.d.ts
CHANGED
|
@@ -91,6 +91,7 @@ export type Options = {
|
|
|
91
91
|
workdir?: string;
|
|
92
92
|
entrypoint?: string;
|
|
93
93
|
};
|
|
94
|
+
writeDigestTo?: string;
|
|
94
95
|
};
|
|
95
96
|
export declare enum InsecureRegistrySupport {
|
|
96
97
|
NO = 0,
|
|
@@ -101,4 +102,5 @@ export type Registry = {
|
|
|
101
102
|
upload: (imageStr: string, folder: string, doCrossMount: boolean, originalManifest: Manifest, originalRepository: string) => Promise<void>;
|
|
102
103
|
registryBaseUrl: string;
|
|
103
104
|
};
|
|
105
|
+
export type ManifestDescriptor = Descriptor;
|
|
104
106
|
export {};
|
package/lib/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "3.2
|
|
1
|
+
export declare const VERSION = "3.3.2";
|
package/lib/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "containerify",
|
|
3
|
-
"version": "3.2
|
|
3
|
+
"version": "3.3.2",
|
|
4
4
|
"description": "Build node.js docker images without docker",
|
|
5
5
|
"main": "./lib/cli.js",
|
|
6
6
|
"scripts": {
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
],
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"commander": "^13.1.0",
|
|
40
|
-
"fs-extra": "^11.3.
|
|
41
|
-
"tar": "^
|
|
40
|
+
"fs-extra": "^11.3.2",
|
|
41
|
+
"tar": "^7.5.7"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@eslint/eslintrc": "^3.3.1",
|