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).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.length;ii++) {
291                 var cmd = repo.item(ii);
292     
293                 
294                 switch(cmd.name) {
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                 } 
327             }
328             
329             //repo.debug = 1;
330             // these can fail... at present... as we wildcard stuff.
331             stdout.printf("ADD : %d files"  , add_files.length);
332             
333             // make sure added files do not get removed..
334
335             var remove_files_f = new Array<GitMontitorQueue>();
336             for(var ii = 0;ii < remove_files.length;ii++) {
337                 if (GitMontitorQueue.indexOfAdd(add_files,  remove_files.item(ii).rm) > -1 ) {
338                      continue;
339                 }
340                 remove_files_f.append_val(remove_files.item(ii));
341             };
342             stdout.printf("REMOVE : %d files"  , remove_files.length);
343              
344             // make sure monitoring is paused so it does not recursively pick up
345             // deletions
346             
347             // -- DO STUFF..
348             
349             repo.add(add_files);
350             repo.remove(remove_files);
351             this.paused = false;
352             
353             
354             try { 
355                 success.append_val(repo.commit(
356                     GitMontitorQueue.messageToString(messages)
357                     add_files  
358                 ));
359                 success.push(repo.push());
360
361             } catch(Error e) {
362                 failure.append_val(e.message);
363                 
364             }   
365         }
366         
367         // finally merge all the commit messages.
368          
369         try {
370             // catch notification failures.. so we can carry on..
371             if (success.length) {
372                 var success_str = "";
373                 for(var ii = 0;ii < success.length;ii++) {
374                     success_str+= success.item(ii) + "\n";
375                 }
376                 
377                 var notification = new Notify.Notification(
378                     "Git Live Commited",
379                     success_str,
380                      "dialog-information"
381                     
382                 );
383     
384                 notification.set_timeout(5);
385                 notification.show();   
386             }
387             
388             if (failure.length) {
389                 var failure_str = "";
390                 for(var ii = 0;ii < failure.length;ii++) {
391                     failure_str+= failure.item(ii) + "\n";
392                 }
393                 var notification = new Notify.Notification({
394                     summary: "Git Live ERROR!!",
395                     failure_str,
396                     "dialog-information"
397                     
398                 });
399     
400                 notification.set_timeout(5); // show errros for longer
401                 notification.show();   
402             }
403         } catch(Error e) {
404             print(e.message);
405             
406         }
407         this.queueRunning = false;
408     }
409     
410
411
412     
413
414     //string[] just_created;
415  
416  
417
418
419
420    
421
422
423     public void onChanged(MonitorNamePathDir src) { }
424     { 
425         return; // always ignore this..?
426         //this.parsePath(src);
427     },
428     
429
430  
431     /**
432      *  results in  git add  + git commit..
433      *
434      */
435     public void onChangesDoneHint(MonitorNamePathDir src) { }
436     { 
437         
438         if (this.paused) {
439             return true;
440         }
441             
442
443         this.lastAdd = new DateTime.now(); 
444         var cmd = new GitMontitorQueue(src, this.gitlive);
445         if (cmd.shouldIgnore()) {
446             return;
447         }
448         
449        
450         var add_it = false;
451         /*
452         if (this.is_just_created(cmd.path)) {
453             
454         if (typeof(this.just_created[src.path]) !='undefined') {
455             delete this.just_created[src.path];
456             
457             this.queue.push( 
458                 [ src.gitpath,  'add', src.vpath ],
459                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
460                 
461             );
462          
463             return;
464         }
465         */
466         cmd.add = src.vpath;
467         this.queue.append_val(cmd);
468
469         var cmd = new GitMontitorQueue(src, this.gitlive);
470         cmd.name = "commit";
471         cmd.message = src.vpath;
472         this.queue.append_val(cmd);
473  
474          
475     }
476     public void onDeleted(MonitorNamePathDir src) 
477    { 
478         if (this.paused) {
479             return true;
480         }
481         this.lastAdd = new DateTime.now(); 
482         var cmd = new GitMontitorQueue(src, this.gitlive);
483         if (cmd.shouldIgnore()) {
484             return;
485         }
486         // should check if monitor needs removing..
487         // it should also check if it was a directory.. - so we dont have to commit all..
488         cmd.name = "rm";
489         cmd.rm = src.vpath;
490         this.queue.append_val(cmd);
491
492         var cmd = new GitMontitorQueue(src, this.gitlive);
493         cmd.name = "commit";
494         cmd.message = src.vpath;
495         cmd.commit_all = true;
496
497         this.queue.append_val(cmd);
498  
499     }
500     public void onCreated(MonitorNamePathDir src) {
501
502         if (this.paused) {
503             return true;
504         }
505         this.lastAdd = new DateTime.now(); 
506         var cmd = new GitMontitorQueue(src, this.gitlive);
507         if (cmd.shouldIgnore()) {
508             return;
509         }
510
511         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
512            // this.just_created[src.path] = true;
513             return; // we do not handle file create flags... - use done hint.
514         }
515         // directory has bee created
516         this.monitor(src.path);
517         this.top.append_val(src.path);
518         this.monitor(src.path );
519
520
521 // -- no point in adding a dir.. as git does not handle them...
522 //        this.queue.push( 
523   //          [ src.gitpath, 'add' , src.vpath,  { all: true } ],
524  //           [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
525   //          
526    //     );
527
528     }
529
530     public void onAttributeChanged(MonitorNamePathDir src) { }
531
532         if (this.paused) {
533             return true;
534         }
535         this.lastAdd = new DateTime.now(); 
536         var cmd = new GitMontitorQueue(src, this.gitlive);
537         if (cmd.shouldIgnore()) {
538             return;
539         }
540         cmd.name = "add";
541         cmd.add = src.vpath;
542         this.queue.append_val(cmd);
543
544         var cmd = new GitMontitorQueue(src, this.gitlive);
545         cmd.name = "commit";
546         cmd.message = "Attribute changed " + cmd.vpath;
547         this.queue.append_val(cmd);
548     }
549
550
551    public void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest) { }
552     { 
553         this.lastAdd = new DateTime.now(); 
554         var cmd_s = new GitMontitorQueue(src, this.gitlive);
555
556         var cmd_d = new GitMontitorQueue(src, this.gitlive);
557    
558         
559         if (cmd_d.gitpath != cmd_s.gitpath) {
560             this.onDeleted(src);
561             this.onCreated(dest);
562             this.onChangedDoneHint(dest);
563             return;
564         }
565         // needs to handle move to/from unsupported types..
566         
567         if (this.shouldIgnore(src)) {
568             this.onCreated(dest);
569             this.onChangedDoneHint(dest);
570             return;
571
572         }
573         if (this.shouldIgnore(dest)) {
574             
575             this.onDeleted(src);
576  
577
578             return;
579         }
580         
581         cmd_s.name = "rm";
582         cmd_s.rm = src.vpath;
583         this.queue.append_val(cmd_s);
584
585
586
587
588         cmd_d.name = "add";
589         cmd_d.add = src.vpath;
590         this.queue.append_val(cmd_d);
591
592
593         var cmd = new GitMontitorQueue(dest, this.gitlive);
594         cmd.name = "commit";
595         cmd.message = "MOVED " + cmd_s.vpath + " to " + cmd_d.vpath;
596         this.queue.append_val(cmd);
597
598
599          
600     }
601        
602 }