diff --git a/.gitignore b/.gitignore index 91f748bb6..1f63036f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,11 @@ -.lock-wscript -build -doc -!doc/Theme.css -example/stress/test -node_modules +# Files .DS_Store +/sftp-config.json + +# Directories +/build +/example/stress/test +/doc +!doc/Theme.css +/node_modules + diff --git a/.travis.yml b/.travis.yml index baa0031d5..f6e2ee0ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,5 @@ language: node_js node_js: - 0.8 +git: + depth: 1000 diff --git a/LICENSE b/LICENSE index 01edb91b1..4782c6003 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011 Tim Branyen +Copyright (c) 2013 Tim Branyen This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, diff --git a/README.md b/README.md index 86ed14aa4..2442f8583 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,26 @@ -Node.js libgit2 bindings [![Build Status](https://travis-ci.org/tbranyen/nodegit.png)](https://travis-ci.org/tbranyen/nodegit) -======================= +nodegit +======= -Created by Tim Branyen [@tbranyen](http://twitter.com/tbranyen) +> Node.js libgit2 bindings -Currently under active development (and seeking contributions), `nodegit` provides asynchronous native bindings to the [`libgit2`](http://libgit2.github.com/libgit2/) C API. +**v0.0.72** [![Build +Status](https://travis-ci.org/tbranyen/nodegit.png)](https://travis-ci.org/tbranyen/nodegit) +Maintained by Tim Branyen [@tbranyen](http://twitter.com/tbranyen) and Michael +Robinson [@codeofinterest](http://twitter.com/codeofinterest), with help from +[awesome +contributors](https://github.com/tbranyen/nodegit/contributors)! Contributing ------------ -Nodegit aims to eventually provide native asynchronous bindings for as much of libgit2 as possible, but we can't do it alone! +Nodegit aims to eventually provide native asynchronous bindings for as much of +libgit2 as possible, but we can't do it alone! -We welcome pull requests, but please pay attention to the following: whether your lovely code fixes a bug or adds a new feature, please include unit tests that either prove the bug is fixed, or that your new feature works as expected. See [running tests](#running-tests) +We welcome pull requests, but please pay attention to the following: whether +your lovely code fixes a bug or adds a new feature, please include unit tests +that either prove the bug is fixed, or that your new feature works as expected. +See [running tests](#running-tests) Unit tests are what makes the Node event loop go around. @@ -19,7 +28,8 @@ Building and installing ----------------------- ### Dependencies ### -To run `nodegit` you need `Node.js` and to run unit tests you will need to have `git` installed and accessible from your `PATH` to fetch any `vendor/` addons. +To install `nodegit` you need `Node.js` and `cmake`. To run unit tests you will need to have +`git` installed and accessible from your `PATH` to fetch any `vendor/` addons. ### Easy install (Recommended) ### This will install and configure everything you need to use `nodegit`. @@ -97,85 +107,86 @@ var git = require('nodegit').raw; var repo = new git.Repo(); // Read a repository -repo.open('.git', function(error) { - // Err is an integer, success is 0, use strError for string representation - if(error) { - var error = new git.Error(); - throw error.strError(error); +repo.open('.git', function(err) { + // Err is an integer, success is 0, use strError for string representation + if (err) { + var error = new git.Error(); + throw error.strError(err); + } + + // Create instance of Ref constructor with this repository + var ref = new git.Ref(repo); + + // Find the master branch + repo.lookupRef(ref, '/refs/heads/master', function(err) { + if (err) { + var error = new git.Error(); + throw error.strError(err); } - // Create instance of Ref constructor with this repository - var ref = new git.Ref(repo); - - // Find the master branch - repo.lookupRef(ref, '/refs/heads/master', function(err) { - if(error) { - var error = new git.Error(); - throw error.strError(err); - } - - // Create instance of Commit constructor with this repository - var commit = new git.Commit(repo), - // Create instance of Oid constructor - oid = new git.Oid(); + // Create instance of Commit constructor with this repository + var commit = new git.Commit(repo); - // Set the oid constructor internal reference to this branch reference - ref.oid(oid); + // Create instance of Oid constructor + var oid = new git.Oid(); - // Lookup the commit for this oid - commit.lookup(oid, function(err) { - if(err) { - var error = new git.Error(); - throw error.strError( err ); - } + // Set the oid constructor internal reference to this branch reference + ref.oid(oid); - // Create instance of RevWalk constructor with this repository - var revwalk = new git.RevWalk(repo); + // Lookup the commit for this oid + commit.lookup(oid, function(err) { + if (err) { + var error = new git.Error(); + throw error.strError(err); + } - // Push the commit as the start to walk - revwalk.push(commit); + // Create instance of RevWalk constructor with this repository + var revwalk = new git.RevWalk(repo); - // Recursive walk - function walk() { - // Each revision walk iteration yields a commit - var revisionCommit = new git.Commit(repo); + // Push the commit as the start to walk + revwalk.push(commit); - revwalk.next( revisionCommit, function(err) { - // Finish recursion once no more revision commits are left - if(err) { return; } + // Recursive walk + function walk() { + // Each revision walk iteration yields a commit + var revisionCommit = new git.Commit(repo); - // Create instance of Oid for sha - var oid = new git.Oid(); + revwalk.next(revisionCommit, function(err) { + // Finish recursion once no more revision commits are left + if (err) { return; } - // Set oid to the revision commit - revisionCommit.id(oid); + // Create instance of Oid for sha + var oid = new git.Oid(); - // Create instance of Sig for author - var author = new git.Sig(); + // Set oid to the revision commit + revisionCommit.id(oid); - // Set the author to the revision commit author - revisionCommit.author(author); + // Create instance of Sig for author + var author = new git.Sig(); - // Convert timestamp to milliseconds and set new Date object - var time = new Date( revisionCommit.time() * 1000 ); + // Set the author to the revision commit author + revisionCommit.author(author); - // Print out `git log` emulation - console.log(oid.toString( 40 )); - console.log(author.name() + '<' + author.email() + '>'); - console.log(time); - console.log('\n'); - console.log(revisionCommit.message()); - console.log('\n'); + // Convert timestamp to milliseconds and set new Date object + var time = new Date( revisionCommit.time() * 1000 ); - // Recurse! - walk(); - }); - } + // Print out `git log` emulation + console.log(oid.toString( 40 )); + console.log(author.name() + '<' + author.email() + '>'); + console.log(time); + console.log('\n'); + console.log(revisionCommit.message()); + console.log('\n'); - // Initiate recursion - walk(): + // Recurse! + walk(); }); + } + + // Initiate recursion + walk(): }); + }); }); ```` @@ -255,6 +266,10 @@ __Can keep track of current method coverage at: [http://bit.ly/tb_methods](http: Getting involved ---------------- -If you find this project of interest, please document all issues and fork if you feel you can provide a patch. Testing is of huge importance; by simply running the unit tests on your system and reporting issues you can contribute! +If you find this project of interest, please document all issues and fork if +you feel you can provide a patch. Testing is of huge importance; by simply +running the unit tests on your system and reporting issues you can contribute! -__Before submitting a pull request, please ensure both that you've added unit tests to cover your shiny new code, and that all unit tests and lint checks pass.__ +__Before submitting a pull request, please ensure both that you've added unit +tests to cover your shiny new code, and that all unit tests and lint checks +pass.__ diff --git a/binding.gyp b/binding.gyp index 7902aedd6..ad556410f 100644 --- a/binding.gyp +++ b/binding.gyp @@ -14,9 +14,10 @@ 'src/revwalk.cc', 'src/sig.cc', 'src/tree.cc', - 'src/tree_entry.cc' - ], - 'todosources': [ + 'src/tree_entry.cc', + 'src/diff_list.cc', + 'src/threads.cc', + 'src/functions/string.cc' ], 'include_dirs': [ diff --git a/example/raw-commit.js b/example/raw-commit.js index bb0ff3986..07212061d 100644 --- a/example/raw-commit.js +++ b/example/raw-commit.js @@ -1,5 +1,5 @@ -var git = require( '../' ).raw - , path = require( 'path' ); +var git = require( '../' ).raw, + path = require( 'path' ); var repo = new git.Repo(); repo.open( path.resolve( '../.git' ), function() { diff --git a/include/commit.h b/include/commit.h index ac63ae59c..da626c8ac 100755 --- a/include/commit.h +++ b/include/commit.h @@ -1,13 +1,13 @@ /* * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * * Dual licensed under the MIT and GPL licenses. */ -#ifndef COMMIT_H -#define COMMIT_H - #include #include +#include #include "../vendor/libgit2/include/git2.h" @@ -38,45 +38,31 @@ class GitCommit : public ObjectWrap { git_commit* GetValue(); void SetValue(git_commit* commit); - int Lookup(git_repository* repo, git_oid* oid); void Close(); - const git_oid* Id(); - const char* MessageShort(); - const char* Message(); - time_t Time(); - int TimeOffset(); - const git_signature* Committer(); - const git_signature* Author(); + int Tree(git_tree** tree); - unsigned int ParentCount(); - int Parent(git_commit** commit, int pos); protected: GitCommit() {} ~GitCommit() {} static Handle New(const Arguments& args); - static Handle NewInstance(); + + static Handle FetchDetailsSync(const Arguments& args); + static Handle FetchDetails(const Arguments& args); + static void FetchDetailsWork(uv_work_t *req); + static void FetchDetailsAfterWork(uv_work_t *req); static Handle Lookup(const Arguments& args); static void LookupWork(uv_work_t *req); static void LookupAfterWork(uv_work_t *req); static Handle Close(const Arguments& args); - static Handle Id(const Arguments& args); - static Handle MessageShort(const Arguments& args); - static Handle Message(const Arguments& args); - static Handle Time(const Arguments& args); - static Handle TimeOffset(const Arguments& args); - static Handle Committer(const Arguments& args); - static Handle Author(const Arguments& args); static Handle Tree(const Arguments& args); static void TreeWork(uv_work_t* req); static void TreeAfterWork(uv_work_t* req); - static Handle ParentCount(const Arguments& args); - static Handle ParentSync(const Arguments& args); static Handle Parent(const Arguments& args); static void ParentWork(uv_work_t* req); @@ -86,30 +72,53 @@ class GitCommit : public ObjectWrap { git_commit* commit; git_oid* oid; - struct lookup_request { - GitCommit* commit; - GitRepo* repo; - GitOid* oid; - int err; + struct LookupBaton { + uv_work_t request; + const git_error* error; + + git_repository* repo; + git_oid oid; + std::string sha; + git_commit* rawCommit; + Persistent callback; }; /** - * Struct: parent_request - * Contains references to the current commit, parent commit (output) - * parent commit's index, also contains references to an error code post - * lookup, and a callback function to execute. + * Struct containing details for a commit. + */ + struct FetchDetailsBaton { + uv_work_t request; + const git_error* error; + + git_commit* rawCommit; + const git_oid *oid; + char sha[GIT_OID_HEXSZ + 1]; + const char* message; + time_t time; + int timeOffset; + const git_signature* committer; + const git_signature* author; + unsigned int parentCount; + std::vector parentShas; + + Persistent callback; + }; + + /** + * Contains references to the current commit, parent commit (output) + * parent commit's index, also contains references to an error code post + * lookup, and a callback function to execute. */ struct ParentBaton { uv_work_t request; - int errorCode; - const char* errorMessage; + const git_error* error; int index; - GitCommit *commit; - git_commit *rawParentCommit; + GitCommit* commit; + git_commit* rawParentCommit; + Persistent callback; }; }; -#endif diff --git a/include/diff_list.h b/include/diff_list.h new file mode 100644 index 000000000..429c96145 --- /dev/null +++ b/include/diff_list.h @@ -0,0 +1,133 @@ +/* + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ + +#include +#include +#include +#include +#include + +#include "../vendor/libgit2/include/git2.h" + +#include "../include/repo.h" + +using namespace node; +using namespace v8; + +/** + * Class wrapper for libgit2 git_diff_list + */ +class GitDiffList : public ObjectWrap { + public: + + /** + * v8::FunctionTemplate used to create Node.js constructor + */ + static Persistent constructor_template; + + static const int WALK_DELTA_THRESHHOLD = 10; + + /** + * Used to intialize the EventEmitter from Node.js + * + * @param target v8::Object the Node.js module object + */ + static void Initialize (Handle target); + + git_diff_list* GetValue(); + void SetValue(git_diff_list* diffList); + void Close(); + + protected: + GitDiffList() {} + ~GitDiffList() {} + + static Handle New(const Arguments& args); + static Handle Close(const Arguments& args); + + static Handle TreeToTree(const Arguments& args); + static void TreeToTreeWork(uv_work_t *req); + static void TreeToTreeAfterWork(uv_work_t *req); + + /** + * Walk the current git_diff_list + */ + static Handle Walk(const Arguments& args); + static void WalkWork(void *payload); + static int WalkWorkFile(const git_diff_delta *delta, float progress, + void *payload); + static int WalkWorkHunk(const git_diff_delta *delta, const git_diff_range *range, + const char *header, size_t header_len, void *payload); + static int WalkWorkData(const git_diff_delta *delta, /** delta that contains this data */ + const git_diff_range *range, /** range of lines containing this data */ + char line_origin, /** git_diff_list_t value from above */ + const char *content, /** diff data - not NUL terminated */ + size_t content_len, /** number of bytes of diff data */ + void *payload); /** user reference data */ + /** + * Called when WalkWorkFile reaches its cache + * thresholds. Passes data back to main thread + * + * @param payload The WalkBaton + */ + static void WalkWorkSendFile(uv_async_t *handle, int status /*UNUSED*/); + static void WalkWorkSendHunk(uv_async_t *handle, int status /*UNUSED*/); + static void WalkWorkSendData(uv_async_t *handle, int status /*UNUSED*/); + static void WalkWorkSendEnd(uv_async_t *handle, int status /*UNUSED*/); + + private: + git_diff_list* diffList; + // git_oid* oldOid; + // git_oid* newOid; + + struct TreeToTreeBaton { + uv_work_t request; + const git_error* error; + + GitDiffList *diffList; + git_repository* repo; + git_oid oldOid; + std::string oldSha; + git_oid newOid; + std::string newSha; + + git_diff_list* rawDiffList; + + Persistent callback; + }; + + struct DeltaContent { + git_diff_range *range; + char lineOrigin; + size_t contentLength; + std::string content; + }; + + struct Delta { + git_diff_delta *raw; + std::vector contents; + }; + + struct WalkBaton { + uv_thread_t threadId; + uv_mutex_t mutex; + uv_async_t asyncFile; + uv_async_t asyncHunk; + uv_async_t asyncData; + uv_async_t asyncEnd; + + const git_error* error; + + std::map fileDeltas; + + git_diff_list* rawDiffList; + Persistent fileCallback; + Persistent hunkCallback; + Persistent lineCallback; + Persistent endCallback; + }; +}; diff --git a/include/error.h b/include/error.h index 0ca2bddd0..87c3e593a 100755 --- a/include/error.h +++ b/include/error.h @@ -10,6 +10,7 @@ #include "../vendor/libgit2/include/git2.h" +using namespace v8; using namespace node; /** @@ -22,28 +23,21 @@ class GitError : public ObjectWrap { * Variable: constructor_template * Used to create Node.js constructor. */ - static v8::Persistent constructor_template; + static Persistent constructor_template; /** * Function: Initialize * Used to intialize the EventEmitter from Node.js * * Parameters: - * target - v8::Object the Node.js global module object + * target - Object the Node.js global module object */ - static void Initialize(v8::Handle target); - /** - * Function: StrError - * Get a read-only buffer with the raw content of a blob. - * - * Parameters: - * err - A signed int error code - * - * Returns: - * a string explaining the error code. - */ - const char* StrError(int err); + static void Initialize(Handle target); + + static Local WrapError(const git_error* error); protected: + const git_error* error; + /** * Constructor: GitError */ @@ -52,26 +46,17 @@ class GitError : public ObjectWrap { * Deconstructor: GitError */ ~GitError() {}; + /** * Function: New * * Parameters: - * args v8::Arguments function call - * - * Returns: - * v8::Object args.This() - */ - static v8::Handle New(const v8::Arguments& args); - /** - * Function: StrError - * - * Parameters: - * args v8::Arguments function call + * args Arguments function call * * Returns: - * v8::Object args.This() + * Object args.This() */ - static v8::Handle StrError(const v8::Arguments& args); + static Handle New(const Arguments& args); }; - + #endif diff --git a/include/functions/string.h b/include/functions/string.h new file mode 100644 index 000000000..85c63027b --- /dev/null +++ b/include/functions/string.h @@ -0,0 +1,8 @@ +#include + +#ifndef STRING_FUNCTIONS +#define STRING_FUNCTIONS + +std::string stringArgToString(const v8::Local arg); + +#endif diff --git a/include/odb_backend.h b/include/odb_backend.h deleted file mode 100755 index 0615cda43..000000000 --- a/include/odb_backend.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2011, Tim Branyen @tbranyen - * Dual licensed under the MIT and GPL licenses. - */ - -#ifndef ODB_BACKEND_H -#define ODB_BACKEND_H - -#include - -#include "../vendor/libgit2/include/git2.h" - -using namespace node; - -/** - * Class: GitOdbBackend - * Wrapper for libgit2 git_error. - */ -class GitOdbBackend : public ObjectWrap { - public: - /** - * Variable: constructor_template - * Used to create Node.js constructor. - */ - static v8::Persistent constructor_template; - /** - * Function: Initialize - * Used to intialize the EventEmitter from Node.js - * - * Parameters: - * target - v8::Object the Node.js global module object - */ - static void Initialize(v8::Handle target); - - protected: - /** - * Constructor: GitOdbBackend - */ - GitOdbBackend() {}; - /** - * Deconstructor: GitOdbBackend - */ - ~GitOdbBackend() {}; - /** - * Function: New - * - * Parameters: - * args v8::Arguments function call - * - * Returns: - * v8::Object args.This() - */ - static v8::Handle New(const v8::Arguments& args); -}; - -#endif diff --git a/include/oid.h b/include/oid.h index da782eddb..cfab6db64 100755 --- a/include/oid.h +++ b/include/oid.h @@ -15,7 +15,9 @@ using namespace v8; class GitOid : public ObjectWrap { public: - static Persistent constructor_template; + + static Persistent constructor_template; + static void Initialize (Handle target); Handle WrapObj(Local obj); git_oid GetValue(); diff --git a/include/repo.h b/include/repo.h index 322f5b3b3..e5493b11d 100755 --- a/include/repo.h +++ b/include/repo.h @@ -18,63 +18,54 @@ using namespace v8; class GitRepo : public ObjectWrap { public: - static Persistent constructor_template; + static Persistent constructor_template; static void Initialize(Handle target); + git_repository* GetValue(); void SetValue(git_repository* repo); - // Asynchronous - int Open(const char* path); - int Init(const char* path, bool is_bare); + // Synchronous void Free(); - // TODO: Implement these methods - //int Open2(const char* path); - //int Open3(const char* path); - //int Lookup(Object **obj, Oid *id, Otype type); - //Odb Database(); - //int Index(Index **index); - //int NewObject(git_object **obj, Otype type); - protected: GitRepo() {} ~GitRepo() {} static Handle New(const Arguments& args); static Handle Open(const Arguments& args); - static void EIO_Open(uv_work_t* req); - static void EIO_AfterOpen(uv_work_t* req); - - static Handle Lookup(const Arguments& args); - static void EIO_Lookup(uv_work_t* req); - static void EIO_AfterLookup(uv_work_t* req); + static void OpenWork(uv_work_t* req); + static void OpenAfterWork(uv_work_t* req); static Handle Free(const Arguments& args); static Handle Init(const Arguments& args); - static void EIO_Init(uv_work_t* req); - static void EIO_AfterInit(uv_work_t* req); + static void InitWork(uv_work_t* req); + static void InitAfterWork(uv_work_t* req); private: git_repository* repo; - struct open_request { - GitRepo* repo; - int err; + struct OpenBaton { + uv_work_t request; + const git_error* error; + + git_repository* rawRepo; + GitRepo *repo; + std::string path; - Persistent callback; - }; - struct lookup_request { - GitRepo* repo; Persistent callback; }; - struct init_request { + struct InitBaton { + uv_work_t request; + const git_error* error; + GitRepo* repo; - int err; + git_repository* rawRepo; std::string path; - bool is_bare; + bool isBare; + Persistent callback; }; }; diff --git a/include/revwalk.h b/include/revwalk.h index 203e2cf53..09a0c0588 100755 --- a/include/revwalk.h +++ b/include/revwalk.h @@ -1,7 +1,6 @@ /* Copyright (c) 2011, Tim Branyen @tbranyen */ - #ifndef REVWALK_H #define REVWALK_H @@ -11,7 +10,6 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include "../vendor/libgit2/include/git2.h" #include "repo.h" -#include "commit.h" using namespace node; using namespace v8; @@ -27,7 +25,6 @@ class GitRevWalk : public ObjectWrap { void Reset(); int Push(git_oid* oid); int Hide(); - int Next(git_oid* oid); int Sorting(int sort); void Free(); git_repository* Repository(); @@ -37,12 +34,21 @@ class GitRevWalk : public ObjectWrap { ~GitRevWalk() {} static Handle New(const Arguments& args); static Handle Reset(const Arguments& args); + + /** + * Although git_revwalk_next is not blocking when iterating with a + * time-sorting mode, options may be added later to allow different sort + * modes, hence the async implementation. + */ static Handle Push(const Arguments& args); + static void PushWork(uv_work_t *req); + static void PushAfterWork(uv_work_t *req); + static Handle Hide(const Arguments& args); static Handle Next(const Arguments& args); - static void EIO_Next(uv_work_t* req); - static void EIO_AfterNext(uv_work_t* req); + static void NextWork(uv_work_t* req); + static void NextAfterWork(uv_work_t* req); static Handle Sorting(const Arguments& args); static Handle Free(const Arguments& args); @@ -52,10 +58,24 @@ class GitRevWalk : public ObjectWrap { git_revwalk* revwalk; git_repository* repo; - struct next_request { - GitRevWalk* revwalk; - GitOid* oid; - int err; + struct PushBaton { + uv_work_t request; + const git_error* error; + + git_revwalk *revwalk; + git_oid oid; + + Persistent callback; + }; + + struct NextBaton { + uv_work_t request; + const git_error* error; + bool walkOver; + + git_revwalk *revwalk; + git_oid oid; + Persistent callback; }; }; diff --git a/include/threads.h b/include/threads.h new file mode 100755 index 000000000..469911d8c --- /dev/null +++ b/include/threads.h @@ -0,0 +1,41 @@ +/* + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ + +#include +#include + +#include "../vendor/libgit2/include/git2.h" + +using namespace node; +using namespace v8; + +/** + * Class wrapper for libgit2 git_threads_* + */ +class GitThreads : public ObjectWrap { + public: + /** + * v8::FunctionTemplate used to create Node.js constructor + */ + static Persistent constructor_template; + + static void Initialize (Handle target); + + /** + * Calls git_threads_init synchronously. This is called one time + * on initialization, and is required for libgit2 to run correctly. + */ + static Handle Init(const Arguments& args); + + protected: + + GitThreads() {} + ~GitThreads() {} + + static Handle New(const Arguments& args); + +}; diff --git a/install.js b/install.js index 1207a4a43..2275fff38 100644 --- a/install.js +++ b/install.js @@ -2,9 +2,10 @@ var async = require('async'), child_process = require('child_process'), spawn = child_process.spawn, path = require('path'), - fs = require('fs'), request = require('request'), - AdmZip = require('adm-zip'); + zlib = require('zlib'), + fs = require('fs-extra'), + tar = require('tar'); function passthru() { var args = Array.prototype.slice.call(arguments); @@ -46,38 +47,23 @@ var updateSubmodules = function(mainCallback) { var checkoutDependencies = function(mainCallback) { console.log('[nodegit] Downloading libgit2 dependency.'); + var commit = 'e953c1606d0d7aea680c9b19db0b955b34ae63c2'; - var libgit2ZipUrl = 'https://github.com/libgit2/libgit2/archive/v0.15.0.zip'; - zipFile = __dirname + '/vendor/libgit2.zip', - unzippedFolderName = __dirname + '/vendor/libgit2-0.15.0', - targetFolderName = __dirname + '/vendor/libgit2'; - - async.series([ - function(callback) { - request(libgit2ZipUrl) - .pipe(fs.createWriteStream(zipFile)) - .on('close', function () { - callback(); - }); - - }, function(callback) { - var zip = new AdmZip(zipFile); - zip.extractAllTo(__dirname + '/vendor/', true); - fs.unlink(zipFile); - callback(); - }, - function renameLibgit2Folder(callback) { - fs.rename(unzippedFolderName, targetFolderName, callback); - } - ], function(error) { - if (error) process.exit(error); - mainCallback(); - }); + var url = 'https://github.com/libgit2/libgit2/tarball/'+ commit; + var path = __dirname + '/vendor/libgit2/'; + request({ + url: url + }).pipe(zlib.createUnzip()).pipe(tar.Extract({ + path: path, + strip: true + })).on('end', function() { + mainCallback(); + }); }; -var buildDir = path.join(__dirname, 'vendor/libgit2/build'); +var libgit2BuildDirectory = path.join(__dirname, 'vendor/libgit2/build'); async.series([ - function(callback) { + function prepareLibgit2Repository(callback) { // Check for presence of .git folder fs.exists(__dirname + '/.git', function(exists) { if (exists) { @@ -87,28 +73,37 @@ async.series([ } }); }, - function(callback) { + function deleteExistingLibgit2BuildFolder(callback) { + fs.exists(libgit2BuildDirectory, function(exists) { + if (exists) { + fs.remove(libgit2BuildDirectory, callback); + } else { + callback(); + } + }); + }, + function createLibgit2BuildDirectory(callback) { console.log('[nodegit] Building libgit2 dependency.'); - envpassthru('mkdir', '-p', buildDir, callback); + fs.mkdirs(libgit2BuildDirectory, callback); }, - function(callback) { + function configureLibgit2(callback) { envpassthru('cmake', '-DTHREADSAFE=1', '-DBUILD_CLAR=0', '..', { - cwd: buildDir + cwd: libgit2BuildDirectory }, callback); }, - function(callback) { + function buildLibgit2(callback) { envpassthru('cmake', '--build', '.', { - cwd: buildDir + cwd: libgit2BuildDirectory }, callback); }, - function(callback) { + function configureNodegit(callback) { console.log('[nodegit] Building native module.'); - // shpassthru('node-gyp configure --debug', callback); - shpassthru('node-gyp configure', callback); + // shpassthru('node-gyp configure --python python2 --debug', callback); + shpassthru('node-gyp configure --python python2', callback); }, - function(callback) { + function buildNodegit(callback) { shpassthru('node-gyp build', callback); } -], function(err) { - if(err) process.exit(err); +], function handleError(error) { + if(error) process.exit(error); }); diff --git a/lib/commit.js b/lib/commit.js index 4d7efeb32..5a75b5103 100644 --- a/lib/commit.js +++ b/lib/commit.js @@ -1,123 +1,121 @@ -var git = require( '../' ) - , events = require( 'events' ); - -var _Commit = function( obj ) { - var self = { _cache: {} }; - - if( obj instanceof git.raw.Commit ) { - self.commit = obj; +var git = require( '../' ), + events = require( 'events' ); + +/** + * Apply given details to the context. + * + * @param {Object} details + * @param {Object} context + * @return {Object} The modified context. + */ +function applyDetails(details, context) { + if (details) { + for (var detailKey in details) { + context[detailKey] = details[detailKey]; + } } - else { + return context; +} + +/** + * Convenience commit constructor. + * + * @param {RawCommit|Null} rawCommit + * @return {Commit} + */ +var _Commit = function(rawCommit) { + var self = {}; + + if(rawCommit && rawCommit instanceof git.raw.Commit) { + self.commit = rawCommit; + } else { self.commit = new git.raw.Commit(); } - Object.defineProperty( self, 'id', { - get: function() { - var oid = new git.raw.Oid(); - self.commit.id( oid ); - - return oid; - }, - enumerable: true - }); - - Object.defineProperty(self, 'sha', { - get: function() { - var oid = new git.raw.Oid(); - self.commit.id(oid); - - return oid.toString(40); - }, - enumerable: true - }); - - Object.defineProperty( self, 'msg', { - get: function() { - return self.commit.messageShort(); - }, - enumerable: true - }); - - Object.defineProperty( self, 'message', { - get: function() { - return self.commit.message(); - }, - enumerable: true - }); - - Object.defineProperty( self, 'time', { - get: function() { - return new Date( self.commit.time() * 1000 ); - }, - enumerable: true - }); - - Object.defineProperty( self, 'offset', { - get: function() { - return self.commit.timeOffset(); - }, - enumerable: true - }); - - Object.defineProperty(self, 'parentCount', { - get: function() { - return self.commit.parentCount(); - }, - enumerable: true - }); - - Object.defineProperty( self, 'author', { - get: function() { - var sig = new git.raw.Sig(); - - self.commit.author( sig ); - - return git.sig( sig ); - }, - enumerable: true - }); - - self.lookup = function( repo, oid, callback ) { - self.repo = repo; - self.commit.lookup( repo, oid, function() { - var args = Array.prototype.slice.call( arguments ); + /** + * Fetch the commit's details asynchronously. + * + * @param {Function} callback + */ + self.fetchDetails = function(callback) { + var error = null; + self.commit.fetchDetails(function(error, details) { + if (error) { + error = git.error(error); + } + applyDetails(details, self); + callback(error); + }); + }; - args[0] = git.util().error( args[0] ); + /** + * Fetch the commit's details synchronously. + */ + self.fetchDetailsSync = function(callback) { + var details = self.commit.fetchDetailsSync(); + return applyDetails(details, self); + }; - callback.apply( self, args.concat( self ) ); + /** + * Look up the commit referenced by oid, replace self.commit + * with the result. + * + * @param {Repo} repo + * @param {Oid|String} oid Raw OID object or SHA string + * @param {Function} callback + */ + self.lookup = function(repo, oid, callback) { + self.repo = repo; + self.commit.lookup(repo, oid, function(error, commit) { + if (error) { + callback(git.error(error), null); + return; + } + self.commit = commit; + self.fetchDetails(function(error) { + if (error) { + callback(git.error(error), null); + return; + } + callback(null, self); + }); }); }; self.tree = function() { - var tree = new git.raw.Tree( self.repo ); - if( tree.error ) { - return git.error( tree.error ); - } - else { - self.commit.tree( tree ); + var tree = new git.raw.Tree(self.repo); + if(tree.error) { + return git.error(tree.error); + } else { + self.commit.tree(tree); } - - return git.tree( self.repo, tree ); + return git.tree(self.repo, tree); }; - self.file = function( path ) { - return self.tree().entry( path ); + self.file = function(path) { + return self.tree().entry(path); }; - self.history = function(start, end) { + /** + * Walk the history of this commit. + * + * @return {Event} Event emits 'commit', with error, commit and 'end', with + * error, commits[] + */ + self.history = function() { var revwalk = git.revwalk(self.repo), event = new events.EventEmitter(), commits = []; - revwalk.walk(self.id, function(error, index, commit) { + revwalk.walk(self.id, function(error, index, commit, noMoreCommits) { if(error) { - if (error === git.error.GIT_EREVWALKOVER) { - event.emit('end', null, commits); - return; - } else { - event.emit('commit', new git.error(error), commit); - return; - } + event.emit('end', error, commits); + return false; + } + + if (noMoreCommits) { + event.emit('end', null, commits); + return; } event.emit('commit', null, commit); commits.push(commit); @@ -127,26 +125,61 @@ var _Commit = function( obj ) { }; /** - * Retrieve the commit's parent at the given position. - * - * @todo implement async + * Retrieve the commit's parent at the given position asynchronously. * * @param {Integer} position */ self.parent = function(position, callback) { - var parent = - self.commit.parent(position, function(errorCode, parent) { + var parent = null; + self.commit.parent(position, function processParent(errorCode, parent) { var error = null; - if (errorCode !== git.error.GIT_SUCCESS) { + if (errorCode) { error = git.error(errorCode); + return callback(error, null); } - callback(error, new _Commit(parent)); + var parentCommit = new _Commit(parent); + parentCommit.fetchDetails(function returnParent(error) { + callback(error, parentCommit); + }); }); - }; + /** + * Retrieve the commit's parent at the given positino synchronously. + * + * @param {Integer} position + * @return {Commit} + */ self.parentSync = function(position) { - return new _Commit(self.commit.parentSync(position)); + var parent = new _Commit(self.commit.parentSync(position)); + return parent.fetchDetailsSync(); + }; + + /** + * Get a diff tree showing changes between this commit and its parent(s). + * Assumes commit has been populated with fetchDetails|fetchDetailsSync + * + * @param {Function} callback Called with error (null if no error) and the + * diff tree + */ + self.parentsDiffTrees = function(callback) { + if (!self.parentCount) { + callback(null, {}); + return; + } + var parentDiffLists = []; + self.parentShas.forEach(function eachParentSha(parentSha) { + git.diffList(self.repo).treeToTree(parentSha, self.sha, function walkDiffList(error, diffList) { + if (error) { + callback(error, null); + return; + } + parentDiffLists.push(diffList); + if (parentDiffLists.length === self.parentShas.length) { + callback(null, parentDiffLists); + } + }); + }); }; return self; diff --git a/lib/diff_list.js b/lib/diff_list.js new file mode 100644 index 000000000..d9a615ce3 --- /dev/null +++ b/lib/diff_list.js @@ -0,0 +1,67 @@ +var git = require('../'), + events = require('events'); + +var GitDiffList = function(rawRepo, rawDiffList) { + var self = { + repo: rawRepo, + diffList: rawDiffList || new git.raw.DiffList() + }; + + self.walk = function() { + var event = new events.EventEmitter(), + allFileDeltas = []; + + process.nextTick(function() { + self.diffList.walk(function fileCallback(error, fileDeltas) { + if (error) { + event.emit('end', error, null); + } + fileDeltas.forEach(function(fileDelta) { + event.emit('file', null, fileDelta); + allFileDeltas.push(fileDelta); + }) + }, function hunkCallback(error, diffHunk) { + // @todo implement? + }, function lineCallback(error, diffLine) { + // @todo implement? + }, function endCallback(error) { + event.emit('end', error, allFileDeltas); + }); + }) + + return event; + }; + + self.treeToTree = function(oldSha, newSha, callback) { + self.diffList.treeToTree(self.repo, oldSha, newSha, function(error, rawDifflist) { + if (error) { + callback(error, null); + return; + } + self.diffList = rawDifflist; + callback(null, self); + }); + }; + + /** + * Add libgit2 delta types to git.diffList object. + * + * Refer to vendor/libgit2/include/git2/diff.h for definitions. + */ + for (var deltaType in git.raw.DiffList.deltaTypes) { + self[deltaType] = git.raw.DiffList.deltaTypes[deltaType]; + } + + /** + * Add libgit2 line origin types to git.diffList object. + * + * Refer to vendor/libgit2/include/git2/diff.h for definitions. + */ + for (var lineOriginType in git.raw.DiffList.lineOriginTypes) { + self[lineOriginType] = git.raw.DiffList.lineOriginTypes[lineOriginType]; + } + + return self; +}; + +exports.diffList = GitDiffList; diff --git a/lib/error.js b/lib/error.js index de7716670..3edd99493 100644 --- a/lib/error.js +++ b/lib/error.js @@ -2,28 +2,40 @@ var git = require('../'), util = require('util'); /** - * Initialise an Error object + * GitError constructor. * - * @param {mixed} obj A git.raw.Error object or a string describing the error. - * @return {Object} + * @param {String} message giterr_last->message + * @param {Integer} code giterr_last->klass */ -var GitError = function(object) { - var error = null; - var gitError = new git.raw.Error(); - if (typeof object === 'number') { - error = new Error(gitError.strError(object)); - error.code = object; - } - return error; +var GitError = function(message, code) { + Error.call(this); + Error.captureStackTrace(this, exports.error); + + this.name = 'GitError'; + this.message = message; + this.code = code; }; +util.inherits(GitError, Error); + /** * Add libgit2 error codes to git.error object. * * Refer to vendor/libgit2/include/git2/errors.h for error code definitions. */ for (var errorName in git.raw.Error.codes) { - GitError[errorName] = git.raw.Error.codes[errorName]; + GitError.prototype[errorName] = git.raw.Error.codes[errorName]; +} + +/** + * Add libgit2 return codes to git.error object. + * + * Refer to vendor/libgit2/include/git2/errors.h for return code definitions. + */ +for (var errorName in git.raw.Error.returnCodes) { + GitError.prototype[errorName] = git.raw.Error.returnCodes[errorName]; } -exports.error = GitError; +exports.error = function(error) { + return new GitError(error.message, error.code); +}; diff --git a/lib/index.js b/lib/index.js index 3d687095f..37c6e39c0 100755 --- a/lib/index.js +++ b/lib/index.js @@ -2,7 +2,7 @@ var os = require("os"); // Required for Windows/Cygwin support -var root = [ __dirname, "/../vendor/libgit2/build/shared" ].join(""), +var root = [__dirname, "/../vendor/libgit2/build/shared"].join(""), path = process.env.PATH; if (~os.type().indexOf("CYGWIN") && !~path.indexOf(root)) { @@ -10,7 +10,6 @@ if (~os.type().indexOf("CYGWIN") && !~path.indexOf(root)) { } // Import libraries -exports.util = require("./util.js").util; exports.blob = require("./blob.js").blob; exports.repo = require("./repo.js").repo; exports.sig = require("./sig.js").sig; @@ -29,8 +28,12 @@ try { exports.raw = require('../build/Release/nodegit'); } -// Initialize error object after so it may access raw.Error +// Initialize objects that need to access their raw counterparts +exports.diffList = require("./diff_list.js").diffList; exports.error = require("./error.js").error; // Set version -exports.version = "0.0.7"; +exports.version = require('../package').version; + +// Initialize threads +(new exports.raw.Threads()).init(); diff --git a/lib/oid.js b/lib/oid.js index dedc686c4..cda090b15 100644 --- a/lib/oid.js +++ b/lib/oid.js @@ -1,19 +1,17 @@ var git = require( '../' ); -var _Oid = function( obj ) { +var _Oid = function(obj) { var self = {}; - if( obj instanceof git.raw.Oid ) { + if(obj instanceof git.raw.Oid) { self.oid = obj; - } - else { + } else { self.oid = new git.raw.Oid(); - if( typeof obj === 'string' ) { - self.oid.mkstr( obj ); + if (typeof obj === 'string') { + self.oid.mkstr(obj); } } - return self; }; diff --git a/lib/ref.js b/lib/ref.js index 84d786a0e..5c244cece 100644 --- a/lib/ref.js +++ b/lib/ref.js @@ -1,32 +1,32 @@ -var git = require( '../' ); +var git = require('../'); -var _Ref = function( obj ) { +var _Ref = function(obj) { var self = {}; - if( obj instanceof git.raw.Repo ) { + if(obj instanceof git.raw.Repo) { self.repo = obj; - self.ref = new git.raw.Ref( obj ); - } - else if( obj instanceof git.raw.Ref ) { + self.ref = new git.raw.Ref(obj); + } else if(obj instanceof git.raw.Ref) { self.ref = obj; } - self.lookup = function( name, callback ) { - if( !callback ) { return; } - - self.ref.lookup( self.repo, name, function() { - var args = Array.prototype.slice.call( arguments ); - args[0] = git.util().error( args[0] ); - - callback.apply( self, args.concat( self ) ); + self.lookup = function(name, callback) { + if(!callback || typeof callback !== 'function') { + throw new Error('Callback is required and must be a function'); + } + + self.ref.lookup(self.repo, name, function(error) { + if (error) { + callback(git.error(error), self); + return; + } + callback(null, self); }); }; self.oid = function() { var oid = git.oid(); - - self.ref.oid( oid.oid ); - + self.ref.oid(oid.oid); return oid; }; diff --git a/lib/repo.js b/lib/repo.js index 4e05f3276..2420ba45b 100644 --- a/lib/repo.js +++ b/lib/repo.js @@ -1,71 +1,86 @@ -var git = require("../"); +var git = require('../'), + fs = require('fs'); /* Module: Repo * Work with a repository. */ -exports.repo = function(dir, async) { +exports.repo = function(directory, callback) { var self = { // Assign a new repo object repo: new git.raw.Repo() }; - if (dir && async) { - self.repo.open(dir, function() { - git.util().asyncComplete.call(self, arguments, async); + if (directory) { + if (!callback || typeof callback !== 'function') { + throw new Error('If directory is provided, callback function is required'); + } + fs.exists(directory, function directoryExists(exists) { + if (!exists) { + callback(new Error('Directory must exist'), null); + return; + } + fs.realpath(directory, function realpathCallback(error, directory) { + if (error) { + callback(git.error(error), null); + return; + } + self.repo.open(directory, function(error, rawRepo) { + if (error) { + callback(git.error(error), null); + return; + } + self.repo = rawRepo; + callback(null, self); + }); + }); }); } - else if (dir) { - // TODO: Make this eventually - // this.repo.openSync(path.resolve(dir) - //this.repo.open(path.resolve(dir) - self.repo.open(dir); - } - // Look up a branch and find its tree - self.branch = function(name, async) { - if (!async) { - // TODO: Implement Sync API - return; - } - - git.ref(self.repo).lookup("refs/heads/" + name, function(err, ref) { - if (err) { - return git.util().asyncComplete.call(this, arguments, async); + /** + * Look up a branch and find its tree. + * + * @param {String} name Branch name, e.g. 'master' + * @param {Function} + */ + self.branch = function(name, callback) { + git.ref(self.repo).lookup('refs/heads/' + name, function(error, ref) { + if (error) { + callback(git.error(error), null); + return; } - git.commit(self.repo).lookup(self.repo, ref.oid().oid, function() { - git.util().asyncComplete.call(this, arguments, async); + git.commit(self.repo).lookup(self.repo, ref.oid().oid, function(error, commit) { + if (error) { + callback(git.error(error), null); + return; + } + callback(null, commit); }); }); }; // Find a single commit - self.commit = function(sha, async) { - if (!async) { - // TODO: Implement Sync API - return; - } - - git.commit().lookup(self.repo, git.oid(sha).oid, async); + self.commit = function(sha, callback) { + git.commit().lookup(self.repo, sha, function(error, commit) { + callback(error, commit); + }); }; - self.init = function(dir, isBare, async) { - if (!async) { - // TODO: Implement Sync API - return; - } + self.commitSync = function(sha) { + throw new Error('commitSync not yet implemented'); + // return git.commit().lookupSync(sha); + }; - self.repo.init(dir, isBare, function() { - git.util().asyncComplete.call(this, arguments, async); + self.init = function(directory, isBare, callback) { + self.repo.init(directory, isBare, function(error) { + callback.call(this, error, self); }); - - return self; }; - self.free = function() { + self.free = function() { self.repo.free(); delete self.repo; }; - + return self; }; diff --git a/lib/revwalk.js b/lib/revwalk.js index f5ef4de1d..9659828d7 100644 --- a/lib/revwalk.js +++ b/lib/revwalk.js @@ -3,43 +3,67 @@ var git = require( '../' ); var _RevWalk = function( obj ) { var self = {}; - if( obj instanceof git.raw.Repo ) { + if (obj instanceof git.raw.Repo) { self.repo = obj; - self.revwalk = new git.raw.RevWalk( obj ); - } - else if( obj instanceof git.raw.RevWalk ) { + self.revwalk = new git.raw.RevWalk(obj); + } else if (obj instanceof git.raw.RevWalk) { self.revwalk = obj; } - // Walk will map to the next method - self.walk = function( oid, callback ) { - if( !callback ) { return; } - - self.revwalk.push( oid ); + /** + * Walk the history from the given oid. + * + * @param {Oid} oid + * @param {Function} callback Callback accepting the following arguments: + * error, index, commit, noMoreCommits + */ + self.walk = function(oid, callback) { + if(!callback) { return; } - var cont = true, i = 0; + self.revwalk.push(oid, function(error) { + if (error) { + callback.apply(this, [git.error(error)]); + return; + } - function walk() { - if( !cont ) { return; } - var _tmp = git.oid(); + var shouldContinue = true, index = 0; - self.revwalk.next( _tmp.oid, function( err ) { - if( err ) { callback.apply( this, [ err ] ); return; } + function walk() { + if(!shouldContinue) { + return; + } - git.commit( self.repo ).lookup( self.repo, _tmp.oid, function( err ) { - if( err ) { callback.apply( this, [ err, i, this ] ); } + self.revwalk.next(function(error, oid, walkOver) { + if(error) { + callback.apply(this, [git.error(error), index, commit]); + return; + } - if( callback.apply( this, [ err, i, this ] ) === false ) { - cont = false; + // Finished walking history, apply callback with noMoreCommits = true + if (walkOver) { + callback.apply(this, [null, index, null, walkOver]); + return; } - i = i + 1; - walk(); + git.commit(self.repo).lookup(self.repo, oid, function(error, commit) { + + if(error) { + callback.apply(this, [git.error(error), index, commit]); + return; + } + + if(callback.apply(this, [null, index, commit]) === false) { + shouldContinue = false; + } + + index++; + walk(); + }); }); - }); - } + } - walk(); + walk(); + }); }; return self; diff --git a/lib/threads.js b/lib/threads.js new file mode 100644 index 000000000..ae9f31efe --- /dev/null +++ b/lib/threads.js @@ -0,0 +1,36 @@ +var git = require('../'); + +var _Blob = function(obj) { + var self = {}; + + if( obj instanceof git.raw.Repo ) { + self.repo = obj; + self.blob = new git.raw.Blob( obj ); + } + else if( obj instanceof git.raw.Blob ) { + self.blob = obj; + } + + Object.defineProperty( self, 'raw', { + get: function() { + return self.blob.rawContent().toString(); + }, + enumerable: true + }); + + self.lookup = function( oid ) { + self.blob.lookup( self.repo, oid, function() { + var args = Array.prototype.slice.call( arguments ); + args[0] = git.util().error( args[0] ); + + callback.apply( self, args.concat( self ) ); + }); + }; + + return self; +}; + +exports.blob = _Blob; + + +exports = _Threads; diff --git a/lib/tree.js b/lib/tree.js index e51d3de41..2b7f5b96d 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -1,20 +1,19 @@ -var git = require( '../' ) - , events = require( 'events' ); +var git = require('../'), + events = require('events'); -var _Tree = function( obj, tree ) { +var _Tree = function(rawObject, tree) { var self = {}; - if ( obj instanceof git.raw.Repo && tree instanceof git.raw.Tree ) { - self.repo = obj; + + if (rawObject instanceof git.raw.Repo && + tree instanceof git.raw.Tree) { + self.repo = rawObject; self.tree = tree; - } - else if( obj instanceof git.raw.Repo ) { - self.repo = obj; - self.tree = new git.raw.Tree( tree ); - } - else if ( obj instanceof git.raw.Tree ) { - self.tree = obj; - } - else { + } else if(rawObject instanceof git.raw.Repo) { + self.repo = rawObject; + self.tree = new git.raw.Tree(tree); + } else if (rawObject instanceof git.raw.Tree) { + self.tree = rawObject; + } else { self.tree = new git.raw.Tree(); } @@ -91,24 +90,26 @@ var _Tree = function( obj, tree ) { return event; }; - self.entry = function( name, callback ) { - if( !callback ) { return; } + self.entry = function(name, callback) { + if(!callback) { + return; + } - var entry = git.entry( self.repo ); + var entry = git.entry(self.repo); - var path = name.split( '/' ); - if( path.length === 1 ) { - self.tree.entryByName( entry.entry, path[0], function( valid ) { - callback( valid ? entry : undefined ); + var path = name.split('/'); + if(path.length === 1) { + self.tree.entryByName(entry.entry, path[0], function(valid) { + callback(valid ? entry : undefined); }); } else { - function recurse( tree ) { + var recurse = function(tree) { var name = path.shift(); - var tree = tree || self.tree; + tree = tree || self.tree; - tree.entryByName( entry.entry, name, function( valid ) { - if( !path.length ) { + tree.entryByName(entry.entry, name, function(valid) { + if(!path.length) { callback( valid ? entry : undefined ); } else { @@ -120,7 +121,7 @@ var _Tree = function( obj, tree ) { } } }); - } + }; recurse(); } diff --git a/lib/tree_entry.js b/lib/tree_entry.js index f9c9a8e0a..5b954047c 100644 --- a/lib/tree_entry.js +++ b/lib/tree_entry.js @@ -1,14 +1,13 @@ var git = require( '../' ); -var _TreeEntry = function( obj ) { +var _TreeEntry = function(rawObject) { var self = {}; - if( obj instanceof git.raw.TreeEntry ) { - self.entry = obj; - } - else { + if(rawObject instanceof git.raw.TreeEntry) { + self.entry = rawObject; + } else { self.entry = new git.raw.TreeEntry(); - self.repo = obj; + self.repo = rawObject; } self.dir = ''; @@ -47,7 +46,6 @@ var _TreeEntry = function( obj ) { Object.defineProperty( self, 'sha', { get: function() { var oid = self.id; - //console.log(self.id); return oid.oid.toString( 40 ); }, diff --git a/lib/util.js b/lib/util.js deleted file mode 100644 index 256d91c94..000000000 --- a/lib/util.js +++ /dev/null @@ -1,24 +0,0 @@ -var git = require( '../' ); - -var _Util = function( error ) { - var self = {}; - - self.error = function error( err ) { - if(err !== 0) { - return git.error( err ); - } - - return 0; - }; - - self.asyncComplete = function(args, callback) { - args = Array.prototype.slice.call(args); - args[0] = git.util().error(args[0]); - - callback.apply(this, args.concat(this)); - }; - - return self; -}; - -exports.util = _Util; diff --git a/package.json b/package.json index b15fe3957..a3e7c9f5f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.0.72", + "version": "0.0.73", "homepage": "https://github.com/tbranyen/nodegit", "keywords": [ "libgit2", @@ -31,12 +31,13 @@ }, "dependencies": { "async": ">= 0.1.21", - "adm-zip": "0.2.x", "request": "2.9.x", - "node-gyp": "~0.8.2" + "node-gyp": "~0.8.2", + "tar": "0.1.17", + "fs-extra": "0.6.0" }, "devDependencies": { - "nodeunit": "0.7.x", + "nodeunit": "", "rimraf": "1.0.x" }, "scripts": { diff --git a/src/base.cc b/src/base.cc index a74f08273..5a73900a2 100755 --- a/src/base.cc +++ b/src/base.cc @@ -18,19 +18,30 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include "../include/revwalk.h" #include "../include/tree.h" #include "../include/tree_entry.h" +#include "../include/diff_list.h" +#include "../include/threads.h" extern "C" void init(Handle target) { HandleScope scope; + GitError::Initialize(target); + GitReference::Initialize(target); GitSig::Initialize(target); - GitError::Initialize(target); GitBlob::Initialize(target); GitOid::Initialize(target); GitObject::Initialize(target); GitRepo::Initialize(target); GitCommit::Initialize(target); GitRevWalk::Initialize(target); + GitTree::Initialize(target); GitTreeEntry::Initialize(target); + + GitDiffList::Initialize(target); + + GitThreads::Initialize(target); + } + +NODE_MODULE(nodegit, init) diff --git a/src/blob.cc b/src/blob.cc index ff56275b5..ef2b9b7ac 100755 --- a/src/blob.cc +++ b/src/blob.cc @@ -57,11 +57,11 @@ int GitBlob::RawSize() { } void GitBlob::Close() { - git_blob_close(this->blob); + git_blob_free(this->blob); } int CreateFromFile(git_oid* oid, git_repository* repo, const char* path) { - return git_blob_create_fromfile(oid, repo, path); + return git_blob_create_fromdisk(oid, repo, path); } int CreateFromBuffer(git_oid* oid, git_repository* repo, const void* buffer, size_t len) { @@ -105,7 +105,7 @@ Handle GitBlob::Lookup(const Arguments& args) { uv_work_t *req = new uv_work_t; req->data = ar; - uv_queue_work(uv_default_loop(), req, EIO_Lookup, EIO_AfterLookup); + uv_queue_work(uv_default_loop(), req, EIO_Lookup, (uv_after_work_cb)EIO_AfterLookup); return scope.Close( Undefined() ); } diff --git a/src/commit.cc b/src/commit.cc index a91773de1..2d0f32142 100755 --- a/src/commit.cc +++ b/src/commit.cc @@ -1,5 +1,7 @@ /* * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * * Dual licensed under the MIT and GPL licenses. */ @@ -16,8 +18,12 @@ #include "../include/oid.h" #include "../include/tree.h" #include "../include/commit.h" +#include "../include/error.h" + +#include "../include/functions/string.h" using namespace v8; +using namespace cvv8; using namespace node; void GitCommit::Initialize(Handle target) { @@ -30,16 +36,12 @@ void GitCommit::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(tpl, "lookup", Lookup); NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close); - NODE_SET_PROTOTYPE_METHOD(tpl, "id", Id); - NODE_SET_PROTOTYPE_METHOD(tpl, "messageShort", MessageShort); - NODE_SET_PROTOTYPE_METHOD(tpl, "message", Message); - NODE_SET_PROTOTYPE_METHOD(tpl, "time", Time); - NODE_SET_PROTOTYPE_METHOD(tpl, "timeOffset", TimeOffset); - NODE_SET_PROTOTYPE_METHOD(tpl, "author", Author); + NODE_SET_PROTOTYPE_METHOD(tpl, "tree", Tree); - NODE_SET_PROTOTYPE_METHOD(tpl, "parentCount", ParentCount); NODE_SET_PROTOTYPE_METHOD(tpl, "parent", Parent); NODE_SET_PROTOTYPE_METHOD(tpl, "parentSync", ParentSync); + NODE_SET_PROTOTYPE_METHOD(tpl, "fetchDetails", FetchDetails); + NODE_SET_PROTOTYPE_METHOD(tpl, "fetchDetailsSync", FetchDetailsSync); constructor_template = Persistent::New(tpl->GetFunction()); target->Set(String::NewSymbol("Commit"), constructor_template); @@ -53,58 +55,15 @@ void GitCommit::SetValue(git_commit* commit) { this->commit = commit; } -int GitCommit::Lookup(git_repository* repo, git_oid* oid) { - int err = git_commit_lookup(&this->commit, repo, oid); - - return err; -} - void GitCommit::Close() { - git_commit_close(this->commit); + git_commit_free(this->commit); this->commit = NULL; } -const git_oid* GitCommit::Id() { - return git_commit_id(this->commit); -} - -const char* GitCommit::MessageShort() { - return ""; - //return git_commit_message_short(this->commit); -} - -const char* GitCommit::Message() { - return git_commit_message(this->commit); -} - -time_t GitCommit::Time() { - return git_commit_time(this->commit); -} - -int GitCommit::TimeOffset() { - return git_commit_time_offset(this->commit); -} - -const git_signature* GitCommit::Committer() { - return git_commit_author(this->commit); -} - -const git_signature* GitCommit::Author() { - return git_commit_author(this->commit); -} - int GitCommit::Tree(git_tree** tree) { return git_commit_tree(tree, this->commit); } -unsigned int GitCommit::ParentCount() { - return git_commit_parentcount(this->commit); -} - -int GitCommit::Parent(git_commit** commit, int pos) { - return git_commit_parent(commit, this->commit, pos); -} - Handle GitCommit::New(const Arguments& args) { HandleScope scope; @@ -115,169 +74,285 @@ Handle GitCommit::New(const Arguments& args) { return scope.Close(args.This()); } -Handle GitCommit::NewInstance() { +Handle GitCommit::FetchDetailsSync(const Arguments& args) { HandleScope scope; - Local instance = constructor_template->NewInstance(); + GitCommit *commit = ObjectWrap::Unwrap(args.This()); + + Local details = Object::New(); + + Handle oid = GitOid::constructor_template->NewInstance(); + + char sha[GIT_OID_HEXSZ + 1]; + sha[GIT_OID_HEXSZ] = '\0'; + GitOid *oidInstance = ObjectWrap::Unwrap(oid); + const git_oid* rawOid = git_commit_id(commit->commit); + oidInstance->SetValue(*const_cast(rawOid)); + git_oid_fmt(sha, rawOid); + + details->Set(String::NewSymbol("id"), oid); + details->Set(String::NewSymbol("sha"), String::New(sha)); + details->Set(String::NewSymbol("message"), cvv8::CastToJS(git_commit_message(commit->commit))); + details->Set(String::NewSymbol("time"), cvv8::CastToJS(git_commit_time(commit->commit))); + details->Set(String::NewSymbol("timeOffset"), cvv8::CastToJS(git_commit_time_offset(commit->commit))); + + const git_signature *rawCommitter = git_commit_committer(commit->commit); + Local committer = Object::New(); + committer->Set(String::NewSymbol("name"), cvv8::CastToJS(rawCommitter->name)); + committer->Set(String::NewSymbol("email"), cvv8::CastToJS(rawCommitter->email)); + + Local committerWhen = Object::New(); + committerWhen->Set(String::NewSymbol("when"), cvv8::CastToJS(rawCommitter->when.time)); + committerWhen->Set(String::NewSymbol("offset"), cvv8::CastToJS(rawCommitter->when.offset)); + committer->Set(String::NewSymbol("when"), cvv8::CastToJS(committerWhen)); + + details->Set(String::NewSymbol("committer"), committer); + + const git_signature* rawAuthor = git_commit_author(commit->commit); + Local author = Object::New(); + author->Set(String::NewSymbol("name"), cvv8::CastToJS(rawAuthor->name)); + author->Set(String::NewSymbol("email"), cvv8::CastToJS(rawAuthor->email)); + + Local authorWhen = Object::New(); + authorWhen->Set(String::NewSymbol("when"), cvv8::CastToJS(rawAuthor->when.time)); + authorWhen->Set(String::NewSymbol("offset"), cvv8::CastToJS(rawAuthor->when.offset)); + author->Set(String::NewSymbol("when"), authorWhen); + + details->Set(String::NewSymbol("author"), author); + + int parentCount = git_commit_parentcount(commit->commit); + std::vector parentShas; + while (parentCount > 0) { + int parentIndex = parentCount -1; + char sha[GIT_OID_HEXSZ + 1]; + sha[GIT_OID_HEXSZ] = '\0'; + const git_oid *parentOid = git_commit_parent_id(commit->commit, parentIndex); + git_oid_fmt(sha, parentOid); + parentShas.push_back(sha); + parentCount--; + } + + details->Set(String::NewSymbol("parentCount"), cvv8::CastToJS(parentCount)); + details->Set(String::NewSymbol("parentShas"), cvv8::CastToJS(parentShas)); - return scope.Close(instance); + return scope.Close(details); } -Handle GitCommit::Lookup(const Arguments& args) { +Handle GitCommit::FetchDetails(const Arguments& args) { HandleScope scope; - GitCommit *commit = ObjectWrap::Unwrap(args.This()); - Local callback; - - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); + if(args.Length() == 0 || !args[0]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } - if(args.Length() == 1 || !args[1]->IsObject()) { - return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); - } + FetchDetailsBaton* baton = new FetchDetailsBaton(); + baton->request.data = baton; + baton->rawCommit = ObjectWrap::Unwrap(args.This())->commit; + baton->callback = Persistent::New(Local::Cast(args[0])); - if(args.Length() == 2 || !args[2]->IsFunction()) { - return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); - } + uv_queue_work(uv_default_loop(), &baton->request, FetchDetailsWork, (uv_after_work_cb)FetchDetailsAfterWork); - callback = Local::Cast(args[2]); + return Undefined(); +} - lookup_request *ar = new lookup_request(); - ar->commit = commit; - ar->repo = ObjectWrap::Unwrap(args[0]->ToObject()); - ar->oid = ObjectWrap::Unwrap(args[1]->ToObject()); - ar->callback = Persistent::New(callback); +void GitCommit::FetchDetailsWork(uv_work_t *req) { + FetchDetailsBaton* baton = static_cast(req->data); - commit->Ref(); + baton->oid = git_commit_id(baton->rawCommit); - uv_work_t *req = new uv_work_t; - req->data = ar; - uv_queue_work(uv_default_loop(), req, LookupWork, LookupAfterWork); + baton->sha[GIT_OID_HEXSZ] = '\0'; - return scope.Close( Undefined() ); -} + git_oid_fmt(baton->sha, baton->oid); -void GitCommit::LookupWork(uv_work_t *req) { - lookup_request *ar = static_cast(req->data); + baton->message = git_commit_message(baton->rawCommit); + baton->time = git_commit_time(baton->rawCommit); + baton->timeOffset = git_commit_time_offset(baton->rawCommit); + baton->committer = git_commit_committer(baton->rawCommit); + baton->author = git_commit_author(baton->rawCommit); + baton->parentCount = git_commit_parentcount(baton->rawCommit); - git_oid oid = ar->oid->GetValue(); - ar->err = ar->commit->Lookup(ar->repo->GetValue(), &oid); + int parentCount = baton->parentCount; + while (parentCount > 0) { + int parentIndex = parentCount -1; + char sha[GIT_OID_HEXSZ + 1]; + sha[GIT_OID_HEXSZ] = '\0'; + const git_oid *parentOid = git_commit_parent_id(baton->rawCommit, parentIndex); + git_oid_fmt(sha, parentOid); + baton->parentShas.push_back(sha); + parentCount--; + } } -void GitCommit::LookupAfterWork(uv_work_t *req) { +void GitCommit::FetchDetailsAfterWork(uv_work_t *req) { HandleScope scope; - lookup_request *ar = static_cast(req->data); - delete req; + FetchDetailsBaton* baton = static_cast(req->data); - ar->commit->Unref(); + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; - Handle argv[1]; - argv[0] = Integer::New(ar->err); + TryCatch try_catch; - TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); - ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { - if(try_catch.HasCaught()) { - FatalException(try_catch); - } + Local details = Object::New(); - ar->callback.Dispose(); + Handle oid = GitOid::constructor_template->NewInstance(); + GitOid *oidInstance = ObjectWrap::Unwrap(oid); + oidInstance->SetValue(*const_cast(baton->oid)); - delete ar; -} + details->Set(String::NewSymbol("id"), oid); + details->Set(String::NewSymbol("sha"), String::New(baton->sha)); + details->Set(String::NewSymbol("message"), cvv8::CastToJS(baton->message)); + details->Set(String::NewSymbol("time"), cvv8::CastToJS(baton->time)); + details->Set(String::NewSymbol("timeOffset"), cvv8::CastToJS(baton->timeOffset)); -Handle GitCommit::Close(const Arguments& args) { - HandleScope scope; + Local committer = Object::New(); + committer->Set(String::NewSymbol("name"), cvv8::CastToJS(baton->committer->name)); + committer->Set(String::NewSymbol("email"), cvv8::CastToJS(baton->committer->email)); - GitCommit *commit = ObjectWrap::Unwrap(args.This()); - commit->Close(); + Local committerWhen = Object::New(); + committerWhen->Set(String::NewSymbol("time"), cvv8::CastToJS(baton->committer->when.time)); + committerWhen->Set(String::NewSymbol("offset"), cvv8::CastToJS(baton->committer->when.offset)); + committer->Set(String::NewSymbol("when"), cvv8::CastToJS(committerWhen)); - return scope.Close(Undefined()); -} + details->Set(String::NewSymbol("committer"), committer); -Handle GitCommit::Id(const Arguments& args) { - HandleScope scope; + Local author = Object::New(); + author->Set(String::NewSymbol("name"), cvv8::CastToJS(baton->author->name)); + author->Set(String::NewSymbol("email"), cvv8::CastToJS(baton->author->email)); - GitCommit *commit = ObjectWrap::Unwrap(args.This()); + Local authorWhen = Object::New(); + authorWhen->Set(String::NewSymbol("time"), cvv8::CastToJS(baton->author->when.time)); + authorWhen->Set(String::NewSymbol("offset"), cvv8::CastToJS(baton->author->when.offset)); + author->Set(String::NewSymbol("when"), authorWhen); - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); - } + details->Set(String::NewSymbol("author"), author); - GitOid *oid = ObjectWrap::Unwrap(args[0]->ToObject()); + details->Set(String::NewSymbol("parentCount"), cvv8::CastToJS(baton->parentCount)); + details->Set(String::NewSymbol("parentShas"), cvv8::CastToJS(baton->parentShas)); - oid->SetValue(*const_cast(commit->Id())); + Handle argv[2] = { + Local::New(Null()), + details + }; - return scope.Close(Undefined()); + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + delete req; } -Handle GitCommit::MessageShort(const Arguments& args) { +Handle GitCommit::Lookup(const Arguments& args) { HandleScope scope; - GitCommit *commit = ObjectWrap::Unwrap(args.This()); + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); + } - return scope.Close( String::New(commit->MessageShort()) ); -} + if(args.Length() == 1 || !(args[1]->IsObject() || args[1]->IsString())) { + return ThrowException(Exception::Error(String::New("Oid is required and must be an Object or String"))); + } -Handle GitCommit::Message(const Arguments& args) { - HandleScope scope; + if(args.Length() == 2 || !args[2]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); + } - GitCommit *commit = ObjectWrap::Unwrap(args.This()); + LookupBaton *baton = new LookupBaton(); + baton->request.data = baton; + baton->error = NULL; + baton->repo = ObjectWrap::Unwrap(args[0]->ToObject())->GetValue(); - return scope.Close(String::New(commit->Message())); -} + if (args[1]->IsObject()) { + baton->oid = ObjectWrap::Unwrap(args[1]->ToObject())->GetValue(); + } else { + baton->sha = stringArgToString(args[1]->ToString()); + } -Handle GitCommit::Time(const Arguments& args) { - HandleScope scope; + baton->callback = Persistent::New(Local::Cast(args[2])); - GitCommit *commit = ObjectWrap::Unwrap(args.This()); + uv_queue_work(uv_default_loop(), &baton->request, LookupWork, (uv_after_work_cb)LookupAfterWork); - return scope.Close( Integer::New(commit->Time()) ); + return Undefined(); } -Handle GitCommit::TimeOffset(const Arguments& args) { - HandleScope scope; - - GitCommit *commit = ObjectWrap::Unwrap(args.This()); +void GitCommit::LookupWork(uv_work_t *req) { + LookupBaton *baton = static_cast(req->data); + + git_oid oid = baton->oid; + if (!baton->sha.empty()) { + int returnCode = git_oid_fromstr(&oid, baton->sha.c_str()); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + } - return scope.Close( Integer::New(commit->TimeOffset()) ); + baton->rawCommit = NULL; + int returnCode = git_commit_lookup(&baton->rawCommit, baton->repo, &oid); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + } } -Handle GitCommit::Committer(const Arguments& args) { +void GitCommit::LookupAfterWork(uv_work_t *req) { HandleScope scope; + LookupBaton *baton = static_cast(req->data); - GitCommit *commit = ObjectWrap::Unwrap(args.This()); - - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Signature is required and must be an Object."))); - } + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; - GitSig *sig = ObjectWrap::Unwrap(args[0]->ToObject()); + TryCatch try_catch; - sig->SetValue(const_cast(commit->Committer())); + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); - return scope.Close( Undefined() ); -} + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { -Handle GitCommit::Author(const Arguments& args) { - HandleScope scope; + Local commit = GitCommit::constructor_template->NewInstance(); + GitCommit *commitInstance = ObjectWrap::Unwrap(commit); + commitInstance->SetValue(baton->rawCommit); - GitCommit *commit = ObjectWrap::Unwrap(args.This()); + Handle argv[2] = { + Local::New(Null()), + commit + }; - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Signature is required and must be an Object."))); + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } } + delete req; +} - GitSig *sig = ObjectWrap::Unwrap(args[0]->ToObject()); +Handle GitCommit::Close(const Arguments& args) { + HandleScope scope; - sig->SetValue(const_cast(commit->Author())); + GitCommit *commit = ObjectWrap::Unwrap(args.This()); + commit->Close(); - return scope.Close( Undefined() ); + return scope.Close(Undefined()); } +/** + * @todo asynchronize + */ Handle GitCommit::Tree(const Arguments& args) { HandleScope scope; @@ -296,16 +371,6 @@ Handle GitCommit::Tree(const Arguments& args) { return scope.Close( Integer::New(err) ); } -Handle GitCommit::ParentCount(const Arguments& args) { - HandleScope scope; - - GitCommit *commit = ObjectWrap::Unwrap(args.This()); - - unsigned int count = commit->ParentCount(); - - return scope.Close( Integer::New(count) ); -} - Handle GitCommit::ParentSync(const Arguments& args) { HandleScope scope; @@ -316,10 +381,10 @@ Handle GitCommit::ParentSync(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); git_commit *parentCommitValue ; - int errorCode = git_commit_parent(&parentCommitValue, commit->commit, args[0]->ToInteger()->Value()); + int returnCode = git_commit_parent(&parentCommitValue, commit->commit, args[0]->ToInteger()->Value()); - if (errorCode) { - return ThrowException(Exception::Error(String::New(git_lasterror()))); + if (returnCode != GIT_OK) { + return ThrowException(Exception::Error(String::New(giterr_last()->message))); } Local parent = GitCommit::constructor_template->NewInstance(); @@ -344,40 +409,37 @@ Handle GitCommit::Parent(const Arguments& args) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } - Local callback = Local::Cast(args[1]); - ParentBaton* baton = new ParentBaton(); baton->request.data = baton; - baton->commit = ObjectWrap::Unwrap(args.This()); + baton->commit = ObjectWrap::Unwrap(args.This()); baton->commit->Ref(); + baton->error = NULL; baton->index = args[0]->ToInteger()->Value(); - baton->callback = Persistent::New(callback); + baton->callback = Persistent::New(Local::Cast(args[1])); - uv_queue_work(uv_default_loop(), &baton->request, ParentWork, ParentAfterWork); + uv_queue_work(uv_default_loop(), &baton->request, ParentWork, (uv_after_work_cb)ParentAfterWork); - return Undefined(); + return Undefined(); } void GitCommit::ParentWork(uv_work_t* req) { ParentBaton* baton = static_cast(req->data); baton->rawParentCommit = NULL; - baton->errorCode = git_commit_parent(&baton->rawParentCommit, baton->commit->commit, baton->index); + int returnCode = git_commit_parent(&baton->rawParentCommit, baton->commit->commit, baton->index); - if (baton->errorCode) { - baton->errorMessage = git_lasterror(); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); } } void GitCommit::ParentAfterWork(uv_work_t* req) { HandleScope scope; - ParentBaton* baton = static_cast(req->data); - delete req; - if (baton->errorCode) { + if (baton->error) { Local argv[1] = { - Exception::Error(String::New(baton->errorMessage)) + GitError::WrapError(baton->error) }; TryCatch try_catch; @@ -390,8 +452,8 @@ void GitCommit::ParentAfterWork(uv_work_t* req) { } else { Local parent = GitCommit::constructor_template->NewInstance(); - GitCommit *parentCommit = ObjectWrap::Unwrap(parent); - parentCommit->SetValue(baton->rawParentCommit); + GitCommit *parentInstance = ObjectWrap::Unwrap(parent); + parentInstance->SetValue(baton->rawParentCommit); Handle argv[2] = { Local::New(Null()), @@ -405,6 +467,7 @@ void GitCommit::ParentAfterWork(uv_work_t* req) { } } baton->commit->Unref(); + delete req; } Persistent GitCommit::constructor_template; diff --git a/src/diff_list.cc b/src/diff_list.cc new file mode 100755 index 000000000..46d14db47 --- /dev/null +++ b/src/diff_list.cc @@ -0,0 +1,510 @@ +/* + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ + +#include +#include + +#include "cvv8/v8-convert.hpp" +#include "git2.h" + +#include "../include/diff_list.h" +#include "../include/error.h" + +#include "../include/functions/string.h" + +using namespace v8; +using namespace node; + +namespace cvv8 { + template <> + struct NativeToJS : NativeToJS {}; +} + +void GitDiffList::Initialize(Handle target) { + HandleScope scope; + + Local tpl = FunctionTemplate::New(New); + + tpl->InstanceTemplate()->SetInternalFieldCount(1); + tpl->SetClassName(String::NewSymbol("DiffList")); + + NODE_SET_PROTOTYPE_METHOD(tpl, "treeToTree", TreeToTree); + NODE_SET_PROTOTYPE_METHOD(tpl, "walk", Walk); + NODE_SET_PROTOTYPE_METHOD(tpl, "close", Close); + + // Add libgit2 delta types to diff_list object + Local libgit2DeltaTypes = Object::New(); + + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_UNMODIFIED"), cvv8::CastToJS(GIT_DELTA_UNMODIFIED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_ADDED"), cvv8::CastToJS(GIT_DELTA_ADDED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_DELETED"), cvv8::CastToJS(GIT_DELTA_DELETED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_MODIFIED"), cvv8::CastToJS(GIT_DELTA_MODIFIED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_RENAMED"), cvv8::CastToJS(GIT_DELTA_RENAMED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_COPIED"), cvv8::CastToJS(GIT_DELTA_COPIED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_IGNORED"), cvv8::CastToJS(GIT_DELTA_IGNORED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_UNTRACKED"), cvv8::CastToJS(GIT_DELTA_UNTRACKED), ReadOnly); + libgit2DeltaTypes->Set(String::NewSymbol("GIT_DELTA_TYPECHANGE"), cvv8::CastToJS(GIT_DELTA_TYPECHANGE), ReadOnly); + + Local libgit2LineOriginConstants = Object::New(); + + // @todo refactor this into something sane + char _GIT_DIFF_LINE_CONTEXT[2]; + _GIT_DIFF_LINE_CONTEXT[0] = GIT_DIFF_LINE_CONTEXT; + _GIT_DIFF_LINE_CONTEXT[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_CONTEXT"), cvv8::CastToJS(_GIT_DIFF_LINE_CONTEXT), ReadOnly); + + char _GIT_DIFF_LINE_ADDITION[2]; + _GIT_DIFF_LINE_ADDITION[0] = GIT_DIFF_LINE_ADDITION; + _GIT_DIFF_LINE_ADDITION[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_ADDITION"), cvv8::CastToJS(_GIT_DIFF_LINE_ADDITION), ReadOnly); + + char _GIT_DIFF_LINE_DELETION[2]; + _GIT_DIFF_LINE_DELETION[0] = GIT_DIFF_LINE_DELETION; + _GIT_DIFF_LINE_DELETION[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_DELETION"), cvv8::CastToJS(_GIT_DIFF_LINE_DELETION), ReadOnly); + + char _GIT_DIFF_LINE_ADD_EOFNL[2]; + _GIT_DIFF_LINE_ADD_EOFNL[0] = GIT_DIFF_LINE_ADD_EOFNL; + _GIT_DIFF_LINE_ADD_EOFNL[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_ADD_EOFNL"), cvv8::CastToJS(_GIT_DIFF_LINE_ADD_EOFNL), ReadOnly); + + char _GIT_DIFF_LINE_DEL_EOFNL[2]; + _GIT_DIFF_LINE_DEL_EOFNL[0] = GIT_DIFF_LINE_DEL_EOFNL; + _GIT_DIFF_LINE_DEL_EOFNL[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_DEL_EOFNL"), cvv8::CastToJS(_GIT_DIFF_LINE_DEL_EOFNL), ReadOnly); + + char _GIT_DIFF_LINE_FILE_HDR[2]; + _GIT_DIFF_LINE_FILE_HDR[0] = GIT_DIFF_LINE_FILE_HDR; + _GIT_DIFF_LINE_FILE_HDR[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_FILE_HDR"), cvv8::CastToJS(_GIT_DIFF_LINE_FILE_HDR), ReadOnly); + + char _GIT_DIFF_LINE_HUNK_HDR[2]; + _GIT_DIFF_LINE_HUNK_HDR[0] = GIT_DIFF_LINE_HUNK_HDR; + _GIT_DIFF_LINE_HUNK_HDR[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_HUNK_HDR"), cvv8::CastToJS(_GIT_DIFF_LINE_HUNK_HDR), ReadOnly); + + char _GIT_DIFF_LINE_BINARY[2]; + _GIT_DIFF_LINE_BINARY[0] = GIT_DIFF_LINE_BINARY; + _GIT_DIFF_LINE_BINARY[1] = '\0'; + libgit2LineOriginConstants->Set(String::NewSymbol("GIT_DIFF_LINE_BINARY"), cvv8::CastToJS(_GIT_DIFF_LINE_BINARY), ReadOnly); + + constructor_template = Persistent::New(tpl->GetFunction()); + constructor_template->Set(String::NewSymbol("deltaTypes"), libgit2DeltaTypes, ReadOnly); + constructor_template->Set(String::NewSymbol("lineOriginTypes"), libgit2LineOriginConstants, ReadOnly); + target->Set(String::NewSymbol("DiffList"), constructor_template); +} + +git_diff_list* GitDiffList::GetValue() { + return this->diffList; +} + +void GitDiffList::SetValue(git_diff_list* diffList) { + this->diffList = diffList; +} + +Handle GitDiffList::New(const Arguments& args) { + HandleScope scope; + + GitDiffList *diffList = new GitDiffList(); + diffList->Wrap(args.This()); + + return scope.Close(args.This()); +} + +void GitDiffList::Close() { + git_diff_list_free(this->diffList); + this->diffList = NULL; +} + +Handle GitDiffList::Close(const Arguments& args) { + HandleScope scope; + + GitDiffList *diffList = ObjectWrap::Unwrap(args.This()); + diffList->Close(); + + return scope.Close(Undefined()); +} + +Handle GitDiffList::TreeToTree(const Arguments& args) { + HandleScope scope; + + if(args.Length() == 0 || !(args[0]->IsObject() || args[0]->IsString())) { + return ThrowException(Exception::Error(String::New("Repo is required and must be an Object or String"))); + } + + if(args.Length() == 1 || !(args[1]->IsObject() || args[1]->IsString())) { + return ThrowException(Exception::Error(String::New("Old Oid/SHA is required and must be an Object or String"))); + } + + if(args.Length() == 2 || !(args[2]->IsObject() || args[2]->IsString())) { + return ThrowException(Exception::Error(String::New("New Oid/SHA is required and must be an Object or String"))); + } + + if(args.Length() == 3 || !args[3]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); + } + + TreeToTreeBaton *baton = new TreeToTreeBaton(); + baton->request.data = baton; + baton->error = NULL; + baton->diffList = ObjectWrap::Unwrap(args.This()); + baton->repo = ObjectWrap::Unwrap(args[0]->ToObject())->GetValue(); + + if (args[1]->IsObject()) { + baton->oldOid = ObjectWrap::Unwrap(args[1]->ToObject())->GetValue(); + } else { + baton->oldSha = stringArgToString(args[1]->ToString()); + } + + if (args[2]->IsObject()) { + baton->newOid = ObjectWrap::Unwrap(args[2]->ToObject())->GetValue(); + } else { + baton->newSha = stringArgToString(args[2]->ToString()); + } + + baton->callback = Persistent::New(Local::Cast(args[3])); + + uv_queue_work(uv_default_loop(), &baton->request, TreeToTreeWork, (uv_after_work_cb)TreeToTreeAfterWork); + + return Undefined(); +} + +void GitDiffList::TreeToTreeWork(uv_work_t *req) { + TreeToTreeBaton *baton = static_cast(req->data); + + // Prepare git_oid's + git_oid *oldOid = &baton->oldOid; + if (!baton->oldSha.empty()) { + int returnCode = git_oid_fromstr(oldOid, baton->oldSha.c_str()); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + } + git_oid *newOid = &baton->newOid; + if (!baton->newSha.empty()) { + int returnCode = git_oid_fromstr(newOid, baton->newSha.c_str()); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + } + + // Get commits + git_commit* oldCommit = NULL; + int returnCode = git_commit_lookup(&oldCommit, baton->repo, oldOid); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + + git_commit* newCommit = NULL; + returnCode = git_commit_lookup(&newCommit, baton->repo, newOid); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + + // Prepare trees + git_tree* oldTree = NULL; + returnCode = git_commit_tree(&oldTree, oldCommit); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + git_tree* newTree = NULL; + returnCode = git_commit_tree(&newTree, newCommit); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + return; + } + + baton->rawDiffList = NULL; + returnCode = git_diff_tree_to_tree(&baton->rawDiffList, baton->repo, oldTree, newTree, NULL); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + } +} + +void GitDiffList::TreeToTreeAfterWork(uv_work_t *req) { + HandleScope scope; + TreeToTreeBaton *baton = static_cast(req->data); + + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; + + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + + baton->diffList->SetValue(baton->rawDiffList); + + Handle argv[2] = { + Local::New(Null()), + baton->diffList->handle_ + }; + + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } + delete req; +} + +Handle GitDiffList::Walk(const Arguments& args) { + HandleScope scope; + + GitDiffList* diffList = ObjectWrap::Unwrap(args.This()); + + if (diffList->GetValue() == NULL) { + return ThrowException(Exception::Error(String::New("No diff list to Walk."))); + } + + if(args.Length() == 0 || !args[0]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Diff callback is required and must be a Function."))); + } + + if(args.Length() == 1 || !args[1]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Hunk callback is required and must be a Function."))); + } + + if(args.Length() == 2 || !args[2]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Line callback is required and must be a Function."))); + } + + if(args.Length() == 3 || !args[3]->IsFunction()) { + return ThrowException(Exception::Error(String::New("End callback is required and must be a Function."))); + } + + + WalkBaton* baton = new WalkBaton(); + uv_async_init(uv_default_loop(), &baton->asyncFile, WalkWorkSendFile); + uv_async_init(uv_default_loop(), &baton->asyncHunk, WalkWorkSendHunk); + uv_async_init(uv_default_loop(), &baton->asyncData, WalkWorkSendData); + uv_async_init(uv_default_loop(), &baton->asyncEnd, WalkWorkSendEnd); + + uv_mutex_init(&baton->mutex); + + baton->rawDiffList = diffList->GetValue(); + diffList->Ref(); + + baton->fileCallback = Persistent::New(Local::Cast(args[0])); + baton->hunkCallback = Persistent::New(Local::Cast(args[1])); + baton->lineCallback = Persistent::New(Local::Cast(args[2])); + baton->endCallback = Persistent::New(Local::Cast(args[3])); + + uv_thread_create(&baton->threadId, WalkWork, baton); + + return Undefined(); +} + +void GitDiffList::WalkWork(void *payload) { + WalkBaton *baton = static_cast(payload); + + int returnCode = git_diff_foreach(baton->rawDiffList, WalkWorkFile, WalkWorkHunk, WalkWorkData, payload); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + baton->asyncEnd.data = baton; + uv_async_send(&baton->asyncEnd); + return; + } + + baton->asyncFile.data = baton; + uv_async_send(&baton->asyncFile); + + baton->asyncEnd.data = baton; + uv_async_send(&baton->asyncEnd); +} + +int GitDiffList::WalkWorkFile(const git_diff_delta *delta, float progress, + void *payload) { + WalkBaton *baton = static_cast(payload); + + /* + diff_file_delta + git_diff_file old_file + git_oid oid + const char *path + git_off_t size + uint32_t flags + uint16_t mode + + git_diff_file new_file + git_delta_t status + uint32_t similarity + uint32_t flags + */ + + uv_mutex_lock(&baton->mutex); + + GitDiffList::Delta* newDelta = new GitDiffList::Delta(); + newDelta->raw = (git_diff_delta*)malloc(sizeof(git_diff_delta)); + memcpy(newDelta->raw, delta, sizeof(git_diff_delta)); + + // @todo use combined OID or another less stupid way to index deltas + std::string key(newDelta->raw->old_file.path); + key.append(newDelta->raw->new_file.path); + baton->fileDeltas[key] = newDelta; + uv_mutex_unlock(&baton->mutex); + + if ((unsigned int)baton->fileDeltas.size() == (unsigned int)GitDiffList::WALK_DELTA_THRESHHOLD) { + uv_async_send(&baton->asyncFile); + } + + return GIT_OK; +} + +int GitDiffList::WalkWorkHunk(const git_diff_delta *delta, const git_diff_range *range, const char *header, size_t header_len, void *payload) { + return GIT_OK; +} + +int GitDiffList::WalkWorkData(const git_diff_delta *delta, const git_diff_range *range, + char line_origin, const char *content, size_t content_len, + void *payload) { + WalkBaton *baton = static_cast(payload); + uv_mutex_lock(&baton->mutex); + + GitDiffList::DeltaContent *deltaContent = new GitDiffList::DeltaContent; + + deltaContent->range = (git_diff_range*)malloc(sizeof(git_diff_range)); + memcpy(deltaContent->range, range, sizeof(git_diff_range)); + + deltaContent->lineOrigin = line_origin; + + deltaContent->contentLength = content_len; + deltaContent->content = content; + + std::string key(delta->old_file.path); + key.append(delta->new_file.path); + baton->fileDeltas[key]->contents.push_back(deltaContent); + + uv_mutex_unlock(&baton->mutex); + + return GIT_OK; +} + +void GitDiffList::WalkWorkSendFile(uv_async_t *handle, int status /*UNUSED*/) { + HandleScope scope; + + WalkBaton *baton = static_cast(handle->data); + + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; + + TryCatch try_catch; + baton->fileCallback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + + uv_mutex_lock(&baton->mutex); + + std::vector > fileDeltasArray; + + for(std::map::iterator iterator = baton->fileDeltas.begin(); iterator != baton->fileDeltas.end(); ++iterator) { + + Local fileDelta = Object::New(); + GitDiffList::Delta* delta = iterator->second; + + Local oldFile = Object::New(); + oldFile->Set(String::NewSymbol("path"), String::New(delta->raw->old_file.path)); + fileDelta->Set(String::NewSymbol("oldFile"), oldFile); + + Local newFile = Object::New(); + newFile->Set(String::NewSymbol("path"), String::New(delta->raw->new_file.path)); + fileDelta->Set(String::NewSymbol("newFile"), newFile); + + std::vector > deltaContent; + for(std::vector::iterator contentIterator = delta->contents.begin(); contentIterator != delta->contents.end(); ++contentIterator) { + DeltaContent* rawContent = (*contentIterator); + Local content = Object::New(); + + Local range = Object::New(); + /* + int old_start + int old_lines + int new_start + int new_lines + */ + Local oldRange = Object::New(); + oldRange->Set(String::New("start"), Integer::New(rawContent->range->old_start)); + oldRange->Set(String::New("lines"), Integer::New(rawContent->range->old_lines)); + range->Set(String::New("old"), oldRange); + + Local newRange = Object::New(); + newRange->Set(String::New("start"), Integer::New(rawContent->range->new_start)); + newRange->Set(String::New("lines"), Integer::New(rawContent->range->new_lines)); + range->Set(String::New("new"), newRange); + + content->Set(String::New("range"), range); + content->Set(String::New("content"), String::New(rawContent->content.c_str())); + + char lineOrigin[2]; + strncpy(lineOrigin, &rawContent->lineOrigin, 1); + content->Set(String::New("lineOrigin"), String::New(lineOrigin)); + content->Set(String::New("contentLength"), Integer::New(rawContent->contentLength)); + + deltaContent.push_back(content); + } + + fileDelta->Set(String::NewSymbol("content"), cvv8::CastToJS(deltaContent)); + fileDelta->Set(String::NewSymbol("status"), cvv8::CastToJS(delta->raw->status)); + + fileDeltasArray.push_back(fileDelta); + } + + baton->fileDeltas.clear(); + + uv_mutex_unlock(&baton->mutex); + + Handle argv[2] = { + Local::New(Null()), + cvv8::CastToJS(fileDeltasArray) + }; + + TryCatch try_catch; + baton->fileCallback->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } +} + +void GitDiffList::WalkWorkSendHunk(uv_async_t *handle, int status /*UNUSED*/) { } +void GitDiffList::WalkWorkSendData(uv_async_t *handle, int status /*UNUSED*/) { } +void GitDiffList::WalkWorkSendEnd(uv_async_t *handle, int status /*UNUSED*/) { + WalkBaton *baton = static_cast(handle->data); + + uv_mutex_destroy(&baton->mutex); + + Local argv[1]; + if (baton->error) { + argv[0] = GitError::WrapError(baton->error); + } else { + argv[0] = Local::New(Null()); + } + + TryCatch try_catch; + + baton->endCallback->Call(Context::GetCurrent()->Global(), 1, argv); + + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } +} + +Persistent GitDiffList::constructor_template; diff --git a/src/error.cc b/src/error.cc index 586163731..9a7565607 100755 --- a/src/error.cc +++ b/src/error.cc @@ -15,89 +15,95 @@ using namespace v8; using namespace cvv8; using namespace node; +/** + * Copied from libgit2/include/errors.h, to allow exporting to JS + */ +typedef enum { + _GIT_OK = 0, + _GIT_ERROR = -1, + _GIT_ENOTFOUND = -3, + _GIT_EEXISTS = -4, + _GIT_EAMBIGUOUS = -5, + _GIT_EBUFS = -6, + + _GIT_PASSTHROUGH = -30, + _GIT_ITEROVER = -31, +} git_error_return_t; + namespace cvv8 { template <> - struct NativeToJS : NativeToJS {}; + struct NativeToJS : NativeToJS {}; + + template <> + struct NativeToJS : NativeToJS {}; } void GitError::Initialize (Handle target) { HandleScope scope; - Local t = FunctionTemplate::New(New); - - constructor_template = Persistent::New(t); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - constructor_template->SetClassName(String::NewSymbol("Error")); + Local tpl = FunctionTemplate::New(New); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "strError", StrError); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + tpl->SetClassName(String::NewSymbol("Error")); // Add libgit2 error codes to error object Local libgit2Errors = Object::New(); - libgit2Errors->Set(String::NewSymbol("GIT_SUCCESS"), cvv8::CastToJS(GIT_SUCCESS), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ERROR"), cvv8::CastToJS(GIT_ERROR), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOTOID"), cvv8::CastToJS(GIT_ENOTOID), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOTFOUND"), cvv8::CastToJS(GIT_ENOTFOUND), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOMEM"), cvv8::CastToJS(GIT_ENOMEM), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EOSERR"), cvv8::CastToJS(GIT_EOSERR), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EOBJTYPE"), cvv8::CastToJS(GIT_EOBJTYPE), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOTAREPO"), cvv8::CastToJS(GIT_ENOTAREPO), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EINVALIDTYPE"), cvv8::CastToJS(GIT_EINVALIDTYPE), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EMISSINGOBJDATA"), cvv8::CastToJS(GIT_EMISSINGOBJDATA), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EPACKCORRUPTED"), cvv8::CastToJS(GIT_EPACKCORRUPTED), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EFLOCKFAIL"), cvv8::CastToJS(GIT_EFLOCKFAIL), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EZLIB"), cvv8::CastToJS(GIT_EZLIB), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EBUSY"), cvv8::CastToJS(GIT_EBUSY), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EBAREINDEX"), cvv8::CastToJS(GIT_EBAREINDEX), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EINVALIDREFNAME"), cvv8::CastToJS(GIT_EINVALIDREFNAME), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EREFCORRUPTED"), cvv8::CastToJS(GIT_EREFCORRUPTED), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ETOONESTEDSYMREF"), cvv8::CastToJS(GIT_ETOONESTEDSYMREF), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EPACKEDREFSCORRUPTED"), cvv8::CastToJS(GIT_EPACKEDREFSCORRUPTED), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EINVALIDPATH"), cvv8::CastToJS(GIT_EINVALIDPATH), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EREVWALKOVER"), cvv8::CastToJS(GIT_EREVWALKOVER), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EINVALIDREFSTATE"), cvv8::CastToJS(GIT_EINVALIDREFSTATE), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOTIMPLEMENTED"), cvv8::CastToJS(GIT_ENOTIMPLEMENTED), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EEXISTS"), cvv8::CastToJS(GIT_EEXISTS), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EOVERFLOW"), cvv8::CastToJS(GIT_EOVERFLOW), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOTNUM"), cvv8::CastToJS(GIT_ENOTNUM), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ESTREAM"), cvv8::CastToJS(GIT_ESTREAM), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EINVALIDARGS"), cvv8::CastToJS(GIT_EINVALIDARGS), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EOBJCORRUPTED"), cvv8::CastToJS(GIT_EOBJCORRUPTED), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EAMBIGUOUSOIDPREFIX"), cvv8::CastToJS(GIT_EAMBIGUOUSOIDPREFIX), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_EPASSTHROUGH"), cvv8::CastToJS(GIT_EPASSTHROUGH), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ENOMATCH"), cvv8::CastToJS(GIT_ENOMATCH), ReadOnly); - libgit2Errors->Set(String::NewSymbol("GIT_ESHORTBUFFER"), cvv8::CastToJS(GIT_ESHORTBUFFER), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_NOMEMORY"), cvv8::CastToJS(GITERR_NOMEMORY), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_OS"), cvv8::CastToJS(GITERR_OS), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_INVALID"), cvv8::CastToJS(GITERR_INVALID), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_REFERENCE"), cvv8::CastToJS(GITERR_REFERENCE), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_ZLIB"), cvv8::CastToJS(GITERR_ZLIB), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_REPOSITORY"), cvv8::CastToJS(GITERR_REPOSITORY), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_CONFIG"), cvv8::CastToJS(GITERR_CONFIG), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_REGEX"), cvv8::CastToJS(GITERR_REGEX), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_ODB"), cvv8::CastToJS(GITERR_ODB), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_INDEX"), cvv8::CastToJS(GITERR_INDEX), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_OBJECT"), cvv8::CastToJS(GITERR_OBJECT), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_NET"), cvv8::CastToJS(GITERR_NET), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_TAG"), cvv8::CastToJS(GITERR_TAG), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_TREE"), cvv8::CastToJS(GITERR_TREE), ReadOnly); + libgit2Errors->Set(String::NewSymbol("GITERR_INDEXER"), cvv8::CastToJS(GITERR_INDEXER), ReadOnly); + // Add libgit2 error codes to error object + Local libgit2ReturnCodes = Object::New(); + + libgit2ReturnCodes->Set(String::NewSymbol("GIT_OK"), cvv8::CastToJS(_GIT_OK), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_ERROR"), cvv8::CastToJS(_GIT_ERROR), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_ENOTFOUND"), cvv8::CastToJS(_GIT_ENOTFOUND), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_EEXISTS"), cvv8::CastToJS(_GIT_EEXISTS), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_EAMBIGUOUS"), cvv8::CastToJS(_GIT_EAMBIGUOUS), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_EBUFS"), cvv8::CastToJS(_GIT_EBUFS), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_PASSTHROUGH"), cvv8::CastToJS(_GIT_PASSTHROUGH), ReadOnly); + libgit2ReturnCodes->Set(String::NewSymbol("GIT_ITEROVER"), cvv8::CastToJS(_GIT_ITEROVER), ReadOnly); + + constructor_template = Persistent::New(tpl->GetFunction()); constructor_template->Set(String::NewSymbol("codes"), libgit2Errors, ReadOnly); + constructor_template->Set(String::NewSymbol("returnCodes"), libgit2ReturnCodes, ReadOnly); - target->Set(String::NewSymbol("Error"), constructor_template->GetFunction()); -} -const char* GitError::StrError(int err) { - return git_strerror(err); + target->Set(String::NewSymbol("Error"), constructor_template); } -Handle GitError::New(const Arguments& args) { - HandleScope scope; +Local GitError::WrapError(const git_error* error) { - GitError *error = new GitError(); - error->Wrap(args.This()); + Local gitError = GitError::constructor_template->NewInstance(); + Local stackTrace = StackTrace::CurrentStackTrace(10); - return scope.Close( args.This() ); + gitError->Set(String::NewSymbol("stackTrace"), cvv8::CastToJS(stackTrace->AsArray())); + gitError->Set(String::NewSymbol("message"), String::New(error->message)); + gitError->Set(String::NewSymbol("code"), Integer::New(error->klass)); + + return gitError; } -Handle GitError::StrError(const Arguments& args) { +Handle GitError::New(const Arguments& args) { HandleScope scope; - GitError* error = ObjectWrap::Unwrap(args.This()); - - if(args.Length() == 0 || !args[0]->IsNumber()) { - return ThrowException(Exception::Error(String::New("Error is required and must be a Number."))); - } - - Local err = Local::Cast(args[0]); + GitError *error = new GitError(); + error->Wrap(args.This()); - return scope.Close( String::New(error->StrError(err->Value())) ); + return scope.Close(args.This()); } -Persistent GitError::constructor_template; +Persistent GitError::constructor_template; diff --git a/src/functions/string.cc b/src/functions/string.cc new file mode 100644 index 000000000..5c74f4aa7 --- /dev/null +++ b/src/functions/string.cc @@ -0,0 +1,9 @@ +#include +#include + +#include "../../include/functions/string.h" + +std::string stringArgToString(const v8::Local arg) { + v8::String::Utf8Value param1(arg); + return std::string(*param1); +} diff --git a/src/oid.cc b/src/oid.cc index 064457918..016246d38 100755 --- a/src/oid.cc +++ b/src/oid.cc @@ -15,22 +15,22 @@ using namespace node; void GitOid::Initialize(Handle target) { HandleScope scope; - Local t = FunctionTemplate::New(New); + Local tpl = FunctionTemplate::New(New); - constructor_template = Persistent::New(t); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - constructor_template->SetClassName(String::NewSymbol("Oid")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + tpl->SetClassName(String::NewSymbol("Oid")); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "mkstr", Mkstr); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "mkraw", Mkraw); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "fmt", Fmt); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "pathFmt", PathFmt); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "allocFmt", AllocFmt); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "cpy", Cpy); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "cmp", Cmp); + NODE_SET_PROTOTYPE_METHOD(tpl, "mkstr", Mkstr); + NODE_SET_PROTOTYPE_METHOD(tpl, "mkraw", Mkraw); + NODE_SET_PROTOTYPE_METHOD(tpl, "fmt", Fmt); + NODE_SET_PROTOTYPE_METHOD(tpl, "pathFmt", PathFmt); + NODE_SET_PROTOTYPE_METHOD(tpl, "allocFmt", AllocFmt); + NODE_SET_PROTOTYPE_METHOD(tpl, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(tpl, "cpy", Cpy); + NODE_SET_PROTOTYPE_METHOD(tpl, "cmp", Cmp); - target->Set(String::NewSymbol("Oid"), constructor_template->GetFunction()); + constructor_template = Persistent::New(tpl->GetFunction()); + target->Set(String::NewSymbol("Oid"), constructor_template); } git_oid GitOid::GetValue() { @@ -62,7 +62,7 @@ char* GitOid::AllocFmt() { } char* GitOid::ToString(char* buffer, size_t bufferSize) { - return git_oid_to_string(buffer, bufferSize, &this->oid); + return git_oid_tostr(buffer, bufferSize, &this->oid); } void GitOid::Cpy(git_oid* out) { @@ -119,7 +119,7 @@ Handle GitOid::Fmt(const Arguments& args) { char buffer[40]; oid->Fmt(buffer); - return scope.Close( String::New(buffer) ); + return scope.Close(String::New(buffer)); } Handle GitOid::PathFmt(const Arguments& args) { @@ -195,4 +195,4 @@ Handle GitOid::Cmp(const Arguments& args) { return scope.Close( Integer::New(cmp) ); } -Persistent GitOid::constructor_template; +Persistent GitOid::constructor_template; diff --git a/src/reference.cc b/src/reference.cc index ac824c3b4..0993635d9 100755 --- a/src/reference.cc +++ b/src/reference.cc @@ -1,6 +1,9 @@ /* -Copyright (c) 2011, Tim Branyen @tbranyen -*/ + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ #include #include @@ -43,7 +46,7 @@ int GitReference::Lookup(git_repository* repo, const char* name) { } const git_oid* GitReference::Oid() { - return git_reference_oid(this->ref); + return git_reference_target(this->ref); } Handle GitReference::New(const Arguments& args) { @@ -89,7 +92,7 @@ Handle GitReference::Lookup(const Arguments& args) { uv_work_t *req = new uv_work_t; req->data = ar; - uv_queue_work(uv_default_loop(), req, EIO_Lookup, EIO_AfterLookup); + uv_queue_work(uv_default_loop(), req, EIO_Lookup, (uv_after_work_cb)EIO_AfterLookup); return scope.Close( Undefined() ); } @@ -105,9 +108,8 @@ void GitReference::EIO_Lookup(uv_work_t *req) { void GitReference::EIO_AfterLookup(uv_work_t *req) { HandleScope scope; - lookup_request *ar = static_cast(req->data); - delete req; + ar->ref->Unref(); Local argv[1]; @@ -123,6 +125,7 @@ void GitReference::EIO_AfterLookup(uv_work_t *req) { ar->callback.Dispose(); delete ar; + delete req; } Handle GitReference::Oid(const Arguments& args) { diff --git a/src/repo.cc b/src/repo.cc index 2a9b153f1..42e05026f 100755 --- a/src/repo.cc +++ b/src/repo.cc @@ -1,16 +1,21 @@ /* -Copyright (c) 2011, Tim Branyen @tbranyen -*/ + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ #include #include -#include #include "../vendor/libgit2/include/git2.h" #include "../include/object.h" #include "../include/repo.h" #include "../include/commit.h" +#include "../include/error.h" + +#include "../include/functions/string.h" using namespace v8; using namespace node; @@ -18,62 +23,43 @@ using namespace node; void GitRepo::Initialize(Handle target) { HandleScope scope; - Local t = FunctionTemplate::New(New); + Local tpl = FunctionTemplate::New(New); - constructor_template = Persistent::New(t); - constructor_template->InstanceTemplate()->SetInternalFieldCount(1); - constructor_template->SetClassName(String::NewSymbol("Repo")); + tpl->InstanceTemplate()->SetInternalFieldCount(1); + tpl->SetClassName(String::NewSymbol("Repo")); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "open", Open); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookup", Lookup); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "free", Free); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "init", Init); + NODE_SET_PROTOTYPE_METHOD(tpl, "open", Open); + NODE_SET_PROTOTYPE_METHOD(tpl, "free", Free); + NODE_SET_PROTOTYPE_METHOD(tpl, "init", Init); - target->Set(String::NewSymbol("Repo"), constructor_template->GetFunction()); + constructor_template = Persistent::New(tpl->GetFunction()); + target->Set(String::NewSymbol("Repo"), constructor_template); } git_repository* GitRepo::GetValue() { - return this->repo; + return this->repo; } void GitRepo::SetValue(git_repository* repo) { this->repo = repo; } -int GitRepo::Open(const char* path) { - return git_repository_open(&this->repo, path); -} - void GitRepo::Free() { git_repository_free(this->repo); } -int GitRepo::Init(const char* path, bool is_bare) { - git_repository* repo_; - int err = git_repository_init(&repo_, path, is_bare); - - if(err == 0) { - this->repo = *&repo_; - } - - return err; -} - Handle GitRepo::New(const Arguments& args) { HandleScope scope; GitRepo *repo = new GitRepo(); repo->Wrap(args.This()); - return scope.Close( args.This() ); + return scope.Close(args.This()); } Handle GitRepo::Open(const Arguments& args) { HandleScope scope; - GitRepo *repo = ObjectWrap::Unwrap(args.This()); - Local callback; - if(args.Length() == 0 || !args[0]->IsString()) { return ThrowException(Exception::Error(String::New("Path is required and must be a String."))); } @@ -82,130 +68,61 @@ Handle GitRepo::Open(const Arguments& args) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } - callback = Local::Cast(args[1]); - - open_request *ar = new open_request(); - ar->repo = repo; - - String::Utf8Value path(args[0]); - ar->path = *path; - - ar->callback = Persistent::New(callback); + OpenBaton *baton = new OpenBaton(); + baton->request.data = baton; + baton->error = NULL; + baton->path = stringArgToString(args[0]->ToString());; + baton->repo = ObjectWrap::Unwrap(args.This()); + baton->callback = Persistent::New(Handle::Cast(args[1])); - repo->Ref(); + baton->repo->Ref(); - uv_work_t *req = new uv_work_t; - req->data = ar; - uv_queue_work(uv_default_loop(), req, EIO_Open, EIO_AfterOpen); + uv_queue_work(uv_default_loop(), &baton->request, OpenWork, (uv_after_work_cb)OpenAfterWork); - return scope.Close( Undefined() ); + return Undefined(); } -void GitRepo::EIO_Open(uv_work_t *req) { - open_request *ar = static_cast(req->data); - - ar->err = ar->repo->Open(ar->path.c_str()); +void GitRepo::OpenWork(uv_work_t *req) { + OpenBaton *baton = static_cast(req->data); + int returnCode = git_repository_open(&baton->rawRepo, baton->path.c_str()); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + } } -void GitRepo::EIO_AfterOpen(uv_work_t *req) { +void GitRepo::OpenAfterWork(uv_work_t *req) { HandleScope scope; - open_request *ar = static_cast(req->data); - delete req; - ar->repo->Unref(); + OpenBaton *baton = static_cast(req->data); - Local argv[1]; - argv[0] = Integer::New(ar->err); - - TryCatch try_catch; + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; - ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { - if(try_catch.HasCaught()) - FatalException(try_catch); + baton->repo->SetValue(baton->rawRepo); - ar->callback.Dispose(); - - delete ar; -} - -Handle GitRepo::Lookup(const Arguments& args) { - HandleScope scope; - - GitRepo *repo = ObjectWrap::Unwrap(args.This()); - Local callback; + Handle argv[2] = { + Local::New(Null()), + baton->repo->handle_ + }; - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Object is required and must be a Object."))); + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 2, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } } - - if(args.Length() == 1 || !args[1]->IsObject()) { - return ThrowException(Exception::Error(String::New("GitRepo is required and must be a Object."))); - } - - if(args.Length() == 2 || !args[2]->IsObject()) { - return ThrowException(Exception::Error(String::New("Oid is required and must be a Object."))); - } - - if(args.Length() == 3 || !args[3]->IsFunction()) { - return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); - } - - callback = Local::Cast(args[3]); - - lookup_request *ar = new lookup_request(); - ar->repo = repo; - ar->callback = Persistent::New(callback); - - repo->Ref(); - - //eio_custom(EIO_LookupRef, EIO_PRI_DEFAULT, EIO_AfterLookupRef, ar); - //ev_ref(EV_DEFAULT_UC); - - return scope.Close( Undefined() ); -} - -void GitRepo::EIO_Lookup(uv_work_t *req) { - //lookup_request *ar = static_cast(req->data); - // - //String::Utf8Value name(ar->name); - //git_reference *ref; - // - //int err = ar->repo->LookupRef((git_reference **)ref, *name); - //ar->err = Persistent::New(Integer::New(err)); - // - //if(Int32::Cast(*ar->err)->Value() == 0) { - // ar->ref->SetValue(*&ref); - //} - // - //return 0; -} - -void GitRepo::EIO_AfterLookup(uv_work_t *req) { - //HandleScope scope; - - //lookup_request *ar = static_cast(req->data); - // delete req; - //ar->repo->Unref(); - - //Local argv[1]; - //argv[0] = Number::Cast(*ar->err); - - //TryCatch try_catch; - - //ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); - - //if(try_catch.HasCaught()) - // FatalException(try_catch); - // - //ar->err.Dispose(); - //ar->name.Dispose(); - //ar->callback.Dispose(); - - //delete ar; - - //return 0; + delete req; + baton->repo->Unref(); } Handle GitRepo::Free(const Arguments& args) { @@ -221,8 +138,6 @@ Handle GitRepo::Free(const Arguments& args) { Handle GitRepo::Init(const Arguments& args) { HandleScope scope; - GitRepo *repo = ObjectWrap::Unwrap(args.This()); - Local callback; if(args.Length() == 0 || !args[0]->IsString()) { return ThrowException(Exception::Error(String::New("path is required and must be a String."))); @@ -236,52 +151,50 @@ Handle GitRepo::Init(const Arguments& args) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } - callback = Local::Cast(args[2]); - - init_request *ar = new init_request(); - ar->repo = repo; - + InitBaton *baton = new InitBaton(); + baton->request.data = baton; + baton->error = NULL; + baton->repo = ObjectWrap::Unwrap(args.This()); + baton->repo->Ref(); + baton->rawRepo = baton->repo->GetValue(); String::Utf8Value path(args[0]); - ar->path = *path; - - ar->is_bare = args[1]->ToBoolean()->Value(); - ar->callback = Persistent::New(callback); + baton->path = *path; + baton->isBare = args[1]->ToBoolean()->Value(); + baton->callback = Persistent::New(Local::Cast(args[2])); - repo->Ref(); + uv_queue_work(uv_default_loop(), &baton->request, InitWork, (uv_after_work_cb)InitAfterWork); - uv_work_t *req = new uv_work_t; - req->data = ar; - uv_queue_work(uv_default_loop(), req, EIO_Init, EIO_AfterInit); - - return scope.Close( Undefined() ); + return Undefined(); } -void GitRepo::EIO_Init(uv_work_t *req) { - init_request *ar = static_cast(req->data); - - ar->err = ar->repo->Init(ar->path.c_str(), ar->is_bare); +void GitRepo::InitWork(uv_work_t *req) { + InitBaton *baton = static_cast(req->data); + int returnCode = git_repository_init(&baton->rawRepo, baton->path.c_str(), baton->isBare); + if (returnCode != GIT_OK) { + baton->error = giterr_last(); + } } -void GitRepo::EIO_AfterInit(uv_work_t *req) { +void GitRepo::InitAfterWork(uv_work_t *req) { HandleScope scope; - init_request *ar = static_cast(req->data); - delete req; - ar->repo->Unref(); + InitBaton *baton = static_cast(req->data); - Local argv[2]; - argv[0] = Integer::New(ar->err); + Local argv[1]; + if (baton->error) { + argv[0] = GitError::WrapError(baton->error); + } else { + argv[0] = Local::New(Null()); + } TryCatch try_catch; - - ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); - - if(try_catch.HasCaught()) - FatalException(try_catch); - - ar->callback.Dispose(); - - delete ar; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + delete req; + baton->repo->Unref(); } -Persistent GitRepo::constructor_template; + +Persistent GitRepo::constructor_template; diff --git a/src/revwalk.cc b/src/revwalk.cc index ec3f6163e..23a9d96c6 100755 --- a/src/revwalk.cc +++ b/src/revwalk.cc @@ -1,6 +1,9 @@ /* -Copyright (c) 2011, Tim Branyen @tbranyen -*/ + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ #include #include @@ -10,6 +13,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include "../include/revwalk.h" #include "../include/repo.h" #include "../include/commit.h" +#include "../include/error.h" using namespace v8; using namespace node; @@ -59,22 +63,6 @@ void GitRevWalk::Reset() { git_revwalk_reset(this->revwalk); } -int GitRevWalk::Push(git_oid* oid) { - // Test - git_revwalk_sorting(this->revwalk, GIT_SORT_TIME | GIT_SORT_REVERSE); - - return git_revwalk_push(this->revwalk, oid); -} - -// Not for 0.0.1 -//int GitRevWalk::Hide() { -// git_revwalk_hide(this->revwalk); -//} - -int GitRevWalk::Next(git_oid *oid) { - return git_revwalk_next(oid, this->revwalk); -} - void GitRevWalk::Free() { git_revwalk_free(this->revwalk); } @@ -113,78 +101,126 @@ Handle GitRevWalk::Reset(const Arguments& args) { Handle GitRevWalk::Push(const Arguments& args) { HandleScope scope; - GitRevWalk *revwalk = ObjectWrap::Unwrap(args.This()); if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); } - GitOid *oid = ObjectWrap::Unwrap(args[0]->ToObject()); + if(args.Length() == 1 || !args[1]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); + } + + PushBaton* baton = new PushBaton(); + + baton->request.data = baton; + baton->revwalk = ObjectWrap::Unwrap(args.This())->GetValue(); + baton->oid = ObjectWrap::Unwrap(args[0]->ToObject())->GetValue(); + baton->callback = Persistent::New(Local::Cast(args[1])); - git_oid tmp = oid->GetValue(); - int err = revwalk->Push(&tmp); + uv_queue_work(uv_default_loop(), &baton->request, PushWork, (uv_after_work_cb)PushAfterWork); - return scope.Close( Integer::New(err) ); + return Undefined(); } -Handle GitRevWalk::Next(const Arguments& args) { +void GitRevWalk::PushWork(uv_work_t *req) { + PushBaton *baton = static_cast(req->data); + + git_revwalk_sorting(baton->revwalk, GIT_SORT_TIME | GIT_SORT_REVERSE); + + int returnCode = git_revwalk_push(baton->revwalk, &baton->oid); + if (returnCode) { + baton->error = giterr_last(); + } +} + +void GitRevWalk::PushAfterWork(uv_work_t *req) { HandleScope scope; + PushBaton *baton = static_cast(req->data); - GitRevWalk* revwalk = ObjectWrap::Unwrap(args.This()); - Local callback; + Local argv[1]; + if (baton->error) { + argv[0] = GitError::WrapError(baton->error); + } else { + argv[0] = Local::New(Null()); + } - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); + TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); + if (try_catch.HasCaught()) { + node::FatalException(try_catch); } + delete req; +} - if(args.Length() == 1 || !args[1]->IsFunction()) { +Handle GitRevWalk::Next(const Arguments& args) { + HandleScope scope; + + if(args.Length() == 0 || !args[0]->IsFunction()) { return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); } - callback = Local::Cast(args[1]); - - next_request* ar = new next_request(); - ar->revwalk = revwalk; - ar->oid = ObjectWrap::Unwrap(args[0]->ToObject()); - ar->callback = Persistent::New(callback); + NextBaton* baton = new NextBaton(); - revwalk->Ref(); + baton->request.data = baton; + baton->revwalk = ObjectWrap::Unwrap(args.This())->GetValue(); + baton->walkOver = false; + baton->callback = Persistent::New(Local::Cast(args[0])); - uv_work_t *req = new uv_work_t; - req->data = ar; - uv_queue_work(uv_default_loop(), req, EIO_Next, EIO_AfterNext); + uv_queue_work(uv_default_loop(), &baton->request, NextWork, (uv_after_work_cb)NextAfterWork); - return scope.Close( Undefined() ); + return Undefined(); } -void GitRevWalk::EIO_Next(uv_work_t *req) { - next_request *ar = static_cast(req->data); - git_oid oid = ar->oid->GetValue(); - - ar->err = ar->revwalk->Next(&oid); - ar->oid->SetValue(oid); +void GitRevWalk::NextWork(uv_work_t *req) { + NextBaton *baton = static_cast(req->data); + // baton->oid = NULL; + int returnCode = git_revwalk_next(&baton->oid, baton->revwalk); + if (returnCode != GIT_OK) { + if (returnCode == GIT_ITEROVER) { + baton->walkOver = true; + } else { + baton->error = giterr_last(); + } + } } -void GitRevWalk::EIO_AfterNext(uv_work_t *req) { +void GitRevWalk::NextAfterWork(uv_work_t *req) { HandleScope scope; + NextBaton *baton = static_cast(req->data); - next_request *ar = static_cast(req->data); - delete req; - ar->revwalk->Unref(); + if (baton->error) { + Local argv[1] = { + GitError::WrapError(baton->error) + }; - Local argv[1]; - argv[0] = Integer::New(ar->err); + TryCatch try_catch; - TryCatch try_catch; + baton->callback->Call(Context::GetCurrent()->Global(), 1, argv); + + if (try_catch.HasCaught()) { + node::FatalException(try_catch); + } + } else { + + Local oid = GitOid::constructor_template->NewInstance(); + GitOid *oidInstance = ObjectWrap::Unwrap(oid); + oidInstance->SetValue(baton->oid); - ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); + Local argv[3] = { + Local::New(Null()), + oid, + Local::New(Boolean::New(baton->walkOver)) + }; - if(try_catch.HasCaught()) - FatalException(try_catch); + TryCatch try_catch; - ar->callback.Dispose(); + baton->callback->Call(Context::GetCurrent()->Global(), 3, argv); - delete ar; + if(try_catch.HasCaught()) { + FatalException(try_catch); + } + } + delete req; } Handle GitRevWalk::Free(const Arguments& args) { diff --git a/src/threads.cc b/src/threads.cc new file mode 100755 index 000000000..14c4b7f1c --- /dev/null +++ b/src/threads.cc @@ -0,0 +1,54 @@ +/* + * Copyright 2011, Tim Branyen @tbranyen + * @author Michael Robinson @codeofinterest + * + * Dual licensed under the MIT and GPL licenses. + */ + +#include +#include +#include + +#include "../vendor/libgit2/include/git2.h" + +#include "../include/threads.h" +#include "../include/error.h" + +using namespace v8; +using namespace node; + +void GitThreads::Initialize(Handle target) { + HandleScope scope; + + Local tpl = FunctionTemplate::New(New); + + tpl->InstanceTemplate()->SetInternalFieldCount(1); + tpl->SetClassName(String::NewSymbol("Threads")); + + NODE_SET_PROTOTYPE_METHOD(tpl, "init", Init); + + constructor_template = Persistent::New(tpl->GetFunction()); + target->Set(String::NewSymbol("Threads"), constructor_template); +} + +Handle GitThreads::New(const Arguments& args) { + HandleScope scope; + + GitThreads *threads = new GitThreads(); + + threads->Wrap(args.This()); + + return scope.Close(args.This()); +} + +Handle GitThreads::Init(const Arguments& args) { + HandleScope scope; + + int returnCode = git_threads_init(); + if (returnCode) { + return GitError::WrapError(giterr_last()); + } + return True(); +} + +Persistent GitThreads::constructor_template; diff --git a/src/tree.cc b/src/tree.cc index 6a985b967..14fa22efa 100755 --- a/src/tree.cc +++ b/src/tree.cc @@ -69,7 +69,7 @@ Handle GitTree::New(const Arguments& args) { tree->Wrap(args.This()); - return scope.Close( args.This() ); + return scope.Close(args.This()); } Handle GitTree::Lookup(const Arguments& args) { @@ -185,7 +185,7 @@ Handle GitTree::EntryByIndex(const Arguments& args) { uv_work_t *req = new uv_work_t; req->data = er; - uv_queue_work(uv_default_loop(), req, EIO_EntryByIndex, EIO_AfterEntryByIndex); + uv_queue_work(uv_default_loop(), req, EIO_EntryByIndex, (uv_after_work_cb)EIO_AfterEntryByIndex); return scope.Close( Undefined() ); } @@ -200,9 +200,6 @@ void GitTree::EIO_EntryByIndex(uv_work_t *req) { void GitTree::EIO_AfterEntryByIndex(uv_work_t *req) { entryindex_request *er = static_cast(req->data); - delete req; - er->tree->Unref(); - Handle argv[0]; TryCatch try_catch; @@ -214,6 +211,8 @@ void GitTree::EIO_AfterEntryByIndex(uv_work_t *req) { er->callback.Dispose(); + delete req; + er->tree->Unref(); delete er; } @@ -249,7 +248,7 @@ Handle GitTree::EntryByName(const Arguments& args) { uv_work_t *req = new uv_work_t; req->data = er; - uv_queue_work(uv_default_loop(), req, EIO_EntryByName, EIO_AfterEntryByName); + uv_queue_work(uv_default_loop(), req, EIO_EntryByName, (uv_after_work_cb)EIO_AfterEntryByName); return scope.Close( Undefined() ); } diff --git a/src/tree_entry.cc b/src/tree_entry.cc index bc35a78eb..f8541fd18 100755 --- a/src/tree_entry.cc +++ b/src/tree_entry.cc @@ -45,7 +45,7 @@ const char* GitTreeEntry::Name() { } int GitTreeEntry::Attributes() { - return git_tree_entry_attributes(this->entry); + return git_tree_entry_filemode(this->entry); } const git_oid* GitTreeEntry::Id() { @@ -53,7 +53,7 @@ const git_oid* GitTreeEntry::Id() { } int GitTreeEntry::ToObject(git_repository* repo, git_object** obj) { - return git_tree_entry_2object(obj, repo, this->entry); + return git_tree_entry_to_object(obj, repo, this->entry); } Handle GitTreeEntry::New(const Arguments& args) { diff --git a/test/convenience-commit.js b/test/convenience-commit.js index ee56240d8..34154ac62 100644 --- a/test/convenience-commit.js +++ b/test/convenience-commit.js @@ -25,29 +25,21 @@ var helper = { /** * Test that the commit object is present. - * - * @param {Object} test */ exports.method = function(test){ test.expect(2); - helper.testFunction(test.equals, git.commit, 'Commmit'); - test.done(); }; /** - * Test that - * - * @param {Object} test + * Test that improper commit ID's result in an error message */ exports.improperCommitId = function(test) { - test.expect(2); + test.expect(1); git.repo('../.git', function(error, repository) { repository.commit('not a proper commit sha', function(error, commit) { - test.equals(error.code, git.error.GIT_ENOTFOUND, 'Correct error should occur'); - test.equals(error.message, 'Object does not exist in the scope searched.', 'Attempting to get commit by invalid SHA should error'); - + test.notEqual(error, null, 'Error should occur'); test.done(); }); }); @@ -63,18 +55,15 @@ var historyCountKnownSHA = 'fce88902e66c72b5b93e75bdb5ae717038b221f6'; exports.history = function(test) { test.expect(368); git.repo('../.git', function(error, repository) { - repository.commit(historyCountKnownSHA, function(error, commit) { - test.equals(error, 0, 'Getting latest branch commit should not error'); - + test.equals(null, error, 'Getting latest branch commit should not error'); var historyCount = 0; var expectedHistoryCount = 364; commit.history().on('commit', function(error, commit) { - test.equals(error, null, 'There should be no errors'); + test.equals(null, error, 'There should be no errors'); historyCount++; }).on('end', function(error, commits) { - - test.equals(error, null, 'There should be no errors'); + test.equals(null, error, 'There should be no errors'); test.equals(historyCount, expectedHistoryCount, 'Manual count does not match expected'); test.equals(commits.length, expectedHistoryCount, '"end" count does not match expected'); @@ -86,19 +75,17 @@ exports.history = function(test) { /** * Test that retreiving master branch's HEAD commit works as expected. - * - * @param {Object} test */ exports.masterHead = function(test) { test.expect(2); git.repo('../.git', function(error, repository) { repository.branch('master', function(error, branch) { - test.equals(error, 0, 'Getting branch should not error'); + test.equals(error, null, 'Getting branch should not error'); repository.commit(branch.sha, function(error, commit) { - test.equals(error, 0, 'Getting latest branch commit should not error'); + test.equals(error, null, 'Getting latest branch commit should not error'); test.done(); }); @@ -116,7 +103,7 @@ exports.parentSync = function(test) { git.repo('../.git', function(error, repository) { repository.commit('2d71044741412280370cb0326c96d3a5a7b5dca1', function(error, commit) { test.equals(commit.parentCount, 1, 'Commit has exactly one parent'); - var parent = commit.parentSync(0) + var parent = commit.parentSync(0); test.equals(parent.sha, 'e8876707938abf94d5cc02b0c4017c4fec2aa44e', 'Parent SHA should match expected value'); test.done(); }); @@ -145,8 +132,6 @@ exports.parent = function(test) { /** * Test that retrieving and walking a commit's tree works as expected. - * - * @param {Object} test */ exports.tree = function(test) { test.expect(2); @@ -154,7 +139,7 @@ exports.tree = function(test) { repository.commit(historyCountKnownSHA, function(error, commit) { - test.equals(error, 0, 'Getting latest branch commit should not error'); + test.equals(error, null, 'Getting latest branch commit should not error'); var commitTreeEntryCount = 0; var expectedCommitTreeEntryCount = 200; @@ -170,3 +155,18 @@ exports.tree = function(test) { }); }); }; + +/** + * Test that parentsDiffTrees works as expected. + */ +exports.parentsDiffTrees = function(test) { + test.expect(1); + git.repo('../.git', function(error, repository) { + repository.commit(historyCountKnownSHA, function(error, commit) { + commit.parentsDiffTrees(function(error, parentsDiffTrees) { + test.equals(parentsDiffTrees.length, 1, 'Should be one item in parents diff trees'); + test.done(); + }); + }); + }); +}; diff --git a/test/convenience-error.js b/test/convenience-error.js index c2152f1aa..cb1b10cca 100644 --- a/test/convenience-error.js +++ b/test/convenience-error.js @@ -1,6 +1,6 @@ -var git = require('../'); -var rimraf = require('rimraf'); -var fs = require( 'fs' ); +var git = require('../'), + rimraf = require('rimraf'), + fs = require( 'fs' ); // Helper functions var helper = { @@ -30,9 +30,7 @@ var helper = { */ exports.method = function(test){ test.expect(2); - helper.testFunction(test.equals, git.error, 'Error'); - test.done(); }; @@ -44,11 +42,8 @@ exports.method = function(test){ exports.improperCommitId = function(test) { test.expect(1); git.repo('../.git', function(error, repository) { - repository.commit('not a proper commit sha', function(error, commit) { - test.notEqual(error.code, git.error.GIT_SUCCESS, 'Attempting to get commit by invalid SHA should error'); - test.done(); }); }); diff --git a/test/convenience-repo.js b/test/convenience-repo.js index d9f359dce..94e9eb4a6 100644 --- a/test/convenience-repo.js +++ b/test/convenience-repo.js @@ -1,6 +1,6 @@ -var git = require( '../' ); -var rimraf = require('rimraf'); -var fs = require( 'fs' ); +var git = require('../'), + rimraf = require('rimraf'), + fs = require( 'fs' ); // Helper functions var helper = { @@ -16,16 +16,17 @@ var helper = { try { fun(); test(false, label); - } - catch (ex) { + } catch (ex) { test(true, label); } } }; -// Repo -// Ensure the repo method can handle opening repositories with async/sync -// signatures properly. +/** + * Repo + * Ensure the repo method can handle opening repositories with async/sync + * signatures properly. + */ exports.method = function(test){ test.expect(5); @@ -37,22 +38,36 @@ exports.method = function(test){ }, 'Throw an exception if no callback'); // Test invalid repository - git.repo('/etc/hosts', function(err, path) { - test.equals('The specified repository is invalid', err.message, 'Invalid repository error code'); + git.repo('/etc/hosts', function(error, path) { + test.equals(error.code, error.GITERR_REPOSITORY, error.message, 'Invalid repository error code'); // Test valid repository - git.repo('../.git', function(err, path) { - test.equals(0, err, 'Valid repository error code'); - + git.repo('../.git', function(error, path) { + test.equals(null, error, 'Valid repository error code'); test.done(); }); }); }; -// Repo::Init -// Ensure the init method can create repositories at the destination path and -// can create either bare/non-bare. This should work async/sync and provide -// the proper return values. +/** + * Ensure repo doesn't attempt to open missing directories + */ +exports.nonexistentDirectory = function(test) { + test.expect(2); + git.repo('/surely/this/directory/does/not/exist/on/this/machine', function(error, repository) { + test.notEqual(error, null, 'Attempting to open a nonexistent directory should error'); + test.equals(repository, null, 'Non existent directory should result in null repository'); + test.done(); + }); +}; + +/** + * Repo::Init + * + * Ensure the init method can create repositories at the destination path and + * can create either bare/non-bare. This should work async/sync and provide + * the proper return values. + */ exports.init = function(test) { test.expect(4); @@ -61,11 +76,11 @@ exports.init = function(test) { // Cleanup, remove test repo directory - if it exists rimraf('./test.git', function() { // Create bare repo and test for creation - git.repo().init('./test.git', true, function(err, path, isBare) { - test.equals(0, err, 'Successfully created bare repository'); + git.repo().init('./test.git', true, function(error, path, isBare) { + test.equals(null, error, 'Successfully created bare repository'); // Verify repo exists - git.repo('./test.git', function(err, path, repo) { - test.equals(0, err, 'Valid repository created'); + git.repo('./test.git', function(error, path, repo) { + test.equals(null, error, 'Valid repository created'); // Cleanup, remove test repo directory rimraf('./test.git', test.done); diff --git a/test/convenience-tree.js b/test/convenience-tree.js index d97e51b0e..5144a0137 100644 --- a/test/convenience-tree.js +++ b/test/convenience-tree.js @@ -1,6 +1,6 @@ -var git = require('../'); -var rimraf = require('rimraf'); -var fs = require('fs'); +var git = require('../'), + rimraf = require('rimraf'), + fs = require('fs'); var sha = '5716e9757886eaf38d51c86b192258c960d9cfea'; var fileCount = 513; diff --git a/test/raw-blob.js b/test/raw-blob.js index eab916974..c8ba41a71 100644 --- a/test/raw-blob.js +++ b/test/raw-blob.js @@ -1,173 +1,173 @@ -var git = require( '../' ).raw - , path = require( 'path' ) - , rimraf = require('rimraf'); +var git = require('../').raw, + path = require('path'), + rimraf = require('rimraf'); var testRepo = new git.Repo(); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, - // Test code and handle exception thrown - testException: function( test, fun, label ) { + // Test code and handle exception thrown + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; // Blob -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Blob, 'Blob' ); + helper.testFunction(test.equals, git.Blob, 'Blob'); // Ensure we get an instance of Blob - test.ok( new git.Blob() instanceof git.Blob, 'Invocation returns an instance of Blob' ); + test.ok(new git.Blob() instanceof git.Blob, 'Invocation returns an instance of Blob'); test.done(); }; // Blob::Lookup -exports.lookup = function( test ) { - var testOid = new git.Oid() - , testRef = new git.Ref( testRepo ) - , testBlob = new git.Blob(); +exports.lookup = function(test) { + var testOid = new git.Oid(), + testRef = new git.Ref(testRepo), + testBlob = new git.Blob(); - test.expect( 5 ); + test.expect(5); // Test for function - helper.testFunction( test.equals, testBlob.lookup, 'Blob::Lookup' ); + helper.testFunction(test.equals, testBlob.lookup, 'Blob::Lookup'); // Test repo argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { testBlob.lookup(); - }, 'Throw an exception if no repo Object' ); + }, 'Throw an exception if no repo Object'); // Test Oid argument existence - helper.testException( test.ok, function() { - testBlob.lookup( testRepo ); - }, 'Throw an exception if no oid Object' ); + helper.testException(test.ok, function() { + testBlob.lookup(testRepo); + }, 'Throw an exception if no oid Object'); // Test Callback argument existence - helper.testException( test.ok, function() { - testBlob.lookup( testRepo, testOid ); - }, 'Throw an exception if no callback Object' ); + helper.testException(test.ok, function() { + testBlob.lookup(testRepo, testOid); + }, 'Throw an exception if no callback Object'); - testRepo.open( path.resolve( '../.git' ), function() { + testRepo.open(path.resolve('../.git'), function() { - //testOid.mkstr( '59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5' ); + //testOid.mkstr('59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5'); - //testCommit.lookup( testRepo, testOid, function( err ) { - // var tree = new git.Tree( testRepo ) + //testCommit.lookup(testRepo, testOid, function(err) { + // var tree = new git.Tree(testRepo) // , entry = new git.TreeEntry() - // , blob = new git.Blob( testRepo ); + // , blob = new git.Blob(testRepo); - // if( !testCommit.tree( tree ) && tree.entryCount() > 1 ) { - // tree.entryByIndex( entry, 1 ); - // entry.toObject( testRepo, blob ); + // if(!testCommit.tree(tree) && tree.entryCount() > 1) { + // tree.entryByIndex(entry, 1); + // entry.toObject(testRepo, blob); - // //console.log( entry.name() + ':' ); - // //console.log( blob.rawSize() ); - // //console.dir( blob.rawContent() ); + // //console.log(entry.name() + ':'); + // //console.log(blob.rawSize()); + // //console.dir(blob.rawContent()); // } //}); test.done(); - + }); }; // Blob::RawContent -exports.rawContent = function( test ) { +exports.rawContent = function(test) { var testOid = new git.Oid() , testBlob = new git.Blob() , testCommit = new git.Commit(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testBlob.rawContent, 'Blob::RawContent' ); + helper.testFunction(test.equals, testBlob.rawContent, 'Blob::RawContent'); - testRepo.open( path.resolve( '../.git' ), function() { - testOid.mkstr( '59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5' ); + testRepo.open(path.resolve('../.git'), function() { + testOid.mkstr('59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5'); - testCommit.lookup( testRepo, testOid, function( err ) { - var tree = new git.Tree( testRepo ), + testCommit.lookup(testRepo, testOid, function(err) { + var tree = new git.Tree(testRepo), entry = new git.TreeEntry(), - blob = new git.Blob( testRepo ); + blob = new git.Blob(testRepo); - //if( !testCommit.tree( tree ) && tree.entryCount() > 1 ) { - // tree.entryByIndex( entry, 1 ); - // entry.toObject( testRepo, blob ); + //if(!testCommit.tree(tree) && tree.entryCount() > 1) { + // tree.entryByIndex(entry, 1); + // entry.toObject(testRepo, blob); - // //console.log( entry.name() + ':' ); - // //console.log( blob.rawSize() ); - // //console.dir( blob.rawContent() ); + // //console.log(entry.name() + ':'); + // //console.log(blob.rawSize()); + // //console.dir(blob.rawContent()); //} }); }); - + test.done(); }; // Blob::RawSize -exports.rawSize = function( test ) { +exports.rawSize = function(test) { var testOid = new git.Oid(), testBlob = new git.Blob(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testBlob.rawSize, 'Blob::RawSize' ); - + helper.testFunction(test.equals, testBlob.rawSize, 'Blob::RawSize'); + test.done(); }; // Blob::Close -exports.close = function( test ) { +exports.close = function(test) { var testOid = new git.Oid(), testBlob = new git.Blob(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testBlob.close, 'Blob::Close' ); - + helper.testFunction(test.equals, testBlob.close, 'Blob::Close'); + test.done(); }; // Blob::CreateFromFile -exports.createFromFile = function( test ) { +exports.createFromFile = function(test) { var testOid = new git.Oid(), testBlob = new git.Blob(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testBlob.createFromFile, 'Blob::Close' ); - + helper.testFunction(test.equals, testBlob.createFromFile, 'Blob::Close'); + test.done(); }; // Blob::CreateFromBuffer -exports.createFromBuffer = function( test ) { +exports.createFromBuffer = function(test) { var testOid = new git.Oid(), testBlob = new git.Blob(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testBlob.createFromBuffer, 'Blob::CreateFromBuffer' ); - + helper.testFunction(test.equals, testBlob.createFromBuffer, 'Blob::CreateFromBuffer'); + test.done(); }; diff --git a/test/raw-commit.js b/test/raw-commit.js index e1a3c23a6..e66443ca5 100644 --- a/test/raw-commit.js +++ b/test/raw-commit.js @@ -1,89 +1,143 @@ -var git = require( '../' ).raw, - rimraf = require( 'rimraf' ), - path = require( 'path' ); +var git = require('../').raw, + rimraf = require('rimraf'), + path = require('path'); var testRepo = new git.Repo(); -// Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, - // Test code and handle exception thrown - testException: function( test, fun, label ) { + // Test code and handle exception thrown + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; -// Commit -exports.constructor = function( test ){ - test.expect( 3 ); +/** + * Commit + */ +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Commit, 'Commit' ); - - testRepo.open( path.resolve( '../.git' ), function( err ) { + helper.testFunction(test.equals, git.Commit, 'Commit'); + + testRepo.open(path.resolve('../.git'), function(err) { // Ensure we get an instance of Commit - test.ok( new git.Commit( testRepo ) instanceof git.Commit, 'Invocation returns an instance of Commit' ); + test.ok(new git.Commit(testRepo) instanceof git.Commit, 'Invocation returns an instance of Commit'); test.done(); }); }; -// Commit::Lookup -exports.lookup = function( test ) { +/** + * Commit::Lookup + */ +exports.lookup = function(test) { var testOid = new git.Oid(), testCommit = new git.Commit(); - testOid.mkstr( 'cb09e99e91d41705197e0fb60823fdc7df776691' ); + testOid.mkstr('cb09e99e91d41705197e0fb60823fdc7df776691'); - test.expect( 8 ); + test.expect(8); // Test for function - helper.testFunction( test.equals, testCommit.lookup, 'Commit::Lookup' ); + helper.testFunction(test.equals, testCommit.lookup, 'Commit::Lookup'); // Test repo argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { testCommit.lookup(); - }, 'Throw an exception if no repo' ); + }, 'Throw an exception if no repo'); // Test oid argument existence - helper.testException( test.ok, function() { - testCommit.lookup( testRepo ); - }, 'Throw an exception if no oid' ); + helper.testException(test.ok, function() { + testCommit.lookup(testRepo); + }, 'Throw an exception if no oid'); // Test callback argument existence - helper.testException( test.ok, function() { - testCommit.lookup( testOid ); - }, 'Throw an exception if no callback' ); + helper.testException(test.ok, function() { + testCommit.lookup(testOid); + }, 'Throw an exception if no callback'); // Test that all arguments result correctly - helper.testException( test.ifError, function() { - testCommit.lookup( testRepo, testOid, function() {} ); - }, 'No exception is thrown with proper arguments' ); + helper.testException(test.ifError, function() { + testCommit.lookup(testRepo, testOid, function() {}); + }, 'No exception is thrown with proper arguments'); - testRepo.open( path.resolve( '../.git' ), function() { + testRepo.open(path.resolve('../.git'), function() { // Test invalid commit - testOid.mkstr( '100644' ); - testCommit.lookup( testRepo, testOid, function( err ) { - test.notEqual( 0, err, 'Not a valid commit' ); - + testOid.mkstr('100644'); + testCommit.lookup(testRepo, testOid, function(err) { + test.notEqual(0, err, 'Not a valid commit'); + // Test valid commit - testOid.mkstr( 'cb76e3c030ab29db332aff3b297dc39451a84762' ); - testCommit.lookup( testRepo, testOid, function( err ) { - test.equals( 0, err, 'Valid commit'); + testOid.mkstr('cb76e3c030ab29db332aff3b297dc39451a84762'); + testCommit.lookup(testRepo, testOid, function(err) { + test.equals(null, err, 'Valid commit'); + + //test.equals('Updated gitignore and raw-commit test', testCommit.messageShort(), 'Commit message is valid'); + + test.done(); + }); + }); + }); +}; - //test.equals( 'Updated gitignore and raw-commit test', testCommit.messageShort(), 'Commit message is valid' ); +exports.fetchDetails = function(test) { + + test.expect(14); + + var testOid = new git.Oid(); + testOid.mkstr('cb76e3c030ab29db332aff3b297dc39451a84762'); + testRepo.open(path.resolve('../.git'), function() { + var testCommit = new git.Commit(); + testCommit.lookup(testRepo, testOid, function(error, commit) { + commit.fetchDetails(function(error, details) { + + var expected = { + sha: 'cb76e3c030ab29db332aff3b297dc39451a84762', + message: 'bumped package.json up\n', + time: 1300145116, + timeOffset: -240, + committer: + { name: 'Tim Branyen', + email: 'tim.branyen@gmail.com', + when: { time: 1300145116, offset: -240 } }, + author: + { name: 'Tim Branyen', + email: 'tim.branyen@gmail.com', + when: { time: 1300145116, offset: -240 } }, + parentCount: 1, + parentShas: [ 'b1f941c62f508db5f392a6bb0ea1d591753a045b' ] }; + + test.equals(expected.sha, details.sha, 'Expected SHA does not match result'); + test.equals(expected.message, details.message, 'Expected message does not match result'); + test.equals(expected.time, details.time, 'Expected time does not match result'); + test.equals(expected.offset, details.offset, 'Expected offset does not match result'); + + test.equals(expected.committer.name, details.committer.name, 'Expected committer.name does not match result'); + test.equals(expected.committer.email, details.committer.email, 'Expected committer.email does not match result'); + test.equals(expected.committer.when.time, details.committer.when.time, 'Expected committer.when.time does not match result'); + test.equals(expected.committer.when.offset, details.committer.when.offset, 'Expected committer.when.offset does not match result'); + + test.equals(expected.author.name, details.author.name, 'Expected author.name does not match result'); + test.equals(expected.author.email, details.author.email, 'Expected author.email does not match result'); + test.equals(expected.author.when.time, details.author.when.time, 'Expected author.when.time does not match result'); + test.equals(expected.author.when.offset, details.author.when.offset, 'Expected author.when.offset does not match result'); + + test.equals(expected.parentCount, details.parentCount, 'Expected parentCount does not match result'); + test.equals(expected.parentShas[0], details.parentShas[0], 'Expected parentShas[0] does not match result'); test.done(); }); diff --git a/test/raw-error.js b/test/raw-error.js index 075a3d805..3c23a4244 100644 --- a/test/raw-error.js +++ b/test/raw-error.js @@ -1,64 +1,67 @@ -var git = require( '../' ).raw, +var git = require('../').raw, rimraf = require('rimraf'); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, // Test code and handle exception thrown - testException: function( test, fun, label ) { + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; // Error -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Error, 'Error' ); + helper.testFunction(test.equals, git.Error, 'Error'); // Ensure we get an instance of Error - test.ok( new git.Error() instanceof git.Error, 'Invocation returns an instance of Error' ); + test.ok(new git.Error() instanceof git.Error, 'Invocation returns an instance of Error'); test.done(); }; -// Error::StrError -exports.str_error = function( test ) { - var testError = new git.Error(); +exports.codes = function(test) { + test.expect(23); - test.expect( 6 ); + test.equals(git.Error.returnCodes.GIT_OK, 0, 'GIT_OK should equal 0'), + test.equals(git.Error.returnCodes.GIT_ERROR, -1, 'GIT_ERROR should equal -1'), + test.equals(git.Error.returnCodes.GIT_ENOTFOUND, -3, 'GIT_ENOTFOUND should equal -3'), + test.equals(git.Error.returnCodes.GIT_EEXISTS, -4, 'GIT_EEXISTS should equal -4'), + test.equals(git.Error.returnCodes.GIT_EAMBIGUOUS, -5, 'GIT_EAMBIGUOUS should equal -5'), + test.equals(git.Error.returnCodes.GIT_EBUFS, -6, 'GIT_EBUFS should equal -6'), + test.equals(git.Error.returnCodes.GIT_PASSTHROUGH, -30, 'GIT_PASSTHROUGH should equal -30'), + test.equals(git.Error.returnCodes.GIT_ITEROVER, -31, 'GIT_ITEROVER should equal -31'), - // Test for function - helper.testFunction( test.equals, testError.strError, 'Error::StrError' ); - - // Test path argument existence - helper.testException( test.ok, function() { - testError.strError(); - }, 'Throw an exception if no error code' ); - - // Test that arguments result correctly - helper.testException( test.ifError, function() { - testError.strError( 0 ); - }, 'No exception is thrown with proper arguments' ); - - // Finding an actual error - test.equals( 'Input was not a properly formatted Git object id.', testError.strError( -2 ), 'Returns proper error message per code.' ); - - // Returning a consistent error message for all unknown errors - test.equals( 'Unknown error', testError.strError( 1000 ), 'Returns consistent error message with an unknown.' ); + test.equals(git.Error.codes.GITERR_NOMEMORY, 0, 'GITERR_NOMEMORY should equal 0'); + test.equals(git.Error.codes.GITERR_OS, 1, 'GITERR_OS should equal 1'); + test.equals(git.Error.codes.GITERR_INVALID, 2, 'GITERR_INVALID should equal 2'); + test.equals(git.Error.codes.GITERR_REFERENCE, 3, 'GITERR_REFERENCE should equal 3'); + test.equals(git.Error.codes.GITERR_ZLIB, 4, 'GITERR_ZLIB should equal 4'); + test.equals(git.Error.codes.GITERR_REPOSITORY, 5, 'GITERR_REPOSITORY should equal 5'); + test.equals(git.Error.codes.GITERR_CONFIG, 6, 'GITERR_CONFIG should equal 6'); + test.equals(git.Error.codes.GITERR_REGEX, 7, 'GITERR_REGEX should equal 7'); + test.equals(git.Error.codes.GITERR_ODB, 8, 'GITERR_ODB should equal 8'); + test.equals(git.Error.codes.GITERR_INDEX, 9, 'GITERR_INDEX should equal 9'); + test.equals(git.Error.codes.GITERR_OBJECT, 10, 'GITERR_OBJECT should equal 10'); + test.equals(git.Error.codes.GITERR_NET, 11, 'GITERR_NET should equal 11'); + test.equals(git.Error.codes.GITERR_TAG, 12, 'GITERR_TAG should equal 12'); + test.equals(git.Error.codes.GITERR_TREE, 13, 'GITERR_TREE should equal 13'); + test.equals(git.Error.codes.GITERR_INDEXER, 14, 'GITERR_INDEXER should equal 14'); test.done(); }; diff --git a/test/raw-object.js b/test/raw-object.js index 7a04f76f7..df9235a8b 100644 --- a/test/raw-object.js +++ b/test/raw-object.js @@ -1,23 +1,23 @@ -var git = require( '../' ).raw, +var git = require('../').raw, rimraf = require('rimraf'); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, // Test code and handle exception thrown - testException: function( test, fun, label ) { + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; @@ -25,14 +25,14 @@ var helper = { var repo = new git.Repo(); // Obj -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Object, 'GitObject' ); + helper.testFunction(test.equals, git.Object, 'GitObject'); // Ensure we get an instance of Obj - test.ok( new git.Object() instanceof git.Object, 'Invocation returns an instance of GitObject' ); + test.ok(new git.Object() instanceof git.Object, 'Invocation returns an instance of GitObject'); test.done(); }; diff --git a/test/raw-oid.js b/test/raw-oid.js index 3ebf4fdaa..20219a6f8 100644 --- a/test/raw-oid.js +++ b/test/raw-oid.js @@ -1,98 +1,98 @@ -var git = require( '../' ).raw, +var git = require('../').raw, rimraf = require('rimraf'); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, // Test code and handle exception thrown - testException: function( test, fun, label ) { + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; // Oid -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Oid, 'Oid' ); + helper.testFunction(test.equals, git.Oid, 'Oid'); // Ensure we get an instance of Oid - test.ok( new git.Oid() instanceof git.Oid, 'Invocation returns an instance of Oid' ); + test.ok(new git.Oid() instanceof git.Oid, 'Invocation returns an instance of Oid'); test.done(); }; // Oid::Mkstr -exports.mkstr = function( test ) { +exports.mkstr = function(test) { var testOid = new git.Oid(); - test.expect( 6 ); + test.expect(6); // Test for function - helper.testFunction( test.equals, testOid.mkstr, 'Oid::Mkstr' ); + helper.testFunction(test.equals, testOid.mkstr, 'Oid::Mkstr'); // Test path argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { testOid.mkstr(); - }, 'Throw an exception if no hex String' ); + }, 'Throw an exception if no hex String'); // Test that both arguments result correctly - helper.testException( test.ifError, function() { - testOid.mkstr( "somestr" ); - }, 'No exception is thrown with proper arguments' ); + helper.testException(test.ifError, function() { + testOid.mkstr("somestr"); + }, 'No exception is thrown with proper arguments'); // Test invalid hex id string - test.equals( -2, testOid.mkstr( '1392DLFJIOS' ), 'Invalid hex id String' ); + test.equals(git.Error.returnCodes.GIT_ERROR, testOid.mkstr('1392DLFJIOS'), 'Invalid hex id String'); // Test valid hex id string - test.equals( 0, testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ), 'Valid hex id String' ); + test.equals(git.Error.returnCodes.GIT_OK, testOid.mkstr('1810DFF58D8A660512D4832E740F692884338CCD'), 'Valid hex id String'); test.done(); }; // Oid::Fmt -exports.fmt = function( test ) { +exports.fmt = function(test) { var testOid = new git.Oid(); - test.expect( 3 ); + test.expect(3); // Test for function - helper.testFunction( test.equals, testOid.fmt, 'Oid::Fmt' ); + helper.testFunction(test.equals, testOid.fmt, 'Oid::Fmt'); // Test valid hex id string - testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ); + testOid.mkstr('1810DFF58D8A660512D4832E740F692884338CCD'); // Slight hackery to get this to work... should investigate oid fmt - test.equals( '1810DFF58D8A660512D4832E740F692884338CCD', testOid.fmt().substring(0, 40).toUpperCase(), 'Valid hex id String' ); + test.equals('1810DFF58D8A660512D4832E740F692884338CCD', testOid.fmt().substring(0, 40).toUpperCase(), 'Valid hex id String'); test.done(); }; // Oid::Fmt -exports.toString = function( test ) { +exports.toString = function(test) { var testOid = new git.Oid(); - test.expect( 3 ); + test.expect(3); // Test for function - helper.testFunction( test.equals, testOid.toString, 'Oid::ToString' ); + helper.testFunction(test.equals, testOid.toString, 'Oid::ToString'); // Test valid hex id string - testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ); - test.equals( '1810DFF58D8A660512D4832E740F692884338CCD', testOid.toString( 40 ).toUpperCase(), 'Valid hex id String' ); + testOid.mkstr('1810DFF58D8A660512D4832E740F692884338CCD'); + test.equals('1810DFF58D8A660512D4832E740F692884338CCD', testOid.toString(40).toUpperCase(), 'Valid hex id String'); test.done(); }; diff --git a/test/raw-reference.js b/test/raw-reference.js index 08b003979..06afa0aaa 100644 --- a/test/raw-reference.js +++ b/test/raw-reference.js @@ -1,79 +1,79 @@ -var git = require( '../' ).raw, +var git = require('../').raw, rimraf = require('rimraf'); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, - // Test code and handle exception thrown - testException: function( test, fun, label ) { + // Test code and handle exception thrown + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; // Ref -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Ref, 'Ref' ); - + helper.testFunction(test.equals, git.Ref, 'Ref'); + // Ensure we get an instance of Ref - test.ok( new git.Ref() instanceof git.Ref, 'Invocation returns an instance of Ref' ); + test.ok(new git.Ref() instanceof git.Ref, 'Invocation returns an instance of Ref'); test.done(); }; // Ref::Lookup -exports.lookup = function( test ) { +exports.lookup = function(test) { var testRepo = new git.Repo(), master = new git.Ref(); - test.expect( 5 ); + test.expect(5); // Test for function - helper.testFunction( test.equals, master.lookup, 'Ref::Lookup' ); + helper.testFunction(test.equals, master.lookup, 'Ref::Lookup'); // Test repo argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { master.lookup(); - }, 'Throw an exception if no repo' ); - + }, 'Throw an exception if no repo'); + // Test name argument existence - helper.testException( test.ok, function() { - master.lookup( testRepo ); - }, 'Throw an exception if no name' ); + helper.testException(test.ok, function() { + master.lookup(testRepo); + }, 'Throw an exception if no name'); // Test callback argument existence - helper.testException( test.ok, function() { - master.lookup( testRepo, 'refs/heads/master' ); - }, 'Throw an exception if no callback' ); + helper.testException(test.ok, function() { + master.lookup(testRepo, 'refs/heads/master'); + }, 'Throw an exception if no callback'); // Cleanup, remove test repo directory - if it exists - rimraf( './test.git', function() { + rimraf('./test.git', function() { // // Create bare repo and test for creation - // testRepo.init( './test.git', true, function( err, path, is_bare ) { - // test.equals( 0, err, 'Successfully created bare repository' ); + // testRepo.init('./test.git', true, function(err, path, is_bare) { + // test.equals(0, err, 'Successfully created bare repository'); // // Verify repo exists - // testRepo.open( './test.git', function(err, path) { - // test.equals( 0, err, 'Valid repository created' ); - // test.equals( true, is_bare, 'Returns valid is_bare value' ); + // testRepo.open('./test.git', function(err, path) { + // test.equals(0, err, 'Valid repository created'); + // test.equals(true, is_bare, 'Returns valid is_bare value'); - // testRepo.free(); + // testRepo.free(); // // Cleanup, remove test repo directory - // rimraf( './test.git', function() { + // rimraf('./test.git', function() { test.done(); // }); // }); diff --git a/test/raw-repo.js b/test/raw-repo.js index 20fc927d3..b6c475e21 100644 --- a/test/raw-repo.js +++ b/test/raw-repo.js @@ -1,71 +1,68 @@ -var git = require( '../' ).raw, +var git = require('../').raw, rimraf = require('rimraf'), - path = require( 'path' ), - fs = require( 'fs' ); + path = require('path'), + fs = require('fs'); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, - // Test code and handle exception thrown - testException: function( test, fun, label ) { + // Test code and handle exception thrown + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; // Repo -exports.constructor = function( test ){ - test.expect( 3 ); +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.Repo, 'Repo' ); - + helper.testFunction(test.equals, git.Repo, 'Repo'); + // Ensure we get an instance of Repo - test.ok( new git.Repo() instanceof git.Repo, 'Invocation returns an instance of Repo' ); + test.ok(new git.Repo() instanceof git.Repo, 'Invocation returns an instance of Repo'); test.done(); }; // Repo::Open -exports.open = function( test ) { +exports.open = function(test) { var testRepo = new git.Repo(); - test.expect( 6 ); + test.expect(6); // Test for function - helper.testFunction( test.equals, testRepo.open, 'Repo::Open' ); + helper.testFunction(test.equals, testRepo.open, 'Repo::Open'); // Test path argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { testRepo.open(); - }, 'Throw an exception if no path' ); - + }, 'Throw an exception if no path'); + // Test callback argument existence - helper.testException( test.ok, function() { - testRepo.open( "some/path" ); - }, 'Throw an exception if no callback' ); + helper.testException(test.ok, function() { + testRepo.open('some/path'); + }, 'Throw an exception if no callback'); // Test invalid repository - testRepo.open( '/etc/hosts', function( err ) { - test.equals( -7, err, 'Invalid repository error code' ); + testRepo.open('/etc/hosts', function(error) { + test.equals(git.Error.codes.GIT_ERROR, error.klass, 'Invalid repository error code'); // Test valid repository - testRepo.open( path.resolve( '../.git' ), function( err ) { - test.equals( 0, err, 'Valid repository error code' ); - -// testRepo.free(); - + testRepo.open(path.resolve('../.git'), function(error) { + test.equals(null, error, 'Valid repository error code'); test.done(); }); }); @@ -73,54 +70,54 @@ exports.open = function( test ) { // TODO: Figure out how write unit tests for free // Repo::Free -exports.free = function( test ) { +exports.free = function(test) { var testRepo = new git.Repo(); - test.expect( 2 ); + test.expect(2); // Test for function - helper.testFunction( test.equals, testRepo.free, 'Repo::Free' ); + helper.testFunction(test.equals, testRepo.free, 'Repo::Free'); test.done(); }; // Repo::Init -exports.init = function( test ) { +exports.init = function(test) { var testRepo = new git.Repo(); - test.expect( 7 ); + test.expect(7); // Test for function - helper.testFunction( test.equals, testRepo.init, 'Repo::Init' ); + helper.testFunction(test.equals, testRepo.init, 'Repo::Init'); // Test path argument existence - helper.testException( test.ok, function() { + helper.testException(test.ok, function() { testRepo.init(); - }, 'Throw an exception if no path' ); - + }, 'Throw an exception if no path'); + // Test is_bare argument existence - helper.testException( test.ok, function() { - testRepo.init( "some/path" ); - }, 'Throw an exception if no is_bare' ); + helper.testException(test.ok, function() { + testRepo.init("some/path"); + }, 'Throw an exception if no is_bare'); // Test callback argument existence - helper.testException( test.ok, function() { - testRepo.init( "some/path", true ); - }, 'Throw an exception if no callback' ); + helper.testException(test.ok, function() { + testRepo.init("some/path", true); + }, 'Throw an exception if no callback'); // Cleanup, remove test repo directory - if it exists - rimraf( './test.git', function() { + rimraf('./test.git', function() { // Create bare repo and test for creation - testRepo.init( './test.git', true, function( err, path, is_bare ) { - test.equals( 0, err, 'Successfully created bare repository' ); + testRepo.init('./test.git', true, function(error, path, is_bare) { + test.equals(null, error, 'Successfully created bare repository'); // Verify repo exists - testRepo.open( './test.git', function(err, path) { - test.equals( 0, err, 'Valid repository created' ); + testRepo.open('./test.git', function(error, path) { + test.equals(null, error, 'Valid repository created'); - testRepo.free(); + testRepo.free(); // Cleanup, remove test repo directory - rimraf( './test.git', function() { + rimraf('./test.git', function() { test.done(); }); }); diff --git a/test/raw-revwalk.js b/test/raw-revwalk.js index 4e7ef0f3b..e7338fa32 100644 --- a/test/raw-revwalk.js +++ b/test/raw-revwalk.js @@ -1,4 +1,5 @@ -var git = require( '../' ).raw, +var git = require('../').raw, + path = require('path'), rimraf = require('rimraf'); var testRepo = new git.Repo(); @@ -6,35 +7,36 @@ var testRepo = new git.Repo(); // Helper functions var helper = { // Test if obj is a true function - testFunction: function( test, obj, label ) { + testFunction: function(test, obj, label) { // The object reports itself as a function - test( typeof obj, 'function', label +' reports as a function.' ); + test(typeof obj, 'function', label +' reports as a function.'); // This ensures the repo is actually a derivative of the Function [[Class]] - test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + test(toString.call(obj), '[object Function]', label +' [[Class]] is of type function.'); }, - // Test code and handle exception thrown - testException: function( test, fun, label ) { + // Test code and handle exception thrown + testException: function(test, fun, label) { try { fun(); - test( false, label ); + test(false, label); } catch (ex) { - test( true, label ); + test(true, label); } } }; -// RevWalk -exports.constructor = function( test ){ - test.expect( 3 ); +/** + * RevWalk + */ +exports.constructor = function(test){ + test.expect(3); // Test for function - helper.testFunction( test.equals, git.RevWalk, 'RevWalk' ); - - // Ensure we get an instance of Oid - testRepo.open( './dummyrepo/.git', function( err, path ) { - test.ok( new git.RevWalk( testRepo ) instanceof git.RevWalk, 'Invocation returns an instance of RevWalk' ); + helper.testFunction(test.equals, git.RevWalk, 'RevWalk'); + // Ensure we get an instance of Oid + testRepo.open('../.git', function(error, repository) { + test.ok(new git.RevWalk(repository) instanceof git.RevWalk, 'Invocation returns an instance of RevWalk'); test.done(); }); }; diff --git a/vendor/libgit2 b/vendor/libgit2 index 3eaf34f4c..7dbf4039a 160000 --- a/vendor/libgit2 +++ b/vendor/libgit2 @@ -1 +1 @@ -Subproject commit 3eaf34f4c602b9e155e2f4c6ae26c9250ac37d50 +Subproject commit 7dbf4039ae0881407fc9ead24c09c1d7cfd4103a