@anonymousmister/crane-tool 1.0.0 → 1.0.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/bin/build.js CHANGED
@@ -6,6 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import os from 'os';
7
7
  import * as tar from 'tar';
8
8
  import * as ini from 'ini';
9
+ import {installCrane} from "./install.js";
9
10
 
10
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
12
  const platform = os.platform();
@@ -61,6 +62,11 @@ function injectVars(obj, vars) {
61
62
  }
62
63
 
63
64
  async function run() {
65
+ // 确保二进制文件可用
66
+ if (!fs.existsSync(CRANE_PATH)) {
67
+ await installCrane();
68
+ }
69
+
64
70
  const args = process.argv.slice(2);
65
71
  const tIndex = args.indexOf('-t');
66
72
  const templatePath = (tIndex > -1 && args[tIndex + 1]) ? path.resolve(args[tIndex + 1]) : null;
@@ -70,6 +76,9 @@ async function run() {
70
76
  process.exit(1);
71
77
  }
72
78
 
79
+
80
+
81
+
73
82
  // 1. 变量处理
74
83
  const varPool = buildVarPool(args);
75
84
  const rawTemplate = JSON.parse(fs.readFileSync(templatePath, 'utf-8'));
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { installCrane } from './install.js';
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+ const isWin = process.platform === 'win32';
10
+ const CRANE_BIN = isWin ? 'crane.exe' : 'crane';
11
+ const CRANE_PATH = path.join(__dirname, CRANE_BIN);
12
+
13
+ async function main() {
14
+ // 如果二进制文件不存在(比如 postinstall 被拦截了),现场下载
15
+ if (!fs.existsSync(CRANE_PATH)) {
16
+ console.log('⚠️ [Crane-Tool] 未发现二进制文件,正在准备环境...');
17
+ await installCrane();
18
+ }
19
+
20
+ // 将用户输入的参数全部转发给真正的 crane 二进制文件
21
+ const args = process.argv.slice(2);
22
+ const child = spawn(CRANE_PATH, args, {
23
+ stdio: 'inherit', // 保持交互式输出,支持登录时的密码输入
24
+ shell: false
25
+ });
26
+
27
+ child.on('exit', (code) => {
28
+ process.exit(code);
29
+ });
30
+ }
31
+
32
+ main().catch(err => {
33
+ console.error('❌ 执行失败:', err);
34
+ process.exit(1);
35
+ });
package/bin/install.js CHANGED
@@ -3,12 +3,16 @@ import os from 'os';
3
3
  import fs from 'fs';
4
4
  import path from 'path';
5
5
  import { fileURLToPath } from 'url';
6
- import { execSync } from 'child_process';
6
+ import * as tar from 'tar'; // 引入 tar 模块
7
7
 
8
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
9
10
  const VERSION = '0.20.2';
10
11
 
11
- async function install() {
12
+ /**
13
+ * 暴露给 build.js 调用的安装函数
14
+ */
15
+ export async function installCrane() {
12
16
  const platform = os.platform();
13
17
  const arch = os.arch();
14
18
 
@@ -19,29 +23,54 @@ async function install() {
19
23
 
20
24
  const url = `https://github.com/google/go-containerregistry/releases/download/v${VERSION}/go-containerregistry_${platformName}.tar.gz`;
21
25
  const exeName = platform === 'win32' ? 'crane.exe' : 'crane';
22
- const tarFile = path.join(__dirname, 'crane.tar.gz');
26
+ const targetPath = path.join(__dirname, exeName);
23
27
 
24
- console.log(`[Crane-Install] 正在下载 Crane v${VERSION} (${platformName})...`);
28
+ // 如果文件已存在,直接返回
29
+ if (fs.existsSync(targetPath)) return targetPath;
30
+
31
+ console.log(`[Crane-Install] 正在下载并解压 Crane v${VERSION}...`);
25
32
 
26
33
  try {
27
34
  const response = await fetch(url);
28
- if (!response.ok) throw new Error(`HTTP ${response.status}`);
35
+ if (!response.ok) throw new Error(`下载失败: HTTP ${response.status}`);
36
+
37
+ // 使用 tar.x 替代命令行解压
38
+ // 直接将 fetch 的 body 管道流向 tar 解压器
39
+ const readableStream = Buffer.from(await response.arrayBuffer());
29
40
 
30
- const arrayBuffer = await response.arrayBuffer();
31
- fs.writeFileSync(tarFile, Buffer.from(arrayBuffer));
41
+ // 创建一个临时目录或在当前目录解压指定文件
42
+ // tar.x ({ x: extract }) 参数说明:
43
+ // cwd: 解压到的目录
44
+ // filter: 只解压我们需要的那一个二进制文件
45
+ await new Promise((resolve, reject) => {
46
+ const writer = tar.x({
47
+ cwd: __dirname,
48
+ sync: true, // 使用同步或包装成 promise
49
+ }, [exeName]);
32
50
 
33
- // 解压到当前 bin 目录
34
- execSync(`tar -xzf "${tarFile}" -C "${__dirname}" ${exeName}`, { stdio: 'inherit' });
35
- fs.unlinkSync(tarFile);
51
+ // buffer 写入解压器
52
+ writer.end(readableStream);
53
+ resolve();
54
+ });
36
55
 
56
+ // 赋予执行权限 (非 Windows 系统)
37
57
  if (platform !== 'win32') {
38
- fs.chmodSync(path.join(__dirname, exeName), 0o755);
58
+ fs.chmodSync(targetPath, 0o755);
59
+ }
60
+
61
+ if (fs.existsSync(targetPath)) {
62
+ console.log(`✅ Crane 安装就绪: ${targetPath}`);
63
+ return targetPath;
64
+ } else {
65
+ throw new Error('解压过程未产生预期的二进制文件');
39
66
  }
40
- console.log(`✅ Crane 二进制文件就绪: ${path.join(__dirname, exeName)}`);
41
67
  } catch (err) {
42
- console.error('❌ 下载失败:', err.message);
43
- process.exit(1);
68
+ console.error('❌ Crane 安装失败:', err.message);
69
+ throw err;
44
70
  }
45
71
  }
46
72
 
47
- install();
73
+ // 支持直接运行
74
+ if (process.argv[1] === __filename) {
75
+ installCrane().catch(() => process.exit(1));
76
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@anonymousmister/crane-tool",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "基于 Crane 的分层镜像构建工具,模仿 jib 的功能",
5
5
  "type": "module",
6
6
  "main": "bin/build.js",
7
7
  "bin": {
8
- "crane": "./bin/crane",
8
+ "crane": "./bin/crane-cli.js",
9
9
  "crane-tool-build": "./bin/build.js"
10
10
  },
11
11
  "files": [