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