Skip to content

Commit

Permalink
Added support for blame per issue atom#11
Browse files Browse the repository at this point in the history
  • Loading branch information
Gabriel Isenberg committed Sep 13, 2015
1 parent 3259d70 commit 26ca831
Show file tree
Hide file tree
Showing 12 changed files with 93 additions and 0 deletions.
1 change: 1 addition & 0 deletions spec/fixtures/blame.git/HEAD
@@ -0,0 +1 @@
ref: refs/heads/master
Binary file added spec/fixtures/blame.git/index
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
x5���0 �3�O�1= b)�;"��@�t��[����a���Rot�L6�U<��_U'�S�$.�TPD9\�����ό��)v�����%
Expand Down
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions spec/fixtures/blame.git/refs/heads/master
@@ -0,0 +1 @@
fcfc9307b3c7864cbb8bbfe457f44d7a33202de4
21 changes: 21 additions & 0 deletions spec/git-spec.coffee
Expand Up @@ -724,3 +724,24 @@ describe "git", ->

it "throws an error if the file doesn't exist", ->
expect(-> repo.add('missing.txt')).toThrow()

describe ".getBlame(path)", ->
beforeEach ->
repoDirectory = temp.mkdirSync('node-git-repo-')
wrench.copyDirSyncRecursive(path.join(__dirname, 'fixtures/blame.git'), path.join(repoDirectory, '.git'))
repo = git.open(repoDirectory)

it "returns the blame for the path", ->
blame = repo.getBlame('a.txt')

expect(blame.length).toBe 1
expect(blame[0].commitId).toBe 'fcfc9307b'
expect(blame[0].startLineNumber).toBe 1
expect(blame[0].linesInHunk).toBe 3
expect(blame[0].signature.name).toBe 'Gabriel Isenberg'
expect(blame[0].signature.email).toBe 'gisenberg@gmail.com'
expect(blame[0].signature.when.time).toBe 1442122439
expect(blame[0].signature.when.offset).toBe -420

it "throws an error if the file doesn't exist", ->
expect(-> repo.getBlame('missing.txt')).toThrow()
68 changes: 68 additions & 0 deletions src/repository.cc
Expand Up @@ -61,6 +61,7 @@ void Repository::Init(Local<Object> target) {
Nan::SetMethod(proto, "getReferences", Repository::GetReferences);
Nan::SetMethod(proto, "checkoutRef", Repository::CheckoutReference);
Nan::SetMethod(proto, "add", Repository::Add);
Nan::SetMethod(proto, "getBlame", Repository::GetBlame);

target->Set(Nan::New<String>("Repository").ToLocalChecked(),
newTemplate->GetFunction());
Expand Down Expand Up @@ -910,6 +911,73 @@ NAN_METHOD(Repository::Add) {
info.GetReturnValue().Set(Nan::New<Boolean>(true));
}

NAN_METHOD(Repository::GetBlame) {
Nan::HandleScope scope;

git_repository* repository = GetRepository(info);
std::string path(*String::Utf8Value(info[0]));

git_blame_options blameOpts = GIT_BLAME_OPTIONS_INIT;
git_blame *blame = NULL;

if (git_blame_file(&blame, repository, path.c_str(), &blameOpts) != GIT_OK) {
const git_error* e = giterr_last();
if (e != NULL)
return Nan::ThrowError(e->message);
else
return Nan::ThrowError("Unknown error getting blame.");
}

// git_blob* blob = NULL;
//
// int getBlobResult = GetBlob(info, repository, blob);
// if (getBlobResult != 0) {
// git_blame_free(blame);
// return info.GetReturnValue().Set(Nan::Null());
// }

size_t hunkCount = git_blame_get_hunk_count(blame);
Local<Object> v8Ranges = Nan::New<Array>(hunkCount);

for (size_t i = 0; i < hunkCount; i++) {
const git_blame_hunk *hunk = git_blame_get_hunk_byindex(blame, i);
const git_signature *finalSig = hunk->final_signature;
char commitId[10] = {0};
git_oid_tostr(commitId, sizeof(commitId), &hunk->final_commit_id);

Local<Object> v8Range = Nan::New<Object>();
Local<Object> signature = Nan::New<Object>();
Local<Object> when = Nan::New<Object>();

when->Set(Nan::New<String>("time").ToLocalChecked(),
Nan::New<Number>(finalSig->when.time));
when->Set(Nan::New<String>("offset").ToLocalChecked(),
Nan::New<Number>(finalSig->when.offset));

signature->Set(Nan::New<String>("name").ToLocalChecked(),
Nan::New<String>(finalSig->name).ToLocalChecked());
signature->Set(Nan::New<String>("email").ToLocalChecked(),
Nan::New<String>(finalSig->email).ToLocalChecked());
signature->Set(Nan::New<String>("when").ToLocalChecked(),
when);

v8Range->Set(Nan::New<String>("commitId").ToLocalChecked(),
Nan::New<String>(commitId).ToLocalChecked());
v8Range->Set(Nan::New<String>("startLineNumber").ToLocalChecked(),
Nan::New<Number>(hunk->final_start_line_number));
v8Range->Set(Nan::New<String>("linesInHunk").ToLocalChecked(),
Nan::New<Number>(hunk->lines_in_hunk));
v8Range->Set(Nan::New<String>("signature").ToLocalChecked(),
signature);

v8Ranges->Set(i, v8Range);
}

git_blame_free(blame);

info.GetReturnValue().Set(v8Ranges);
}

Repository::Repository(Local<String> path) {
Nan::HandleScope scope;

Expand Down
1 change: 1 addition & 0 deletions src/repository.h
Expand Up @@ -59,6 +59,7 @@ class Repository : public Nan::ObjectWrap {
static NAN_METHOD(GetReferences);
static NAN_METHOD(CheckoutReference);
static NAN_METHOD(Add);
static NAN_METHOD(GetBlame);

static int StatusCallback(const char *path, unsigned int status,
void *payload);
Expand Down

0 comments on commit 26ca831

Please sign in to comment.