Skip to content

Commit

Permalink
Fixes get working file & file commit quickpick nav
Browse files Browse the repository at this point in the history
Adds GitService.getWorkingUri
Removes WorkspaceFileExistsRequestType from vsls protocol
  • Loading branch information
eamodio committed May 2, 2019
1 parent 36b6b96 commit c5f510e
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 365 deletions.
9 changes: 7 additions & 2 deletions src/commands/diffLineWithWorking.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use strict';
import { commands, TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { commands, TextDocumentShowOptions, TextEditor, Uri, window } from 'vscode';
import { Container } from '../container';
import { GitCommit, GitService, GitUri } from '../git/gitService';
import { Logger } from '../logger';
Expand Down Expand Up @@ -69,6 +69,11 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
}
}

const workingUri = await args.commit.getWorkingUri();
if (workingUri === undefined) {
return window.showWarningMessage('Unable to open compare. File has been deleted from the working tree');
}

const diffArgs: DiffWithCommandArgs = {
repoPath: args.commit.repoPath,
lhs: {
Expand All @@ -77,7 +82,7 @@ export class DiffLineWithWorkingCommand extends ActiveEditorCommand {
},
rhs: {
sha: '',
uri: args.commit.workingUri
uri: workingUri
},
line: args.line,
showOptions: args.showOptions
Expand Down
8 changes: 3 additions & 5 deletions src/commands/diffWithWorking.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,11 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
}
}

