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), ( fm,  f_orig,  of_orig,  event_type) => {
115                     this.onEvent (fm,  f_orig,  of_orig,  event_type ) ;
116                 } );
117             }
118             StatusIcon.statusicon.set_from_stock( Gtk.Stock.MEDIA_PLAY );
119              
120            
121             
122             try { 
123                 var notification = new Notify.Notification({
124                     "Git Live",
125                     this.gitlive + "\nMonitoring " + _this.monitors.length + " Directories",
126                      "dialog-information"
127                 });
128         
129                 notification.set_timeout(5);
130                 notification.show();
131             } catch(Error e) {
132                 print(e.toString());
133             }
134
135         });
136         
137         Timeout.add_full(GLib.PRIORITY_LOW, 1000, () => {
138             //TIMEOUT", _this.queue.length , _this.queueRunning].join(', '));
139             if (!_this.queue.length || _this.queueRunning) {
140                 return true;
141             }
142
143             var last = this.lastAdd.difference(new DateTime.now());
144
145             
146             //print("LAST RUN?" + last);
147             
148             if (last < 5 * Timespan.SECOND) { // wait 1/2 a seconnd before running.
149                 return 1;
150             }
151             //_this.lastAdd = new Date();
152             //return 1;
153         
154             this.runQueue();
155             return true;
156         },null,null);
157         
158       
159     }
160
161
162     public void stop() {
163         StatusIcon.statusicon.set_from_stock( Gtk.Stock.MEDIA_PAUSE );;
164         base.stop();
165     }
166     
167     
168     public void monitor (string path, onEventHander fn , int depth = 0)
169     {
170         
171         //var depth = typeof(depth) == 'number'  ? depth *1 : 0;
172         
173          
174         // if we are not at top level.. and there is a .git directory  (it's a submodule .. ignore) 
175         if (depth > 1 && GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR)) {
176             return;
177         }
178         
179         if (depth == 1) {
180             // FIXME - check if repo is flagged as not autocommit..
181             //var repo = imports.Scm.Repo.Repo.get(path);
182             //if (!repo || !repo.autocommit()) {
183             //    return;
184             //} 
185         }
186         
187         
188         // check if the repo is to be monitored.
189         //print("PATH : " + path);
190         
191         
192         base.monitor(path,fn, depth);
193     }
194
195     
196
197     /**
198      * run the queue.
199      * - pulls the items off the queue 
200      *    (as commands run concurrently and new items may get added while it's running)
201      * - runs the queue items
202      * - pushes upstream.
203      * 
204      */
205     public void runQueue()
206     {
207         
208         if (this.paused) {
209             return;
210         }
211         this.queueRunning = true;
212
213         var cmds = new Array<GitMontitorQueue>();
214         for(var i = 0; i < this.queue.length; i++) {
215             cmds.append_val(this.queue.item(i));
216         }
217
218         this.queue = new Array<GitMontitorQueue>();// empty queue!
219
220         
221         var success = new Array<String>();
222         var failure = new Array<GitMontitorQueue>();
223         var repos = new Array<GitMontitorQueue>(); //??
224         var done = new Array<GitMontitorQueue>();
225         
226         // first build a array of repo's to work with
227         var repo_list = new Array<GitMontitorRepo>();
228         
229         // pull and group.
230         
231         //print(JSON.stringify(cmds));
232         this.paused = true;
233         
234         for(var i = 0; i < cmds.length; i++) {
235            
236         
237             var gitpath = cmd.gitpath; 
238             var ix  = GitMontitorRepo.indexOf(this.repos,  cmd.gitpath);
239             if (ix < 0) {
240                     repo_list.append_val(new GitMontitorRepo( gitpath ));
241                     ix = GitMontitorRepo.indexOf(this.repos,  cmd.gitpath);
242             }
243             
244
245             //if (typeof(repo_list[gitpath]) == 'undefined') {
246             //    repo_list[gitpath] = new imports.Scm.Git.Repo.Repo( { repopath : gitpath });
247             //    repo_list[gitpath].cmds = [];
248              //   repo_list[gitpath].pull();
249             //}
250             repo_list.item(ix).append_val(cmd);
251
252         }
253         this.paused = false;
254         // build add, remove and commit message list..
255         
256         for(var i = 0;i < repo_list.length;i++) {
257     
258
259             var repo = repo_list.item(i);
260
261             var add_files = new Array<GitMontitorQueue>();
262             var remove_files = new Array<GitMontitorQueue>();
263             var messages = new Array<GitMontitorQueue>();
264             //print(JSON.stringify(repo.cmds,null,4));
265             
266             for(var ii = 0;ii < repo.length;ii++) {
267                 var cmd = repo.item(ii);
268     
269                 
270                 switch(cmd.name) {
271                     case "add" :
272                         
273                         if (GitMontitorQueue.indexOfAdd(add_files, cmd.add) > -1) {
274                            break;
275                         }
276         
277                         
278                         add_files.append_val(cmd);
279                         break;
280                     
281                     case 'rm':
282                         if (GitMontitorQueue.indexOfAdd(add_files, cmd.rm) > -1 ) {
283                            break;
284                         }
285                         
286                         // if file exists, do not try and delete it.
287                         if (GLib.file_test(cmd.rm, GLib.FileTest.EXISTS)) {
288                             break;
289                         }
290                         
291                         remove_files.append_val(cmd);
292                         break;
293                     
294                     case 'commit' :
295                         if (GitMontitorQueue.indexOfMessage(messages, cmd.message) > -1 ) {
296                            break;
297                         }
298                          
299                         messages.append_val(cmd);
300                         
301                         break;    
302                 } 
303             }
304             
305             //repo.debug = 1;
306             // these can fail... at present... as we wildcard stuff.
307             stdout.printf("ADD : %d files"  , add_files.length);
308             
309             // make sure added files do not get removed..
310
311             var remove_files_f = new Array<GitMontitorQueue>();
312             for(var ii = 0;ii < remove_files.length;ii++) {
313                 if (GitMontitorQueue.indexOfAdd(add_files,  remove_files.item(ii).rm) > -1 ) {
314                      continue;
315                 }
316                 remove_files_f.append_val(remove_files.item(ii));
317             };
318             stdout.printf("REMOVE : %d files"  , remove_files.length);
319              
320             // make sure monitoring is paused so it does not recursively pick up
321             // deletions
322             
323             // -- DO STUFF..
324             
325             repo.add(add_files);
326             repo.remove(remove_files);
327             this.paused = false;
328             
329             
330             try { 
331                 success.append_val(repo.commit(
332                     GitMontitorQueue.messageToString(messages)
333                     add_files  
334                 ));
335                 success.push(repo.push());
336
337             } catch(Error e) {
338                 failure.append_val(e.message);
339                 
340             }   
341         }
342         
343         // finally merge all the commit messages.
344          
345         try {
346             // catch notification failures.. so we can carry on..
347             if (success.length) {
348                 var success_str = "";
349                 for(var ii = 0;ii < success.length;ii++) {
350                     success_str+= success.item(ii) + "\n";
351                 }
352                 
353                 var notification = new Notify.Notification(
354                     "Git Live Commited",
355                     success_str,
356                      "dialog-information"
357                     
358                 );
359     
360                 notification.set_timeout(5);
361                 notification.show();   
362             }
363             
364             if (failure.length) {
365                 var failure_str = "";
366                 for(var ii = 0;ii < failure.length;ii++) {
367                     failure_str+= failure.item(ii) + "\n";
368                 }
369                 var notification = new Notify.Notification({
370                     summary: "Git Live ERROR!!",
371                     failure_str,
372                     "dialog-information"
373                     
374                 });
375     
376                 notification.set_timeout(5); // show errros for longer
377                 notification.show();   
378             }
379         } catch(Error e) {
380             print(e.message);
381             
382         }
383         this.queueRunning = false;
384     }
385     
386
387
388     
389
390     string[] just_created;
391
392     public void initRepo(MonitorNamePathDir src) { } // called on startup at the top level repo dir.
393  
394  
395  
396
397
398     public void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest) { }
399    
400
401
402     public void onChanged(MonitorNamePathDir src) { }
403     { 
404         return; // always ignore this..?
405         //this.parsePath(src);
406     },
407     
408
409  
410     /**
411      *  results in  git add  + git commit..
412      *
413      */
414     public void onChangesDoneHint(MonitorNamePathDir src) { }
415     { 
416         
417         if (this.paused) {
418             return true;
419         }
420             
421
422         this.lastAdd = new DateTime.now(); 
423         var cmd = new GitMontitorQueue(src, this.gitlive);
424         if (cmd.shouldIgnore()) {
425             return;
426         }
427         
428        
429         var add_it = false;
430         /*
431         if (this.is_just_created(cmd.path)) {
432             
433         if (typeof(this.just_created[src.path]) !='undefined') {
434             delete this.just_created[src.path];
435             
436             this.queue.push( 
437                 [ src.gitpath,  'add', src.vpath ],
438                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
439                 
440             );
441          
442             return;
443         }
444         */
445         cmd.add = src.vpath;
446         this.queue.append_val(cmd);
447
448         var cmd = new GitMontitorQueue(src, this.gitlive);
449         cmd.name = "commit";
450         cmd.message = src.vpath;
451         this.queue.append_val(cmd);
452  
453          
454     }
455     public void onDeleted(MonitorNamePathDir src) 
456    { 
457         if (this.paused) {
458             return true;
459         }
460         this.lastAdd = new DateTime.now(); 
461         var cmd = new GitMontitorQueue(src, this.gitlive);
462         if (cmd.shouldIgnore()) {
463             return;
464         }
465         // should check if monitor needs removing..
466         // it should also check if it was a directory.. - so we dont have to commit all..
467         cmd.name = "rm";
468         cmd.rm = src.vpath;
469         this.queue.append_val(cmd);
470
471         var cmd = new GitMontitorQueue(src, this.gitlive);
472         cmd.name = "commit";
473         cmd.message = src.vpath;
474         cmd.commit_all = true;
475
476         this.queue.append_val(cmd);
477  
478     }
479     public void onCreated(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
490         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
491            // this.just_created[src.path] = true;
492             return; // we do not handle file create flags... - use done hint.
493         }
494         // directory has bee created
495         this.monitor(src.path);
496         this.top.append_val(src.path);
497         this.monitor(src.path, ( fm,  f_orig,  of_orig,  event_type) => {
498                 this.onEvent (fm,  f_orig,  of_orig,  event_type ) ;
499             } );
500
501
502 // -- no point in adding a dir.. as git does not handle them...
503 //        this.queue.push( 
504   //          [ src.gitpath, 'add' , src.vpath,  { all: true } ],
505  //           [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
506   //          
507    //     );
508
509     }
510
511     public void onAttributeChanged(MonitorNamePathDir src) { }
512
513         if (this.paused) {
514             return true;
515         }
516         this.lastAdd = new DateTime.now(); 
517         var cmd = new GitMontitorQueue(src, this.gitlive);
518         if (cmd.shouldIgnore()) {
519             return;
520         }
521         cmd.name = "add";
522         cmd.add = src.vpath;
523         this.queue.append_val(cmd);
524
525         var cmd = new GitMontitorQueue(src, this.gitlive);
526         cmd.name = "commit";
527         cmd.message = "Attribute changed " + cmd.vpath;
528         this.queue.append_val(cmd);
529     }
530
531
532