提交 1bdf8d3e 编写于 作者: J Joao Moreno

Merge branch 'git-api'

......@@ -1197,6 +1197,7 @@
"file-type": "^7.2.0",
"iconv-lite": "0.4.19",
"jschardet": "^1.6.0",
"semver": "^5.5.1",
"vscode-extension-telemetry": "0.0.18",
"vscode-nls": "^3.2.4",
"which": "^1.3.0"
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Model } from '../model';
import { GitExtension } from './git';
import * as semver from 'semver';
interface ApiCtor {
new(model: Model): GitExtension.API;
}
const versions: string[] = [];
const apis = new Map<string, ApiCtor>();
export function getAPI(model: Model, range: string): GitExtension.API {
if (!range) {
throw new Error(`Please provide a Git extension API version range. Available versions: [${versions.join(', ')}]`);
}
const version = semver.maxSatisfying(versions, range);
if (!version) {
throw new Error(`There's no available Git extension API for the given range: '${range}'. Available versions: [${versions.join(', ')}]`);
}
const api = apis.get(version)!;
return new api(model);
}
export function Api(version: string): Function {
return function (ctor: ApiCtor) {
if (apis.has(version)) {
throw new Error(`Git extension API version ${version} already registered.`);
}
versions.push(version);
apis.set(version, ctor);
};
}
export function deprecated(target: any, key: string, descriptor: any): void {
if (typeof descriptor.value !== 'function') {
throw new Error('not supported');
}
const fn = descriptor.value;
descriptor.value = function () {
console.warn(`Git extension API method '${key}' is deprecated.`);
return fn.apply(this, arguments);
};
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { Model } from '../model';
import { GitExtension } from './git';
import { Api } from './api';
import { Event, SourceControlInputBox, Uri } from 'vscode';
import { mapEvent } from '../util';
import { Repository } from '../repository';
class ApiInputBox implements GitExtension.InputBox {
set value(value: string) { this._inputBox.value = value; }
get value(): string { return this._inputBox.value; }
constructor(private _inputBox: SourceControlInputBox) { }
}
export class ApiRepository implements GitExtension.Repository {
readonly rootUri: Uri;
readonly inputBox: GitExtension.InputBox;
constructor(_repository: Repository) {
this.rootUri = Uri.file(_repository.root);
this.inputBox = new ApiInputBox(_repository.inputBox);
}
}
@Api('0.1.0')
export class ApiImpl implements GitExtension.API {
get gitPath(): string {
return this._model.git.path;
}
get onDidOpenRepository(): Event<GitExtension.Repository> {
return mapEvent(this._model.onDidOpenRepository, r => new ApiRepository(r));
}
get onDidCloseRepository(): Event<GitExtension.Repository> {
return mapEvent(this._model.onDidCloseRepository, r => new ApiRepository(r));
}
get repositories(): GitExtension.Repository[] {
return this._model.repositories.map(r => new ApiRepository(r));
}
constructor(private _model: Model) { }
}
......@@ -5,61 +5,51 @@
'use strict';
import { Model } from './model';
import { Repository as ModelRepository } from './repository';
import { Uri, SourceControlInputBox } from 'vscode';
import { Model } from '../model';
import { GitExtension } from './git';
import { getAPI, deprecated } from './api';
import { ApiRepository } from './api0';
export interface InputBox {
value: string;
}
export class InputBoxImpl implements InputBox {
set value(value: string) { this.inputBox.value = value; }
get value(): string { return this.inputBox.value; }
constructor(private inputBox: SourceControlInputBox) { }
}
export interface Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
}
class NoModelGitExtension implements GitExtension {
export class RepositoryImpl implements Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
@deprecated
async getGitPath(): Promise<string> {
throw new Error('Git model not found');
}
constructor(repository: ModelRepository) {
this.rootUri = Uri.file(repository.root);
this.inputBox = new InputBoxImpl(repository.inputBox);
@deprecated
async getRepositories(): Promise<GitExtension.Repository[]> {
throw new Error('Git model not found');
}
}
export interface API {
getRepositories(): Promise<Repository[]>;
getGitPath(): Promise<string>;
getAPI(): GitExtension.API {
throw new Error('Git model not found');
}
}
export class APIImpl implements API {
class GitExtensionImpl implements GitExtension {
constructor(private model: Model) { }
constructor(private _model: Model) { }
@deprecated
async getGitPath(): Promise<string> {
return this.model.git.path;
return this._model.git.path;
}
async getRepositories(): Promise<Repository[]> {
return this.model.repositories.map(repository => new RepositoryImpl(repository));
@deprecated
async getRepositories(): Promise<GitExtension.Repository[]> {
return this._model.repositories.map(repository => new ApiRepository(repository));
}
}
export class NoopAPIImpl implements API {
async getGitPath(): Promise<string> {
throw new Error('Git model not found');
getAPI(range: string): GitExtension.API {
return getAPI(this._model, range);
}
}
async getRepositories(): Promise<Repository[]> {
throw new Error('Git model not found');
export function createGitExtension(model?: Model): GitExtension {
if (!model) {
return new NoModelGitExtension();
}
return new GitExtensionImpl(model);
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, SourceControlInputBox, Event } from 'vscode';
declare module GitExtension {
export interface API {
readonly gitPath: string;
readonly repositories: Repository[];
readonly onDidOpenRepository: Event<Repository>;
readonly onDidCloseRepository: Event<Repository>;
}
export interface InputBox {
value: string;
}
export interface Repository {
readonly rootUri: Uri;
readonly inputBox: InputBox;
}
}
export interface GitExtension {
/**
* Returns the latest available API compatible with the
* provided version range.
*
* @param range Semver version range for API compatibility.
* @returns API instance
*/
getAPI(range: string): GitExtension.API;
/**
* Returns the collection of active repositories.
*
* @deprecated Use `API.repositories` instead.
*/
getRepositories(): Promise<GitExtension.Repository[]>;
/**
* Returns the path to the current git executable.
*
* @deprecated Use `API.gitPath` instead.
*/
getGitPath(): Promise<string>;
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
function* filter<T>(it: IterableIterator<T>, condition: (t: T, i: number) => boolean): IterableIterator<T> {
let i = 0;
for (let t of it) {
if (condition(t, i++)) {
yield t;
}
}
}
function* map<T, R>(it: IterableIterator<T>, fn: (t: T, i: number) => R): IterableIterator<R> {
let i = 0;
for (let t of it) {
yield fn(t, i++);
}
}
export interface FunctionalIterator<T> extends Iterable<T> {
filter(condition: (t: T, i: number) => boolean): FunctionalIterator<T>;
map<R>(fn: (t: T, i: number) => R): FunctionalIterator<R>;
toArray(): T[];
}
class FunctionalIteratorImpl<T> implements FunctionalIterator<T> {
constructor(private iterator: IterableIterator<T>) { }
filter(condition: (t: T, i: number) => boolean): FunctionalIterator<T> {
return new FunctionalIteratorImpl(filter(this.iterator, condition));
}
map<R>(fn: (t: T, i: number) => R): FunctionalIterator<R> {
return new FunctionalIteratorImpl(map<T, R>(this.iterator, fn));
}
toArray(): T[] {
return Array.from(this.iterator);
}
[Symbol.iterator](): IterableIterator<T> {
return this.iterator;
}
}
export function iterate<T>(obj: T[] | IterableIterator<T>): FunctionalIterator<T> {
if (Array.isArray(obj)) {
return new FunctionalIteratorImpl(obj[Symbol.iterator]());
}
return new FunctionalIteratorImpl(obj);
}
\ No newline at end of file
......@@ -7,6 +7,7 @@
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { ExtensionContext, workspace, window, Disposable, commands, Uri, OutputChannel } from 'vscode';
import { findGit, Git, IGit } from './git';
import { Model } from './model';
......@@ -16,8 +17,11 @@ import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
import { toDisposable, filterEvent, eventToPromise } from './util';
import TelemetryReporter from 'vscode-extension-telemetry';
import { API, NoopAPIImpl, APIImpl } from './api';
import { GitExtension } from './api/git';
import { GitProtocolHandler } from './protocolHandler';
import { createGitExtension } from './api/extension';
import './api/api0';
const deactivateTasks: { (): Promise<any>; }[] = [];
......@@ -69,7 +73,7 @@ async function createModel(context: ExtensionContext, outputChannel: OutputChann
return model;
}
export async function activate(context: ExtensionContext): Promise<API> {
export async function activate(context: ExtensionContext): Promise<GitExtension> {
const disposables: Disposable[] = [];
context.subscriptions.push(new Disposable(() => Disposable.from(...disposables).dispose()));
......@@ -92,7 +96,7 @@ export async function activate(context: ExtensionContext): Promise<API> {
try {
const model = await createModel(context, outputChannel, telemetryReporter, disposables);
return new APIImpl(model);
return createGitExtension(model);
} catch (err) {
if (!/Git installation not found/.test(err.message || '')) {
throw err;
......@@ -121,7 +125,7 @@ export async function activate(context: ExtensionContext): Promise<API> {
}
}
return new NoopAPIImpl();
return createGitExtension();
}
}
......
......@@ -251,6 +251,10 @@ semver@^5.3.0:
version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
semver@^5.5.1:
version "5.5.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.1.tgz#7dfdd8814bdb7cabc7be0fb1d734cfb66c940477"
supports-color@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册