-
Notifications
You must be signed in to change notification settings - Fork 17
/
update.ts
123 lines (104 loc) · 3.26 KB
/
update.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
import { decode, encode, colors } from "./deps.ts";
import { Progress } from "./progress.ts";
import { importUrls } from "./search.ts";
import { versioned, Versioned } from "./versioned.ts";
// FIXME we should catch ctrl-c etc. and write back the original deps.ts
export async function update(
filename: string,
test: () => Promise<boolean>,
options: UpdateOptions
): Promise<UpdateResult[]> {
const u = new Update(filename, test, options);
return await u.update();
}
export interface UpdateOptions {
dryRun: boolean;
}
export interface UpdateResult {
initUrl: string;
initVersion: string;
newVersion?: string;
success?: boolean;
}
export class Update {
private filename: string;
private test: () => Promise<boolean>;
private options: UpdateOptions;
private progress: Progress;
constructor(
filename: string,
test: () => Promise<boolean>,
options: UpdateOptions
) {
this.filename = filename;
this.test = test;
this.options = options;
this.progress = new Progress(1);
}
async update(): Promise<UpdateResult[]> {
const content: string = await this.content();
const urls: string[] = importUrls(content);
this.progress.n = urls.length;
// from a url we need to extract the current version
const results: UpdateResult[] = [];
for (const [i, u] of urls.entries()) {
this.progress.step = i;
const v = versioned(u);
if (v !== undefined) {
// this.progress.log(`Updating ${u}`)
results.push(await this.updateOne(v!));
}
}
return results;
}
async updateOne(
url: Versioned
): Promise<UpdateResult> {
// now we look up the available versions
const versions = await url.all();
// console.log(colors.bold(url.url));
if (url.current() === versions[0]) {
// already at latest version, skip!
await this.progress.log(`Using latest: ${url.url}`);
// console.log();
return { initUrl: url.url, initVersion: url.current() };
}
// TODO: options: try latest, semver compat, or input
// pick a new version (should be in for loop?)
// i.e. rety or skip if fails
// for now, let's pick the most recent!
const newVersion = versions[0];
// console.log(" Current version:", url.current());
// console.log(" Available versions:", versions.join(","));
await this.progress.log(`Updating: ${url.url} -> ${newVersion}`);
const fails: boolean = await this.updateIfTestPasses(url, newVersion);
return {
initUrl: url.url,
initVersion: url.current(),
newVersion,
success: !fails
};
// console.log();
}
async updateIfTestPasses(
url: Versioned,
newVersion: string
): Promise<boolean> {
const newUrl = url.at(newVersion);
// console.log(" Updating to", newUrl.url);
await this.replace(url, newUrl);
const fails = await this.test();
if (fails || this.options.dryRun) {
await this.replace(newUrl, url);
}
return fails;
}
async content(): Promise<string> {
return decode(await Deno.readFile(this.filename));
}
async replace(url: Versioned, newUrl: Versioned) {
const content = await this.content();
const newContent = content.split(url.url).join(newUrl.url);
await Deno.writeFile(this.filename, encode(newContent));
}
}