2 const GLib = imports.gi.GLib;
4 const XObject = imports.XObject.XObject;
5 const Event = imports.Scm.Git.Event.Event;
6 const Spawn = imports.Spawn.Spawn;
7 const File = imports.File.File;
10 Repo = XObject.define(
13 XObject.extend(this,cfg);
14 this.gitdir = cfg.repopath + "/.git";
16 if (!File.isDirectory(this.gitdir)) {
17 this.gitdir = this.repopath;
19 //Repo.superclass.constructor.call(this,cfg);
22 imports.Scm.Repo.Repo, // or Object
30 getMetaData : function() {
37 getBranches : function()
39 if (this.branches !== false) {
43 var bl = this.git([ 'branch', {
48 bl.forEach(function(line) {
49 // * master 61e7e7d oneliner
50 var active = line[0]=='*';
51 line = line.substring(2);
53 var parts = line.split(/\s+/);
54 if (parts[0] == '->') {
55 return; // it's an alias like remotes/origin/HEAD -> origin/master
57 this.branches[parts[0]] = parts[1];
59 this.curBranch = parts[0];
66 public function getTags()
68 if ($this->tags !== null) {
71 $this->tags = array();
72 $fp = $this->git('tag');
73 while ($line = fgets($fp)) {
75 $this->tags[$line] = $line;
81 public function readdir($path, $object = null, $ident = null)
85 if ($object === null) {
89 $rev = $this->resolveRevision(null, $object, $ident);
92 $path = rtrim($path, '/') . '/';
95 $fp = $this->git('ls-tree', $rev, $path);
98 require_once 'MTrack/SCM/Git/File.php';
99 while ($line = fgets($fp)) {
100 // blob = file, tree = dir..
101 list($mode, $type, $hash, $name) = preg_split("/\s+/", $line);
102 //echo '<PRE>';echo $line ."\n</PRE>";
103 $res[] = new MTrack_SCM_Git_File($this, "$name", $rev, $type == 'tree', $hash);
108 public function file($path, $object = null, $ident = null)
110 if ($object == null) {
111 $branches = $this->getBranches();
112 if (isset($branches['master'])) {
120 $rev = $this->resolveRevision(null, $object, $ident);
121 require_once 'MTrack/SCM/Git/File.php';
122 return new MTrack_SCM_Git_File($this, $path, $rev);
127 * @param string path (can be empty - eg. '')
128 * @param {number|date} limit how many to fetch
129 * @param {string} object = eg. rev|tag|branch (use 'rev' here and ident=HASH to retrieve a speific revision
130 * @param {string} ident =
133 * - fetch on revision?: '.',1,'rev','xxxxxxxxxx'
136 * range... object ='rev' ident ='master..release'
139 history: function(path, limit , object, ident)
141 limit = limit || false;
142 object = object || false;
143 ident = ident || false;
145 var args = [ 'log' ];
148 if (object !== false) {
149 rev = this.resolveRevision(false, object, ident); // from scm...
150 args.push( '' + rev);
152 args.push( "master" );
157 //args.push("--name-status";
163 if (limit !== false) {
164 if (typeof(limit) == 'number') {
165 arg['max-count'] = limit;
166 } else if (typeof(limit) == 'object') {
168 arg['max-count']= limit[1];
181 //echo '<PRE>';print_r($args);echo '</PRE>';
182 path = path[0] == '/' ? path.substring(1) : path;
184 args.push({ '' : true });
187 // print_R(array($args, '--' ,$path));exit;
188 var fp = this.git(args).split("\n");
193 var line = fp.shift() + "\n";
195 if (line.match(/^commit/)) {
196 if (commit !== false) {
197 commits.push( commit );
205 if (commit !== false) {
206 commits.push( commit );
209 //print(JSON.stringify(commits,null,4));
212 commits.forEach( function(c) {
213 // print(typeof(Event)); print(JSON.stringify(c));
214 var ev = new Event( {commit : c, repo: _t });
221 diff : function(path, from, to)
224 from = from || false;
230 if ($path instanceof MTrackSCMFile) {
231 if ($from === null) {
237 // if it's a file event.. we are even lucker..
238 if ($path instanceof MTrackSCMFileEvent) {
239 return $this->git('log', '--max-count=1', '--format=format:', '--patch', $from, '--', $path->name);
243 // diff ignoring white space..
244 args = [ 'diff' , { 'w' : true} ]
251 args.push(from+'..'+to);
252 args.push( { '' : true });
253 if (typeof(path) != 'string') {
254 path.forEach(function(p) { args.push(p); })
256 return this.git(args);
261 dayTree: function (path, limit , object, ident)
264 var ar = this.history(path, limit , object, ident);
266 // the point of this is to extract all the revisions, and group them.
270 //echo '<PRE>';print_R($ar);
272 // need to get a 2 dimensional array of
273 // files along top, and commints down.
279 ar.forEach(function( commit) {
281 var files = commit.files;
282 var day = commit.cday;
283 if (typeof(days[day]) == 'undefined') {
290 var time= commit.ctime;
291 if (typeof(days[day]['children'][time]) == 'undefined' ) {
292 days[day]['children'][time] = {
294 'rev' : day + ' ' + time,
298 days[day]['children'][time]['children'].push( {
299 'text' : commit.changelog,
308 dcn = dr['children'];
312 to['rev'] = to['children'][0]['rev'];
313 dr['children'].push( to);
315 dr['rev'] = dr['children'][0]['rev'];
327 changedFiles :function(path, object, ident)
329 object = object || false;
330 ident = ident || false;
332 var args = [ 'diff', { 'numstat' : true} , { 'w' : true } ];
335 if (object !== false) {
336 rev = this.resolveRevision(false, object, ident); // from scm...
337 args.push( '' + rev);
339 args.push( "master" );
341 path = path[0] == '/' ? path.substring(1) : path;
343 args.push({ '' : true });
345 // in theory you could click a number of them and only merge those changes..
346 // need to do a git diff.. and just get a list of files..
348 var res = this.git(args).split("\n");
349 res.forEach( function(line) {
353 var ar = line.split("\t");
354 if (ar.length !=3 ) {
375 merge : function(branch_from, branch_to, rev, files, use_merge)
378 var mi = this.history("/", 1, "rev", rev);
379 // echo '<PRE>';print_R($mi);exit;
382 this.git([ 'checkout', { 'b': true }, to]);
383 //$wd->git('checkout', '-b', $this->release, 'remotes/origin/'. $this->release);
387 //$patchfile = $this->tempName('txt');
390 if (files !== false) {
395 if (is_array($files)) {
397 var diff = this.diff(files, from, to);
402 args : [ 'patch' , '-p1' ] ,
403 env : [ "HOME=" + GLib.get_home_dir() ],
415 ; //eg . patch -p1 < /var/lib/php5/MTrackTMPgZFeAN.txt
417 // if no files -- it means all?/
418 // although we should check to see if this is valid..
419 this.git([' merge', { 'squash' : true }, rev ]);
424 $commit = (object) array(
425 'when' => $mi[0]->ctime,
426 'reason' => $_REQUEST['message'],
427 'name' => $this->authUser->name,
428 'email' => $this->authUser->email,
431 $res = $wd->commit($commit);
432 if (!is_array($files)) {
433 // we do an actually merge commit seperatly from the merge diff, so that
434 // our logs show a nice history in each of those commits.
435 // not sure if this is a good idea or not..
436 $wd->git('merge', '-m', "Merge Commit with working branch (no code changed)" , $rev);
443 // $wd->checkout($this->release);
444 // generate the patch
446 // commit with message..
463 public function getWorkingCopy()
465 require_once 'MTrack/SCM/Git/WorkingCopy.php';
466 return new MTrack_SCM_Git_WorkingCopy($this);
469 public function getRelatedChanges($revision) // pretty nasty.. could end up with 1000's of changes..
474 $fp = $this->git('rev-parse', "$revision^");
475 while (($line = fgets($fp)) !== false) {
476 $parents[] = trim($line);
479 // Ugh!: http://stackoverflow.com/questions/1761825/referencing-the-child-of-a-commit-in-git
480 $fp = $this->git('rev-list', '--all', '--parents');
481 while (($line = fgets($fp)) !== false) {
482 $hashes = preg_split("/\s+/", $line);
483 $kid = array_shift($hashes);
484 if (in_array($revision, $hashes)) {
489 return array($parents, $kids);
495 git: function(args_in)
497 // convert arguments.
499 //print(JSON.stringify(args_in,null,4));
501 'git-dir' : this.gitdir,
506 if (this.gitdir != this.repopath) {
507 args_in.unshift( { "work-tree" : this.gitdir } );
510 args_in.forEach(function(arg) {
511 if (typeof(arg) == 'string') {
515 if (typeof(arg) == 'object') {
519 args.push(k.length != 1 ? ('--' + k) : ('-' + k));
528 this.lastCmd = args.join(" ");
531 print( args.join(" "));
534 var env = [ "HOME=" + GLib.get_home_dir() ];
535 // do not need to set gitpath..
536 //if (File.exists(this.repo + '/.git/config')) {
537 //env.push("GITPATH=" + this.repo );
540 //print(JSON.stringify(args,null,4)); Seed.quit();
544 env : env, // optional
550 //print(JSON.stringify(sp,null,4)); Seed.quit();
552 //print("GOT: " + output)
553 // parse output for some commands ?