This repository was archived by the owner on Oct 13, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathcargo.ts
149 lines (134 loc) · 4.85 KB
/
cargo.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
import * as os from 'os';
import * as io from '@actions/io';
import * as core from '@actions/core';
import * as exec from '@actions/exec';
import * as cache from '@actions/cache';
import * as http from '@actions/http-client';
import * as path from 'path';
export async function resolveVersion(crate: string): Promise<string> {
const url = `https://crates.io/api/v1/crates/${crate}`;
const client = new http.HttpClient(
'@actions-rs (https://github.com/actions-rs/)',
);
const resp: any = await client.getJson(url);
if (resp.result == null) {
throw new Error('Unable to fetch latest crate version');
}
return resp.result['crate']['newest_version'];
}
export class Cargo {
private readonly path: string;
private constructor(path: string) {
this.path = path;
}
public static async get(): Promise<Cargo> {
try {
const path = await io.which('cargo', true);
return new Cargo(path);
} catch (error) {
core.error(
'cargo is not installed by default for some virtual environments, \
see https://help.github.com/en/articles/software-in-virtual-environments-for-github-actions',
);
core.error(
'To install it, use this action: https://github.com/actions-rs/toolchain',
);
throw error;
}
}
/**
* Executes `cargo install ${program}` or uses the cached ${program} from
* the GitHub Actions cache.
*
* `version` argument could either be the actual program version or
* `"latest"`, which can be provided by user input.
*
* If `version` is `undefined` or `"latest"`, this method calls the
* Crates.io API, fetches the latest version and search for it in the cache.
*
* ## Returns
*
* Path to the installed program.
* As the $PATH should be already tuned properly at this point,
* returned value at the moment is simply equal to the `program` argument.
*/
public async installCached(
program: string,
version?: string,
): Promise<string> {
version = version || (await resolveVersion(program));
if (version == 'latest') {
version = await resolveVersion(program);
}
const runner = os.platform() + '-' + os.release() + '-' + os.arch();
const paths = [path.join(path.dirname(this.path), program)];
const programKey = program + '-' + version + '-' + runner;
const cacheKey = await cache.restoreCache(paths, programKey);
if (cacheKey) {
core.info(`Using cached \`${program}\` with version ${version}`);
return program;
} else {
const res = await this.install(program, version);
try {
core.info(`Caching \`${program}\` with key ${programKey}`);
await cache.saveCache(paths, programKey);
} catch (error) {
if (error.name === cache.ValidationError.name) {
throw error;
} else if (error.name === cache.ReserveCacheError.name) {
core.info(error.message);
} else {
core.info('[warning]' + error.message);
}
}
return res;
}
}
/**
* Executes `cargo install ${program}`.
*
* `version` argument could either be the actual program version or
* `"latest"`, which can be provided by user input.
*
* If `version` is `undefined` or `"latest"`, this method calls the
* Crates.io API, fetches the latest version and search for it in the cache.
*
* ## Returns
*
* Path to the installed program.
* As the $PATH should be already tuned properly at this point,
* returned value at the moment is simply equal to the `program` argument.
*/
public async install(program: string, version?: string): Promise<string> {
const args = ['install'];
if (version && version != 'latest') {
args.push('--version');
args.push(version);
}
args.push(program);
try {
core.startGroup(`Installing "${program} = ${version || 'latest'}"`);
await this.call(args);
} finally {
core.endGroup();
}
return program;
}
/**
* Find the cargo sub-command or install it
*/
public async findOrInstall(
program: string,
version?: string,
): Promise<string> {
try {
return await io.which(program, true);
} catch (error) {
core.info(`${program} is not installed, installing it now`);
}
return await this.installCached(program, version);
}
public async call(args: string[], options?: {}): Promise<number> {
return await exec.exec(this.path, args, options);
}
}