mirror of
https://github.com/ckaczor/vscode-gitlens.git
synced 2026-02-17 02:51:47 -05:00
Adds support for custom git installation locations
Also gracefully deals with the times when git isn't in the PATH
This commit is contained in:
8
.vscode/settings.json
vendored
8
.vscode/settings.json
vendored
@@ -1,13 +1,11 @@
|
|||||||
// Place your settings in this file to overwrite default and user settings.
|
|
||||||
{
|
{
|
||||||
"files.exclude": {
|
"files.exclude": {
|
||||||
"out": false, // set this to true to hide the "out" folder with the compiled JS files
|
"node_modules": true,
|
||||||
"node_modules": true
|
"out": true
|
||||||
},
|
},
|
||||||
"search.exclude": {
|
"search.exclude": {
|
||||||
"out": true, // set this to false to include "out" folder in search results
|
|
||||||
"node_modules": true,
|
"node_modules": true,
|
||||||
"typings": true
|
"out": true
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
|
"typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version
|
||||||
}
|
}
|
||||||
@@ -221,6 +221,11 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"description": "Specifies debug mode"
|
"description": "Specifies debug mode"
|
||||||
},
|
},
|
||||||
|
"gitlens.advanced.git": {
|
||||||
|
"type": "string",
|
||||||
|
"default": null,
|
||||||
|
"description": "Specifies a git path to use"
|
||||||
|
},
|
||||||
"gitlens.advanced.output.level": {
|
"gitlens.advanced.output.level": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "silent",
|
"default": "silent",
|
||||||
@@ -346,8 +351,8 @@
|
|||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
"lodash.escaperegexp": "^4.1.2",
|
"lodash.escaperegexp": "^4.1.2",
|
||||||
"lodash.isequal": "^4.4.0",
|
"lodash.isequal": "^4.4.0",
|
||||||
"moment": "^2.15.2",
|
"moment": "^2.16.0",
|
||||||
"spawn-rx": "^2.0.3",
|
"spawn-rx": "^2.0.6",
|
||||||
"tmp": "^0.0.30"
|
"tmp": "^0.0.30"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
10
src/@types/spawn-rx/index.d.ts
vendored
10
src/@types/spawn-rx/index.d.ts
vendored
@@ -3,11 +3,11 @@ declare module "spawn-rx" {
|
|||||||
import { Observable } from 'rxjs/Observable';
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
|
||||||
namespace spawnrx {
|
namespace spawnrx {
|
||||||
function findActualExecutable(exe: string, args: Array<string>): { cmd: string, args: Array<string> };
|
function findActualExecutable(exe: string, args?: Array<string> | undefined): { cmd: string, args: Array<string> };
|
||||||
function spawnDetached(exe: string, params: Array<string>, opts: Object|undefined): Observable<string>;
|
function spawnDetached(exe: string, params?: Array<string> | undefined, opts?: Object | undefined): Observable<string>;
|
||||||
function spawn(exe: string, params: Array<string>, opts: Object|undefined): Observable<string>;
|
function spawn(exe: string, params?: Array<string> | undefined, opts?: Object | undefined): Observable<string>;
|
||||||
function spawnDetachedPromise(exe: string, params: Array<string>, opts: Object|undefined): Promise<string>;
|
function spawnDetachedPromise(exe: string, params?: Array<string> | undefined, opts?: Object | undefined): Promise<string>;
|
||||||
function spawnPromise(exe: string, params: Array<string>, opts: Object|undefined): Promise<string>;
|
function spawnPromise(exe: string, params?: Array<string> | undefined, opts?: Object | undefined): Promise<string>;
|
||||||
}
|
}
|
||||||
export = spawnrx;
|
export = spawnrx;
|
||||||
}
|
}
|
||||||
@@ -87,6 +87,7 @@ export interface IAdvancedConfig {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
};
|
};
|
||||||
debug: boolean;
|
debug: boolean;
|
||||||
|
git: string;
|
||||||
output: {
|
output: {
|
||||||
level: OutputLevel;
|
level: OutputLevel;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
import { ExtensionContext, extensions, languages, workspace } from 'vscode';
|
import { ExtensionContext, extensions, languages, window, workspace } from 'vscode';
|
||||||
import BlameAnnotationController from './blameAnnotationController';
|
import BlameAnnotationController from './blameAnnotationController';
|
||||||
import BlameStatusBarController from './blameStatusBarController';
|
import BlameStatusBarController from './blameStatusBarController';
|
||||||
import GitContentProvider from './gitContentProvider';
|
import GitContentProvider from './gitContentProvider';
|
||||||
@@ -7,6 +7,8 @@ import GitBlameCodeLensProvider from './gitBlameCodeLensProvider';
|
|||||||
import GitBlameContentProvider from './gitBlameContentProvider';
|
import GitBlameContentProvider from './gitBlameContentProvider';
|
||||||
import GitProvider, { Git } from './gitProvider';
|
import GitProvider, { Git } from './gitProvider';
|
||||||
import { WorkspaceState } from './constants';
|
import { WorkspaceState } from './constants';
|
||||||
|
import { IAdvancedConfig } from './configuration';
|
||||||
|
import { Logger } from './logger';
|
||||||
import DiffWithPreviousCommand from './commands/diffWithPrevious';
|
import DiffWithPreviousCommand from './commands/diffWithPrevious';
|
||||||
import DiffLineWithPreviousCommand from './commands/diffLineWithPrevious';
|
import DiffLineWithPreviousCommand from './commands/diffLineWithPrevious';
|
||||||
import DiffWithWorkingCommand from './commands/diffWithWorking';
|
import DiffWithWorkingCommand from './commands/diffWithWorking';
|
||||||
@@ -16,10 +18,9 @@ import ShowBlameHistoryCommand from './commands/showBlameHistory';
|
|||||||
import ShowHistoryCommand from './commands/showHistory';
|
import ShowHistoryCommand from './commands/showHistory';
|
||||||
import ToggleBlameCommand from './commands/toggleBlame';
|
import ToggleBlameCommand from './commands/toggleBlame';
|
||||||
import ToggleCodeLensCommand from './commands/toggleCodeLens';
|
import ToggleCodeLensCommand from './commands/toggleCodeLens';
|
||||||
import { Logger } from './logger';
|
|
||||||
|
|
||||||
// this method is called when your extension is activated
|
// this method is called when your extension is activated
|
||||||
export function activate(context: ExtensionContext) {
|
export async function activate(context: ExtensionContext) {
|
||||||
// Workspace not using a folder. No access to git repo.
|
// Workspace not using a folder. No access to git repo.
|
||||||
if (!workspace.rootPath) {
|
if (!workspace.rootPath) {
|
||||||
Logger.warn('GitLens inactive: no rootPath');
|
Logger.warn('GitLens inactive: no rootPath');
|
||||||
@@ -30,7 +31,18 @@ export function activate(context: ExtensionContext) {
|
|||||||
const rootPath = workspace.rootPath.replace(/\\/g, '/');
|
const rootPath = workspace.rootPath.replace(/\\/g, '/');
|
||||||
Logger.log(`GitLens active: ${rootPath}`);
|
Logger.log(`GitLens active: ${rootPath}`);
|
||||||
|
|
||||||
Git.repoPath(rootPath).then(repoPath => {
|
const gitPath = workspace.getConfiguration('gitlens').get<IAdvancedConfig>('advanced').git;
|
||||||
|
|
||||||
|
let repoPath: string;
|
||||||
|
try {
|
||||||
|
repoPath = await Git.repoPath(rootPath, gitPath);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
Logger.error(ex);
|
||||||
|
await window.showErrorMessage(`GitLens: Unable to find Git. Please make sure Git is installed. Also ensure that Git is either in the PATH, or that 'gitlens.advanced.git' is pointed to its installed location.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context.workspaceState.update(WorkspaceState.RepoPath, repoPath);
|
context.workspaceState.update(WorkspaceState.RepoPath, repoPath);
|
||||||
context.workspaceState.update(WorkspaceState.HasGitHistoryExtension, extensions.getExtension('donjayamanne.githistory') !== undefined);
|
context.workspaceState.update(WorkspaceState.HasGitHistoryExtension, extensions.getExtension('donjayamanne.githistory') !== undefined);
|
||||||
|
|
||||||
@@ -57,7 +69,6 @@ export function activate(context: ExtensionContext) {
|
|||||||
context.subscriptions.push(new ShowBlameHistoryCommand(git));
|
context.subscriptions.push(new ShowBlameHistoryCommand(git));
|
||||||
context.subscriptions.push(new ShowHistoryCommand(git));
|
context.subscriptions.push(new ShowHistoryCommand(git));
|
||||||
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
context.subscriptions.push(new ToggleCodeLensCommand(git));
|
||||||
}).catch(reason => Logger.warn(reason));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// this method is called when your extension is deactivated
|
// this method is called when your extension is deactivated
|
||||||
|
|||||||
@@ -1,28 +1,30 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
import { findGitPath, IGit } from './gitLocator';
|
||||||
|
import { Logger } from '../logger';
|
||||||
|
import { spawnPromise } from 'spawn-rx';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as tmp from 'tmp';
|
import * as tmp from 'tmp';
|
||||||
import { spawnPromise } from 'spawn-rx';
|
|
||||||
import { Logger } from '../logger';
|
|
||||||
|
|
||||||
export * from './gitEnrichment';
|
export * from './gitEnrichment';
|
||||||
export * from './enrichers/blameParserEnricher';
|
export * from './enrichers/blameParserEnricher';
|
||||||
export * from './enrichers/logParserEnricher';
|
export * from './enrichers/logParserEnricher';
|
||||||
|
|
||||||
|
let git: IGit;
|
||||||
const UncommittedRegex = /^[0]+$/;
|
const UncommittedRegex = /^[0]+$/;
|
||||||
|
|
||||||
async function gitCommand(cwd: string, ...args: any[]) {
|
async function gitCommand(cwd: string, ...args: any[]) {
|
||||||
try {
|
try {
|
||||||
const s = await spawnPromise('git', args, { cwd: cwd });
|
const s = await spawnPromise(git.path, args, { cwd: cwd });
|
||||||
Logger.log('git', ...args, cwd);
|
Logger.log('git', ...args, ` cwd='${cwd}'`);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
const msg = ex && ex.toString();
|
const msg = ex && ex.toString();
|
||||||
if (msg && (msg.includes('is outside repository') || msg.includes('no such path'))) {
|
if (msg && (msg.includes('Not a git repository') || msg.includes('is outside repository') || msg.includes('no such path'))) {
|
||||||
Logger.warn('git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
|
Logger.warn('git', ...args, ` cwd='${cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
||||||
} else {
|
} else {
|
||||||
Logger.error('git', ...args, cwd, msg && msg.replace(/\r?\n|\r/g, ' '));
|
Logger.error('git', ...args, ` cwd='${cwd}'`, msg && `\n ${msg.replace(/\r?\n|\r/g, ' ')}`);
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@@ -52,8 +54,12 @@ export default class Git {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static repoPath(cwd: string) {
|
static async repoPath(cwd: string, gitPath?: string) {
|
||||||
return gitCommand(cwd, 'rev-parse', '--show-toplevel').then(data => data.replace(/\r?\n|\r/g, '').replace(/\\/g, '/'));
|
git = await findGitPath(gitPath);
|
||||||
|
|
||||||
|
let data = await gitCommand(cwd, 'rev-parse', '--show-toplevel');
|
||||||
|
data = data.replace(/\r?\n|\r/g, '').replace(/\\/g, '/');
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static blame(format: GitBlameFormat, fileName: string, sha?: string, repoPath?: string) {
|
static blame(format: GitBlameFormat, fileName: string, sha?: string, repoPath?: string) {
|
||||||
|
|||||||
74
src/git/gitLocator.ts
Normal file
74
src/git/gitLocator.ts
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
import { spawnPromise } from 'spawn-rx';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
export interface IGit {
|
||||||
|
path: string;
|
||||||
|
version: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseVersion(raw: string): string {
|
||||||
|
return raw.replace(/^git version /, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findSpecificGit(path: string): Promise<IGit> {
|
||||||
|
const version = await spawnPromise(path, ['--version']);
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
version: parseVersion(version.trim())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function findGitDarwin(): Promise<IGit> {
|
||||||
|
try {
|
||||||
|
let path = await spawnPromise('which', ['git']);
|
||||||
|
path = path.replace(/^\s+|\s+$/g, '');
|
||||||
|
|
||||||
|
if (path !== '/usr/bin/git') {
|
||||||
|
return findSpecificGit(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await spawnPromise('xcode-select', ['-p']);
|
||||||
|
return findSpecificGit(path);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
if (ex.code === 2) {
|
||||||
|
return Promise.reject('Unable to find git');
|
||||||
|
}
|
||||||
|
return findSpecificGit(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
return Promise.reject('Unable to find git');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findSystemGitWin32(basePath: string): Promise<IGit> {
|
||||||
|
if (!basePath) return Promise.reject('Unable to find git');
|
||||||
|
return findSpecificGit(path.join(basePath, 'Git', 'cmd', 'git.exe'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function findGitWin32(): Promise<IGit> {
|
||||||
|
return findSystemGitWin32(process.env['ProgramW6432'])
|
||||||
|
.then(null, () => findSystemGitWin32(process.env['ProgramFiles(x86)']))
|
||||||
|
.then(null, () => findSystemGitWin32(process.env['ProgramFiles']))
|
||||||
|
.then(null, () => findSpecificGit('git'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function findGitPath(path?: string): Promise<IGit> {
|
||||||
|
try {
|
||||||
|
return await findSpecificGit(path || 'git');
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
try {
|
||||||
|
switch (process.platform) {
|
||||||
|
case 'darwin': return await findGitDarwin();
|
||||||
|
case 'win32': return await findGitWin32();
|
||||||
|
default: return Promise.reject('Unable to find git');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
return Promise.reject('Unable to find git');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import { Iterables, Strings } from './system';
|
|||||||
import { CancellationToken, CodeLens, CodeLensProvider, commands, DocumentSelector, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode';
|
import { CancellationToken, CodeLens, CodeLensProvider, commands, DocumentSelector, ExtensionContext, Position, Range, SymbolInformation, SymbolKind, TextDocument, Uri, workspace } from 'vscode';
|
||||||
import { BuiltInCommands, Commands, DocumentSchemes, WorkspaceState } from './constants';
|
import { BuiltInCommands, Commands, DocumentSchemes, WorkspaceState } from './constants';
|
||||||
import { CodeLensCommand, CodeLensLocation, IConfig, ICodeLensLanguageLocation } from './configuration';
|
import { CodeLensCommand, CodeLensLocation, IConfig, ICodeLensLanguageLocation } from './configuration';
|
||||||
import GitProvider, { GitCommit, IGitBlame, IGitBlameLines, IGitLog } from './gitProvider';
|
import GitProvider, { GitCommit, IGitBlame, IGitBlameLines } from './gitProvider';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
|
||||||
export class GitRecentChangeCodeLens extends CodeLens {
|
export class GitRecentChangeCodeLens extends CodeLens {
|
||||||
|
|||||||
Reference in New Issue
Block a user