Permalink
Browse files

clone now resolves HEAD ref commit tree and checks it out into workin…

…g directory.
  • Loading branch information...
1 parent 8c180d5 commit 88b6576045cf88944abf6ccc8c22fcd2303f92cd @samcday samcday committed Jun 2, 2012
Showing with 84 additions and 34 deletions.
  1. +74 −26 coffee/gitteh.coffee
  2. +1 −1 examples/clone.js
  3. +0 −1 examples/load_commit.js
  4. +9 −6 examples/load_commit_tree.js
View
100 coffee/gitteh.coffee
@@ -1,5 +1,7 @@
{EventEmitter} = require "events"
async = require "async"
+fs = require "fs"
+_path = require "path"
args = require "./args"
bindings = require "../build/Debug/gitteh"
@@ -48,7 +50,7 @@ Signature = (obj) ->
Gitteh.Refspec = Refspec = (src, dst) ->
srcRoot = src
- srcRoot = srcRoot[0...-1] if srcRoot[-1..] is "*"
+ srcRoot = srcRoot[0...-1] if srcRoot? and srcRoot[-1..] is "*"
immutable(@, {src, dst})
.set("src")
@@ -113,8 +115,7 @@ Gitteh.Tag = Tag = (@repository, obj) ->
Gitteh.Remote = Remote = (@repository, nativeRemote) ->
if nativeRemote not instanceof NativeRemote
throw new Error "Don't construct me, see Repository.remote()"
- nativeRemote.fetchSpec = new Refspec nativeRemote.fetchSpec.src, nativeRemote.fetchSpec.dst
- nativeRemote.pushSpec = new Refspec nativeRemote.pushSpec.src, nativeRemote.pushSpec.dst
+
connected = false
Object.defineProperty @, "connected",
@@ -125,8 +126,13 @@ Gitteh.Remote = Remote = (@repository, nativeRemote) ->
immutable(@, nativeRemote)
.set("name")
.set("url")
+
+ fetchSpec = new Refspec nativeRemote.fetchSpec.src, nativeRemote.fetchSpec.dst
+ pushSpec = new Refspec nativeRemote.pushSpec.src, nativeRemote.pushSpec.dst
+ immutable(@, {fetchSpec, pushSpec})
.set("fetchSpec")
.set("pushSpec")
+
@connect = =>
[dir, cb] = args
dir: type: "remoteDir"
@@ -140,33 +146,34 @@ Gitteh.Remote = Remote = (@repository, nativeRemote) ->
for ref, oid of refs
continue if ref is "HEAD"
if oid is headOid
- immutable(@, {ref}).set "ref", "HEAD"
+ headRef = fetchSpec.transform ref
+ immutable(@, {headRef}).set "headRef", "HEAD"
break
immutable(@, {refNames}).set "refNames", "refs"
connected = true
cb()
@fetch = =>
throw new Error "Remote isn't connected." if not connected
+ [progressCb, cb] = args
+ progressCb: type: "function"
+ cb: type: "function"
updateTimer = null
update = =>
{bytes, total, done} = nativeRemote.stats
- @emit "progress", bytes, total, done
+ progressCb bytes, total, done
updateTimer = setTimeout update, 500
setTimeout update, 500
nativeRemote.download (err) =>
clearTimeout updateTimer
- return @emit "error", err if err?
- nativeRemote.updateTips =>
- return @emit "error", err if err?
- @emit "complete"
+ return cb err if err?
+ nativeRemote.updateTips wrapCallback cb, =>
+ cb()
return @
-Remote.prototype = EventEmitter.prototype
-
wrapCallback = (orig, cb) ->
return (err) ->
return orig err if err?
@@ -250,28 +257,69 @@ Gitteh.clone = =>
emitter = new EventEmitter
async.waterfall [
+ # Initialize a fresh repo in the path specified.
(cb) -> Gitteh.initRepository path, false, cb
+
+ # Create the origin remote with provided URL.
(repo, cb) ->
repo.createRemote "origin", url, wrapCallback cb, (remote) ->
cb null, repo, remote
+
+ # Connect to the remote to commence fetch.
(repo, remote, cb) ->
remote.connect "fetch", wrapCallback cb, ->
cb null, repo, remote
- # TODO: checkout HEAD into working dir.
- ], (err, repo, remote) ->
- remote.fetch wrapCallback cb, ->
+
+ # Perform the actual fetch, sending progress updates as they come in.
+ (repo, remote, cb) ->
+ emitProgress = (bytes, done, complete) ->
+ emitter.emit "status", bytes, done, complete
+ remote.fetch emitProgress, wrapCallback cb, ->
cb null, repo, remote
- errorHandler = (err) ->
- emitter.emit "error", err
- progressHandler = (bytes, done, complete) ->
- emitter.emit "status", bytes, done, complete
- completeHandler = () ->
- remote.removeListener "error", errorHandler
- remote.removeListener "progress", progressHandler
- remote.removeListener "complete", completeHandler
- emitter.emit "complete", repo
- remote.on "error", errorHandler
- remote.on "progress", progressHandler
- remote.on "complete", completeHandler
+
+ # The connect step earlier resolved remote HEAD. Let's fetch that ref.
+ (repo, remote, cb) ->
+ repo.ref remote.HEAD, true, wrapCallback cb, (ref) ->
+ cb null, repo, remote, ref
+
+ # We now have fully resolved OID head ref. Fetch the commit.
+ (repo, remote, headRef, cb) ->
+ repo.commit headRef.target, wrapCallback cb, (commit) ->
+ cb null, repo, remote, commit
+
+ # Now fetch the tree for the commit.
+ (repo, remote, headCommit, cb) ->
+ headCommit.tree wrapCallback cb, (tree) ->
+ cb null, repo, remote, tree
+
+ # Now we can go ahead and checkout this tree into working directory.
+ (repo, remote, headTree, cb) ->
+ handleEntry = (dest, entry, cb) ->
+ if entry.type is "tree"
+ subPath = _path.join dest, entry.name
+ async.series [
+ # TODO: mode?
+ (cb) -> fs.mkdir subPath, cb
+ (cb) ->
+ repo.tree entry.id, wrapCallback cb, (subtree) ->
+ checkoutTree subtree, subPath, cb
+ ], cb
+ else if entry.type is "blob"
+ repo.blob entry.id, wrapCallback cb, (blob) ->
+ file = fs.createWriteStream _path.join(dest, entry.name),
+ mode: entry.attributes
+ file.write blob.data
+ file.end()
+ cb()
+ else
+ cb()
+ checkoutTree = (tree, dest, cb) ->
+ async.forEach tree.entries, handleEntry.bind(null, dest), cb
+ checkoutTree headTree, repo.workingDirectory, wrapCallback cb, ->
+ cb null, repo
+ ], (err, repo) ->
+ return emitter.emit "error", err if err?
+
+ emitter.emit "complete", repo
return emitter
View
2 examples/clone.js
@@ -20,6 +20,6 @@ clone.on("complete", function(repo) {
});
clone.on("error", function(err) {
- console.log("\n");
+ console.log("\n... Error during clone!");
console.error(err);
});
View
1 examples/load_commit.js
@@ -3,7 +3,6 @@ var path = require("path");
gitteh.openRepository(path.join(__dirname, ".."), function(err, repo) {
repo.commit("8a916d5fbce49f5780668a1ee780e0ef2e89360f", function (err, commit) {
- meh = commit;
console.log(commit);
});
});
View
15 examples/load_commit_tree.js
@@ -1,7 +1,10 @@
-gitteh = require "../lib/gitteh"
-path = require "path"
+var gitteh = require("../lib/gitteh");
+var path = require("path");
-gitteh.openRepository path.join(__dirname, ".."), (err, repo) ->
- repo.commit "1f4425ce2a14f21b96b9c8dde5bcfd3733467b14", (err, commit) ->
- commit.tree (err, tree) ->
- console.log tree
+gitteh.openRepository(path.join(__dirname, ".."), function(err, repo) {
+ repo.commit("8a916d5fbce49f5780668a1ee780e0ef2e89360f", function (err, commit) {
+ commit.tree(function(err, tree) {
+ console.log(tree.entries);
+ });
+ });
+});

0 comments on commit 88b6576

Please sign in to comment.