-
-
Notifications
You must be signed in to change notification settings - Fork 440
/
Copy pathinstallable.ts
101 lines (90 loc) · 3.94 KB
/
installable.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
import * as semver from 'semver';
import { Progress } from '@theia/core/lib/common/message-service-protocol';
import { CancellationToken, CancellationTokenSource } from '@theia/core/lib/common/cancellation';
import { naturalCompare } from './../utils';
import { ArduinoComponent } from './arduino-component';
import { MessageService } from '@theia/core';
import { ResponseServiceImpl } from '../../browser/response-service-impl';
export interface Installable<T extends ArduinoComponent> {
/**
* If `options.version` is specified, that will be installed. Otherwise, `item.availableVersions[0]`.
*/
install(options: { item: T, progressId?: string, version?: Installable.Version }): Promise<void>;
/**
* Uninstalls the given component. It is a NOOP if not installed.
*/
uninstall(options: { item: T, progressId?: string }): Promise<void>;
}
export namespace Installable {
export type Version = string;
export namespace Version {
/**
* Most recent version comes first, then the previous versions. (`1.8.1`, `1.6.3`, `1.6.2`, `1.6.1` and so on.)
*/
export const COMPARATOR = (left: Version, right: Version) => {
if (semver.valid(left) && semver.valid(right)) {
return semver.compare(left, right);
}
return naturalCompare(left, right);
};
}
export async function installWithProgress<T extends ArduinoComponent>(options: {
installable: Installable<T>,
messageService: MessageService,
responseService: ResponseServiceImpl,
item: T,
version: Installable.Version
}): Promise<void> {
const { item, version } = options;
return doWithProgress({
...options,
progressText: `Processing ${item.name}:${version}`,
run: ({ progressId }) => options.installable.install({ item: options.item, version: options.version, progressId })
});
}
export async function uninstallWithProgress<T extends ArduinoComponent>(options: {
installable: Installable<T>,
messageService: MessageService,
responseService: ResponseServiceImpl,
item: T
}): Promise<void> {
const { item } = options;
return doWithProgress({
...options,
progressText: `Processing ${item.name}${item.installedVersion ? `:${item.installedVersion}` : ''}`,
run: ({ progressId }) => options.installable.uninstall({ item: options.item, progressId })
});
}
export async function doWithProgress(options: {
run: ({ progressId }: { progressId: string }) => Promise<void>,
messageService: MessageService,
responseService: ResponseServiceImpl,
progressText: string
}): Promise<void> {
return withProgress(options.progressText, options.messageService, async (progress, _) => {
const progressId = progress.id;
const toDispose = options.responseService.onProgressDidChange(progressMessage => {
if (progressId === progressMessage.progressId) {
const { message, work } = progressMessage;
progress.report({ message, work });
}
});
try {
options.responseService.clearArduinoChannel();
await options.run({ progressId });
} finally {
toDispose.dispose();
}
});
}
async function withProgress(text: string, messageService: MessageService, cb: (progress: Progress, token: CancellationToken) => Promise<void>): Promise<void> {
const cancellationSource = new CancellationTokenSource();
const { token } = cancellationSource;
const progress = await messageService.showProgress({ text, options: { cancelable: false } }, () => cancellationSource.cancel());
try {
await cb(progress, token);
} finally {
progress.cancel();
}
}
}