@miosa/cli 2.0.0 → 2.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/lib/archive.js +64 -2
- package/package.json +6 -5
package/lib/archive.js
CHANGED
|
@@ -3,14 +3,22 @@
|
|
|
3
3
|
const fs = require("node:fs");
|
|
4
4
|
const os = require("node:os");
|
|
5
5
|
const path = require("node:path");
|
|
6
|
+
const zlib = require("node:zlib");
|
|
6
7
|
const { execFileSync } = require("node:child_process");
|
|
7
8
|
|
|
8
9
|
// Returns the binary named `binName` from a .tar.gz / .zip archive buffer.
|
|
9
|
-
//
|
|
10
|
+
// .tar.gz goes through the system `tar`, present on macOS, Linux and Windows
|
|
11
|
+
// 10+. .zip is read here in pure JavaScript: GNU tar on Linux cannot read a
|
|
12
|
+
// zip archive, and `unzip` is not installed everywhere.
|
|
10
13
|
function extractBinary(archive, ext, binName) {
|
|
14
|
+
if (ext === "zip") return extractFromZip(archive, binName);
|
|
15
|
+
return extractFromTarGz(archive, binName);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function extractFromTarGz(archive, binName) {
|
|
11
19
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "miosa-cli-"));
|
|
12
20
|
try {
|
|
13
|
-
const file = path.join(dir,
|
|
21
|
+
const file = path.join(dir, "archive.tar.gz");
|
|
14
22
|
fs.writeFileSync(file, archive);
|
|
15
23
|
const out = path.join(dir, "out");
|
|
16
24
|
fs.mkdirSync(out);
|
|
@@ -23,4 +31,58 @@ function extractBinary(archive, ext, binName) {
|
|
|
23
31
|
}
|
|
24
32
|
}
|
|
25
33
|
|
|
34
|
+
// extractFromZip reads one entry out of a zip buffer. The central directory is
|
|
35
|
+
// the authority for sizes and offsets, so an entry written with a trailing data
|
|
36
|
+
// descriptor still resolves.
|
|
37
|
+
function extractFromZip(archive, binName) {
|
|
38
|
+
const entry = findZipEntry(archive, binName);
|
|
39
|
+
if (!entry) throw new Error(`archive has no ${binName}`);
|
|
40
|
+
if (archive.readUInt32LE(entry.offset) !== 0x04034b50) throw new Error("corrupt zip: bad local header");
|
|
41
|
+
|
|
42
|
+
const nameLen = archive.readUInt16LE(entry.offset + 26);
|
|
43
|
+
const extraLen = archive.readUInt16LE(entry.offset + 28);
|
|
44
|
+
const start = entry.offset + 30 + nameLen + extraLen;
|
|
45
|
+
const data = archive.subarray(start, start + entry.compressedSize);
|
|
46
|
+
|
|
47
|
+
switch (entry.method) {
|
|
48
|
+
case 0: // stored
|
|
49
|
+
return Buffer.from(data);
|
|
50
|
+
case 8: // deflate
|
|
51
|
+
return zlib.inflateRawSync(data);
|
|
52
|
+
default:
|
|
53
|
+
throw new Error(`unsupported zip compression method ${entry.method}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function findZipEntry(archive, binName) {
|
|
58
|
+
const eocd = findEndOfCentralDirectory(archive);
|
|
59
|
+
if (eocd < 0) throw new Error("not a zip archive");
|
|
60
|
+
const count = archive.readUInt16LE(eocd + 10);
|
|
61
|
+
let p = archive.readUInt32LE(eocd + 16);
|
|
62
|
+
for (let i = 0; i < count; i++) {
|
|
63
|
+
if (p + 46 > archive.length || archive.readUInt32LE(p) !== 0x02014b50) {
|
|
64
|
+
throw new Error("corrupt zip: bad central directory");
|
|
65
|
+
}
|
|
66
|
+
const method = archive.readUInt16LE(p + 10);
|
|
67
|
+
const compressedSize = archive.readUInt32LE(p + 20);
|
|
68
|
+
const nameLen = archive.readUInt16LE(p + 28);
|
|
69
|
+
const extraLen = archive.readUInt16LE(p + 30);
|
|
70
|
+
const commentLen = archive.readUInt16LE(p + 32);
|
|
71
|
+
const offset = archive.readUInt32LE(p + 42);
|
|
72
|
+
const name = archive.toString("utf8", p + 46, p + 46 + nameLen);
|
|
73
|
+
if (path.basename(name) === binName) return { method, compressedSize, offset };
|
|
74
|
+
p += 46 + nameLen + extraLen + commentLen;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// findEndOfCentralDirectory scans back from the end, allowing for a comment.
|
|
80
|
+
function findEndOfCentralDirectory(archive) {
|
|
81
|
+
const min = Math.max(0, archive.length - 22 - 0xffff);
|
|
82
|
+
for (let i = archive.length - 22; i >= min; i--) {
|
|
83
|
+
if (archive.readUInt32LE(i) === 0x06054b50) return i;
|
|
84
|
+
}
|
|
85
|
+
return -1;
|
|
86
|
+
}
|
|
87
|
+
|
|
26
88
|
module.exports = { extractBinary };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miosa/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "The official MIOSA command-line tool (native binary, installed per platform)",
|
|
5
5
|
"bin": {
|
|
6
6
|
"miosa": "bin/miosa.js"
|
|
@@ -9,10 +9,11 @@
|
|
|
9
9
|
"postinstall": "node scripts/postinstall.js"
|
|
10
10
|
},
|
|
11
11
|
"optionalDependencies": {
|
|
12
|
-
"@miosa/cli-darwin-arm64": "2.
|
|
13
|
-
"@miosa/cli-darwin-x64": "2.
|
|
14
|
-
"@miosa/cli-linux-arm64": "2.
|
|
15
|
-
"@miosa/cli-linux-x64": "2.
|
|
12
|
+
"@miosa/cli-darwin-arm64": "2.1.0",
|
|
13
|
+
"@miosa/cli-darwin-x64": "2.1.0",
|
|
14
|
+
"@miosa/cli-linux-arm64": "2.1.0",
|
|
15
|
+
"@miosa/cli-linux-x64": "2.1.0",
|
|
16
|
+
"@miosa/cli-win32-x64": "2.1.0"
|
|
16
17
|
},
|
|
17
18
|
"files": [
|
|
18
19
|
"bin",
|