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