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