UNPKG

30.1 kBJavaScriptView Raw
1var util = require('util'),
2 fs = require('fs'),
3 GitFileOperations = require('./git_file_operations').GitFileOperations,
4 exec = require('child_process').exec,
5 FileIndex = require('./file_index').FileIndex,
6 Repository = require('./repository').Repository,
7 Difference = require('../diff/diff').Difference;
8
9var Git = exports.Git = function(git_directory) {
10 var _git_diretory = git_directory, _git_file_index;
11 var _repository = new Repository(_git_diretory, {});
12 // Control access to internal variables
13 Object.defineProperty(this, "git_directory", { get: function() { return _git_diretory; }, set: function(value) { _git_diretory = value; }, enumerable: true});
14 Object.defineProperty(this, "git_file_index", { get: function() { return _git_file_index; }, set: function(value) { _git_file_index = value; }, enumerable: true});
15 Object.defineProperty(this, "repository", { get: function() { return _repository; }, set: function(value) { _repository = value; }, enumerable: true});
16}
17
18// Set up the gitbinary
19if(process.platform.toLowerCase().match(/mswin(?!ce)|mingw|bccwin|win32/)) {
20 Git.git_binary = "git";
21} else {
22 Git.git_binary = "/usr/bin/env git";
23}
24
25// Chomp text removing end carriage returns
26var chomp = function chomp(raw_text) {
27 return raw_text ? raw_text.replace(/(\n|\r)+$/, '') : '';
28}
29
30var read_file = function(path, callback) {
31 fs.stat(path, function(err, stat) {
32 if(err) return callback(err, null);
33 fs.readFile(path, 'ascii', callback);
34 })
35}
36
37// Retrieve references
38Git.prototype.refs = function(options, prefix, callback) {
39 var refs = [];
40 var already = {};
41 var self = this;
42
43 // Locate all files in underlying directories
44 var stream = GitFileOperations.glob_streaming(this.git_directory + "/" + prefix);
45 // Triggers on each entry in the directory
46 stream.addListener("data", function(result) {
47 // If we have a directory check if we have a reference file
48 if(result.stat.isFile()) {
49 // Read the file content
50 try {
51 var id = chomp(fs.readFileSync(result.path, 'ascii'));
52 var name = result.path.replace(self.git_directory + "/" + prefix + "/", '');
53
54 if(!already[name]) {
55 refs.push(name + " " + id);
56 already[name] = true;
57 }
58 } catch(err) {
59 // Seems to be some instances where it's not able to tell that a directory is not a file ?
60 }
61 }
62 });
63
64 // Triggers at the end of the call
65 stream.addListener("end", function(err, result) {
66 fs.stat(self.git_directory + "/packed-refs", function(err, stat) {
67 if(err || !stat.isFile()) return callback(null, refs.join("\n"));
68
69 read_file(self.git_directory + "/packed-refs", function(err, data) {
70 var parts = data.split(/\n/);
71 // Scan all lines
72 for(var i = 0; i < parts.length; i++) {
73 var match = parts[i].match(/^(\w{40}) (.*?)$/)
74 if(match) {
75 if(match[2].match("^" + prefix)) {
76 var id = chomp(match[1]);
77 var name = match[2].replace(prefix + "/", '');
78
79 if(!already[name]) {
80 refs.push(name + " " + id);
81 already[name] = true;
82 }
83 }
84 }
85 }
86 // Return all the references
87 callback(null, refs.join("\n"));
88 });
89 })
90 })
91}
92
93// Read a specific file
94Git.prototype.fs_read = function(file, callback) {
95 GitFileOperations.fs_read(this.git_directory, file, callback);
96}
97
98// // Parse revisions
99// Git.prototype.rev_parse = function(options, string, callback) {
100// if(string == null || string.constructor != String) return callback("invalid string: " + string);
101// var self = this;
102//
103// // Make sure we don't have a directory up ..
104// if(string.match(/\.\./)) {
105// var shas = string.split(/\.\./);
106// var sha1 = shas[0], sha2 = shas[1];
107// // Need to rev_parse the two keys and return the data
108// new Simplifier().execute(new ParallelFlow(
109// function(callback) { self.rev_parse({}, sha1, callback); },
110// function(callback) { self.rev_parse({}, sha2, callback); }
111// ), function(sha1_results, sha2_results) {
112// // Return the collected files
113// return callback(null, [sha1_results[1], sha2_results[1]]);
114// });
115// }
116//
117// // If we have a sha being returned nop it
118// if(string.match(/^[0-9a-f]{40}$/)) {
119// return callback(null, chomp(string));
120// }
121//
122// // Check in heads directory
123// read_file(self.git_directory + "/refs/heads/" + string, function(err, data) {
124// if(!err) return fs.readFile(self.git_directory + "/refs/heads/" + string, function(err, data) { callback(err, chomp(data)); });
125// // If not in heads then check in remotes
126// read_file(self.git_directory + "/refs/remotes/" + string, function(err, data) {
127// if(!err) return fs.readFile(self.git_directory + "/refs/remotes/" + string, function(err, data) { callback(err, chomp(data)); });
128// // If not in remotes check in tags
129// read_file(self.git_directory + "/refs/tags/" + string, function(err, data) {
130// if(!err) return fs.readFile(self.git_directory + "/refs/tags/" + string, function(err, data) { callback(err, chomp(data)); });
131//
132// // Not pin any of the main refs, look in packed packed-refs
133// read_file(self.git_directory + "/packed-refs", function(err, data) {
134// if(err) return callback(err, data);
135// // Split the data on new line
136// var ref = null;
137// var parts = data.split(/\n/);
138// // Locate head
139// for(var i = 0; i < parts.length; i++) {
140// var match_parts = parts[i].match(/^(\w{40}) refs\/.+?\/(.*?)$/);
141// if(match_parts) {
142// ref = match_parts[1];
143// // If we have a match fetch reference and return
144// if(new RegExp(string + '$').test(match_parts[3])) {
145// break;
146// }
147// }
148// }
149//
150// // If we have a reference lets terminate
151// if(ref) return callback(null, ref);
152//
153// // !! more partials and such !!
154//
155//
156// // revert to calling git
157// self.call_git('', 'rev-parse', '', options, string, function(err, result) {
158// result = result ? chomp(result) : result;
159// callback(err, result);
160// })
161// });
162// });
163// });
164// });
165// }
166
167Git.prototype.transform_options = function(options) {
168 var args = [];
169 var keys = Object.keys(options);
170
171 // Process all entries
172 Object.keys(options).forEach(function(key) {
173 if(key.length == 1) {
174 if(options[key] == true && options[key].constructor == Boolean) { args.push('-' + key);
175 } else if(options[key] == false && options[key].constructor == Boolean) {
176 } else { args.push('-' + key + ' "' + options[key].toString().replace('"', "\\\"") + '"'); }
177 } else {
178 if(options[key] == true && options[key].constructor == Boolean) { args.push("--" + key.toString().replace(/_/, '-'));
179 } else if(options[key] == false && options[key].constructor == Boolean) {
180 } else { args.push('--' + key.toString().replace(/_/, '-') + '="' + options[key].toString().replace('"', "\\\"") + '"'); }
181 }
182 });
183
184 // Return formated parametes
185 return args;
186}
187
188Git.prototype.git = function() {
189 // Unpack parameters as commit might be null
190 var args = Array.prototype.slice.call(arguments, 0);
191 var callback = args.pop();
192 // Unpack the variables
193 var function_name = args.length ? args.shift() : null;
194 var options = args.length ? args.shift() : {};
195 var arguments = args;
196 // Execute blame command
197 this.call_git('', function_name, '', options, arguments, function(err, result) {
198 callback(err, result);
199 });
200}
201
202var shell_escape = function(str) {
203 return str.toString().replace('"', "\\\"").replace(/\;/g, "\\;");
204}
205
206// Call the native git binary
207Git.prototype.call_git = function(prefix, command, postfix, options, args, callback) {
208 // Do we have a timeout
209 var timeout = options['timeout'] ? timeout : 1000 * 60;
210 var call_string = '';
211 // Remove the timeout property if we have one
212 if(options['timeout']) delete options['timeout'];
213 var option_arguments = this.transform_options(options);
214
215 if(process.platform.toLowerCase().match(/mswin(?!ce)|mingw|bccwin/)) {
216 } else {
217 // Map the extra parameters
218 var ext_args = args.map(function(arg) { return (arg == '--' || arg.substr(0, 1) == '|' ? arg : ('"' + shell_escape(arg) + '"'))})
219 .filter(function(arg) { return arg == null || arg == '' ? false : true});
220 // Join the arguments
221 var final_arguments = option_arguments.concat(ext_args);
222 // Build a call
223 call_string = prefix + Git.git_binary + ' --git-dir="'+ this.git_directory + '" ' + command.toString().replace(/_/, '-') + ' ' + final_arguments.join(" ") + postfix;
224 }
225 // Execute the function
226 execute_git_call(call_string, { encoding: 'utf8', timeout: timeout, killSignal: 'SIGKILL'}, callback);
227}
228
229var execute_git_call = function(call_string, options, callback) {
230 // Execute the git command
231 options.maxBuffer = 1024 * 1024;
232 exec(call_string, options,
233 function (error, stdout, stderr) {
234 if (error != null) {
235 var result = error.toString();
236 callback(result != null ? result.trim() : result, null);
237 } else {
238 var result = stdout.toString();
239 callback(null, result != null ? result.trim() : result)
240 }
241 });
242}
243
244var file_index = function(git, callback) {
245 // If we have a file index object return it otherwise create a new one
246 if(!git.git_file_index) {
247 new FileIndex(git.git_directory, function(err, _file_index) {
248 git.git_file_index = _file_index;
249 callback(null, _file_index);
250 });
251 } else {
252 callback(null, git.git_file_index);
253 }
254}
255
256// Fetch a revision list
257Git.prototype.rev_list = function(options, reference, callback) {
258 var self = this;
259 var args = Array.prototype.slice.call(arguments, 0);
260 var callback = args.pop();
261 options = args.length ? args.shift() : {};
262 reference = args.length ? args.shift() : 'master';
263
264 // Remove skip option if it's set to 0
265 if(options['skip'] != null && parseInt(options['skip']) == 0) delete options['skip'];
266 var allowed_options = {"max_count":1, "since":1, "until":1, "pretty":1};
267 var establish_keys = Object.keys(options).filter(function(key) {
268 return allowed_options[key] ? false : true;
269 });
270
271 // If we have commands we don't support call through to native git
272 if(establish_keys.length > 0) {
273 self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
274 callback(err, result);
275 })
276 } else if(Object.keys(options).length == 0){
277 // Fetch the file index (will create a file index on the first call)
278 file_index(self, function(err, _file_index) {
279 if(err) return callback(err, _file_index);
280 // Parse the revision
281 self.rev_parse({}, reference, 0, function(err, ref) {
282 if(err) return callback(err, ref);
283 // Fetch the commits from the revision passed in
284 _file_index.commits_from(ref, function(err, commits) {
285 if(err) {
286 self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
287 callback(err, result);
288 })
289 } else {
290 callback(null, commits.join("\n") + "\n");
291 }
292 })
293 });
294 })
295 } else {
296 self.rev_parse({}, reference, 0, function(err, ref) {
297 if(err) return callback(err, ref);
298
299 if(Array.isArray(ref)) {
300 self.call_git('', 'rev_list', '', options, [reference], function(err, result) {
301 callback(err, result);
302 })
303 } else {
304 try {
305 // Try to execute revision fetch
306 self.repository.rev_list(ref, options, function(err, result) {
307 callback(err, result);
308 })
309 } catch(err) {
310 callback(err, null);
311 }
312 }
313 });
314 }
315}
316
317// Chomp text removing end carriage returns
318var chomp = function chomp(raw_text) {
319 return raw_text.replace(/(\n|\r)+$/, '');
320}
321
322Git.prototype.rev_parse = function(options, string, level, callback) {
323 if(string != null && string.constructor != String) return callback('only supports single sha reference');
324 var self = this;
325
326 // Allow leaving of level
327 var args = Array.prototype.slice.call(arguments, 2);
328 var callback = args.pop();
329 level = args.length ? args.shift() : 0;
330
331 if(string.match(/\.\./)) {
332 var parts = string.split("..");
333 var sha1 = parts[0], sha2 = parts[1];
334 var value = [this.rev_parse({}, sha1, level + 1, callback), this.rev_parse({}, sha2, level + 1, callback)];
335 if(level == 0) return callback(null, value);
336 }
337
338 // a sha is being passed in, chomp and return
339 if(string.match(/^[0-9a-f]{40}$/)) {
340 var value = chomp(string);
341 if(level == 0) {
342 return callback(null, value);
343 } else {
344 return value;
345 }
346 }
347
348 // Check all the references
349 var head = this.git_directory + "/refs/heads/" + string;
350 try {
351 if(level == 0) {
352 return callback(null, chomp(fs.readFileSync(head, 'utf8')));
353 } else {
354 return chomp(fs.readFileSync(head, 'utf8'));
355 }
356 } catch(err) {}
357
358 var head = this.git_directory + "/refs/remotes/" + string;
359 try {
360 if(level == 0) {
361 return callback(null, chomp(fs.readFileSync(head, 'utf8')));
362 } else {
363 return chomp(fs.readFileSync(head, 'utf8'));
364 }
365 } catch(err) {}
366
367 var head = this.git_directory + "/refs/tags/" + string;
368 try {
369 if(level == 0) {
370 return callback(null, chomp(fs.readFileSync(head, 'utf8')));
371 } else {
372 return chomp(fs.readFileSync(head, 'utf8'));
373 }
374 } catch(err) {}
375
376 // Check packed-refs file, too
377 var packref = this.git_directory + "/packed-refs";
378 try {
379 // Read the file
380 var parts = data.split(/\n/);
381 // Locate head
382 for(var i = 0; i < parts.length; i++) {
383 var match_parts = parts[i].match(/^(\w{40}) refs\/.+?\/(.*?)$/);
384 if(match_parts) {
385 ref = match_parts[1];
386 // If we have a match fetch reference and return
387 if(new RegExp(string + '$').test(match_parts[3])) {
388 if(level == 0) {
389 return callback(null, chomp(ref));
390 } else {
391 return chomp(ref);
392 }
393 }
394 }
395 }
396 } catch(err) {}
397
398 // Wait until we got the git call
399 self.call_git('', 'rev-parse', '', options, [string], function(err, result) {
400 callback(null, result ? chomp(result) : result);
401 })
402}
403
404// List tree content
405Git.prototype.ls_tree = function(treeish, paths, options, callback) {
406 var self = this;
407 var args = Array.prototype.slice.call(arguments, 1);
408 var callback = args.pop();
409 paths = args.length ? args.shift() : [];
410 paths = paths ? paths : [];
411 options = args.length ? args.shift() : {};
412
413 try {
414 // Reverse parse the tree sha
415 this.rev_parse({}, treeish, function(err, sha) {
416 if(err) return callback(err, sha);
417 var tree = self.repository.ls_tree(sha, flatten(paths), options['r']);
418 if(tree == '') return callback('no such sha found', null);
419 // Ls_tree
420 callback(null, tree);
421 })
422 } catch(err) {
423 callback(err, null);
424 }
425}
426
427// Cat a file
428Git.prototype.cat_file = function(type, ref, callback) {
429 if(type == "t") {
430 this.file_type(ref, callback);
431 } else if(type == "s") {
432 this.file_size(ref, callback);
433 } else if(type == "p") {
434 callback(null, this.repository.cat_file(ref));
435 }
436}
437
438Git.prototype.file_size = function(ref, callback) {
439 callback(null, this.repository.cat_file_size(ref));
440}
441
442// Make a directory
443// dir: is the relative path to the directory to create
444//
445// Return nothing
446Git.prototype.fs_mkdir = function(dir, callback) {
447 var path = this.git_directory + "/" + dir;
448 GitFileOperations.fs_mkdir(path, callback);
449}
450
451// Initialize a new git repository (create physical setup)
452Git.prototype.init = function(options, callback) {
453 var self = this;
454 var arguments = Array.prototype.slice(arguments);
455
456 if(Object.keys(options).length == 0) {
457 Repository.init(this.git_directory, callback);
458 } else {
459 // Execute init with call git and return the object
460 this.call_git('', 'init', '', options, arguments, function(err, result) {
461 if(err) return callback(err, result);
462 callback(null, self);
463 });
464 }
465}
466
467// Clone a directory
468Git.prototype.clone = function(options, original_path, target_path, callback) {
469}
470
471// Generate diff from the changes between two shas
472// Git.prototype.diff = function(options, sha1, sha2, callback) {
473// }
474//
475// var simple_diff = function(repo, options, sha1, sha2, callback) {
476//
477// }
478//
479// var native_diff = function(repo, options, sha1, sha2, base, paths, callback) {
480//
481// }
482
483// Gotten from
484var flatten = function(array) {
485 return array.reduce(function(a,b) {
486 return a.concat(b);
487 }, []);
488}
489
490Git.prototype.diff = function(commit1, commit2, options, callback) {
491 try {
492 var self = this;
493 var args = Array.prototype.slice.call(arguments, 2);
494 // Pop the callback
495 var callback = args.pop();
496 options = args.length ? args.shift() : {};
497
498 // Initialize patch variable
499 var patch = '', commit_obj1 = null, tree1 = null, tree2 = null;
500 // Retrieve the first commit object
501 var commit_obj1 = self.repository.get_object_by_sha1(commit1);
502 var tree1 = commit_obj1.tree;
503
504 if(commit2) {
505 tree2 = self.repository.get_object_by_sha1(commit2).tree;
506 } else {
507 tree2 = self.repository.get_object_by_sha1(commit_obj1.parent[0]).tree;
508 }
509
510 var qdiff = self.repository.quick_diff(tree1, tree2).sort();
511 qdiff.forEach(function(diff_arr) {
512 // Set up all the variables
513 var path = diff_arr[0];
514 var status = diff_arr[1];
515 var treeSHA1 = diff_arr[2];
516 var treeSHA2 = diff_arr[3];
517 var format = 'unified';
518 var lines = 3;
519 var output = '';
520 var file_length_difference = 0;
521
522 // Fetch the files
523 var fileA = treeSHA1 ? self.repository.cat_file(treeSHA1) : '';
524 var fileB = treeSHA2 ? self.repository.cat_file(treeSHA2) : '';
525
526 // Get the sha's or set empty shas
527 var sha1 = treeSHA1 || '0000000000000000000000000000000000000000';
528 var sha2 = treeSHA2 || '0000000000000000000000000000000000000000';
529
530 // Split up data
531 var data_old = fileA.trim().split(/\n/).map(function(e) { return chomp(e); });
532 var data_new = fileB.trim().split(/\n/).map(function(e) { return chomp(e); });
533 // Javascript split's a file into [''] if it's an empty file
534 if(data_old.length == 1 && data_old[0] == '') data_old = [];
535 if(data_new.length == 1 && data_new[0] == '') data_new = [];
536
537 // Get diffs
538 var diffs = Difference.LCS.diff(data_old, data_new);
539 if(diffs.length > 0) {
540 // Create paths
541 var a_path = "a/" + path.replace(/\.\//g, '');
542 var b_path = "b/" + path.replace(/\.\//g, '');
543 // Let's create the header
544 var header = "diff --git " + a_path + " " + b_path;
545 if(options['full_index']) {
546 header = header + '\n' + 'index ' + sha1 + '..' + sha2;
547 if(treeSHA2) header = header + "' 100644";
548 } else {
549 header = header + '\n' + 'index ' + sha1.substr(0, 7) + '..' + sha2.substr(0, 7);
550 if(treeSHA2) header = header + ' 100644';
551 }
552
553 header = header + '\n--- ' + (treeSHA1 ? a_path : '/dev/null');
554 header = header + '\n+++ ' + (treeSHA2 ? b_path : '/dev/null');
555 header = header + '\n';
556
557 // standard hunk
558 var old_hunk = null, hunk = null;
559 // Process all the diff changes
560 diffs.forEach(function(piece) {
561
562 try {
563 hunk = new Difference.LCS.Hunk(data_old, data_new, piece, lines, file_length_difference);
564 file_length_difference = hunk.file_length_difference;
565
566 if(old_hunk) {
567 if(lines > 0 && hunk.overlaps(old_hunk)) {
568 hunk.unshift(old_hunk);
569 } else {
570 output = output + old_hunk.diff(format);
571 }
572 }
573 } catch(err) {}
574
575 old_hunk = hunk;
576 output = output + '\n';
577 });
578
579 // Prepare next
580 output = output + old_hunk.diff(format);
581 output = output + '\n';
582 patch = patch + header + output.trimLeft();
583 }
584 });
585
586 // Return the patch
587 callback(null, patch);
588 } catch(err) {
589 callback('tree was bad or lcs is not working', null);
590 }
591}
592
593// Check if a file exists
594Git.prototype.fs_exist = function(path, callback) {
595 GitFileOperations.fs_exist(this.git_directory, path, callback);
596}
597
598// Write a normal file to the filesystem
599// file: relative path from the Git dir
600// contents: String content to be written
601//
602// Return nothing
603Git.prototype.fs_write = function(file, content, callback) {
604 GitFileOperations.fs_write(this.git_directory, file, content, callback);
605}
606
607// Log function, returns the number of logs
608Git.prototype.log = function(commit, path, options, callback) {
609 args = ['--raw', '--no-abbrev', '--numstat'];
610 if (path) {
611 args.push('--');
612 args.push(path);
613 }
614 options.color = 'never';
615 this.call_git('', 'log', '', options, args, callback);
616}
617
618// Select the objects that exists
619// object_ids: array of object sha's
620//
621// Returns array of ids's that exist
622Git.prototype.select_existing_objects = function(object_ids, callback) {
623 var existing_object_ids = [];
624 // Process all the object ids
625 for(var i = 0; i < object_ids.length; i++) {
626 // Check if the object_id exists in the db
627 this.repository.object_exists(object_ids[i], function(err, result) {
628 if(err) return callback(err, result);
629 if(result) existing_object_ids.push(object_ids[i]);
630 });
631 }
632 // Return all the existing objects
633 callback(null, existing_object_ids);
634}
635
636// Format the patch
637Git.prototype.format_patch = function(options, reference, callback) {
638 this.call_git('', 'format_patch', '', options, [reference], function(err, result) {
639 callback(err, result);
640 })
641}
642
643// Fetch the blame
644Git.prototype.blame = function() {
645 // Unpack parameters as commit might be null
646 var args = Array.prototype.slice.call(arguments, 0);
647 var callback = args.pop();
648 var options = args.length ? args.shift() : {};
649 var arguments = args;
650
651 // Execute blame command
652 this.call_git('', 'blame', '', options, arguments, function(err, result) {
653 callback(err, result);
654 });
655}
656
657var clean_paths = function(commits) {
658 var new_commits = {};
659 // Iterate over all the commit hash entries and clean the directory names
660 Object.keys(commits).forEach(function(file) {
661 var sha = commits[file];
662 file = file.substr(file.length - 1, 1) == '/' ? file.substr(0, file.length - 1) : file;
663 new_commits[file] = sha;
664 })
665 // Return all the cleaned commits
666 return new_commits;
667}
668
669// Fetch blame tree
670Git.prototype.blame_tree = function(commit, path, callback) {
671 var self = this;
672 var args = Array.prototype.slice.call(arguments, 1);
673 var callback = args.pop();
674 path = args.length ? args.shift() : null;
675
676 // Create path
677 path = path != null && path != '' ? [path].join("/").toString() + '/' : path;
678 path = !path || path.constructor != String ? '' : path;
679
680 // Fetch the file_index
681 file_index(this, function(err, file_index_instance) {
682 if(err) return callback(err, file_index_instance);
683
684 self.rev_parse({}, commit, 0, function(err, rev_parse_output) {
685 if(err) return callback(err, rev_parse_output);
686
687 self.looking_for(commit, path, function(err, looking_for) {
688 if(err) return callback(err, looking_for);
689
690 file_index_instance.last_commits(rev_parse_output, looking_for, function(err, commits) {
691 if(err) return callback(err, commits);
692
693 callback(null, clean_paths(commits));
694 });
695 });
696 });
697 });
698}
699
700// Looking for
701Git.prototype.looking_for = function(commit, path, callback) {
702 var self = this;
703 var args = Array.prototype.slice.call(arguments, 1);
704 var callback = args.pop();
705 path = args.length ? args.shift() : null;
706 var file = null;
707
708 // Fetch the commit sha
709 self.rev_parse({}, commit, 0, function(err, rev_parse_output) {
710 if(err) return callback(err, rev_parse_output);
711
712 // Fetch the sub tree
713 self.repository.get_subtree(rev_parse_output, path, function(err, tree_sha) {
714 if(err) return callback(err, tree_sha);
715
716 // Contains the files
717 var looking_for = [];
718 // Fetch and return the object by the tree sha
719 var object = self.repository.get_object_by_sha1(tree_sha);
720 // Process all the entries for the object
721 object.entries.forEach(function(entry) {
722 file = path && !(path == '' || path == '.' || path == './') ? path + "/" + entry.name : entry.name;
723 // Ensure no double path characters
724 file = file.replace('//', '/');
725 // Add a slash if it's a directory
726 if(entry.type == 'directory') file = file + "/";
727 // Add to list of looking_for entries
728 looking_for.push(file);
729 });
730
731 // Return the entries
732 return callback(null, looking_for);
733 });
734 });
735}
736
737// Peform commit
738Git.prototype.commit = function() {
739 // Unpack parameters as commit might be null
740 var args = Array.prototype.slice.call(arguments, 0);
741 var callback = args.pop();
742 var options = args.length ? args.shift() : {};
743 var arguments = args;
744
745 // Execute blame command
746 this.call_git('', 'commit', '', options, arguments, function(err, result) {
747 callback(err, result);
748 });
749}
750
751// Fetch config
752Git.prototype.config = function() {
753 // Unpack parameters as commit might be null
754 var args = Array.prototype.slice.call(arguments, 0);
755 var callback = args.pop();
756 var options = args.length ? args.shift() : {};
757 var arguments = args;
758 // Execute blame command
759 this.call_git('', 'config', '', options, arguments, function(err, result) {
760 callback(err, result);
761 });
762}
763
764// Execute add command
765Git.prototype.add = function() {
766 // Unpack parameters as commit might be null
767 var args = Array.prototype.slice.call(arguments, 0);
768 var callback = args.pop();
769 var options = args.length ? args.shift() : {};
770 var arguments = args;
771 // Execute blame command
772 this.call_git('', 'add', '', options, arguments, function(err, result) {
773 callback(err, result);
774 });
775}
776
777// Execute remove command
778Git.prototype.remove = function() {
779 // Unpack parameters as commit might be null
780 var args = Array.prototype.slice.call(arguments, 0);
781 var callback = args.pop();
782 var options = args.length ? args.shift() : {};
783 var arguments = args;
784 // Execute blame command
785 this.call_git('', 'rm', '', options, arguments, function(err, result) {
786 callback(err, result);
787 });
788}
789
790// Execute ls-files
791Git.prototype.ls_files = function() {
792 // Unpack parameters as commit might be null
793 var args = Array.prototype.slice.call(arguments, 0);
794 var callback = args.pop();
795 var options = args.length ? args.shift() : {};
796 var arguments = args;
797 // Execute blame command
798 this.call_git('', 'ls-files', '', options, arguments, function(err, result) {
799 callback(err, result);
800 });
801}
802
803// Execute diff-files
804Git.prototype.diff_files = function() {
805 // Unpack parameters as commit might be null
806 var args = Array.prototype.slice.call(arguments, 0);
807 var callback = args.pop();
808 var options = args.length ? args.shift() : {};
809 var arguments = args;
810 // Execute blame command
811 this.call_git('', 'diff-files', '', options, arguments, function(err, result) {
812 callback(err, result);
813 });
814}
815
816// Execute diff-index
817Git.prototype.diff_index = function() {
818 // Unpack parameters as commit might be null
819 var args = Array.prototype.slice.call(arguments, 0);
820 var callback = args.pop();
821 var options = args.length ? args.shift() : {};
822 var arguments = args;
823 // Execute blame command
824 this.call_git('', 'diff-index', '', options, arguments, function(err, result) {
825 callback(err, result);
826 });
827}
828
829Git.prototype.file_type = function(ref, callback) {
830 return callback(null, this.repository.cat_file_type(ref));
831}
832
833Git.prototype.put_raw_object = function(content, type, callback) {
834 return this.repository.put_raw_object(content, type, callback);
835}
836
837Git.prototype.commit_from_sha = function(id) {
838 var repository = new Repository(this.git_directory);
839 var object = repository.get_object_by_sha1(id);
840
841 if(object.type == "commit") {
842 return id;
843 } else if(object.type == "tag") {
844 return object.object;
845 } else {
846 return '';
847 }
848}
849
850
851// // ===================================================================================================
852// //
853// // Decorates the Class prototype with functions wrapping git native functions (if not defined already)
854// //
855// // ===================================================================================================
856// Git.prototype.call_git('', 'help', '', {}, ['--all'], function(err, result) {
857// var index = result.indexOf("-----------");
858// result = result.substr(index);
859// var lines = result.trim().split("\n");
860// // Ship the first line
861// lines.shift();
862// // Process all the lines
863// while(lines.length > 0 && lines[0] != '') {
864// var line = lines.shift().trim().replace(/ +/g, ' ');
865// var parts = line.split(" ");
866//
867// parts.forEach(function(command) {
868// var function_name = command.replace(/\-/g, '_');
869// // For each entry create a new function if it does not exist on the prototype
870// if(Git.prototype[function_name] == null) {
871// Git.prototype[function_name] = function() {
872// // Unpack parameters as commit might be null
873// var args = Array.prototype.slice.call(arguments, 0);
874// callback = args.pop();
875// var options = args.length ? args.shift() : {};
876// var arguments = args;
877// // Execute blame command
878// this.call_git('', command, '', options, arguments, function(err, result) {
879// callback(err, result);
880// });
881// }
882// }
883// });
884//
885// }
886//
887// // callback(null, null);
888// pre_loading_done = true
889// // var g = new Git("..../")
890// });
891