From 6c0cbba315ea2551f8db8189a5c55571536de08c Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 11 Apr 2017 16:35:05 +1000 Subject: [PATCH 1/3] extract the gold out before changing the world --- lib/git-environment.ts | 90 ++++++++++++++++++++++++++++++++++++++++++ lib/git-process.ts | 83 ++------------------------------------ 2 files changed, 94 insertions(+), 79 deletions(-) create mode 100644 lib/git-environment.ts diff --git a/lib/git-environment.ts b/lib/git-environment.ts new file mode 100644 index 00000000..c5600a35 --- /dev/null +++ b/lib/git-environment.ts @@ -0,0 +1,90 @@ +import * as path from 'path' + +import { IGitExecutionOptions } from './git-process' + +/** + * Find the path to the embedded Git environment + */ +function resolveGitDir(): string { + if (process.env.TEST_WITH_LOCAL_GIT) { + return path.join(__dirname, '..', 'git') + } else { + return path.join(__dirname, '..', '..', 'git') + } +} + +/** + * Find the path to the embedded Git binary + */ +function resolveGitBinary(): string { + const gitDir = resolveGitDir() + if (process.platform === 'darwin' || process.platform === 'linux') { + return path.join(gitDir, 'bin', 'git') + } else if (process.platform === 'win32') { + return path.join(gitDir, 'cmd', 'git.exe') + } + + throw new Error('Git not supported on platform: ' + process.platform) +} + +/** + * Find the path to the embedded git exec path. + */ +function resolveGitExecPath(): string { + const gitDir = resolveGitDir() + if (process.platform === 'darwin' || process.platform === 'linux') { + return path.join(gitDir, 'libexec', 'git-core') + } else if (process.platform === 'win32') { + return path.join(gitDir, 'mingw64', 'libexec', 'git-core') + } + + throw new Error('Git not supported on platform: ' + process.platform) +} + +export function setupEnvironment(options?: IGitExecutionOptions): { env: Object, gitLocation: string } { + const gitLocation = resolveGitBinary() + + let envPath: string = process.env.PATH || '' + const gitDir = resolveGitDir() + + if (process.platform === 'win32') { + envPath = `${gitDir}\\mingw64\\bin;${envPath}` + } + + const env = Object.assign({}, process.env, { + GIT_EXEC_PATH: resolveGitExecPath(), + PATH: envPath, + }, options ? options.env : { }) + + if (process.platform === 'win32') { + // while reading the environment variable is case-insensitive + // you can create a hash with multiple values, which means the + // wrong value might be used when spawning the child process + // + // this ensures we only ever supply one value for PATH + if (env.Path) { + delete env.Path + } + } + + if (process.platform === 'darwin' || process.platform === 'linux') { + // templates are used to populate your .git folder + // when a repository is initialized locally + const templateDir = `${gitDir}/share/git-core/templates` + env.GIT_TEMPLATE_DIR = templateDir + } + + if (process.platform === 'linux') { + // when building Git for Linux and then running it from + // an arbitrary location, you should set PREFIX for the + // process to ensure that it knows how to resolve things + env.PREFIX = gitDir + + // bypass whatever certificates might be set and use + // the bundle included in the distibution + const sslCABundle = `${gitDir}/ssl/cacert.pem` + env.GIT_SSL_CAINFO = sslCABundle + } + + return { env, gitLocation } +} diff --git a/lib/git-process.ts b/lib/git-process.ts index ba0a5eba..33cd99b7 100644 --- a/lib/git-process.ts +++ b/lib/git-process.ts @@ -1,10 +1,12 @@ -import * as path from 'path' + import * as fs from 'fs' import { execFile, ExecOptionsWithStringEncoding } from 'child_process' import { GitError, GitErrorRegexes, RepositoryDoesNotExistErrorCode, GitNotFoundErrorCode } from './errors' import { ChildProcess } from 'child_process' +import { setupEnvironment } from './git-environment' + /** The result of shelling out to git. */ export interface IGitResult { /** The standard output from git. */ @@ -70,42 +72,6 @@ interface ErrorWithCode extends Error { } export class GitProcess { - /** - * Find the path to the embedded Git environment - */ - private static resolveGitDir(): string { - if (process.env.TEST_WITH_LOCAL_GIT) { - return path.join(__dirname, '..', 'git') - } else { - return path.join(__dirname, '..', '..', 'git') - } - } - - /** - * Find the path to the embedded Git binary - */ - private static resolveGitBinary(): string { - const gitDir = GitProcess.resolveGitDir() - if (process.platform === 'darwin' || process.platform === 'linux') { - return path.join(gitDir, 'bin', 'git') - } else if (process.platform === 'win32') { - return path.join(gitDir, 'cmd', 'git.exe') - } - - throw new Error('Git not supported on platform: ' + process.platform) - } - - /** Find the path to the embedded git exec path. */ - private static resolveGitExecPath(): string { - const gitDir = GitProcess.resolveGitDir() - if (process.platform === 'darwin' || process.platform === 'linux') { - return path.join(gitDir, 'libexec', 'git-core') - } else if (process.platform === 'win32') { - return path.join(gitDir, 'mingw64', 'libexec', 'git-core') - } - - throw new Error('Git not supported on platform: ' + process.platform) - } private static pathExists(path: string): Boolean { try { @@ -128,49 +94,8 @@ export class GitProcess { */ public static exec(args: string[], path: string, options?: IGitExecutionOptions): Promise { return new Promise(function(resolve, reject) { - const gitLocation = GitProcess.resolveGitBinary() - - let envPath: string = process.env.PATH || '' - const gitDir = GitProcess.resolveGitDir() - if (process.platform === 'win32') { - envPath = `${gitDir}\\mingw64\\bin;${envPath}` - } - - const env = Object.assign({}, process.env, { - GIT_EXEC_PATH: GitProcess.resolveGitExecPath(), - PATH: envPath, - }, options ? options.env : { }) - - if (process.platform === 'win32') { - // while reading the environment variable is case-insensitive - // you can create a hash with multiple values, which means the - // wrong value might be used when spawning the child process - // - // this ensures we only ever supply one value for PATH - if (env.Path) { - delete env.Path - } - } - - if (process.platform === 'darwin' || process.platform === 'linux') { - // templates are used to populate your .git folder - // when a repository is initialized locally - const templateDir = `${gitDir}/share/git-core/templates` - env.GIT_TEMPLATE_DIR = templateDir - } - - if (process.platform === 'linux') { - // when building Git for Linux and then running it from - // an arbitrary location, you should set PREFIX for the - // process to ensure that it knows how to resolve things - env.PREFIX = gitDir - - // bypass whatever certificates might be set and use - // the bundle included in the distibution - const sslCABundle = `${gitDir}/ssl/cacert.pem` - env.GIT_SSL_CAINFO = sslCABundle - } + const { env, gitLocation } = setupEnvironment(options) // Explicitly annotate opts since typescript is unable to infer the correct // signature for execFile when options is passed as an opaque hash. The type From 168fdcc3d50cd23d6fa63cf8d889962bb91d6a0f Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 11 Apr 2017 16:38:06 +1000 Subject: [PATCH 2/3] clarify environment variable to use alternate Git --- lib/git-environment.ts | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/git-environment.ts b/lib/git-environment.ts index c5600a35..3317a26f 100644 --- a/lib/git-environment.ts +++ b/lib/git-environment.ts @@ -6,8 +6,8 @@ import { IGitExecutionOptions } from './git-process' * Find the path to the embedded Git environment */ function resolveGitDir(): string { - if (process.env.TEST_WITH_LOCAL_GIT) { - return path.join(__dirname, '..', 'git') + if (process.env.LOCAL_GIT_DIRECTORY) { + return path.resolve(process.env.LOCAL_GIT_DIRECTORY) } else { return path.join(__dirname, '..', '..', 'git') } diff --git a/package.json b/package.json index ea75be20..6f0e7147 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,8 @@ "build": "npm run clean && npm run lint && tsc -p ./tsconfig.json && tsc -p ./examples/tsconfig.json", "prepublish": "npm run build && npm run test", "test": "npm run test:fast && npm run test:slow", - "test:fast": "cross-env TEST_WITH_LOCAL_GIT=1 mocha --require ts-node/register test/fast/*.ts test/auth/*.ts", - "test:slow": "cross-env TEST_WITH_LOCAL_GIT=1 mocha -t 10000ms --require ts-node/register test/slow/*.ts test/auth/*.ts", + "test:fast": "cross-env LOCAL_GIT_DIRECTORY=./git/ mocha --require ts-node/register test/fast/*.ts test/auth/*.ts", + "test:slow": "cross-env LOCAL_GIT_DIRECTORY=./git/ mocha -t 10000ms --require ts-node/register test/slow/*.ts test/auth/*.ts", "postinstall": "node ./script/download-git.js" }, "engines": { From 0d02be37c566ad818261e3735ed976edf3b900db Mon Sep 17 00:00:00 2001 From: Brendan Forster Date: Tue, 11 Apr 2017 16:44:13 +1000 Subject: [PATCH 3/3] some tidy up --- lib/git-environment.ts | 14 ++++++++++---- lib/git-process.ts | 6 +++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/git-environment.ts b/lib/git-environment.ts index 3317a26f..dc2934ad 100644 --- a/lib/git-environment.ts +++ b/lib/git-environment.ts @@ -1,7 +1,5 @@ import * as path from 'path' -import { IGitExecutionOptions } from './git-process' - /** * Find the path to the embedded Git environment */ @@ -41,7 +39,15 @@ function resolveGitExecPath(): string { throw new Error('Git not supported on platform: ' + process.platform) } -export function setupEnvironment(options?: IGitExecutionOptions): { env: Object, gitLocation: string } { +/** + * Setup the process environment before invoking Git. + * + * This method resolves the Git executable and creates the array of key-value + * pairs which should be used as environment variables. + * + * @param additional options to include with the process + */ +export function setupEnvironment(environmentVariables: Object): { env: Object, gitLocation: string } { const gitLocation = resolveGitBinary() let envPath: string = process.env.PATH || '' @@ -54,7 +60,7 @@ export function setupEnvironment(options?: IGitExecutionOptions): { env: Object, const env = Object.assign({}, process.env, { GIT_EXEC_PATH: resolveGitExecPath(), PATH: envPath, - }, options ? options.env : { }) + }, environmentVariables) if (process.platform === 'win32') { // while reading the environment variable is case-insensitive diff --git a/lib/git-process.ts b/lib/git-process.ts index 33cd99b7..ec084945 100644 --- a/lib/git-process.ts +++ b/lib/git-process.ts @@ -94,8 +94,12 @@ export class GitProcess { */ public static exec(args: string[], path: string, options?: IGitExecutionOptions): Promise { return new Promise(function(resolve, reject) { + let customEnv = { } + if (options && options.env) { + customEnv = options.env + } - const { env, gitLocation } = setupEnvironment(options) + const { env, gitLocation } = setupEnvironment(customEnv) // Explicitly annotate opts since typescript is unable to infer the correct // signature for execFile when options is passed as an opaque hash. The type