@@ -1,24 +1,95 @@
//assumes that the hash you want and the repo are obtainable via closure scope
// repo is assumed to be in closure
var repo ;
function findPrevious ( commit , previousCommit ) {
repo . load ( commit . parents [ 0 ] , function ( err , obj ) {
if ( obj . type !== 'commit' ) {
console . error ( obj ) ;
throw 'Unexpected type returned' ;
// commit - the hash of the current commit
// path - the path to the hash in the current commit
// callback -> the previous blob value
function findPrevious ( commit , path , callback ) {
var log ; // The log stream
var currentBlob ; // The current value of the blob
var oldBlob ; // The last value of the blob
var changeCommit ; // The commit that made the last change to the blob
var oldCommit ; // The previous commit
// First get the log stream
repo . logWalk ( commit , onLog ) ;
function onLog ( err , result ) {
if ( err ) return callback ( err ) ;
log = result ;
// Read the current commit
log . read ( onCurrentCommit ) ;
}
function onCurrentCommit ( err , result ) {
if ( err ) return callback ( err ) ;
changeCommit = result ;
// Find the file by path in the current commit
walkPath ( changeCommit . tree , path , onCurrentBlob ) ;
}
function onCurrentBlob ( err , result ) {
if ( err ) return callback ( err ) ;
currentBlob = result ;
// Start our search loop looking for a change in the next commit
log . read ( onCommit ) ;
}
function onCommit ( err , result ) {
if ( err ) return callback ( err ) ;
oldCommit = result
if ( oldCommit === undefined ) {
// We've reached the beginning of history, this was created in the initial commit
return callback ( null , {
oldBlob : undefined ,
currentBlob : currentBlob ,
changeCommit : changeCommit
} ) ;
}
walkPath ( oldCommit . tree , path , onBlob ) ;
}
function onBlob ( err , result ) {
if ( err ) return callback ( err ) ;
oldBlob = result ;
if ( ( oldBlob && oldBlob . hash ) !== currentBlob . hash ) {
return callback ( null , {
oldBlob : oldBlob ,
currentBlob : currentBlob ,
changeCommit : changeCommit
} ) ;
}
repo . load ( obj . body . tree , function ( err , tree ) {
if ( tree . type !== 'tree' ) {
console . error ( tree ) ;
throw 'Object is not a tree' ;
}
var match = tree . body . filter ( function ( obj ) { return obj . hash == hash ; } ) ;
if ( match . length ) {
console . dir ( match ) ;
findPrevious ( obj . body , commit ) ;
} else {
console . log ( 'we have a winner!' ) ;
console . dir ( obj ) ;
}
} )
} ) ;
}
changeCommit = oldCommit ;
log . read ( onCommit ) ;
}
}
function walkPath ( tree , path , callback ) {
// Remove leading and trailing slashes, '.' entries, and split artifacts.
var names = path . split ( "/" ) . filter ( cleanPath ) ;
repo . loadAs ( "tree" , tree , onTree ) ;
function onTree ( err , tree ) {
if ( err ) return callback ( err ) ;
var name = names . shift ( ) ;
var entry = findByName ( tree , name ) ;
// return undefined for not-found errors
if ( ! entry ) return callback ( ) ;
// If there are still segments left, keep reading tree paths
if ( names . length ) return repo . loadAs ( "tree" , entry . hash , onTree ) ;
// Otherwise, load and return the blob
repo . loadAs ( "blob" , entry . hash , callback ) ;
}
}
function findByName ( tree , name ) {
for ( var i = 0 , l = tree . length ; i < l ; i ++ ) {
var entry = tree [ i ] ;
if ( entry . name === name ) return entry ;
}
}
function cleanPath ( name ) {
return name && name !== "." ;
}