|
1 | | -import {ICore} from './src/core' |
| 1 | +import {run} from './src/action' |
2 | 2 | import {ActionsCore} from './src/actions_core' |
3 | | -import {mkdirp} from './src/downloader' |
4 | | -import process from 'process' |
5 | | -import {spawnSync} from 'child_process' |
6 | | -import { |
7 | | - getArtifactMetadata, |
8 | | - getViaGit, |
9 | | - gitForWindowsUsrBinPath |
10 | | -} from './src/git' |
11 | | -import {getViaCIArtifacts} from './src/ci_artifacts' |
12 | | -import * as fs from 'fs' |
13 | | - |
14 | | -/** |
15 | | - * Some Azure VM types have a temporary disk which is local to the VM and therefore provides |
16 | | - * _much_ faster disk IO than the OS Disk (or any other attached disk). |
17 | | - * |
18 | | - * Hosted GitHub Actions runners also leverage this disk and do their work in D:/a/_work, so let's |
19 | | - * use it too if we can. It leads to a ~25% speed increase when doing heavy IO operations. |
20 | | - * |
21 | | - * https://learn.microsoft.com/en-us/azure/virtual-machines/managed-disks-overview#temporary-disk |
22 | | - */ |
23 | | -function getDriveLetterPrefix(core: ICore): string { |
24 | | - if (fs.existsSync('D:/')) { |
25 | | - core.info('Found a fast, temporary disk on this VM (D:/). Will use that.') |
26 | | - return 'D:/' |
27 | | - } |
28 | | - |
29 | | - return 'C:/' |
30 | | -} |
31 | | - |
32 | | -async function setup( |
33 | | - core: ICore, |
34 | | - flavor: string, |
35 | | - architecture: string |
36 | | -): Promise<void> { |
37 | | - try { |
38 | | - if (process.platform !== 'win32') { |
39 | | - core.warning( |
40 | | - `Skipping this Action because it only works on Windows, not on ${process.platform}` |
41 | | - ) |
42 | | - return |
43 | | - } |
44 | | - |
45 | | - const githubToken = core.getInput('github-token') |
46 | | - const verbose = core.getInput('verbose') |
47 | | - const msysMode = core.getInput('msys') === 'true' |
48 | | - |
49 | | - const {artifactName, download, id} = |
50 | | - flavor === 'minimal' |
51 | | - ? await getViaCIArtifacts(core, architecture, githubToken) |
52 | | - : await getViaGit(core, flavor, architecture, githubToken) |
53 | | - const outputDirectory = |
54 | | - core.getInput('path') || `${getDriveLetterPrefix(core)}${artifactName}` |
55 | | - core.setOutput('result', outputDirectory) |
56 | | - |
57 | | - let useCache: boolean |
58 | | - switch (core.getInput('cache')) { |
59 | | - case 'true': |
60 | | - useCache = true |
61 | | - break |
62 | | - case 'auto': |
63 | | - useCache = !['full', 'minimal'].includes(flavor) |
64 | | - break |
65 | | - default: |
66 | | - useCache = false |
67 | | - } |
68 | | - |
69 | | - if (!core.isCacheAvailable()) { |
70 | | - useCache = false |
71 | | - } |
72 | | - |
73 | | - let needToDownload = true |
74 | | - try { |
75 | | - if (useCache && (await core.restoreCache([outputDirectory], id))) { |
76 | | - core.info(`Cached ${id} was successfully restored`) |
77 | | - needToDownload = false |
78 | | - } |
79 | | - } catch (e) { |
80 | | - core.warning(`Cannot use @actions/cache (${e})`) |
81 | | - useCache = false |
82 | | - } |
83 | | - |
84 | | - if (needToDownload) { |
85 | | - core.info(`Downloading ${artifactName}`) |
86 | | - await download( |
87 | | - outputDirectory, |
88 | | - verbose.match(/^\d+$/) ? parseInt(verbose) : verbose === 'true' |
89 | | - ) |
90 | | - |
91 | | - try { |
92 | | - if (useCache && !(await core.saveCache([outputDirectory], id))) { |
93 | | - core.warning(`Failed to cache ${id}`) |
94 | | - } |
95 | | - } catch (e) { |
96 | | - core.warning( |
97 | | - `Failed to cache ${id}: ${e instanceof Error ? e.message : e}` |
98 | | - ) |
99 | | - } |
100 | | - } |
101 | | - |
102 | | - const mingw = { |
103 | | - i686: 'MINGW32', |
104 | | - x86_64: 'MINGW64', |
105 | | - aarch64: 'CLANGARM64' |
106 | | - }[architecture] |
107 | | - |
108 | | - if (mingw === undefined) { |
109 | | - core.setFailed(`Invalid architecture ${architecture} specified`) |
110 | | - return |
111 | | - } |
112 | | - |
113 | | - const msystem = msysMode ? 'MSYS' : mingw |
114 | | - |
115 | | - const binPaths = [ |
116 | | - // Set up PATH so that Git for Windows' SDK's `bash.exe`, `prove` and `gcc` are found |
117 | | - '/usr/bin/core_perl', |
118 | | - '/usr/bin', |
119 | | - `/${mingw.toLocaleLowerCase()}/bin` |
120 | | - ] |
121 | | - |
122 | | - for (const binPath of msysMode ? binPaths.reverse() : binPaths) { |
123 | | - core.addPath(`${outputDirectory}${binPath}`) |
124 | | - } |
125 | | - |
126 | | - core.exportVariable('MSYSTEM', msystem) |
127 | | - if ( |
128 | | - !('LANG' in process.env) && |
129 | | - !('LC_ALL' in process.env) && |
130 | | - !('LC_CTYPE' in process.env) |
131 | | - ) { |
132 | | - core.exportVariable('LC_CTYPE', 'C.UTF-8') |
133 | | - } |
134 | | - |
135 | | - // ensure that /dev/fd/*, /dev/mqueue and friends exist |
136 | | - for (const path of ['/dev/mqueue', '/dev/shm']) { |
137 | | - mkdirp(`${outputDirectory}${path}`) |
138 | | - } |
139 | | - |
140 | | - const ln = (linkPath: string, target: string): void => { |
141 | | - const child = spawnSync( |
142 | | - flavor === 'minimal' ? 'ln.exe' : 'usr\\bin\\ln.exe', |
143 | | - ['-s', target, linkPath], |
144 | | - { |
145 | | - cwd: outputDirectory, |
146 | | - env: { |
147 | | - MSYS: 'winsymlinks:sys' |
148 | | - } |
149 | | - } |
150 | | - ) |
151 | | - if (child.error) throw child.error |
152 | | - } |
153 | | - for (const [linkPath, target] of Object.entries({ |
154 | | - fd: 'fd', |
155 | | - stdin: 'fd/0', |
156 | | - stdout: 'fd/1', |
157 | | - stderr: 'fd/2' |
158 | | - })) { |
159 | | - ln(`/dev/${linkPath}`, `/proc/self/${target}`) |
160 | | - } |
161 | | - } catch (error) { |
162 | | - core.setFailed(error instanceof Error ? error.message : `${error}`) |
163 | | - } |
164 | | -} |
165 | | - |
166 | | -function cleanup(core: ICore, flavor: string, architecture: string): void { |
167 | | - if (core.getInput('cleanup') !== 'true') { |
168 | | - core.info( |
169 | | - `Won't clean up SDK files as the 'cleanup' input was not provided or doesn't equal 'true'.` |
170 | | - ) |
171 | | - return |
172 | | - } |
173 | | - |
174 | | - const outputDirectory = |
175 | | - core.getInput('path') || |
176 | | - `${getDriveLetterPrefix(core)}${ |
177 | | - getArtifactMetadata(flavor, architecture).artifactName |
178 | | - }` |
179 | | - |
180 | | - /** |
181 | | - * Shelling out to `rm -rf` is more than twice as fast as Node's `fs.rmSync` method. |
182 | | - * Let's use it if it's available, and otherwise fall back to `fs.rmSync`. |
183 | | - */ |
184 | | - const cleanupMethod = fs.existsSync(`${gitForWindowsUsrBinPath}/bash.exe`) |
185 | | - ? 'rm -rf' |
186 | | - : 'node' |
187 | | - |
188 | | - core.info( |
189 | | - `Cleaning up ${outputDirectory} using the "${cleanupMethod}" method...` |
190 | | - ) |
191 | | - |
192 | | - if (cleanupMethod === 'rm -rf') { |
193 | | - const child = spawnSync( |
194 | | - `${gitForWindowsUsrBinPath}/bash.exe`, |
195 | | - ['-c', `rm -rf "${outputDirectory}"`], |
196 | | - { |
197 | | - encoding: 'utf-8', |
198 | | - env: {PATH: '/usr/bin'} |
199 | | - } |
200 | | - ) |
201 | | - |
202 | | - if (child.error) throw child.error |
203 | | - if (child.stderr) core.error(child.stderr) |
204 | | - } else { |
205 | | - fs.rmSync(outputDirectory, {recursive: true, force: true}) |
206 | | - } |
207 | | - |
208 | | - core.info(`Finished cleaning up ${outputDirectory}.`) |
209 | | -} |
210 | | - |
211 | | -async function run(core: ICore): Promise<void> { |
212 | | - const flavor = core.getInput('flavor') |
213 | | - const architecture = core.getInput('architecture') |
214 | | - const isPost = !!core.getState('isPost') |
215 | | - if (!isPost) { |
216 | | - setup(core, flavor, architecture) |
217 | | - /* |
218 | | - * Publish a variable so that when the POST action runs, it can determine it should run the cleanup logic. |
219 | | - * This is necessary since we don't have a separate entry point. |
220 | | - * Inspired by https://github.com/actions/checkout/blob/v3.1.0/src/state-helper.ts#L56-L60 |
221 | | - */ |
222 | | - core.saveState('isPost', 'true') |
223 | | - } else { |
224 | | - // If the POST action is running, we cleanup our artifacts |
225 | | - cleanup(core, flavor, architecture) |
226 | | - } |
227 | | -} |
228 | 3 |
|
229 | 4 | run(new ActionsCore()) |
0 commit comments