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