GitMonitor.vala
[gitlive] / GitMonitor.vala
1
2
3 public class GitMonitorQueue : MonitorNamePathDir {
4         // name = basename
5         // path = full path..
6         // dir = dir path
7     
8         public string gitpath;
9         public string vpath;
10         public string message ; // for commit
11         public bool commit_all;
12
13
14         public GitMonitorQueue(MonitorNamePathDir f) {
15
16             base(f.name, f.path, f.dir);
17
18
19             this.message = "";
20             this.commit_all = false;
21  
22            
23             var vpath_ar = this.path.substring(GitMonitor.gitlive.length +1).split("/", 0);
24             
25             this.gitpath = GitMonitor.gitlive + "/" + vpath_ar[0];
26             
27             string[]  vpath = {};
28             for (var i = 1; i< vpath_ar.length; i++) {
29                 vpath += vpath_ar[i];
30             }
31             this.vpath =  string.joinv("/", vpath);
32             //f.repo = new imports.Scm.Git.Repo({ repopath: f.gitpath })
33         
34         
35         }
36
37         public bool shouldIgnore(GitMonitor gm)
38         {
39             
40             
41             
42             // vim.. what a seriously brain dead program..
43             if (this.name == "4913") {
44                 return true;
45             }
46             
47             if (this.name[0] == '.') {
48                 // except!
49                 if (this.name == ".htaccess") {
50                     return false;
51                 }
52                 
53                 return true;
54             }
55             //if (f.name.match(/~$/)) {
56             //    return true;
57             //}
58             //if (f.name.match(/^nbproject/)) {
59             //    return true;
60             //}
61             // ignore anything in top level!!!!
62             if (this.vpath.length < 1) {
63                 return true;
64             }
65             
66             return false;
67         }
68         
69         /** -- statics --*/
70         
71         public static int indexOfAdd( Array<GitMonitorQueue> add_files, string add) {
72             for(var i =0; i < add_files.length; i++) {
73                 if (addfiles.index(i).add == add) {
74                     return i;
75                 }
76             }
77             return -1;
78         }
79         public static  int indexOfMessage(Array<GitMonitorQueue> messages, string message)  {
80             for(var i =0; i < messages.length; i++) {
81                 if (messages.index(i).message == message) {
82                     return i;
83                 }
84             }
85             return -1;
86         }
87         public static string messageToString(Array<GitMonitorQueue> messages ) {
88             string[] ret = {};
89             for(var i =0; i < messages.length; i++) {
90                 ret+= messages.index(i).message;
91             }
92             return string.joinv(ret,"\n");
93         }
94
95 }
96
97
98
99 public class GitMonitor : Monitor
100 {
101
102  
103     /**
104      * @property {String} the "gitlive" directory, normally ~/gitlive
105      *  dset by OWNER... - we should do this as a CTOR.
106      *  
107      */
108     public static string gitlive = "";
109     
110     
111     public Array<GitMonitorQueue> queue ;
112     public bool queueRunning = false;
113     
114     public DateTime lastAdd;
115      
116      
117     public void pause() {
118         this.paused = true;
119         // what does this do to the old one...
120         this.queue = new Array<GitMonitorQueue> ();
121         StatusIconA.statusicon.set_from_stock( Gtk.Stock.MEDIA_PAUSE );
122
123     }
124     
125     public void resume () {
126         this.paused = false;
127         this.queue = new Array<GitMonitorQueue> ();
128         StatusIconA.statusicon.set_from_stock( Gtk.Stock.MEDIA_PLAY );
129         
130         
131     }
132     /**
133      * Start the monitoring
134      * and run the queue every 500 milliseconds..
135      *
136      */
137     public void start() {
138         StatusIconA.statusicon.set_from_stock( Gtk.Stock.MEDIA_REFRESH );
139         
140          
141         this.lastAdd = new DateTime.now(); 
142         
143         Timeout.add_full(GLib.PRIORITY_LOW, 500, () => {
144
145             // call this.monitor on each of 'top'
146             for(int i = 0; i < this.top.length ; i++) {
147                 this.monitor(this.top.index(i) );
148             }
149             StatusIconA.statusicon.set_from_stock( Gtk.Stock.MEDIA_PLAY );
150              
151            
152             
153             try { 
154                 var notification = new Notify.Notification({
155                     "Git Live",
156                     GitMonitor.gitlive + "\nMonitoring " + _this.monitors.length + " Directories",
157                      "dialog-information"
158                 });
159         
160                 notification.set_timeout(5);
161                 notification.show();
162             } catch(Error e) {
163                 print(e.toString());
164             }
165
166         });
167         
168         Timeout.add_full(GLib.PRIORITY_LOW, 1000, () => {
169             //TIMEOUT", _this.queue.length , _this.queueRunning].join(', '));
170             if (!_this.queue.length || _this.queueRunning) {
171                 return true;
172             }
173
174             var last = this.lastAdd.difference(new DateTime.now());
175
176             
177             //print("LAST RUN?" + last);
178             
179             if (last < 5 * Timespan.SECOND) { // wait 1/2 a seconnd before running.
180                 return 1;
181             }
182             //_this.lastAdd = new Date();
183             //return 1;
184         
185             this.runQueue();
186             return true;
187         },null,null);
188         
189       
190     }
191
192
193     public void stop() {
194         StatusIconA.statusicon.set_from_stock( Gtk.Stock.MEDIA_PAUSE );;
195         base.stop();
196     }
197     
198     
199     public void monitor (string path,  int depth = 0)
200     {
201         
202         //var depth = typeof(depth) == 'number'  ? depth *1 : 0;
203         
204          
205         // if we are not at top level.. and there is a .git directory  (it's a submodule .. ignore) 
206         if (depth > 1 && GLib.file_test(path + "/.git" , GLib.FileTest.IS_DIR)) {
207             return;
208         }
209         
210         if (depth == 1) {
211             // FIXME - check if repo is flagged as not autocommit..
212             //var repo = imports.Scm.Repo.Repo.get(path);
213             //if (!repo || !repo.autocommit()) {
214             //    return;
215             //} 
216         }
217         
218         
219         // check if the repo is to be monitored.
220         //print("PATH : " + path);
221         
222         
223         base.monitor(path, depth);
224     }
225
226     
227
228     /**
229      * run the queue.
230      * - pulls the items off the queue 
231      *    (as commands run concurrently and new items may get added while it's running)
232      * - runs the queue items
233      * - pushes upstream.
234      * 
235      */
236     public void runQueue()
237     {
238         
239         if (this.paused) {
240             return;
241         }
242         this.queueRunning = true;
243
244         var cmds = new Array<GitMonitorQueue>();
245         for(var i = 0; i < this.queue.length; i++) {
246             cmds.append_val(this.queue.item(i));
247         }
248
249         this.queue = new Array<GitMonitorQueue>();// empty queue!
250
251         
252         string[] success = {};
253         string[] failure = {};
254         var repos = new Array<GitRepo>(); //??
255         var done = new Array<GitMonitorQueue>();
256         
257         // first build a array of repo's to work with
258         var repo_list = new Array<GitRepo>();
259         
260         // pull and group.
261         
262         //print(JSON.stringify(cmds));
263         this.paused = true;
264         
265         for(var i = 0; i < cmds.length; i++) {
266            
267         
268             var gitpath = cmd.gitpath; 
269             var ix  = GitRepo.indexOf(this.repos,  cmd.gitpath);
270             if (ix < 0) {
271                 repo_list.append_val(new GitRepo( gitpath ));
272                 ix = GitRepo.indexOf(this.repos,  cmd.gitpath);
273             }
274             
275
276             //if (typeof(repo_list[gitpath]) == 'undefined') {
277             //    repo_list[gitpath] = new imports.Scm.Git.Repo.Repo( { repopath : gitpath });
278             //    repo_list[gitpath].cmds = [];
279              //   repo_list[gitpath].pull();
280             //}
281             repo_list.item(ix).cmds.append_val(cmd);
282
283         }
284         this.paused = false;
285         // build add, remove and commit message list..
286         
287         for(var i = 0;i < repo_list.length;i++) {
288     
289
290             var repo = repo_list.item(i);
291
292             var add_files = new Array<GitMonitorQueue>();
293             var remove_files = new Array<GitMonitorQueue>();
294             var messages = new Array<GitMonitorQueue>();
295             //print(JSON.stringify(repo.cmds,null,4));
296             
297             for(var ii = 0;ii < repo.cmds.length;ii++) {
298                 var cmd = repo.cmds.item(ii);
299     
300                 
301                 switch(cmd.action) {
302                     case "add" :
303                         
304                         if (GitMonitorQueue.indexOfAdd(add_files, cmd.add) > -1) {
305                            break;
306                         }
307         
308                         
309                         add_files.append_val(cmd);
310                         break;
311                     
312                     case "rm":
313                         if (GitMonitorQueue.indexOfAdd(add_files, cmd.rm) > -1 ) {
314                            break;
315                         }
316                         
317                         // if file exists, do not try and delete it.
318                         if (GLib.file_test(cmd.rm, GLib.FileTest.EXISTS)) {
319                             break;
320                         }
321                         
322                         remove_files.append_val(cmd);
323                         break;
324                     
325                     case "commit" :
326                         if (GitMonitorQueue.indexOfMessage(messages, cmd.message) > -1 ) {
327                            break;
328                         }
329                          
330                         messages.append_val(cmd);
331                         
332                         break;
333                     default:
334                         print("Opps unmatched action");
335                         break;
336                 } 
337             }
338             
339             //repo.debug = 1;
340             // these can fail... at present... as we wildcard stuff.
341             stdout.printf("ADD : %d files"  , add_files.length);
342             
343             // make sure added files do not get removed..
344
345             var remove_files_f = new Array<GitMonitorQueue>();
346             for(var ii = 0;ii < remove_files.length;ii++) {
347                 if (GitMonitorQueue.indexOfAdd(add_files,  remove_files.item(ii).rm) > -1 ) {
348                      continue;
349                 }
350                 remove_files_f.append_val(remove_files.item(ii));
351             };
352             stdout.printf("REMOVE : %d files"  , remove_files.length);
353              
354             // make sure monitoring is paused so it does not recursively pick up
355             // deletions
356             
357             // -- DO STUFF..
358             
359             repo.add(add_files);
360             repo.remove(remove_files_f);
361             this.paused = false;
362             
363             
364             try { 
365                 success += repo.commit(
366                     GitMonitorQueue.messageToString(messages),
367                     add_files  
368                 );
369                 success += repo.push();
370
371             } catch(Error e) {
372                 failure += e.message;
373                 
374             }   
375         }
376         
377         // finally merge all the commit messages.
378          
379         try {
380             // catch notification failures.. so we can carry on..
381             if (success.length) {
382
383                 
384                 var notification = new Notify.Notification(
385                     "Git Live Commited",
386                     string.joinv("\n",success),
387                      "dialog-information"
388                     
389                 );
390     
391                 notification.set_timeout(5);
392                 notification.show();   
393             }
394             
395             if (failure.length) {
396
397                 var notification = new Notify.Notification({
398                     summary: "Git Live ERROR!!",
399                     string.joinv("\n",failure),
400                     "dialog-information"
401                     
402                 });
403     
404                 notification.set_timeout(5); // show errros for longer
405                 notification.show();   
406             }
407         } catch(Error e) {
408             print(e.message);
409             
410         }
411         this.queueRunning = false;
412     }
413     
414
415
416     
417
418     //string[] just_created;
419  
420  
421
422
423
424    
425
426
427     public void onChanged(MonitorNamePathDir src) 
428     { 
429         return; // always ignore this..?
430         //this.parsePath(src);
431     }
432     
433
434  
435     /**
436      *  results in  git add  + git commit..
437      *
438      */
439     public void onChangesDoneHint(MonitorNamePathDir src)  
440     { 
441         
442         if (this.paused) {
443             return true;
444         }
445             
446
447         this.lastAdd = new DateTime.now(); 
448         var cmd = new GitMonitorQueue(src);
449         if (cmd.shouldIgnore()) {
450             return;
451         }
452         
453        
454         var add_it = false;
455         /*
456         if (this.is_just_created(cmd.path)) {
457             
458         if (typeof(this.just_created[src.path]) !='undefined') {
459             delete this.just_created[src.path];
460             
461             this.queue.push( 
462                 [ src.gitpath,  'add', src.vpath ],
463                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
464                 
465             );
466          
467             return;
468         }
469         */
470         cmd.add = src.vpath;
471         this.queue.append_val(cmd);
472
473         var cmd = new GitMonitorQueue(src);
474         cmd.action = "commit";
475         cmd.message = src.vpath;
476         this.queue.append_val(cmd);
477  
478          
479     }
480     public void onDeleted(MonitorNamePathDir src) 
481    { 
482         if (this.paused) {
483             return true;
484         }
485         this.lastAdd = new DateTime.now(); 
486         var cmd = new GitMonitorQueue(src);
487         if (cmd.shouldIgnore()) {
488             return;
489         }
490         // should check if monitor needs removing..
491         // it should also check if it was a directory.. - so we dont have to commit all..
492         cmd.action = "rm";
493         cmd.rm = src.vpath;
494         this.queue.append_val(cmd);
495
496         var cmd = new GitMonitorQueue(src);
497         cmd.action = "commit";
498         cmd.message = src.vpath;
499         cmd.commit_all = true;
500
501         this.queue.append_val(cmd);
502  
503     }
504     public void onCreated(MonitorNamePathDir src) {
505
506         if (this.paused) {
507             return true;
508         }
509         this.lastAdd = new DateTime.now(); 
510         var cmd = new GitMonitorQueue(src);
511         if (cmd.shouldIgnore()) {
512             return;
513         }
514
515         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
516            // this.just_created[src.path] = true;
517             return; // we do not handle file create flags... - use done hint.
518         }
519         // directory has bee created
520         this.monitor(src.path);
521         this.top.append_val(src.path);
522         this.monitor(src.path );
523
524
525 // -- no point in adding a dir.. as git does not handle them...
526 //        this.queue.push( 
527   //          [ src.gitpath, 'add' , src.vpath,  { all: true } ],
528  //           [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
529   //          
530    //     );
531
532     }
533
534     public void onAttributeChanged(MonitorNamePathDir src) { 
535
536         if (this.paused) {
537             return true;
538         }
539         this.lastAdd = new DateTime.now(); 
540         var cmd = new GitMonitorQueue(src);
541         if (cmd.shouldIgnore()) {
542             return;
543         }
544         cmd.action = "add";
545         cmd.add = src.vpath;
546         this.queue.append_val(cmd);
547
548         var cmd = new GitMonitorQueue(src);
549         cmd.action = "commit";
550         cmd.message = "Attribute changed " + cmd.vpath;
551         this.queue.append_val(cmd);
552     }
553
554
555    public void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest)  
556     { 
557         this.lastAdd = new DateTime.now(); 
558         var cmd_s = new GitMonitorQueue(src);
559
560         var cmd_d = new GitMonitorQueue(src);
561    
562         
563         if (cmd_d.gitpath != cmd_s.gitpath) {
564             this.onDeleted(src);
565             this.onCreated(dest);
566             this.onChangedDoneHint(dest);
567             return;
568         }
569         // needs to handle move to/from unsupported types..
570         
571         if (this.shouldIgnore(src)) {
572             this.onCreated(dest);
573             this.onChangedDoneHint(dest);
574             return;
575
576         }
577         if (this.shouldIgnore(dest)) {
578             
579             this.onDeleted(src);
580  
581
582             return;
583         }
584         
585         cmd_s.action = "rm";
586         cmd_s.rm = src.vpath;
587         this.queue.append_val(cmd_s);
588
589
590
591
592         cmd_d.action = "add";
593         cmd_d.add = src.vpath;
594         this.queue.append_val(cmd_d);
595
596
597         var cmd = new GitMonitorQueue(dest);
598         cmd.action = "commit";
599         cmd.message = "MOVED " + cmd_s.vpath + " to " + cmd_d.vpath;
600         this.queue.append_val(cmd);
601
602
603          
604     }
605        
606 }