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