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