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