GitMonitor.js
[gitlive] / GitMonitor.js
1
2 var Gio      = imports.gi.Gio;
3 var Gtk      = imports.gi.Gtk;
4 var Notify   = imports.gi.Notify;
5 var GLib     = imports.gi.GLib;
6
7 var Spawn = imports.Spawn;
8 var StatusIcon = imports.StatusIcon.StatusIcon;
9 var Monitor = imports.Monitor.Monitor;
10
11
12
13 var GitMonitor = new Monitor({
14     
15     /**
16      * @property {String} the "gitlive" directory, normally ~/gitlive
17      *  dset by OWNER... - we should do this as a CTOR.
18      *  
19      */
20     gitlive : false,
21     
22     
23     queue : [],
24     queueRunning : false,
25      
26      
27      
28     pause : function() {
29         this.paused = true;
30         this.queue = [];
31         imports.StatusIcon.StatusIcon.el.set_from_stock( Gtk.STOCK_MEDIA_PAUSE );
32     },
33     
34     resume : function() {
35         this.paused = false;
36         this.queue = [];
37         imports.StatusIcon.StatusIcon.el.set_from_stock( Gtk.STOCK_MEDIA_PLAY );
38         
39         
40     },
41     
42     /**
43      * Start the monitoring
44      * and run the queue every 500 milliseconds..
45      *
46      */
47     start: function() {
48         var _this = this;
49         this.lastAdd = new Date();
50         
51         this.top.forEach(this.monitor, this);
52          
53         GLib.timeout_add(GLib.PRIORITY_LOW, 500, function() {
54             //TIMEOUT", _this.queue.length , _this.queueRunning].join(', '));
55             if (!_this.queue.length || _this.queueRunning) {
56                 return 1;
57             }
58             var last = Math.floor(((new Date()) - _this.lastAdd) / 100);
59             
60             //print("LAST RUN?" + last);
61             
62             if (last < 5) { // wait 1/2 a seconnd before running.
63                 return 1;
64             }
65             //_this.lastAdd = new Date();
66             //return 1;
67         
68             _this.runQueue();
69             return 1;
70         },null,null);
71         
72         try { 
73             var notification = new Notify.Notification({
74                 summary: "Git Live",
75                 body : this.gitlive + "\nMonitoring " + this.monitors.length + " Directories",
76                 timeout : 5
77             });
78     
79             notification.set_timeout(5);
80             notification.show();
81         } catch(e) {
82             print(e.toString());
83         }
84
85     },
86     
87     
88     monitor : function(path, fn, depth)
89     {
90         
91         
92         Monitor.prototype.monitor.call(this, path,fn, depth);
93     },
94     
95     /**
96      * run the queue.
97      * - pulls the items off the queue 
98      *    (as commands run concurrently and new items may get added while it's running)
99      * - runs the queue items
100      * - pushes upstream.
101      * 
102      */
103     runQueue: function()
104     {
105         
106         if (this.paused) {
107             return;
108         }
109         this.queueRunning = true;
110         var cmds = [];
111         this.queue.forEach(function (q) {
112             cmds.push(q);
113         });
114         this.queue = []; // empty queue!
115         
116         var success = [];
117         var failure = [];
118         var repos = [];
119         var done = [];
120         
121         // first build a array of repo's to work with
122         var repo_list = {};
123         
124         // pull and group.
125         
126         //print(JSON.stringify(cmds));
127         this.paused = true;
128         cmds.forEach(function(cmd) {
129             var gitpath = cmd.shift(); 
130             if (typeof(repo_list[gitpath]) == 'undefined') {
131                 repo_list[gitpath] = new imports.Scm.Git.Repo.Repo( { repopath : gitpath });
132                 repo_list[gitpath].cmds = [];
133                 repo_list[gitpath].pull();
134             }
135             repo_list[gitpath].cmds.push(cmd);
136         });
137         this.paused = false;
138         // build add, remove and commit message list..
139         
140          
141          
142         for (var gitpath in repo_list) {
143             var repo = repo_list[gitpath];
144             var add_files = [];
145             var remove_files = [];
146             var messages = [];
147             //print(JSON.stringify(repo.cmds,null,4));
148             
149             repo.cmds.forEach(function(cmd) {
150                 
151                 var name = cmd.shift();
152                 var arg = cmd.shift();
153                 
154                 switch(name) {
155                     case 'add' :
156                         
157                         if (add_files.indexOf(arg) > -1) {
158                             break;
159                         }
160                         
161                         // if file does not exist.. s,ip
162                         
163                         //if (!GLib.file_test(arg, GLib.FileTest.EXISTS)) {
164                              
165                         //    break;
166                          // }
167         
168                         
169                         add_files.push(arg);
170                         break;
171                     
172                     case 'rm':
173                         
174                         if (add_files.indexOf(arg) > -1) {
175                             break;
176                         }
177                         
178                         // if file exists, do not try and delete it.
179                         if (GLib.file_test(arg, GLib.FileTest.EXISTS)) {
180                             break;
181                         }
182                         
183                         remove_files.push(arg);
184                         break;
185                     
186                     case 'commit' :
187                         
188                         if (messages.indexOf(arg.message) < 0) { 
189                             messages.push(arg.message);
190                         }
191                         break;    
192                 } 
193             });
194             
195             //repo.debug = 1;
196             // these can fail... at present... as we wildcard stuff.
197             print("ADD : "  + JSON.stringify(add_files));
198             
199             // make sure added files do not get removed..
200             remove_files  = remove_files.filter(function(v) {
201                 return add_files.indexOf(v) < 0;
202             });
203             print("REMOVE : "  + JSON.stringify(remove_files));
204             
205             
206             // make sure monitoring is paused so it does not recursively pick up
207             // deletions
208             
209             // -- DO STUFF..
210             
211             repo.add(add_files);
212             
213             repo.remove(remove_files);
214             this.paused = false;
215             
216             
217             try { 
218                 success.push(repo.commit({
219                     reason : messages.join("\n"),
220                     files : add_files  
221                 }));
222                 success.push(repo.push());
223
224             } catch(e) {
225                 failure.push(e.message);
226                 
227             }   
228         }
229         
230         // finally merge all the commit messages.
231          
232         try {
233             // catch notification failures.. so we can carry on..
234             if (success.length) {
235                 print(success.join("\n"));
236                 
237                 var notification = new Notify.Notification({
238                     summary: "Git Live Commited",
239                     body : success.join("\n"),
240                     timeout : 5
241                     
242                 });
243     
244                 notification.set_timeout(5);
245                 notification.show();   
246             }
247             
248             if (failure.length) {
249             
250                 var notification = new Notify.Notification({
251                     summary: "Git Live ERROR!!",
252                     body : failure.join("\n"),
253                     timeout : 5
254                     
255                 });
256     
257                 notification.set_timeout(5); // show errros for longer
258                 notification.show();   
259             }
260         } catch(e) {
261             print(e.toString());
262             
263         }
264         this.queueRunning = false;
265     },
266     
267     shouldIgnore: function(f)
268     {
269         
270         if (this.paused) {
271             return true;
272         }
273         // vim.. what a seriously brain dead program..
274         if (f.name == '4913') {
275             return true;
276         }
277         
278         if (f.name[0] == '.') {
279             // except!
280             if (f.name == '.htaccess') {
281                 return false;
282             }
283             
284             return true;
285         }
286         if (f.name.match(/~$/)) {
287             return true;
288         }
289         if (f.name.match(/^nbproject/)) {
290             return true;
291         }
292         // ignore anything in top level!!!!
293         if (!f.vpath.length) {
294             return true;
295         }
296         
297         return false;
298     },
299     
300     /**
301      * parsePath:
302      * Fill in gitlive, vpath and repo  
303      * 
304      */
305     parsePath: function(f)
306     {
307            
308         var vpath_ar = f.path.substring(this.gitlive.length +1).split('/');
309         
310         f.gitpath = this.gitlive + '/' + vpath_ar.shift();
311         f.vpath =  vpath_ar.join('/');
312         //f.repo = new imports.Scm.Git.Repo({ repopath: f.gitpath })
313         
314         
315     },
316     
317     just_created : {},
318       
319     onChanged : function(src) 
320     { 
321         return; // always ignore this..?
322         //this.parsePath(src);
323     },
324     
325     
326     
327     
328     /**
329      *  results in  git add  + git commit..
330      *
331      */
332     onChangesDoneHint : function(src) 
333     { 
334         this.lastAdd = new Date();
335         this.parsePath(src);
336         if (this.shouldIgnore(src)) {
337             return;
338         }
339         
340        
341         var add_it = false;
342         if (typeof(this.just_created[src.path]) !='undefined') {
343             delete this.just_created[src.path];
344             
345             this.queue.push( 
346                 [ src.gitpath,  'add', src.vpath ],
347                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
348                 
349             );
350          
351             return;
352         }
353         
354         this.queue.push( 
355             [ src.gitpath,  'add', src.vpath ],
356             [ src.gitpath,  'commit',  {  message: src.vpath} ]
357
358             
359         );
360     },
361     onDeleted : function(src) 
362     { 
363         this.lastAdd = new Date();
364         this.parsePath(src);
365         if (this.shouldIgnore(src)) {
366             return;
367         }
368         // should check if monitor needs removing..
369         // it should also check if it was a directory.. - so we dont have to commit all..
370         
371         
372         this.queue.push( 
373             [ src.gitpath, 'rm' , src.vpath ],
374             [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
375             
376         );
377     
378         
379     },
380     onCreated : function(src) 
381     { 
382         this.lastAdd = new Date();
383         this.parsePath(src);
384         if (this.shouldIgnore(src)) {
385             return;
386         }
387         
388         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
389             this.just_created[src.path] = true;
390             return; // we do not handle file create flags... - use done hint.
391         }
392         // director has bee created
393         this.monitor(src.path);
394         
395         this.queue.push( 
396             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
397             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
398             
399         );
400         
401         
402     },
403     onAttributeChanged : function(src)
404     { 
405         this.lastAdd = new Date();
406         this.parsePath(src);
407         if (this.shouldIgnore(src)) {
408             return;
409         }
410         
411         this.queue.push(
412                         
413             //[ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
414             [ src.gitpath, 'add' ,  src.vpath ],
415              [ src.gitpath, 'commit' ,    {  message: "Attribute Changed :" + src.vpath} ]
416         );
417  
418     
419     },
420     
421     onMoved : function(src,dest)
422     { 
423         this.lastAdd = new Date();
424         this.parsePath(src);
425         this.parsePath(dest);
426         
427         if (src.gitpath != dest.gitpath) {
428             this.onDeleted(src);
429             this.onCreated(dest);
430             this.onChangedDoneHint(dest);
431             return;
432         }
433         // needs to handle move to/from unsupported types..
434         
435         if (this.shouldIgnore(src)) {
436             return;
437         }
438         if (this.shouldIgnore(dest)) {
439             return;
440         }
441         
442         this.queue.push( 
443            // [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
444              [ src.gitpath, 'add',    dest.vpath ],
445              [ src.gitpath, 'rm',    src.vpath ],
446              
447             [ src.gitpath, 'commit' , 
448                 { message:   'MOVED ' + src.vpath +' to ' + dest.vpath}
449             ]
450         );
451          
452     }
453           
454     
455 });
456  
457