@bratel/dgit 0.0.13 → 0.0.15

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/src/dgit.ts CHANGED
@@ -1,256 +1,275 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
- import async from 'async';
4
- import repo from './repo';
5
- import { createLogger } from './log';
6
- import { requestGetPromise, requestOnStream } from './request';
7
- import {
8
- DgitGlobalOption,
9
- RepoOptionType,
10
- RepoTreeNode,
11
- DgitLifeCycle,
12
- DgitLoadGitTree,
1
+ import type {
2
+ DgitGlobalOption,
3
+ DgitLifeCycle,
4
+ DgitLoadGitTree,
5
+ RepoOptionType,
6
+ RepoTreeNode,
13
7
  } from './type';
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import process from 'node:process';
11
+ import async from 'async';
14
12
  import {
15
- ParseGithubHttpsLink, isHttpsLink, MakeDirs,
13
+ isHttpsLink,
14
+ MakeDirs,
15
+ ParseGithubHttpsLink,
16
16
  } from './cmd/utils';
17
+ import { createLogger } from './log';
18
+ import repo from './repo';
19
+ import { requestGetPromise, requestOnStream } from './request';
17
20
 
18
21
  const UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36';
19
22
  const DEFAULT_PARALLEL_LIMIT = 10;
20
23
  const MAX_PARALLEL_LIMIT = 100;
21
24
  const JSON_STRINGIFY_PADDING = 2;
22
25
 
23
- const dgit = async (
24
- repoOption: RepoOptionType,
25
- dPath: string,
26
- dgitOptions?: DgitGlobalOption,
27
- hooks?: DgitLifeCycle & DgitLoadGitTree,
28
- ): Promise<void> => {
29
- const {
30
- username, password, token, githubLink, proxy = '',
31
- } = repoOption;
32
-
33
- let {
34
- owner, repoName, ref = 'master', relativePath = '.',
35
- } = repoOption;
36
-
37
- if (githubLink && isHttpsLink(githubLink)) {
38
- const parseResult = ParseGithubHttpsLink(githubLink);
39
- owner = parseResult.owner;
40
- repoName = parseResult.repoName;
41
- ref = parseResult.ref;
42
- relativePath = parseResult.relativePath;
43
- }
26
+ // https://deepwiki.com/search/python-node-treepythonjula-pyt_e06e7d62-6a9a-4d4b-9e74-0a1cf32f4946?mode=fast
27
+ async function dgit(repoOption: RepoOptionType, dPath: string, dgitOptions?: DgitGlobalOption, hooks?: DgitLifeCycle & DgitLoadGitTree): Promise<void> {
28
+ const {
29
+ username,
30
+ password,
31
+ token,
32
+ githubLink,
33
+ proxy = '',
34
+ } = repoOption;
35
+
36
+ let {
37
+ owner,
38
+ repoName,
39
+ ref = 'master',
40
+ relativePath = '.',
41
+ } = repoOption;
42
+
43
+ if (githubLink && isHttpsLink(githubLink)) {
44
+ const parseResult = ParseGithubHttpsLink(githubLink);
45
+ owner = parseResult.owner;
46
+ repoName = parseResult.repoName;
47
+ ref = parseResult.ref;
48
+ relativePath = parseResult.relativePath;
49
+ }
50
+
51
+ if (!owner || !repoName) {
52
+ throw new Error('invalid repo option.');
53
+ }
54
+
55
+ const logger = createLogger(dgitOptions);
56
+
57
+ const { exclude = [], include = [], exactMatch = false } = dgitOptions || {};
58
+
59
+ let { parallelLimit = DEFAULT_PARALLEL_LIMIT } = dgitOptions || {};
60
+ if (!parallelLimit || parallelLimit <= 0) {
61
+ logger('parallelLimit value is invalid.');
62
+ parallelLimit = DEFAULT_PARALLEL_LIMIT;
63
+ }
64
+
65
+ parallelLimit > MAX_PARALLEL_LIMIT && (parallelLimit = MAX_PARALLEL_LIMIT);
66
+
67
+ const {
68
+ onSuccess,
69
+ onError,
70
+ onProgress,
71
+ onFinish,
72
+ onRetry,
73
+ onResolved,
74
+ beforeLoadTree,
75
+ afterLoadTree,
76
+ } = hooks || {};
77
+
78
+ let onSuccessResolve: (data?: any) => void = () => {};
79
+ let onErrorReject: (err?: any) => void = () => {};
80
+
81
+ const prom: Promise<void> = new Promise((resolve, reject) => {
82
+ onSuccessResolve = resolve;
83
+ onErrorReject = reject;
84
+ });
85
+
86
+ const { getRepoTreeUrl, getDownloadUrl } = repo(owner, repoName, ref, proxy);
87
+ const url = getRepoTreeUrl();
88
+
89
+ const headers = {
90
+ 'User-Agent': UserAgent,
91
+ 'Authorization': token ? `token ${token}` : undefined,
92
+ };
93
+
94
+ const auth = username && password
95
+ ? {
96
+ user: username,
97
+ pass: password,
98
+ sendImmediately: true,
99
+ }
100
+ : undefined;
101
+
102
+ const options = {
103
+ url,
104
+ headers,
105
+ auth,
106
+ };
107
+
108
+ const destPath = path.isAbsolute(dPath) ? dPath : path.resolve(process.cwd(), dPath);
109
+
110
+ logger(' request repo tree options.');
111
+ logger(JSON.stringify(options, null, JSON_STRINGIFY_PADDING));
112
+
113
+ try {
114
+ logger(' loading remote repo tree...');
115
+ beforeLoadTree && beforeLoadTree();
116
+ const body = await requestGetPromise(options, dgitOptions || {}, {
117
+ onRetry() {
118
+ logger(` request ${url} failed. Retrying...`);
119
+ onRetry && onRetry();
120
+ },
121
+ });
44
122
 
45
- if (!owner || !repoName) {
46
- throw new Error('invalid repo option.');
47
- }
123
+ logger(' loading remote repo tree succeed.');
124
+ afterLoadTree && afterLoadTree();
125
+ const result = JSON.parse(body);
48
126
 
49
- const logger = createLogger(dgitOptions);
127
+ if (!result.tree || result.tree.length <= 0) {
128
+ throw new Error('404 repo not found!');
129
+ }
50
130
 
51
- const { exclude = [], include = []} = dgitOptions || {};
131
+ const treeNodeList: RepoTreeNode[] = result.tree;
132
+ const includeTreeNodeList = treeNodeList.filter((node) => {
133
+ const nPath = path.resolve(__dirname, node.path);
134
+ const rPath = path.resolve(__dirname, relativePath);
135
+ let pathMatch: boolean;
136
+ if (exactMatch) {
137
+ // 精确匹配:路径完全相等或者路径后跟分隔符
138
+ pathMatch = nPath === rPath || nPath.startsWith(rPath + path.sep) || nPath.startsWith(`${rPath}/`);
139
+ }
140
+ else {
141
+ pathMatch = nPath.startsWith(rPath);
142
+ }
143
+ if (!pathMatch || node.type !== 'blob') {
144
+ return false;
145
+ }
146
+ if (
147
+ exclude.some(v => nPath.startsWith(path.resolve(rPath, v)))
148
+ && include.every(v => !nPath.startsWith(path.resolve(rPath, v)))
149
+ ) {
150
+ return false;
151
+ }
152
+ return true;
153
+ });
52
154
 
53
- let { parallelLimit = DEFAULT_PARALLEL_LIMIT } = dgitOptions || {};
54
- if (!parallelLimit || parallelLimit <= 0) {
55
- logger('parallelLimit value is invalid.');
56
- parallelLimit = DEFAULT_PARALLEL_LIMIT;
155
+ if (includeTreeNodeList.length <= 0) {
156
+ throw new Error(`404 repo ${relativePath} not found!`);
57
157
  }
58
158
 
59
- parallelLimit > MAX_PARALLEL_LIMIT && (parallelLimit = MAX_PARALLEL_LIMIT);
60
-
61
- const {
62
- onSuccess,
63
- onError,
64
- onProgress,
65
- onFinish,
66
- onRetry,
67
- onResolved,
68
- beforeLoadTree,
69
- afterLoadTree,
70
- } = hooks || {};
71
-
72
- let onSuccessResolve: (data?: any)=> void = () => {};
73
- let onErrorReject: (err?: any)=> void = () => {};
74
-
75
- const prom: Promise<void> = new Promise((resolve, reject) => {
76
- onSuccessResolve = resolve;
77
- onErrorReject = reject;
159
+ const totalStatus = includeTreeNodeList.reduce(
160
+ (prev, cur) => {
161
+ if (cur.type === 'blob') {
162
+ prev.size += cur.size;
163
+ prev.count++;
164
+ }
165
+ return prev;
166
+ },
167
+ { size: 0, count: 0 },
168
+ );
169
+
170
+ let currentSize = 0;
171
+ let currentCount = 0;
172
+
173
+ onResolved
174
+ && onResolved({
175
+ currentSize,
176
+ currentCount,
177
+ totalSize: totalStatus.size,
178
+ totalCount: totalStatus.count,
78
179
  });
79
180
 
80
- const { getRepoTreeUrl, getDownloadUrl } = repo(owner, repoName, ref, proxy);
81
- const url = getRepoTreeUrl();
82
-
83
- const headers = {
84
- 'User-Agent' : UserAgent,
85
- Authorization: token ? `token ${ token }` : undefined,
86
- };
87
-
88
- const auth = username && password ?
89
- {
90
- user : username,
91
- pass : password,
92
- sendImmediately: true,
93
- } :
94
- undefined;
95
-
96
- const options = {
97
- url, headers, auth,
98
- };
99
-
100
- const destPath = path.isAbsolute(dPath) ? dPath : path.resolve(process.cwd(), dPath);
101
-
102
- logger(' request repo tree options.');
103
- logger(JSON.stringify(options, null, JSON_STRINGIFY_PADDING));
104
-
105
- try {
106
- logger(' loading remote repo tree...');
107
- beforeLoadTree && beforeLoadTree();
108
- const body = await requestGetPromise(options, dgitOptions || {}, {
109
- onRetry () {
110
- logger(` request ${ url } failed. Retrying...`);
111
- onRetry && onRetry();
112
- },
113
- });
181
+ logger(' include files resolved.');
182
+ logger(
183
+ '',
184
+ JSON.stringify({
185
+ currentSize,
186
+ currentCount,
187
+ totalSize: totalStatus.size,
188
+ totalCount: totalStatus.count,
189
+ }),
190
+ );
191
+
192
+ async.eachLimit(
193
+ includeTreeNodeList,
194
+ parallelLimit,
195
+ (node, callback) => {
196
+ const downloadUrl = getDownloadUrl(node.path);
197
+
198
+ const rPath = path.resolve(destPath, relativePath);
199
+ const tPath = path.resolve(destPath, node.path);
200
+ const root = path.resolve(destPath, '.');
201
+
202
+ let targetPath: string;
203
+ if (rPath === tPath) {
204
+ targetPath = path.resolve(destPath, path.basename(tPath));
205
+ }
206
+ else {
207
+ targetPath = tPath.replace(rPath, root);
208
+ }
114
209
 
115
- logger(' loading remote repo tree succeed.');
116
- afterLoadTree && afterLoadTree();
117
- const result = JSON.parse(body);
210
+ logger('', node.path, relativePath, targetPath);
118
211
 
119
- if (!result.tree || result.tree.length <= 0) {
120
- throw new Error('404 repo not found!');
212
+ if (!fs.existsSync(path.dirname(targetPath))) {
213
+ MakeDirs(path.dirname(targetPath));
121
214
  }
122
215
 
123
- const treeNodeList: RepoTreeNode[] = result.tree;
124
- const includeTreeNodeList = treeNodeList.filter(node => {
125
- const nPath = path.resolve(__dirname, node.path);
126
- const rPath = path.resolve(__dirname, relativePath);
127
- if (!nPath.startsWith(rPath) || node.type !== 'blob') {
128
- return false;
129
- }
130
- if (
131
- exclude.some(v => nPath.startsWith(path.resolve(rPath, v))) &&
132
- include.every(v => !nPath.startsWith(path.resolve(rPath, v)))
133
- ) {
134
- return false;
135
- }
136
- return true;
137
- });
216
+ const ws = fs.createWriteStream(targetPath);
138
217
 
139
- if (includeTreeNodeList.length <= 0) {
140
- throw new Error(`404 repo ${ relativePath } not found!`);
141
- }
218
+ logger(` downloading from ${downloadUrl}...`);
142
219
 
143
- const totalStatus = includeTreeNodeList.reduce(
144
- (prev, cur) => {
145
- if (cur.type === 'blob') {
146
- prev.size += cur.size;
147
- prev.count++;
148
- }
149
- return prev;
150
- },
151
- { size: 0, count: 0 },
152
- );
153
-
154
- let currentSize = 0;
155
- let currentCount = 0;
156
-
157
- onResolved &&
158
- onResolved({
159
- currentSize,
160
- currentCount,
161
- totalSize : totalStatus.size,
162
- totalCount: totalStatus.count,
163
- });
220
+ requestOnStream(downloadUrl, ws, dgitOptions || {}, {
221
+ onSuccess() {
222
+ currentCount++;
223
+ currentSize += node.size;
224
+
225
+ logger(` write file ${node.path} succeed.
226
+ size: [${currentSize}/${totalStatus.size}],
227
+ count: [${currentCount}/${totalStatus.count}]`);
164
228
 
165
- logger(' include files resolved.');
166
- logger(
167
- '',
168
- JSON.stringify({
229
+ onProgress
230
+ && onProgress(
231
+ {
232
+ totalCount: totalStatus.count,
233
+ totalSize: totalStatus.size,
169
234
  currentSize,
170
235
  currentCount,
171
- totalSize : totalStatus.size,
172
- totalCount: totalStatus.count,
173
- }),
174
- );
175
-
176
- async.eachLimit(
177
- includeTreeNodeList,
178
- parallelLimit,
179
- (node, callback) => {
180
- const downloadUrl = getDownloadUrl(node.path);
181
-
182
- const rPath = path.resolve(destPath, relativePath);
183
- const tPath = path.resolve(destPath, node.path);
184
- const root = path.resolve(destPath, '.');
185
-
186
- let targetPath: string;
187
- if (rPath === tPath) {
188
- targetPath = path.resolve(destPath, path.basename(tPath));
189
- } else {
190
- targetPath = tPath.replace(rPath, root);
191
- }
192
-
193
- logger('', node.path, relativePath, targetPath);
194
-
195
- if (!fs.existsSync(path.dirname(targetPath))) {
196
- MakeDirs(path.dirname(targetPath));
197
- }
198
-
199
- const ws = fs.createWriteStream(targetPath);
200
-
201
- logger(` downloading from ${ downloadUrl }...`);
202
-
203
- requestOnStream(downloadUrl, ws, dgitOptions || {}, {
204
- onSuccess () {
205
- currentCount++;
206
- currentSize += node.size;
207
-
208
- logger(` write file ${ node.path } succeed.
209
- size: [${ currentSize }/${ totalStatus.size }],
210
- count: [${ currentCount }/${ totalStatus.count }]`);
211
-
212
- onProgress &&
213
- onProgress(
214
- {
215
- totalCount: totalStatus.count,
216
- totalSize : totalStatus.size,
217
- currentSize,
218
- currentCount,
219
- },
220
- node,
221
- );
222
-
223
- callback();
224
- },
225
- onError (err) {
226
- logger('', err);
227
- callback(new Error(` request ${ downloadUrl } failed.`));
228
- },
229
- onRetry () {
230
- logger(` request ${ downloadUrl } failed. Retrying...`);
231
- onRetry && onRetry();
232
- },
233
- });
234
- },
235
- err => {
236
- if (err) {
237
- onError && onError(err);
238
- onFinish && onFinish();
239
- onErrorReject(err);
240
- } else {
241
- onSuccess && onSuccess();
242
- onFinish && onFinish();
243
- onSuccessResolve();
244
- }
245
- },
246
- );
247
- } catch (error) {
248
- onError && onError(error);
249
- onFinish && onFinish();
250
- onErrorReject(error);
251
- }
252
-
253
- return prom;
254
- };
236
+ },
237
+ node,
238
+ );
239
+
240
+ callback();
241
+ },
242
+ onError(err) {
243
+ logger('', err);
244
+ callback(new Error(` request ${downloadUrl} failed.`));
245
+ },
246
+ onRetry() {
247
+ logger(` request ${downloadUrl} failed. Retrying...`);
248
+ onRetry && onRetry();
249
+ },
250
+ });
251
+ },
252
+ (err) => {
253
+ if (err) {
254
+ onError && onError(err);
255
+ onFinish && onFinish();
256
+ onErrorReject(err);
257
+ }
258
+ else {
259
+ onSuccess && onSuccess();
260
+ onFinish && onFinish();
261
+ onSuccessResolve();
262
+ }
263
+ },
264
+ );
265
+ }
266
+ catch (error) {
267
+ onError && onError(error);
268
+ onFinish && onFinish();
269
+ onErrorReject(error);
270
+ }
271
+
272
+ return prom;
273
+ }
255
274
 
256
275
  export default dgit;
package/src/log.ts CHANGED
@@ -1,12 +1,14 @@
1
- import { DgitGlobalOption } from './type';
1
+ import type { DgitGlobalOption } from './type';
2
2
 
3
3
  const DEFAULT_PREFIX = '[dgit-logger]';
4
4
 
5
- export const createLogger = (option?: DgitGlobalOption) => (...message: any[]) => {
5
+ export function createLogger(option?: DgitGlobalOption) {
6
+ return (...message: any[]) => {
6
7
  if (option && option.log) {
7
- const prefix = option ?
8
- option.logPrefix || DEFAULT_PREFIX :
9
- DEFAULT_PREFIX;
10
- console.log(prefix, ...message, '\n');
8
+ const prefix = option
9
+ ? option.logPrefix || DEFAULT_PREFIX
10
+ : DEFAULT_PREFIX;
11
+ console.log(prefix, ...message, '\n');
11
12
  }
12
- };
13
+ };
14
+ }
package/src/repo.ts CHANGED
@@ -1,6 +1,8 @@
1
- const repoUtils = (owner: string, repoName: string, ref: string, proxy: string) => ({
2
- getRepoTreeUrl: () => `https://api.github.com/repos/${ owner }/${ repoName }/git/trees/${ ref }?recursive=1`,
3
- getDownloadUrl: (path: string) => `${ proxy ? `${ proxy }/` : '' }https://raw.githubusercontent.com/${ owner }/${ repoName }/${ ref }/${ path }`,
4
- });
1
+ function repoUtils(owner: string, repoName: string, ref: string, proxy: string | null) {
2
+ return {
3
+ getRepoTreeUrl: () => `https://api.github.com/repos/${owner}/${repoName}/git/trees/${ref}?recursive=1`,
4
+ getDownloadUrl: (path: string) => `${proxy ? `${proxy}/` : ''}https://raw.githubusercontent.com/${owner}/${repoName}/${ref}/${path}`,
5
+ };
6
+ }
5
7
 
6
8
  export default repoUtils;