@build-script/package-tools 0.0.1
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/LICENSE +21 -0
- package/README.md +136 -0
- package/config/rig.json +6 -0
- package/lib/command-file-map.generated.d.ts +23 -0
- package/lib/command-file-map.generated.d.ts.map +1 -0
- package/lib/command-file-map.generated.js +27 -0
- package/lib/command-file-map.generated.js.map +1 -0
- package/lib/commands/detect-package-change.d.ts +14 -0
- package/lib/commands/detect-package-change.d.ts.map +1 -0
- package/lib/commands/detect-package-change.js +55 -0
- package/lib/commands/detect-package-change.js.map +1 -0
- package/lib/commands/monorepo-bump-version.d.ts +22 -0
- package/lib/commands/monorepo-bump-version.d.ts.map +1 -0
- package/lib/commands/monorepo-bump-version.js +121 -0
- package/lib/commands/monorepo-bump-version.js.map +1 -0
- package/lib/commands/monorepo-cnpm-sync.d.ts +8 -0
- package/lib/commands/monorepo-cnpm-sync.d.ts.map +1 -0
- package/lib/commands/monorepo-cnpm-sync.js +16 -0
- package/lib/commands/monorepo-cnpm-sync.js.map +1 -0
- package/lib/commands/monorepo-invalid.d.ts +8 -0
- package/lib/commands/monorepo-invalid.d.ts.map +1 -0
- package/lib/commands/monorepo-invalid.js +19 -0
- package/lib/commands/monorepo-invalid.js.map +1 -0
- package/lib/commands/monorepo-list.d.ts +22 -0
- package/lib/commands/monorepo-list.d.ts.map +1 -0
- package/lib/commands/monorepo-list.js +40 -0
- package/lib/commands/monorepo-list.js.map +1 -0
- package/lib/commands/monorepo-publish.d.ts +22 -0
- package/lib/commands/monorepo-publish.d.ts.map +1 -0
- package/lib/commands/monorepo-publish.js +178 -0
- package/lib/commands/monorepo-publish.js.map +1 -0
- package/lib/commands/monorepo-tsconfig.d.ts +14 -0
- package/lib/commands/monorepo-tsconfig.d.ts.map +1 -0
- package/lib/commands/monorepo-tsconfig.js +131 -0
- package/lib/commands/monorepo-tsconfig.js.map +1 -0
- package/lib/commands/monorepo-upgrade.d.ts +8 -0
- package/lib/commands/monorepo-upgrade.d.ts.map +1 -0
- package/lib/commands/monorepo-upgrade.js +110 -0
- package/lib/commands/monorepo-upgrade.js.map +1 -0
- package/lib/commands/run-if-version-mismatch.d.ts +23 -0
- package/lib/commands/run-if-version-mismatch.d.ts.map +1 -0
- package/lib/commands/run-if-version-mismatch.js +64 -0
- package/lib/commands/run-if-version-mismatch.js.map +1 -0
- package/lib/commands/sync-my-readme.d.ts +9 -0
- package/lib/commands/sync-my-readme.d.ts.map +1 -0
- package/lib/commands/sync-my-readme.js +51 -0
- package/lib/commands/sync-my-readme.js.map +1 -0
- package/lib/commands/test.d.ts +9 -0
- package/lib/commands/test.d.ts.map +1 -0
- package/lib/commands/test.js +16 -0
- package/lib/commands/test.js.map +1 -0
- package/lib/common/cache/escape-package-path.d.ts +2 -0
- package/lib/common/cache/escape-package-path.d.ts.map +1 -0
- package/lib/common/cache/escape-package-path.js +7 -0
- package/lib/common/cache/escape-package-path.js.map +1 -0
- package/lib/common/cache/native.npm.d.ts +50 -0
- package/lib/common/cache/native.npm.d.ts.map +1 -0
- package/lib/common/cache/native.npm.js +162 -0
- package/lib/common/cache/native.npm.js.map +1 -0
- package/lib/common/functions/cli.d.ts +85 -0
- package/lib/common/functions/cli.d.ts.map +1 -0
- package/lib/common/functions/cli.js +110 -0
- package/lib/common/functions/cli.js.map +1 -0
- package/lib/common/functions/global-lifecycle.d.ts +5 -0
- package/lib/common/functions/global-lifecycle.d.ts.map +1 -0
- package/lib/common/functions/global-lifecycle.js +34 -0
- package/lib/common/functions/global-lifecycle.js.map +1 -0
- package/lib/common/git/git.d.ts +12 -0
- package/lib/common/git/git.d.ts.map +1 -0
- package/lib/common/git/git.js +65 -0
- package/lib/common/git/git.js.map +1 -0
- package/lib/common/package-manager/constant.d.ts +2 -0
- package/lib/common/package-manager/constant.d.ts.map +1 -0
- package/lib/common/package-manager/constant.js +2 -0
- package/lib/common/package-manager/constant.js.map +1 -0
- package/lib/common/package-manager/driver.abstract.d.ts +41 -0
- package/lib/common/package-manager/driver.abstract.d.ts.map +1 -0
- package/lib/common/package-manager/driver.abstract.js +138 -0
- package/lib/common/package-manager/driver.abstract.js.map +1 -0
- package/lib/common/package-manager/driver.npm.d.ts +7 -0
- package/lib/common/package-manager/driver.npm.d.ts.map +1 -0
- package/lib/common/package-manager/driver.npm.js +11 -0
- package/lib/common/package-manager/driver.npm.js.map +1 -0
- package/lib/common/package-manager/driver.pnpm.d.ts +7 -0
- package/lib/common/package-manager/driver.pnpm.d.ts.map +1 -0
- package/lib/common/package-manager/driver.pnpm.js +83 -0
- package/lib/common/package-manager/driver.pnpm.js.map +1 -0
- package/lib/common/package-manager/functions.d.ts +13 -0
- package/lib/common/package-manager/functions.d.ts.map +1 -0
- package/lib/common/package-manager/functions.js +95 -0
- package/lib/common/package-manager/functions.js.map +1 -0
- package/lib/common/package-manager/package-json.d.ts +5 -0
- package/lib/common/package-manager/package-json.d.ts.map +1 -0
- package/lib/common/package-manager/package-json.js +50 -0
- package/lib/common/package-manager/package-json.js.map +1 -0
- package/lib/common/package-manager/package-manager.d.ts +5 -0
- package/lib/common/package-manager/package-manager.d.ts.map +1 -0
- package/lib/common/package-manager/package-manager.js +27 -0
- package/lib/common/package-manager/package-manager.js.map +1 -0
- package/lib/common/package-manager/proxy.d.ts +5 -0
- package/lib/common/package-manager/proxy.d.ts.map +1 -0
- package/lib/common/package-manager/proxy.js +116 -0
- package/lib/common/package-manager/proxy.js.map +1 -0
- package/lib/common/shared-jobs/cnpm-sync.d.ts +4 -0
- package/lib/common/shared-jobs/cnpm-sync.d.ts.map +1 -0
- package/lib/common/shared-jobs/cnpm-sync.js +52 -0
- package/lib/common/shared-jobs/cnpm-sync.js.map +1 -0
- package/lib/common/shared-jobs/detect-change-job.d.ts +12 -0
- package/lib/common/shared-jobs/detect-change-job.d.ts.map +1 -0
- package/lib/common/shared-jobs/detect-change-job.js +52 -0
- package/lib/common/shared-jobs/detect-change-job.js.map +1 -0
- package/lib/common/shared-jobs/publish-package-version-job.d.ts +4 -0
- package/lib/common/shared-jobs/publish-package-version-job.d.ts.map +1 -0
- package/lib/common/shared-jobs/publish-package-version-job.js +40 -0
- package/lib/common/shared-jobs/publish-package-version-job.js.map +1 -0
- package/lib/common/taball/decompress.d.ts +2 -0
- package/lib/common/taball/decompress.d.ts.map +1 -0
- package/lib/common/taball/decompress.js +39 -0
- package/lib/common/taball/decompress.js.map +1 -0
- package/lib/common/taball/file-download.d.ts +15 -0
- package/lib/common/taball/file-download.d.ts.map +1 -0
- package/lib/common/taball/file-download.js +137 -0
- package/lib/common/taball/file-download.js.map +1 -0
- package/lib/common/temp-work-folder.d.ts +20 -0
- package/lib/common/temp-work-folder.d.ts.map +1 -0
- package/lib/common/temp-work-folder.js +68 -0
- package/lib/common/temp-work-folder.js.map +1 -0
- package/lib/common/version.generated.d.ts +12 -0
- package/lib/common/version.generated.d.ts.map +1 -0
- package/lib/common/version.generated.js +17 -0
- package/lib/common/version.generated.js.map +1 -0
- package/lib/main.d.ts +2 -0
- package/lib/main.d.ts.map +1 -0
- package/lib/main.js +115 -0
- package/lib/main.js.map +1 -0
- package/lib/tsconfig.tsbuildinfo +1 -0
- package/load.js +12 -0
- package/package.json +59 -0
- package/src/command-file-map.generated.ts +28 -0
- package/src/command-file-map.generator.ts +23 -0
- package/src/commands/detect-package-change.ts +57 -0
- package/src/commands/monorepo-bump-version.ts +152 -0
- package/src/commands/monorepo-cnpm-sync.ts +19 -0
- package/src/commands/monorepo-invalid.ts +22 -0
- package/src/commands/monorepo-list.ts +46 -0
- package/src/commands/monorepo-publish.ts +227 -0
- package/src/commands/monorepo-tsconfig.ts +156 -0
- package/src/commands/monorepo-upgrade.ts +131 -0
- package/src/commands/run-if-version-mismatch.ts +78 -0
- package/src/commands/sync-my-readme.ts +56 -0
- package/src/commands/test.ts +18 -0
- package/src/common/cache/escape-package-path.ts +6 -0
- package/src/common/cache/native.npm.ts +206 -0
- package/src/common/functions/cli.ts +145 -0
- package/src/common/functions/global-lifecycle.ts +40 -0
- package/src/common/git/git.ts +75 -0
- package/src/common/package-manager/constant.ts +1 -0
- package/src/common/package-manager/driver.abstract.ts +162 -0
- package/src/common/package-manager/driver.npm.ts +13 -0
- package/src/common/package-manager/driver.pnpm.ts +113 -0
- package/src/common/package-manager/functions.ts +117 -0
- package/src/common/package-manager/package-json.ts +56 -0
- package/src/common/package-manager/package-manager.ts +46 -0
- package/src/common/package-manager/proxy.ts +129 -0
- package/src/common/shared-jobs/cnpm-sync.ts +57 -0
- package/src/common/shared-jobs/detect-change-job.ts +76 -0
- package/src/common/shared-jobs/publish-package-version-job.ts +46 -0
- package/src/common/taball/decompress.ts +41 -0
- package/src/common/taball/file-download.ts +166 -0
- package/src/common/temp-work-folder.ts +80 -0
- package/src/common/version.generated.ts +18 -0
- package/src/common/version.generator.ts +15 -0
- package/src/global.d.ts +17 -0
- package/src/main.ts +144 -0
- package/src/tsconfig.json +11 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { escapeRegExp } from '@idlebox/common';
|
|
2
|
+
import { logger } from '@idlebox/logger';
|
|
3
|
+
import { getEnvironment } from '@idlebox/node';
|
|
4
|
+
import type { IPackageManager } from './package-manager.js';
|
|
5
|
+
|
|
6
|
+
let proxy_override_by_env = false;
|
|
7
|
+
|
|
8
|
+
function makeRe(str: string) {
|
|
9
|
+
const reTxt = str
|
|
10
|
+
.split('*')
|
|
11
|
+
.map((v) => escapeRegExp(v))
|
|
12
|
+
.join('.+');
|
|
13
|
+
return new RegExp(`^${reTxt}$`, 'i');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getProxyValue(url: string) {
|
|
17
|
+
const proxyValue = process.env.http_proxy;
|
|
18
|
+
if (!proxyValue) {
|
|
19
|
+
return '';
|
|
20
|
+
}
|
|
21
|
+
logger.verbose`get proxy for: ${url}`;
|
|
22
|
+
if (!process.env.no_proxy) {
|
|
23
|
+
logger.verbose`using http_proxy directly`;
|
|
24
|
+
return proxyValue;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let domain: string;
|
|
28
|
+
if (url.includes('://')) {
|
|
29
|
+
domain = new URL(url).hostname;
|
|
30
|
+
} else {
|
|
31
|
+
domain = url.split('/')[0];
|
|
32
|
+
}
|
|
33
|
+
if (!domain) {
|
|
34
|
+
throw new Error(`无法从URL中获取域名: ${url}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
logger.verbose` trying no_proxy: ${process.env.no_proxy} | ${domain}`;
|
|
38
|
+
|
|
39
|
+
const noProxy = process.env.no_proxy.split(',').map((s) => s.trim());
|
|
40
|
+
for (const npPart of noProxy) {
|
|
41
|
+
logger.verbose`- ${npPart}`;
|
|
42
|
+
if (npPart.includes('*')) {
|
|
43
|
+
const re = makeRe(npPart);
|
|
44
|
+
if (re.test(domain)) {
|
|
45
|
+
logger.verbose(` hit regexp`);
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
if (domain === npPart) {
|
|
50
|
+
logger.verbose(` hit equals`);
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
const domainEnding = npPart[0] === '.' ? npPart : '.' + npPart;
|
|
54
|
+
if (domain.endsWith(domainEnding)) {
|
|
55
|
+
logger.verbose(` hit ending: ${domainEnding}`);
|
|
56
|
+
return '';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
logger.verbose` not hit no_proxy, using http_proxy`;
|
|
62
|
+
return proxyValue;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export async function reconfigureProxyWithNpmrc(pm: IPackageManager) {
|
|
66
|
+
if (proxy_override_by_env) return;
|
|
67
|
+
|
|
68
|
+
logger.debug('通过npm设置代理服务器:');
|
|
69
|
+
const p = await pm.getConfig('proxy');
|
|
70
|
+
const np = await pm.getConfig('noproxy');
|
|
71
|
+
|
|
72
|
+
if (p) {
|
|
73
|
+
logger.debug(` * proxy server = ${p}`);
|
|
74
|
+
}
|
|
75
|
+
if (np) {
|
|
76
|
+
logger.debug(` * no_proxy = ${np}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
applyEnv(p || '', np || '');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function configureProxyFromEnvironment() {
|
|
83
|
+
// bootstrap({
|
|
84
|
+
// environmentVariableNamespace: '',
|
|
85
|
+
// forceGlobalAgent: true,
|
|
86
|
+
// socketConnectionTimeout: 1000,
|
|
87
|
+
// });
|
|
88
|
+
|
|
89
|
+
logger.debug('通过环境变量设置代理服务器:');
|
|
90
|
+
|
|
91
|
+
let noProxy = '';
|
|
92
|
+
const envVar = getEnvironment('NO_PROXY');
|
|
93
|
+
if (envVar.value) {
|
|
94
|
+
logger.debug(` * no_proxy = ${envVar.value}`);
|
|
95
|
+
|
|
96
|
+
noProxy = envVar.value;
|
|
97
|
+
} else {
|
|
98
|
+
noProxy = '';
|
|
99
|
+
logger.debug(' * no_proxy = <unset>');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let httpProxy = getEnvironment('http_proxy').value || '';
|
|
103
|
+
if (!httpProxy) {
|
|
104
|
+
httpProxy = getEnvironment('https_proxy').value || '';
|
|
105
|
+
if (!httpProxy) {
|
|
106
|
+
httpProxy = getEnvironment('all_proxy').value || '';
|
|
107
|
+
if (!httpProxy) {
|
|
108
|
+
httpProxy = getEnvironment('proxy').value || '';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (httpProxy) {
|
|
114
|
+
logger.debug(` * proxy server = ${httpProxy}`);
|
|
115
|
+
proxy_override_by_env = true;
|
|
116
|
+
applyEnv(httpProxy, noProxy);
|
|
117
|
+
} else {
|
|
118
|
+
logger.debug(' * proxy server = <unset>');
|
|
119
|
+
proxy_override_by_env = false;
|
|
120
|
+
applyEnv('', '');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function applyEnv(proxy: string, noproxy: string) {
|
|
125
|
+
process.env.http_proxy = proxy;
|
|
126
|
+
process.env.https_proxy = proxy;
|
|
127
|
+
process.env.all_proxy = proxy;
|
|
128
|
+
process.env.no_proxy = noproxy;
|
|
129
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { IPackageInfo } from '@build-script/monorepo-lib';
|
|
2
|
+
import { logger } from '@idlebox/logger';
|
|
3
|
+
import { checkChildProcessResult, printLine } from '@idlebox/node';
|
|
4
|
+
import { execa } from 'execa';
|
|
5
|
+
import { CSI, isQuiet } from '../functions/cli.js';
|
|
6
|
+
|
|
7
|
+
export function cnpmSync(list: ReadonlyArray<IPackageInfo>, collectOutput = isQuiet, dryRun = false) {
|
|
8
|
+
const names = list
|
|
9
|
+
.filter((e) => {
|
|
10
|
+
return !!e.packageJson.name && !e.packageJson.private;
|
|
11
|
+
})
|
|
12
|
+
.map((e) => e.packageJson.name);
|
|
13
|
+
|
|
14
|
+
return cnpmSyncNames(names, collectOutput, dryRun);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function cnpmSyncNames(names: ReadonlyArray<string>, collectOutput = isQuiet, dryRun = false) {
|
|
18
|
+
console.log(`🔃 cnpm同步${names.length}个包`);
|
|
19
|
+
|
|
20
|
+
if (dryRun) {
|
|
21
|
+
console.log('');
|
|
22
|
+
console.log('');
|
|
23
|
+
console.log('cnpm sync', ...names.map((value) => JSON.stringify(value)));
|
|
24
|
+
console.log('');
|
|
25
|
+
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const p = await execa('cnpm', ['sync', ...names], {
|
|
29
|
+
stdio: collectOutput ? 'pipe' : 'inherit',
|
|
30
|
+
buffer: collectOutput,
|
|
31
|
+
all: collectOutput,
|
|
32
|
+
fail: false,
|
|
33
|
+
verbose: 'short',
|
|
34
|
+
env: {
|
|
35
|
+
http_proxy: undefined,
|
|
36
|
+
https_proxy: undefined,
|
|
37
|
+
all_proxy: undefined,
|
|
38
|
+
HTTP_PROXY: undefined,
|
|
39
|
+
HTTPS_PROXY: undefined,
|
|
40
|
+
ALL_PROXY: undefined,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
checkChildProcessResult(p);
|
|
46
|
+
if (collectOutput) {
|
|
47
|
+
process.stderr.write(`${CSI}K`);
|
|
48
|
+
}
|
|
49
|
+
console.log(' ✨ cnpm同步请求成功');
|
|
50
|
+
} catch (e) {
|
|
51
|
+
if (collectOutput) {
|
|
52
|
+
printLine();
|
|
53
|
+
logger.error(p.all as any);
|
|
54
|
+
}
|
|
55
|
+
console.log(' ⚠️ cnpm同步请求失败');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { logger } from '@idlebox/logger';
|
|
2
|
+
import { PathEnvironment } from '@idlebox/node';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { gt } from 'semver';
|
|
5
|
+
import { distTagInput } from '../functions/cli.js';
|
|
6
|
+
import { GitWorkingTree } from '../git/git.js';
|
|
7
|
+
import { makePackageJsonOrderConsistence } from '../package-manager/package-json.js';
|
|
8
|
+
import type { IPackageManager } from '../package-manager/package-manager.js';
|
|
9
|
+
import { TempWorkingFolder } from '../temp-work-folder.js';
|
|
10
|
+
|
|
11
|
+
interface IResult {
|
|
12
|
+
changedFiles: string[];
|
|
13
|
+
hasChange: boolean;
|
|
14
|
+
remoteVersion?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface IDetectOptions {
|
|
18
|
+
forcePrivate?: boolean;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function executeChangeDetect(pm: IPackageManager, options: IDetectOptions): Promise<IResult> {
|
|
22
|
+
const packageJson = await pm.loadPackageJson();
|
|
23
|
+
logger.debug('修改检测 | 包名: %s', packageJson.name);
|
|
24
|
+
if (!packageJson.name) {
|
|
25
|
+
throw new Error(`${pm.projectPath}/package.json 中缺少 name 字段`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const cache = await pm.createCacheHandler();
|
|
29
|
+
|
|
30
|
+
const p = new PathEnvironment();
|
|
31
|
+
p.add(resolve(pm.projectPath, 'node_modules/.bin'));
|
|
32
|
+
p.add(resolve(process.argv0, '..'));
|
|
33
|
+
for (const l in process.env) {
|
|
34
|
+
if (l.startsWith('LC_')) {
|
|
35
|
+
delete process.env[l];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (packageJson.private && !options.forcePrivate) {
|
|
40
|
+
logger.debug('检测到私有包,禁止运行');
|
|
41
|
+
return { changedFiles: [], hasChange: false };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const remotePackage = await cache.fetchVersion(packageJson.name, distTagInput);
|
|
45
|
+
logger.debug(' -> npm 远程版本 = %s', remotePackage?.version);
|
|
46
|
+
logger.debug(' -> package.json 本地版本 = %s', packageJson.version);
|
|
47
|
+
|
|
48
|
+
if (!remotePackage || gt(packageJson.version, remotePackage.version)) {
|
|
49
|
+
logger.debug('本地版本 (%s) 已经大于远程版本 (%s),无需进一步检测', packageJson.version, remotePackage?.version);
|
|
50
|
+
return { changedFiles: ['package.json'], hasChange: false, remoteVersion: remotePackage?.version };
|
|
51
|
+
}
|
|
52
|
+
logger.debug('本地版本 (%s) 小于或等于远程版本 (%s),尝试检测更改...', packageJson.version, remotePackage.version);
|
|
53
|
+
|
|
54
|
+
const tarball = await cache.downloadTarball(packageJson.name, distTagInput);
|
|
55
|
+
|
|
56
|
+
const tempFolder = new TempWorkingFolder(pm.workspace, 'package-change-detect');
|
|
57
|
+
const workingRoot = tempFolder.resolve('working');
|
|
58
|
+
await workingRoot.unpack(tarball);
|
|
59
|
+
await makePackageJsonOrderConsistence(workingRoot.path);
|
|
60
|
+
|
|
61
|
+
const gitrepo = new GitWorkingTree(workingRoot.path);
|
|
62
|
+
await gitrepo.init();
|
|
63
|
+
|
|
64
|
+
const pack = await pm.pack(tempFolder.joinpath('local-pack.tgz'));
|
|
65
|
+
logger.verbose(' --> %s', pack);
|
|
66
|
+
|
|
67
|
+
await workingRoot.unpack(pack);
|
|
68
|
+
logger.verbose(' unpacked successfully');
|
|
69
|
+
|
|
70
|
+
await makePackageJsonOrderConsistence(workingRoot.path);
|
|
71
|
+
|
|
72
|
+
const changedFiles = await gitrepo.commitChanges();
|
|
73
|
+
logger.verbose` changed files: list<${changedFiles}>`;
|
|
74
|
+
|
|
75
|
+
return { changedFiles, hasChange: changedFiles.length > 0, remoteVersion: remotePackage.version };
|
|
76
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { logger } from '@idlebox/logger';
|
|
2
|
+
import { exists } from '@idlebox/node';
|
|
3
|
+
import { copyFile } from 'node:fs/promises';
|
|
4
|
+
import { resolve } from 'node:path';
|
|
5
|
+
import type { IPackageManager } from '../package-manager/package-manager.js';
|
|
6
|
+
import { TempWorkingFolder } from '../temp-work-folder.js';
|
|
7
|
+
|
|
8
|
+
export const PUBLISH_PACKAGE_METACACHE_KEY = 'published-package';
|
|
9
|
+
|
|
10
|
+
// interface StateCache {
|
|
11
|
+
// id: string;
|
|
12
|
+
// version: string;
|
|
13
|
+
// size: number;
|
|
14
|
+
// unpackedSize: number;
|
|
15
|
+
// shasum: string;
|
|
16
|
+
// entryCount: number;
|
|
17
|
+
// }
|
|
18
|
+
|
|
19
|
+
export async function publishPackageVersion(pm: IPackageManager) {
|
|
20
|
+
const wd = new TempWorkingFolder(pm.workspace, 'publish');
|
|
21
|
+
logger.debug('临时目录: %s', wd.path);
|
|
22
|
+
await wd.mkdir();
|
|
23
|
+
|
|
24
|
+
const packFile = await pm.pack(wd.path);
|
|
25
|
+
logger.debug(' -> %s', packFile);
|
|
26
|
+
|
|
27
|
+
const publish_rc = pm.workspace.getNpmRCPath(true);
|
|
28
|
+
const default_rc = pm.workspace.getNpmRCPath(false);
|
|
29
|
+
if (await exists(publish_rc)) {
|
|
30
|
+
logger.debug('找到配置文件: %s', publish_rc);
|
|
31
|
+
await copyFile(publish_rc, wd.joinpath('.npmrc'));
|
|
32
|
+
} else if (await exists(default_rc)) {
|
|
33
|
+
logger.debug('找到配置文件: %s', default_rc);
|
|
34
|
+
await copyFile(default_rc, wd.joinpath('.npmrc'));
|
|
35
|
+
} else {
|
|
36
|
+
logger.debug('没有找到配置文件.');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await copyFile(resolve(pm.projectPath, 'package.json'), wd.joinpath('package.json'));
|
|
40
|
+
|
|
41
|
+
await pm.uploadTarball(packFile, wd.path);
|
|
42
|
+
|
|
43
|
+
const pkg = await pm.loadPackageJson();
|
|
44
|
+
const cache = await pm.createCacheHandler();
|
|
45
|
+
await cache.deleteMetadata(pkg.name);
|
|
46
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { convertCatchedError } from '@idlebox/common';
|
|
2
|
+
import { logger } from '@idlebox/logger';
|
|
3
|
+
import { unlinkSync } from 'node:fs';
|
|
4
|
+
import tgz from 'targz';
|
|
5
|
+
|
|
6
|
+
const packageFolder = /^package\//;
|
|
7
|
+
|
|
8
|
+
export async function decompressPack(src: string, dest: string) {
|
|
9
|
+
logger.debug(`解压文件: ${src}\n\u3000\u3000目录: ${dest}`);
|
|
10
|
+
await new Promise<void>((resolve, reject) => {
|
|
11
|
+
tgz.decompress(
|
|
12
|
+
{
|
|
13
|
+
src,
|
|
14
|
+
dest,
|
|
15
|
+
tar: {
|
|
16
|
+
ignore(_, header) {
|
|
17
|
+
return !header || !header.name;
|
|
18
|
+
},
|
|
19
|
+
map(header) {
|
|
20
|
+
if (packageFolder.test(header.name)) {
|
|
21
|
+
header.name = header.name.replace(packageFolder, '');
|
|
22
|
+
} else {
|
|
23
|
+
header.name = '';
|
|
24
|
+
}
|
|
25
|
+
return header;
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
(e) => {
|
|
30
|
+
if (e) {
|
|
31
|
+
console.error(convertCatchedError(e).stack);
|
|
32
|
+
unlinkSync(src);
|
|
33
|
+
reject(e);
|
|
34
|
+
} else {
|
|
35
|
+
resolve();
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
logger.debug('解压完成');
|
|
41
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { sleep } from '@idlebox/common';
|
|
2
|
+
import { logger } from '@idlebox/logger';
|
|
3
|
+
import { exists, streamPromise } from '@idlebox/node';
|
|
4
|
+
import { createWriteStream } from 'node:fs';
|
|
5
|
+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
|
|
6
|
+
import type { IncomingHttpHeaders, IncomingMessage, OutgoingHttpHeaders } from 'node:http';
|
|
7
|
+
import { get } from 'node:https';
|
|
8
|
+
import { dirname } from 'node:path';
|
|
9
|
+
import type { Readable } from 'node:stream';
|
|
10
|
+
import { createBrotliDecompress, createGunzip, createInflate } from 'node:zlib';
|
|
11
|
+
|
|
12
|
+
interface IMetaInfo {
|
|
13
|
+
headers: IncomingHttpHeaders;
|
|
14
|
+
url: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function downloadFileCached(url: string, file: string) {
|
|
18
|
+
const metadata = `${file}.meta.json`;
|
|
19
|
+
logger.debug`下载文件:\n 地址: long<${url}>\n 保存到: long<${file}>`;
|
|
20
|
+
let meta: IMetaInfo | undefined;
|
|
21
|
+
if (await exists(metadata)) {
|
|
22
|
+
try {
|
|
23
|
+
meta = JSON.parse(await readFile(metadata, 'utf-8'));
|
|
24
|
+
} catch {}
|
|
25
|
+
|
|
26
|
+
if (meta?.url === url) {
|
|
27
|
+
logger.log(' -> 已经下载');
|
|
28
|
+
return file;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const response = await http_stream(url);
|
|
32
|
+
|
|
33
|
+
await mkdir(dirname(file), { recursive: true });
|
|
34
|
+
const writeOut = createWriteStream(`${file}.downloading`);
|
|
35
|
+
await streamPromise(response.stream.pipe(writeOut));
|
|
36
|
+
|
|
37
|
+
meta = { headers: response.headers, url };
|
|
38
|
+
await writeFile(metadata, JSON.stringify(meta), 'utf-8');
|
|
39
|
+
|
|
40
|
+
await rename(`${file}.downloading`, file);
|
|
41
|
+
logger.log(' -> 下载完成');
|
|
42
|
+
|
|
43
|
+
return file;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
class RedirectError extends Error {
|
|
47
|
+
constructor(
|
|
48
|
+
url: string,
|
|
49
|
+
public readonly location: string,
|
|
50
|
+
public readonly code: number,
|
|
51
|
+
) {
|
|
52
|
+
super(`Request ${url} - Redirect to "${location}" with code ${code}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static is(obj: any): obj is RedirectError {
|
|
56
|
+
return obj instanceof RedirectError;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export class HttpError extends Error {
|
|
61
|
+
constructor(
|
|
62
|
+
public readonly url: string,
|
|
63
|
+
public readonly code: number,
|
|
64
|
+
msg: string,
|
|
65
|
+
) {
|
|
66
|
+
super(`Request ${url} - Server responded with ${code}: ${msg}`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
static is(obj: any): obj is HttpError {
|
|
70
|
+
return obj instanceof HttpError;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
type IStream = { stream: Readable };
|
|
75
|
+
export type INormalizedResponse = Omit<IncomingMessage, keyof Readable> & IStream;
|
|
76
|
+
|
|
77
|
+
async function http_stream(url: string, headers?: OutgoingHttpHeaders): Promise<INormalizedResponse> {
|
|
78
|
+
let try_remain = 3;
|
|
79
|
+
let redirect_cnt = 0;
|
|
80
|
+
while (try_remain-- > 0) {
|
|
81
|
+
try {
|
|
82
|
+
return await send_request(url, headers || {});
|
|
83
|
+
} catch (e: unknown) {
|
|
84
|
+
if (RedirectError.is(e)) {
|
|
85
|
+
redirect_cnt++;
|
|
86
|
+
if (redirect_cnt > 8) {
|
|
87
|
+
throw new HttpError(url, 0, '重定向次数过多');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
logger.debug(`[http] 重定向到 ${e.location}`);
|
|
91
|
+
url = e.location;
|
|
92
|
+
try_remain++;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
logger.error('获取 %s 失败 [剩余尝试次数 %s]', url, try_remain);
|
|
97
|
+
if (try_remain === 0) throw e;
|
|
98
|
+
|
|
99
|
+
await sleep(2000);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
throw new Error('不可能的错误');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function send_request(url: string, headers: OutgoingHttpHeaders): Promise<any> {
|
|
106
|
+
headers['Accept-Encoding'] = 'br,gzip,deflate';
|
|
107
|
+
return new Promise<any>((resolve, reject) => {
|
|
108
|
+
logger.debug(`[http] 请求 ${url}`);
|
|
109
|
+
|
|
110
|
+
const request = get(url, { headers }, (response) => {
|
|
111
|
+
logger.debug(
|
|
112
|
+
`[http] 响应 ${response.statusCode} [encoding: ${response.headers['content-encoding']}][${response.headers['content-length']} bytes]`,
|
|
113
|
+
);
|
|
114
|
+
if (response.statusCode === 200) {
|
|
115
|
+
const bytes = Number.parseInt(response.headers['content-length'] ?? '--');
|
|
116
|
+
|
|
117
|
+
if (bytes > 5 * 1024 * 1024 && process.stderr.isTTY) {
|
|
118
|
+
let downloaded = 0;
|
|
119
|
+
response.on('data', (bs) => {
|
|
120
|
+
downloaded += bs.length;
|
|
121
|
+
process.stderr.write(
|
|
122
|
+
`\x1B[2mdownload: ${downloaded} of ${bytes} bytes (${Math.round((downloaded / bytes) * 100)}%)\x1B[0m\r`,
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
response.on('end', () => {
|
|
126
|
+
process.stderr.write('\x1B[K');
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let stream: Readable;
|
|
131
|
+
switch (response.headers['content-encoding']) {
|
|
132
|
+
case 'br':
|
|
133
|
+
stream = response.pipe(createBrotliDecompress());
|
|
134
|
+
break;
|
|
135
|
+
// Or, just use zlib.createUnzip() to handle both of the following cases:
|
|
136
|
+
case 'gzip':
|
|
137
|
+
stream = response.pipe(createGunzip());
|
|
138
|
+
break;
|
|
139
|
+
case 'deflate':
|
|
140
|
+
stream = response.pipe(createInflate());
|
|
141
|
+
break;
|
|
142
|
+
default:
|
|
143
|
+
stream = response;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
resolve(Object.assign(response, { stream }));
|
|
147
|
+
} else if (
|
|
148
|
+
(response.statusCode === 302 ||
|
|
149
|
+
response.statusCode === 301 ||
|
|
150
|
+
response.statusCode === 303 ||
|
|
151
|
+
response.statusCode === 307 ||
|
|
152
|
+
response.statusCode === 308) &&
|
|
153
|
+
response.headers.location
|
|
154
|
+
) {
|
|
155
|
+
reject(new RedirectError(url, response.headers.location, response.statusCode));
|
|
156
|
+
} else {
|
|
157
|
+
reject(new HttpError(url, response.statusCode as number, response.statusMessage as string));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
request.on('error', (err) => {
|
|
162
|
+
reject(err);
|
|
163
|
+
});
|
|
164
|
+
request.end();
|
|
165
|
+
});
|
|
166
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { MonorepoWorkspace } from '@build-script/monorepo-lib';
|
|
2
|
+
import { registerGlobalLifecycle } from '@idlebox/common';
|
|
3
|
+
import { writeJsonFile } from '@idlebox/json-edit';
|
|
4
|
+
import { logger } from '@idlebox/logger';
|
|
5
|
+
import { emptyDir } from '@idlebox/node';
|
|
6
|
+
import { randomBytes } from 'node:crypto';
|
|
7
|
+
import { rmSync } from 'node:fs';
|
|
8
|
+
import { mkdir } from 'node:fs/promises';
|
|
9
|
+
import { resolve } from 'node:path';
|
|
10
|
+
import { isDebugMode } from './functions/cli.js';
|
|
11
|
+
import { decompressPack } from './taball/decompress.js';
|
|
12
|
+
|
|
13
|
+
export class TempWorkingFolder {
|
|
14
|
+
public readonly path: string;
|
|
15
|
+
private _exists = false;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly workspace: MonorepoWorkspace,
|
|
19
|
+
name: string,
|
|
20
|
+
__internal_isChild = false,
|
|
21
|
+
) {
|
|
22
|
+
if (!__internal_isChild) {
|
|
23
|
+
registerGlobalLifecycle(this);
|
|
24
|
+
name += `-${randomBytes(6).toString('hex')}`;
|
|
25
|
+
}
|
|
26
|
+
this.path = resolve(workspace.temp, name);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
resolve(p0: string, ...paths: string[]) {
|
|
30
|
+
return new TempWorkingFolder(this.workspace, this.joinpath(p0, ...paths), true);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
joinpath(p0: string, ...paths: string[]) {
|
|
34
|
+
const r = resolve(this.path, p0, ...paths);
|
|
35
|
+
if (r.startsWith(this.path)) {
|
|
36
|
+
return r;
|
|
37
|
+
}
|
|
38
|
+
throw new Error(`路径不在临时目录内: ${r}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async mkdir() {
|
|
42
|
+
logger.debug('临时工作目录: %s', this.path);
|
|
43
|
+
await mkdir(this.path, { recursive: true });
|
|
44
|
+
this._exists = true;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get exists() {
|
|
48
|
+
return this._exists;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async createPackage(name: string, type: 'module' | 'commonjs', version = '0.0.0') {
|
|
52
|
+
const packageJson = {
|
|
53
|
+
name,
|
|
54
|
+
version,
|
|
55
|
+
type,
|
|
56
|
+
dependencies: {},
|
|
57
|
+
};
|
|
58
|
+
const file = resolve(this.path, 'package.json');
|
|
59
|
+
const data = JSON.stringify(packageJson, null, 4);
|
|
60
|
+
await writeJsonFile(file, data);
|
|
61
|
+
|
|
62
|
+
const tempDir = resolve(this.path, 'node_modules');
|
|
63
|
+
await emptyDir(tempDir);
|
|
64
|
+
|
|
65
|
+
return packageJson;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
unpack(tarball: string, dest = '.') {
|
|
69
|
+
return decompressPack(tarball, resolve(this.path, dest));
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
dispose() {
|
|
73
|
+
if (!isDebugMode) {
|
|
74
|
+
logger.debug(' * 删除临时目录: %s', this.path);
|
|
75
|
+
rmSync(this.path, { force: true, recursive: true });
|
|
76
|
+
} else {
|
|
77
|
+
logger.debug(' * 由于是调试模式,不删除临时文件夹: %s', this.path);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
// biome-ignore-all lint
|
|
4
|
+
// biome-ignore-all assist
|
|
5
|
+
// biome-ignore-all syntax
|
|
6
|
+
/******************************************************************************
|
|
7
|
+
* GENERATED FILE, DO NOT MODIFY
|
|
8
|
+
* 这是生成的文件,千万不要修改
|
|
9
|
+
*
|
|
10
|
+
* @build-script/codegen 1.0.0 - The Simple Code Generater
|
|
11
|
+
* https://github.com/GongT/baobao
|
|
12
|
+
*
|
|
13
|
+
******************************************************************************/
|
|
14
|
+
|
|
15
|
+
export const self_package_version = "0.0.1";
|
|
16
|
+
export const self_package_name = "@build-script/package-tools";
|
|
17
|
+
export const self_package_repository = "undefined";
|
|
18
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { FileBuilder, IOutputShim } from '@build-script/heft-plugin-base';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
|
|
5
|
+
export function generate(builder: FileBuilder, logger: IOutputShim) {
|
|
6
|
+
const pkgFile = path.resolve(__dirname, '../../package.json');
|
|
7
|
+
const pkg = JSON.parse(fs.readFileSync(pkgFile, 'utf-8'));
|
|
8
|
+
|
|
9
|
+
logger.log(`package info = ${pkg.name} @ ${pkg.version}`);
|
|
10
|
+
|
|
11
|
+
return `export const self_package_version = "${pkg.version}";
|
|
12
|
+
export const self_package_name = "${pkg.name}";
|
|
13
|
+
export const self_package_repository = "${pkg.repository}";
|
|
14
|
+
`;
|
|
15
|
+
}
|
package/src/global.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import stream = require('node:stream');
|
|
3
|
+
|
|
4
|
+
export type Callback = (err?: Error | null) => any;
|
|
5
|
+
|
|
6
|
+
export interface Pack extends stream.Readable {
|
|
7
|
+
/**
|
|
8
|
+
* To create a pack stream use tar.pack() and call pack.entry(header, [callback]) to add tar entries.
|
|
9
|
+
*/
|
|
10
|
+
entry(headers: Headers, callback?: Callback): stream.Writable;
|
|
11
|
+
entry(headers: Headers, buffer?: string | Buffer, callback?: Callback): stream.Writable;
|
|
12
|
+
finalize(): void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
declare module 'make-fetch-happen/make-fetch-happen/lib/cache/key.js' {
|
|
16
|
+
export function cacheKey(key: string): string;
|
|
17
|
+
}
|