Browse Source

Renames sha to ref in more places

Renames path to paths
Reworks sha regex & methods
main
Eric Amodio 6 years ago
parent
commit
a284728137
3 changed files with 121 additions and 122 deletions
  1. +1
    -1
      src/commands/showCommitSearch.ts
  2. +47
    -44
      src/git/git.ts
  3. +73
    -77
      src/git/gitService.ts

+ 1
- 1
src/commands/showCommitSearch.ts View File

@ -80,7 +80,7 @@ export class ShowCommitSearchCommand extends ActiveEditorCachedCommand {
args.searchBy = searchByMap.get(match[1]);
args.search = args.search.substring(args.search[1] === ' ' ? 2 : 1);
}
else if (GitService.isSha(args.search)) {
else if (GitService.isShaLike(args.search)) {
args.searchBy = GitRepoSearchBy.Sha;
}
else {

+ 47
- 44
src/git/git.ts View File

@ -1,6 +1,6 @@
'use strict';
import * as iconv from 'iconv-lite';
import * as path from 'path';
import * as paths from 'path';
import { GlyphChars } from '../constants';
import { Logger } from '../logger';
import { Objects, Strings } from '../system';
@ -165,12 +165,12 @@ function throwExceptionHandler(ex: Error) {
let gitInfo: GitLocation;
export class Git {
static deletedOrMissingSha = 'ffffffffffffffffffffffffffffffffffffffff';
static shaRegex = /^[0-9a-f]{40}(\^[0-9]*?)??( -)?$/;
static shaStrictRegex = /^[0-9a-f]{40}$/;
static stagedUncommittedRegex = /^[0]{40}(\^[0-9]*?)??:$/;
static deletedOrMissingSha = '0000000000000000000000000000000000000000-';
static shaLikeRegex = /(^[0-9a-f]{40}([\^@~:]\S*)?$)|(^[0]{40}(:|-)$)/;
static shaRegex = /(^[0-9a-f]{40}$)|(^[0]{40}(:|-)$)/;
static stagedUncommittedRegex = /^[0]{40}([\^@~]\S*)?:$/;
static stagedUncommittedSha = '0000000000000000000000000000000000000000:';
static uncommittedRegex = /^[0]{40}(\^[0-9]*?)??:??$/;
static uncommittedRegex = /^[0]{40}(?:[\^@~:]\S*)?:?$/;
static uncommittedSha = '0000000000000000000000000000000000000000';
static getEncoding(encoding: string | undefined) {
@ -197,39 +197,42 @@ export class Git {
);
}
static isResolveRequired(sha: string) {
return Git.isSha(sha) && !Git.shaStrictRegex.test(sha);
static isSha(ref: string) {
return Git.shaRegex.test(ref);
}
static isSha(sha: string) {
return Git.shaRegex.test(sha);
static isShaLike(ref: string) {
return Git.shaLikeRegex.test(ref);
}
static isStagedUncommitted(sha: string | undefined): boolean {
return sha === undefined ? false : Git.stagedUncommittedRegex.test(sha);
static isStagedUncommitted(ref: string | undefined): boolean {
return ref ? Git.stagedUncommittedRegex.test(ref) : false;
}
static isUncommitted(sha: string | undefined) {
return sha === undefined ? false : Git.uncommittedRegex.test(sha);
static isUncommitted(ref: string | undefined) {
return ref ? Git.uncommittedRegex.test(ref) : false;
}
static shortenSha(
sha: string,
ref: string,
strings: { stagedUncommitted?: string; uncommitted?: string; working?: string } = {}
) {
strings = { stagedUncommitted: 'index', uncommitted: 'working', working: '', ...strings };
if (sha === '') return strings.working;
if (Git.isStagedUncommitted(sha)) return strings.stagedUncommitted;
if (Git.isUncommitted(sha)) return strings.uncommitted;
if (ref === '') return strings.working;
if (Git.isUncommitted(ref)) {
if (Git.isStagedUncommitted(ref)) return strings.stagedUncommitted;
return strings.uncommitted;
}
const index = sha.indexOf('^');
const index = ref.indexOf('^');
if (index > 6) {
// Only grab a max of 5 chars for the suffix
const suffix = sha.substring(index).substring(0, 5);
return `${sha.substring(0, 8 - suffix.length)}${suffix}`;
const suffix = ref.substring(index).substring(0, 5);
return `${ref.substring(0, 8 - suffix.length)}${suffix}`;
}
return sha.substring(0, 8);
return ref.substring(0, 8);
}
static splitPath(fileName: string, repoPath: string | undefined, extract: boolean = true): [string, string] {
@ -243,8 +246,8 @@ export class Git {
}
}
else {
repoPath = Strings.normalizePath(extract ? path.dirname(fileName) : repoPath!);
fileName = Strings.normalizePath(extract ? path.basename(fileName) : fileName);
repoPath = Strings.normalizePath(extract ? paths.dirname(fileName) : repoPath!);
fileName = Strings.normalizePath(extract ? paths.basename(fileName) : fileName);
}
return [fileName, repoPath];
@ -260,7 +263,7 @@ export class Git {
static async blame(
repoPath: string | undefined,
fileName: string,
sha?: string,
ref?: string,
options: { args?: string[] | null; ignoreWhitespace?: boolean; startLine?: number; endLine?: number } = {}
) {
const [file, root] = Git.splitPath(fileName, repoPath);
@ -278,8 +281,8 @@ export class Git {
}
let stdin;
if (sha) {
if (Git.isStagedUncommitted(sha)) {
if (ref) {
if (Git.isStagedUncommitted(ref)) {
// Pipe the blame contents to stdin
params.push('--contents', '-');
@ -287,7 +290,7 @@ export class Git {
stdin = await Git.show<string>(repoPath, fileName, ':');
}
else {
params.push(sha);
params.push(ref);
}
}
@ -353,10 +356,10 @@ export class Git {
return git<string>({ cwd: repoPath }, 'check-mailmap', author);
}
static checkout(repoPath: string, fileName: string, sha: string) {
static checkout(repoPath: string, fileName: string, ref: string) {
const [file, root] = Git.splitPath(fileName, repoPath);
return git<string>({ cwd: root }, 'checkout', sha, '--', file);
return git<string>({ cwd: root }, 'checkout', ref, '--', file);
}
static async config_get(key: string, repoPath?: string) {
@ -379,38 +382,38 @@ export class Git {
return data === '' ? undefined : data.trim();
}
static diff(repoPath: string, fileName: string, sha1?: string, sha2?: string, options: { encoding?: string } = {}) {
static diff(repoPath: string, fileName: string, ref1?: string, ref2?: string, options: { encoding?: string } = {}) {
const params = ['-c', 'color.diff=false', 'diff', '--diff-filter=M', '-M', '--no-ext-diff', '--minimal'];
if (sha1) {
params.push(Git.isStagedUncommitted(sha1) ? '--staged' : sha1);
if (ref1) {
params.push(Git.isStagedUncommitted(ref1) ? '--staged' : ref1);
}
if (sha2) {
params.push(Git.isStagedUncommitted(sha2) ? '--staged' : sha2);
if (ref2) {
params.push(Git.isStagedUncommitted(ref2) ? '--staged' : ref2);
}
const encoding: BufferEncoding = options.encoding === 'utf8' ? 'utf8' : 'binary';
return git<string>({ cwd: repoPath, encoding: encoding }, ...params, '--', fileName);
}
static diff_nameStatus(repoPath: string, sha1?: string, sha2?: string, options: { filter?: string } = {}) {
static diff_nameStatus(repoPath: string, ref1?: string, ref2?: string, options: { filter?: string } = {}) {
const params = ['-c', 'color.diff=false', 'diff', '--name-status', '-M', '--no-ext-diff'];
if (options && options.filter) {
params.push(`--diff-filter=${options.filter}`);
}
if (sha1) {
params.push(sha1);
if (ref1) {
params.push(ref1);
}
if (sha2) {
params.push(sha2);
if (ref2) {
params.push(ref2);
}
return git<string>({ cwd: repoPath }, ...params);
}
static diff_shortstat(repoPath: string, sha?: string) {
static diff_shortstat(repoPath: string, ref?: string) {
const params = ['-c', 'color.diff=false', 'diff', '--shortstat', '--no-ext-diff'];
if (sha) {
params.push(sha);
if (ref) {
params.push(ref);
}
return git<string>({ cwd: repoPath }, ...params);
}
@ -676,7 +679,7 @@ export class Git {
if (Git.isStagedUncommitted(ref)) {
ref = ':';
}
if (Git.isUncommitted(ref)) throw new Error(`sha=${ref} is uncommitted`);
if (Git.isUncommitted(ref)) throw new Error(`ref=${ref} is uncommitted`);
const opts = {
cwd: root,

+ 73
- 77
src/git/gitService.ts View File

@ -1,6 +1,6 @@
'use strict';
import * as fs from 'fs';
import * as path from 'path';
import * as paths from 'path';
import {
ConfigurationChangeEvent,
Disposable,
@ -284,9 +284,9 @@ export class GitService implements Disposable {
Object.create(null) as any
);
let paths;
let repoPaths;
try {
paths = await this.repositorySearchCore(folderUri.fsPath, depth, excludes);
repoPaths = await this.repositorySearchCore(folderUri.fsPath, depth, excludes);
}
catch (ex) {
if (RepoSearchWarnings.doesNotExist.test(ex.message || '')) {
@ -303,8 +303,8 @@ export class GitService implements Disposable {
return repositories;
}
for (let p of paths) {
p = path.dirname(p);
for (let p of repoPaths) {
p = paths.dirname(p);
// If we are the same as the root, skip it
if (Strings.normalizePath(p) === rootPath) continue;
@ -345,15 +345,15 @@ export class GitService implements Disposable {
const folders: string[] = [];
const promises = files.map(file => {
const fullPath = path.resolve(root, file);
const path = paths.resolve(root, file);
return new Promise<void>((res, rej) => {
fs.stat(fullPath, (err, stat) => {
fs.stat(path, (err, stat) => {
if (file === '.git') {
repositories.push(fullPath);
repositories.push(path);
}
else if (err == null && excludes[file] !== true && stat != null && stat.isDirectory()) {
folders.push(fullPath);
folders.push(path);
}
res();
@ -432,17 +432,17 @@ export class GitService implements Disposable {
fileName: string,
options: { ensureCase: boolean } = { ensureCase: false }
): Promise<boolean> {
const filePath = path.resolve(repoPath, fileName);
const exists = await new Promise<boolean>((resolve, reject) => fs.exists(filePath, resolve));
const path = paths.resolve(repoPath, fileName);
const exists = await new Promise<boolean>((resolve, reject) => fs.exists(path, resolve));
if (!options.ensureCase || !exists) return exists;
// Deal with renames in case only on case-insensative file systems
const normalizedRepoPath = path.normalize(repoPath);
return this.fileExistsWithCase(filePath, normalizedRepoPath, normalizedRepoPath.length);
const normalizedRepoPath = paths.normalize(repoPath);
return this.fileExistsWithCase(path, normalizedRepoPath, normalizedRepoPath.length);
}
private async fileExistsWithCase(filePath: string, repoPath: string, repoPathLength: number): Promise<boolean> {
const dir = path.dirname(filePath);
private async fileExistsWithCase(path: string, repoPath: string, repoPathLength: number): Promise<boolean> {
const dir = paths.dirname(path);
if (dir.length < repoPathLength) return false;
if (dir === repoPath) return true;
@ -456,7 +456,7 @@ export class GitService implements Disposable {
}
})
);
if (filenames.indexOf(path.basename(filePath)) === -1) {
if (filenames.indexOf(paths.basename(path)) === -1) {
return false;
}
return this.fileExistsWithCase(dir, repoPath, repoPathLength);
@ -526,7 +526,7 @@ export class GitService implements Disposable {
[fileName, repoPath] = Git.splitPath(fileName, repoPath);
}
else {
fileName = Strings.normalizePath(path.relative(repoPath, fileName));
fileName = Strings.normalizePath(paths.relative(repoPath, fileName));
}
}
else {
@ -921,10 +921,10 @@ export class GitService implements Disposable {
return GitBranchParser.parse(data, repoPath) || [];
}
async getChangedFilesCount(repoPath: string, sha?: string): Promise<GitDiffShortStat | undefined> {
Logger.log(`getChangedFilesCount('${repoPath}', '${sha}')`);
async getChangedFilesCount(repoPath: string, ref?: string): Promise<GitDiffShortStat | undefined> {
Logger.log(`getChangedFilesCount('${repoPath}', '${ref}')`);
const data = await Git.diff_shortstat(repoPath, sha);
const data = await Git.diff_shortstat(repoPath, ref);
return GitDiffParser.parseShortStat(data);
}
@ -974,17 +974,17 @@ export class GitService implements Disposable {
return user;
}
async getDiffForFile(uri: GitUri, sha1?: string, sha2?: string): Promise<GitDiff | undefined> {
if (sha1 !== undefined && sha2 === undefined && uri.sha !== undefined) {
sha2 = uri.sha;
async getDiffForFile(uri: GitUri, ref1?: string, ref2?: string): Promise<GitDiff | undefined> {
if (ref1 !== undefined && ref2 === undefined && uri.sha !== undefined) {
ref2 = uri.sha;
}
let key = 'diff';
if (sha1 !== undefined) {
key += `:${sha1}`;
if (ref1 !== undefined) {
key += `:${ref1}`;
}
if (sha2 !== undefined) {
key += `:${sha2}`;
if (ref2 !== undefined) {
key += `:${ref2}`;
}
const doc = await Container.tracker.getOrAdd(uri);
@ -993,27 +993,27 @@ export class GitService implements Disposable {
const cachedDiff = doc.state.get<CachedDiff>(key);
if (cachedDiff !== undefined) {
Logger.log(
`getDiffForFile[Cached(${key})]('${uri.repoPath}', '${uri.fsPath}', '${sha1}', '${sha2}')`
`getDiffForFile[Cached(${key})]('${uri.repoPath}', '${uri.fsPath}', '${ref1}', '${ref2}')`
);
return cachedDiff.item;
}
}
Logger.log(`getDiffForFile[Not Cached(${key})]('${uri.repoPath}', '${uri.fsPath}', '${sha1}', '${sha2}')`);
Logger.log(`getDiffForFile[Not Cached(${key})]('${uri.repoPath}', '${uri.fsPath}', '${ref1}', '${ref2}')`);
if (doc.state === undefined) {
doc.state = new GitDocumentState(doc.key);
}
}
else {
Logger.log(`getDiffForFile('${uri.repoPath}', '${uri.fsPath}', '${sha1}', '${sha2}')`);
Logger.log(`getDiffForFile('${uri.repoPath}', '${uri.fsPath}', '${ref1}', '${ref2}')`);
}
const promise = this.getDiffForFileCore(
uri.repoPath,
uri.fsPath,
sha1,
sha2,
ref1,
ref2,
{ encoding: GitService.getEncoding(uri) },
doc,
key
@ -1033,8 +1033,8 @@ export class GitService implements Disposable {
private async getDiffForFileCore(
repoPath: string | undefined,
fileName: string,
sha1: string | undefined,
sha2: string | undefined,
ref1: string | undefined,
ref2: string | undefined,
options: { encoding?: string },
document: TrackedDocument<GitDocumentState>,
key: string
@ -1042,7 +1042,7 @@ export class GitService implements Disposable {
const [file, root] = Git.splitPath(fileName, repoPath, false);
try {
const data = await Git.diff(root, file, sha1, sha2, options);
const data = await Git.diff(root, file, ref1, ref2, options);
const diff = GitDiffParser.parse(data);
return diff;
}
@ -1067,13 +1067,13 @@ export class GitService implements Disposable {
async getDiffForLine(
uri: GitUri,
line: number,
sha1?: string,
sha2?: string
ref1?: string,
ref2?: string
): Promise<GitDiffChunkLine | undefined> {
Logger.log(`getDiffForLine('${uri.repoPath}', '${uri.fsPath}', ${line}, '${sha1}', '${sha2}')`);
Logger.log(`getDiffForLine('${uri.repoPath}', '${uri.fsPath}', ${line}, '${ref1}', '${ref2}')`);
try {
const diff = await this.getDiffForFile(uri, sha1, sha2);
const diff = await this.getDiffForFile(uri, ref1, ref2);
if (diff === undefined) return undefined;
const chunk = diff.chunks.find(c => c.currentPosition.start <= line && c.currentPosition.end >= line);
@ -1088,14 +1088,14 @@ export class GitService implements Disposable {
async getDiffStatus(
repoPath: string,
sha1?: string,
sha2?: string,
ref1?: string,
ref2?: string,
options: { filter?: string } = {}
): Promise<GitStatusFile[] | undefined> {
Logger.log(`getDiffStatus('${repoPath}', '${sha1}', '${sha2}', ${options.filter})`);
Logger.log(`getDiffStatus('${repoPath}', '${ref1}', '${ref2}', ${options.filter})`);
try {
const data = await Git.diff_nameStatus(repoPath, sha1, sha2, options);
const data = await Git.diff_nameStatus(repoPath, ref1, ref2, options);
const diff = GitDiffParser.parseNameStatus(data, repoPath);
return diff;
}
@ -1141,8 +1141,8 @@ export class GitService implements Disposable {
const commit = options.ref && log.commits.get(options.ref);
if (commit === undefined && !options.firstIfNotFound && options.ref) {
// If the sha isn't resolved we will never find it, so let it fall through so we return the first
if (!Git.isResolveRequired(options.ref)) return undefined;
// If the ref isn't a valid sha we will never find it, so let it fall through so we return the first
if (!Git.isSha(options.ref) || Git.isUncommitted(options.ref)) return undefined;
}
return commit || Iterables.first(log.commits.values());
@ -1539,7 +1539,7 @@ export class GitService implements Disposable {
private async getRepoPathCore(filePath: string, isDirectory: boolean): Promise<string | undefined> {
try {
return await Git.revparse_toplevel(isDirectory ? filePath : path.dirname(filePath));
return await Git.revparse_toplevel(isDirectory ? filePath : paths.dirname(filePath));
}
catch (ex) {
Logger.error(ex, 'GitService.getRepoPathCore');
@ -1687,31 +1687,31 @@ export class GitService implements Disposable {
async getVersionedFile(
repoPath: string | undefined,
fileName: string,
sha: string | undefined
ref: string | undefined
): Promise<Uri | undefined> {
if (sha === GitService.deletedOrMissingSha) return undefined;
if (ref === GitService.deletedOrMissingSha) return undefined;
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', '${sha}')`);
Logger.log(`getVersionedFile('${repoPath}', '${fileName}', '${ref}')`);
if (!sha || (Git.isUncommitted(sha) && !Git.isStagedUncommitted(sha))) {
if (!ref || (Git.isUncommitted(ref) && !Git.isStagedUncommitted(ref))) {
if (await this.fileExists(repoPath!, fileName)) return Uri.file(fileName);
return undefined;
}
return GitUri.toRevisionUri(sha, fileName, repoPath!);
return GitUri.toRevisionUri(ref, fileName, repoPath!);
}
getVersionedFileBuffer(repoPath: string, fileName: string, sha: string) {
Logger.log(`getVersionedFileBuffer('${repoPath}', '${fileName}', ${sha})`);
getVersionedFileBuffer(repoPath: string, fileName: string, ref: string) {
Logger.log(`getVersionedFileBuffer('${repoPath}', '${fileName}', ${ref})`);
return Git.show<Buffer>(repoPath, fileName, sha, { encoding: 'buffer' });
return Git.show<Buffer>(repoPath, fileName, ref, { encoding: 'buffer' });
}
// getVersionedFileText(repoPath: string, fileName: string, sha: string) {
// Logger.log(`getVersionedFileText('${repoPath}', '${fileName}', ${sha})`);
// getVersionedFileText(repoPath: string, fileName: string, ref: string) {
// Logger.log(`getVersionedFileText('${repoPath}', '${fileName}', ${ref})`);
// return Git.show<string>(repoPath, fileName, sha, { encoding: GitService.getEncoding(repoPath, fileName) });
// return Git.show<string>(repoPath, fileName, ref, { encoding: GitService.getEncoding(repoPath, fileName) });
// }
getVersionedUri(uri: Uri) {
@ -1795,11 +1795,11 @@ export class GitService implements Disposable {
if (ref === GitService.deletedOrMissingSha) return false;
try {
// Even if we have a sha, check first to see if the file exists (that way the cache will be better reused)
// Even if we have a ref, check first to see if the file exists (that way the cache will be better reused)
let tracked = !!(await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName));
if (!tracked && ref !== undefined) {
tracked = !!(await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName, { ref: ref }));
// If we still haven't found this file, make sure it wasn't deleted in that sha (i.e. check the previous)
// If we still haven't found this file, make sure it wasn't deleted in that ref (i.e. check the previous)
if (!tracked) {
tracked = !!(await Git.ls_files(repoPath === undefined ? '' : repoPath, fileName, {
ref: `${ref}^`
@ -1841,13 +1841,13 @@ export class GitService implements Disposable {
}
async resolveReference(repoPath: string, ref: string, uri?: Uri) {
if (ref.endsWith('^3')) return ref;
if (Git.isSha(ref) || !Git.isShaLike(ref) || ref.endsWith('^3')) return ref;
Logger.log(`resolveReference('${repoPath}', '${ref}', '${uri && uri.toString(true)}')`);
if (uri == null) return (await Git.revparse(repoPath, ref)) || ref;
const fileName = Strings.normalizePath(path.relative(repoPath, uri.fsPath));
const fileName = Strings.normalizePath(paths.relative(repoPath, uri.fsPath));
const resolvedRef = await Git.log_resolve(repoPath, fileName, ref);
const ensuredRef = await Git.cat_file_validate(repoPath, fileName, resolvedRef || ref);
@ -1886,7 +1886,7 @@ export class GitService implements Disposable {
static getEncoding(repoPath: string, fileName: string): string;
static getEncoding(uri: Uri): string;
static getEncoding(repoPathOrUri: string | Uri, fileName?: string): string {
const uri = typeof repoPathOrUri === 'string' ? Uri.file(path.join(repoPathOrUri, fileName!)) : repoPathOrUri;
const uri = typeof repoPathOrUri === 'string' ? Uri.file(paths.join(repoPathOrUri, fileName!)) : repoPathOrUri;
return Git.getEncoding(workspace.getConfiguration('files', uri).get<string>('encoding'));
}
@ -1915,34 +1915,30 @@ export class GitService implements Disposable {
return Git.getGitVersion();
}
static isResolveRequired(sha: string): boolean {
return Git.isResolveRequired(sha);
static isShaLike(ref: string): boolean {
return Git.isShaLike(ref);
}
static isSha(sha: string): boolean {
return Git.isSha(sha);
static isStagedUncommitted(ref: string | undefined): boolean {
return Git.isStagedUncommitted(ref);
}
static isStagedUncommitted(sha: string | undefined): boolean {
return Git.isStagedUncommitted(sha);
}
static isUncommitted(sha: string | undefined): boolean {
return Git.isUncommitted(sha);
static isUncommitted(ref: string | undefined): boolean {
return Git.isUncommitted(ref);
}
static shortenSha(
sha: string | undefined,
ref: string | undefined,
strings: { deletedOrMissing?: string; stagedUncommitted?: string; uncommitted?: string; working?: string } = {}
) {
if (sha === undefined) return undefined;
if (ref === undefined) return undefined;
strings = { deletedOrMissing: '(deleted)', working: '', ...strings };
if (sha === '') return strings.working;
if (sha === GitService.deletedOrMissingSha) return strings.deletedOrMissing;
if (ref === '') return strings.working;
if (ref === GitService.deletedOrMissingSha) return strings.deletedOrMissing;
return Git.isSha(sha) || Git.isStagedUncommitted(sha) ? Git.shortenSha(sha, strings) : sha;
return Git.isShaLike(ref) || Git.isStagedUncommitted(ref) ? Git.shortenSha(ref, strings) : ref;
}
static compareGitVersion(version: string, throwIfLessThan?: Error) {

Loading…
Cancel
Save