1 | import spawn from 'cross-spawn';
|
2 | import rp from 'request-promise';
|
3 | import { getURL } from './url';
|
4 |
|
5 | let gitAccount: any;
|
6 | let serverUrl: string;
|
7 |
|
8 | export function setServerUrl(url: string) {
|
9 | serverUrl = url;
|
10 | }
|
11 |
|
12 | function getHostname(url: string): string {
|
13 | if (/https?/.test(url)) {
|
14 | const match: any = url.match(/^http(s)?:\/\/(.*?)\//);
|
15 | return match[2].split('@').pop();
|
16 | } else {
|
17 | const match: any = url.match(/@(.*):/);
|
18 | return match[1];
|
19 | }
|
20 | }
|
21 |
|
22 | async function prepareAccount() {
|
23 | if (gitAccount) {
|
24 | return;
|
25 | }
|
26 | const url = getURL(serverUrl, 'apply/getlist?name=0');
|
27 | if (!url) {
|
28 | return;
|
29 | }
|
30 | const options = {
|
31 | url: url,
|
32 | method: 'GET'
|
33 | };
|
34 | return rp(options)
|
35 | .then((response: any) => {
|
36 | const data = JSON.parse(response);
|
37 | if (data.account) {
|
38 | gitAccount = data.account;
|
39 | }
|
40 | })
|
41 | .catch((err: any) => {});
|
42 | }
|
43 |
|
44 | export async function transformUrl(url: string, account?: any): Promise<any> {
|
45 | if (account) {
|
46 | gitAccount = account;
|
47 | } else {
|
48 | await prepareAccount();
|
49 | }
|
50 | const hostname = getHostname(url);
|
51 | let transformedUrl;
|
52 | if (/https?/.test(url)) {
|
53 | transformedUrl = url;
|
54 | } else {
|
55 | transformedUrl = url.replace(`git@${hostname}:`, `http://${hostname}/`);
|
56 | }
|
57 | if (gitAccount) {
|
58 | const { username, password } = gitAccount;
|
59 | return transformedUrl.replace(
|
60 | /https?:\/\/(.*?(:.*?)?@)?/,
|
61 | `http://${username}:${password}@`
|
62 | );
|
63 | }
|
64 | return transformedUrl;
|
65 | }
|
66 |
|
67 | export async function clearGitCert(url: string) {
|
68 | const { username } = gitAccount;
|
69 | if (!username) {
|
70 | return;
|
71 | }
|
72 | if (!/https?:\/\/(.*?(:.*?)?@)/.test(url)) {
|
73 | url = await transformUrl(url);
|
74 | }
|
75 | return new Promise(resolve => {
|
76 | const child = spawn('git', ['credential', 'reject'], {
|
77 | windowsHide: true,
|
78 | timeout: 60 * 1000 * 1
|
79 | });
|
80 | child.stdin?.write(`url=${url}`);
|
81 | child.stdin?.end();
|
82 | child.on('close', code => {
|
83 | resolve(code);
|
84 | });
|
85 | });
|
86 | }
|
87 |
|
88 | export async function clearGitCertByPath(repoPath: string) {
|
89 | const ret = spawn.sync('git', ['config', '--get', 'remote.origin.url'], {
|
90 | windowsHide: true,
|
91 | cwd: repoPath
|
92 | });
|
93 | const url = ret?.stdout?.toString().trim();
|
94 | return clearGitCert(url);
|
95 | }
|
96 |
|
97 | export async function download(
|
98 | url: string,
|
99 | tag: string,
|
100 | filepath: string
|
101 | ): Promise<any> {
|
102 | const cloneUrl = await transformUrl(url);
|
103 |
|
104 | console.log('clone from', url);
|
105 | return new Promise((resolve, reject) => {
|
106 | const child = spawn(
|
107 | 'git',
|
108 | ['clone', '-b', tag, '--progress', '--depth', '1', cloneUrl, filepath],
|
109 | {
|
110 | stdio: 'pipe',
|
111 | windowsHide: true
|
112 | }
|
113 | );
|
114 | let doneFlag = false;
|
115 | child.stderr?.on('data', d => {
|
116 | if (doneFlag) {
|
117 | return;
|
118 | }
|
119 | if (
|
120 | d?.toString()?.startsWith('Note:') ||
|
121 | d?.toString()?.startsWith('注意')
|
122 | ) {
|
123 | doneFlag = true;
|
124 | return;
|
125 | }
|
126 | process.stderr.write(d);
|
127 | });
|
128 | child.stdout?.on('data', d => {
|
129 | if (doneFlag) {
|
130 | return;
|
131 | }
|
132 | process.stdout.write(d);
|
133 | });
|
134 | child.on('close', code => {
|
135 | if (code === 0) {
|
136 | resolve(0);
|
137 | } else {
|
138 | reject(code);
|
139 | }
|
140 | });
|
141 | child.on('error', err => {
|
142 | reject(err);
|
143 | });
|
144 | }).finally(() => clearGitCert(cloneUrl));
|
145 | }
|