Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/git/src/protocolHandler.ts
3314 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { UriHandler, Uri, window, Disposable, commands, LogOutputChannel, l10n } from 'vscode';
7
import { dispose, isWindows } from './util';
8
import * as querystring from 'querystring';
9
10
const schemes = isWindows ?
11
new Set(['git', 'http', 'https', 'ssh']) :
12
new Set(['file', 'git', 'http', 'https', 'ssh']);
13
14
const refRegEx = /^$|[~\^:\\\*\s\[\]]|^-|^\.|\/\.|\.\.|\.lock\/|\.lock$|\/$|\.$/;
15
16
export class GitProtocolHandler implements UriHandler {
17
18
private disposables: Disposable[] = [];
19
20
constructor(private readonly logger: LogOutputChannel) {
21
this.disposables.push(window.registerUriHandler(this));
22
}
23
24
handleUri(uri: Uri): void {
25
this.logger.info(`[GitProtocolHandler][handleUri] URI:(${uri.toString()})`);
26
27
switch (uri.path) {
28
case '/clone': this.clone(uri);
29
}
30
}
31
32
private async clone(uri: Uri): Promise<void> {
33
const data = querystring.parse(uri.query);
34
const ref = data.ref;
35
36
if (!data.url) {
37
this.logger.warn('[GitProtocolHandler][clone] Failed to open URI:' + uri.toString());
38
return;
39
}
40
41
if (Array.isArray(data.url) && data.url.length === 0) {
42
this.logger.warn('[GitProtocolHandler][clone] Failed to open URI:' + uri.toString());
43
return;
44
}
45
46
if (ref !== undefined && typeof ref !== 'string') {
47
this.logger.warn('[GitProtocolHandler][clone] Failed to open URI due to multiple references:' + uri.toString());
48
return;
49
}
50
51
let cloneUri: Uri;
52
try {
53
let rawUri = Array.isArray(data.url) ? data.url[0] : data.url;
54
55
// Handle SSH Uri
56
// Ex: [email protected]:microsoft/vscode.git
57
rawUri = rawUri.replace(/^(git@[^\/:]+)(:)/i, 'ssh://$1/');
58
59
cloneUri = Uri.parse(rawUri, true);
60
61
// Validate against supported schemes
62
if (!schemes.has(cloneUri.scheme.toLowerCase())) {
63
throw new Error('Unsupported scheme.');
64
}
65
66
// Validate the reference
67
if (typeof ref === 'string' && refRegEx.test(ref)) {
68
throw new Error('Invalid reference.');
69
}
70
}
71
catch (ex) {
72
this.logger.warn('[GitProtocolHandler][clone] Invalid URI:' + uri.toString());
73
return;
74
}
75
76
if (!(await commands.getCommands(true)).includes('git.clone')) {
77
this.logger.error('[GitProtocolHandler][clone] Could not complete git clone operation as git installation was not found.');
78
79
const errorMessage = l10n.t('Could not clone your repository as Git is not installed.');
80
const downloadGit = l10n.t('Download Git');
81
82
if (await window.showErrorMessage(errorMessage, { modal: true }, downloadGit) === downloadGit) {
83
commands.executeCommand('vscode.open', Uri.parse('https://aka.ms/vscode-download-git'));
84
}
85
86
return;
87
} else {
88
const cloneTarget = cloneUri.toString(true);
89
this.logger.info(`[GitProtocolHandler][clone] Executing git.clone for ${cloneTarget}`);
90
commands.executeCommand('git.clone', cloneTarget, undefined, { ref: ref });
91
}
92
}
93
94
dispose(): void {
95
this.disposables = dispose(this.disposables);
96
}
97
}
98
99