const [workingFileName] = await Container.git.findWorkingFileName(gitUri.fsPath, gitUri.repoPath);
if (workingFileName === undefined) {
const workingUri = await args.commit.getWorkingUri();
if (workingUri === undefined) {
return window.showWarningMessage('Unable to open compare. File has been deleted from the working tree');
}

args.commit.workingFileName = workingFileName;

const diffArgs: DiffWithCommandArgs = {
repoPath: args.commit.repoPath,
lhs: {
Expand All @@ -132,7 +130,7 @@ export class DiffWithWorkingCommand extends ActiveEditorCommand {
},
rhs: {
sha: '',
uri: args.commit.workingUri
uri: workingUri
},
line: args.line,
showOptions: args.showOptions
Expand Down
9 changes: 3 additions & 6 deletions src/commands/openWorkingFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,14 @@ export class OpenWorkingFileCommand extends ActiveEditorCommand {

args.uri = await GitUri.fromUri(uri);
if (args.uri instanceof GitUri && args.uri.sha) {
const [fileName, repoPath] = await Container.git.findWorkingFileName(
args.uri.fsPath,
args.uri.repoPath
);
if (fileName === undefined) {
const workingUri = await Container.git.getWorkingUri(args.uri.repoPath!, args.uri);
if (workingUri === undefined) {
return window.showWarningMessage(
'Unable to open working file. File could not be found in the working tree'
);
}

args.uri = new GitUri(GitUri.resolveToUri(fileName, repoPath), repoPath);
args.uri = new GitUri(workingUri, args.uri.repoPath);
}
}

Expand Down
7 changes: 0 additions & 7 deletions src/commands/showQuickCommitDetails.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
'use strict';
import * as paths from 'path';
import { commands, TextEditor, Uri } from 'vscode';
import { GlyphChars } from '../constants';
import { Container } from '../container';
Expand Down Expand Up @@ -68,7 +67,6 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
const gitUri = await GitUri.fromUri(uri);

let repoPath = gitUri.repoPath;
let workingFileName = repoPath ? paths.relative(repoPath, gitUri.fsPath) : gitUri.fsPath;

args = { ...args };
if (args.sha === undefined) {
Expand All @@ -90,7 +88,6 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {

args.sha = blame.commit.sha;
repoPath = blame.commit.repoPath;
workingFileName = blame.commit.fileName;

args.commit = blame.commit;
}
Expand Down Expand Up @@ -124,10 +121,6 @@ export class ShowQuickCommitDetailsCommand extends ActiveEditorCachedCommand {
return Messages.showCommitNotFoundWarningMessage('Unable to show commit details');
}

if (args.commit.workingFileName === undefined) {
args.commit.workingFileName = workingFileName;
}

if (args.showInView) {
void (await Container.searchView.search(repoPath!, args.commit.sha, GitRepoSearchBy.Sha, {
label: { label: `commits with an id matching '${args.commit.shortSha}'` }
Expand Down
11 changes: 0 additions & 11 deletions src/commands/showQuickCommitFileDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
uri = getCommandUri(uri, editor);
if (uri == null) return undefined;

let workingFileName = args.commit && args.commit.workingFileName;

const gitUri = await GitUri.fromUri(uri);

args = { ...args };
Expand All @@ -91,7 +89,6 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
args.sha = blame.commit.sha;

args.commit = blame.commit;
workingFileName = paths.relative(args.commit.repoPath, gitUri.fsPath);
}
catch (ex) {
Logger.error(ex, 'ShowQuickCommitFileDetailsCommand', `getBlameForLine(${blameline})`);
Expand All @@ -103,10 +100,6 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand

try {
if (args.commit === undefined || !args.commit.isFile) {
if (args.commit !== undefined) {
workingFileName = undefined;
}

if (args.fileLog !== undefined) {
args.commit = args.fileLog.commits.get(args.sha!);
// If we can't find the commit, kill the fileLog
Expand All @@ -128,10 +121,6 @@ export class ShowQuickCommitFileDetailsCommand extends ActiveEditorCachedCommand
return Messages.showCommitNotFoundWarningMessage('Unable to show commit file details');
}

// Attempt to the most recent commit -- so that we can find the real working filename if there was a rename
args.commit.workingFileName = workingFileName;
[args.commit.workingFileName] = await Container.git.findWorkingFileName(args.commit);

const shortSha = GitService.shortenSha(args.sha!);

if (args.goBackCommand === undefined) {
Expand Down
179 changes: 40 additions & 139 deletions src/git/gitService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import {
GitBlameParser,
GitBranch,
GitBranchParser,
GitCommit,
GitCommitType,
GitContributor,
GitDiff,
Expand Down Expand Up @@ -582,136 +581,6 @@ export class GitService implements Disposable {
);
}

async fileExists(
repoPath: string,
fileName: string,
options: { ensureCase: boolean } = { ensureCase: false }
): Promise<boolean> {
if (Container.vsls.isMaybeGuest) {
const guest = await Container.vsls.guest();
if (guest !== undefined) {
return guest.fileExists(repoPath, fileName, options);
}
}

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 = paths.normalize(repoPath);
return this.fileExistsWithCase(path, normalizedRepoPath, normalizedRepoPath.length);
}

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;

const filenames = await new Promise<string[]>((resolve, reject) =>
fs.readdir(dir, (err: NodeJS.ErrnoException, files: string[]) => {
if (err) {
reject(err);
}
else {
resolve(files);
}
})
);
if (filenames.indexOf(paths.basename(path)) === -1) {
return false;
}
return this.fileExistsWithCase(dir, repoPath, repoPathLength);
}

@log()
async findNextCommit(repoPath: string, fileName: string, ref?: string): Promise<GitLogCommit | undefined> {
let log = await this.getLogForFile(repoPath, fileName, { maxCount: 1, ref: ref, renames: true, reverse: true });
let commit = log && Iterables.first(log.commits.values());
if (commit) return commit;

const nextFileName = await this.findNextFileName(repoPath, fileName, ref);
if (nextFileName) {
log = await this.getLogForFile(repoPath, nextFileName, {
maxCount: 1,
ref: ref,
renames: true,
reverse: true
});
commit = log && Iterables.first(log.commits.values());
}

return commit;
}

@log()
async findNextFileName(repoPath: string | undefined, fileName: string, ref?: string): Promise<string | undefined> {
[fileName, repoPath] = Git.splitPath(fileName, repoPath);

return (await this.fileExists(repoPath, fileName, { ensureCase: true }))
? fileName
: this.findNextFileNameCore(repoPath, fileName, ref);
}

private async findNextFileNameCore(repoPath: string, fileName: string, ref?: string): Promise<string | undefined> {
if (ref === undefined) {
// Get the most recent commit for this file name
ref = await this.getRecentShaForFile(repoPath, fileName);
if (ref === undefined) return undefined;
}

// Get the full commit (so we can see if there are any matching renames in the files)
const log = await this.getLog(repoPath, { maxCount: 1, ref: ref });
if (log === undefined) return undefined;

const c = Iterables.first(log.commits.values());
const file = c.files.find(f => f.originalFileName === fileName);
if (file === undefined) return undefined;

return file.fileName;
}

async findWorkingFileName(commit: GitCommit): Promise<[string | undefined, string | undefined]>;
async findWorkingFileName(
fileName: string,
repoPath?: string,
ref?: string
): Promise<[string | undefined, string | undefined]>;
@log()
async findWorkingFileName(
commitOrFileName: GitCommit | string,
repoPath?: string,
ref?: string
): Promise<[string | undefined, string | undefined]> {
let fileName;
if (typeof commitOrFileName === 'string') {
fileName = commitOrFileName;
if (repoPath === undefined) {
repoPath = await this.getRepoPath(fileName, { ref: ref });
[fileName, repoPath] = Git.splitPath(fileName, repoPath);
}
else {
fileName = Strings.normalizePath(paths.relative(repoPath, fileName));
}
}
else {
const c = commitOrFileName;
repoPath = c.repoPath;
if (c.workingFileName && (await this.fileExists(repoPath, c.workingFileName, { ensureCase: true }))) {
return [c.workingFileName, repoPath];
}
fileName = c.fileName;
}

// Keep walking up to the most recent commit for a given filename, until it exists on disk
while (true) {
if (await this.fileExists(repoPath, fileName, { ensureCase: true })) return [fileName, repoPath];

fileName = await this.findNextFileNameCore(repoPath, fileName);
if (fileName === undefined) return [undefined, undefined];
}
}

@log({
args: {
0: (editor: TextEditor) =>
Expand Down Expand Up @@ -1359,13 +1228,6 @@ export class GitService implements Disposable {
return this.getLogCommitForFile(repoPath, fileName, undefined);
}

@log()
getRecentShaForFile(repoPath: string, fileName: string) {
return Git.log_recent(repoPath, fileName, {
similarityThreshold: Container.config.advanced.similarityThreshold
});
}

@log()
async getLogCommit(repoPath: string, ref: string): Promise<GitLogCommit | undefined> {
const log = await this.getLog(repoPath, { maxCount: 2, ref: ref });
Expand Down Expand Up @@ -2255,7 +2117,8 @@ export class GitService implements Disposable {
if (ref === GitService.deletedOrMissingSha) return undefined;

if (!ref || (Git.isUncommitted(ref) && !Git.isStagedUncommitted(ref))) {
if (await this.fileExists(repoPath!, fileName)) return GitUri.file(fileName);
const data = await Git.ls_files(repoPath!, fileName);
if (data !== undefined) return GitUri.file(fileName);

return undefined;
}
Expand All @@ -2267,6 +2130,44 @@ export class GitService implements Disposable {
return GitUri.toRevisionUri(ref, fileName, repoPath!);
}

@log()
async getWorkingUri(repoPath: string, uri: Uri) {
let fileName = GitUri.getRelativePath(uri, repoPath);

let data;
let ref;
do {
data = await Git.ls_files(repoPath, fileName);
if (data !== undefined) {
return GitUri.resolveToUri(data, repoPath);
}

// Get the most recent commit for this file name
ref = await Git.log_recent(repoPath, fileName, {
similarityThreshold: Container.config.advanced.similarityThreshold
});
if (ref === undefined) return undefined;

// Now check if that commit had any renames
data = await Git.log_file(repoPath, '.', ref, {
filters: ['R'],
format: GitLogParser.simpleFormat,
maxCount: 1
});
if (data == null || data.length === 0) {
return GitUri.resolveToUri(fileName, repoPath);
}

const [renamedRef, renamedFile] = GitLogParser.parseSimpleRenamed(data, fileName);
if (renamedRef === undefined || renamedFile === undefined) {
return GitUri.resolveToUri(fileName, repoPath);
}

ref = renamedRef;
fileName = renamedFile;
} while (true);
}

isTrackable(scheme: string): boolean;
isTrackable(uri: Uri): boolean;
isTrackable(schemeOruri: string | Uri): boolean {
Expand Down

0 comments on commit c5f510e

Please sign in to comment.