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             repo.add(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             
174             repo.remove(remove_files);
175             
176             try { 
177                 success.push(repo.commit({
178                     reason : messages.join("\n"),
179                     files : add_files  
180                 }));
181                 success.push(repo.push());
182
183             } catch(e) {
184                 failure.push(e.message);
185                 
186             }   
187         }
188         
189         // finally merge all the commit messages.
190          
191         try {
192             // catch notification failures.. so we can carry on..
193             if (success.length) {
194                 print(success.join("\n"));
195                 
196                 var notification = new Notify.Notification({
197                     summary: "Git Live Commited",
198                     body : success.join("\n"),
199                     timeout : 5
200                     
201                 });
202     
203                 notification.set_timeout(5);
204                 notification.show();   
205             }
206             
207             if (failure.length) {
208             
209                 var notification = new Notify.Notification({
210                     summary: "Git Live ERROR!!",
211                     body : failure.join("\n"),
212                     timeout : 5
213                     
214                 });
215     
216                 notification.set_timeout(5); // show errros for longer
217                 notification.show();   
218             }
219         } catch(e) {
220             print(e.toString());
221             
222         }
223         this.queueRunning = false;
224     },
225     
226     shouldIgnore: function(f)
227     {
228         
229         if (this.paused) {
230             return true;
231         }
232         // vim.. what a seriously brain dead program..
233         if (f.name == '4913') {
234             return true;
235         } 
236         if (f.name[0] == '.') {
237             // except!
238             if (f.name == '.htaccess') {
239                 return false;
240             }
241             
242             return true;
243         }
244         if (f.name.match(/~$/)) {
245             return true;
246         }
247         // ignore anything in top level!!!!
248         if (!f.vpath.length) {
249             return true;
250         }
251         
252         return false;
253     },
254     
255     /**
256      * parsePath:
257      * Fill in gitlive, vpath and repo  
258      * 
259      */
260     parsePath: function(f)
261     {
262            
263         var vpath_ar = f.path.substring(this.gitlive.length +1).split('/');
264         
265         f.gitpath = this.gitlive + '/' + vpath_ar.shift();
266         f.vpath =  vpath_ar.join('/');
267         //f.repo = new imports.Scm.Git.Repo({ repopath: f.gitpath })
268         
269         
270     },
271     
272     just_created : {},
273       
274     onChanged : function(src) 
275     { 
276         return; // always ignore this..?
277         //this.parsePath(src);
278     },
279     
280     
281     
282     
283     /**
284      *  results in  git add  + git commit..
285      *
286      */
287     onChangesDoneHint : function(src) 
288     { 
289         this.parsePath(src);
290         if (this.shouldIgnore(src)) {
291             return;
292         }
293         
294        
295         var add_it = false;
296         if (typeof(this.just_created[src.path]) !='undefined') {
297             delete this.just_created[src.path];
298             this.lastAdd = new Date();
299             this.queue.push( 
300                 [ src.gitpath,  'add', src.vpath ],
301                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
302                 
303             );
304          
305             return;
306         }
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     },
315     onDeleted : function(src) 
316     { 
317         this.parsePath(src);
318         if (this.shouldIgnore(src)) {
319             return;
320         }
321         // should check if monitor needs removing..
322         // it should also check if it was a directory.. - so we dont have to commit all..
323         
324         this.lastAdd = new Date();
325         this.queue.push( 
326             [ src.gitpath, 'rm' , src.vpath ],
327             [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
328             
329         );
330     
331         
332     },
333     onCreated : function(src) 
334     { 
335         this.parsePath(src);
336         if (this.shouldIgnore(src)) {
337             return;
338         }
339         
340         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
341             this.just_created[src.path] = true;
342             return; // we do not handle file create flags... - use done hint.
343         }
344         // director has bee created
345         this.monitor(src.path);
346         this.lastAdd = new Date();
347         this.queue.push( 
348             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
349             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
350             
351         );
352         
353         
354     },
355     onAttributeChanged : function(src) { 
356         this.parsePath(src);
357         if (this.shouldIgnore(src)) {
358             return;
359         }
360         this.lastAdd = new Date();
361         this.queue.push(
362                         
363             //[ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
364             [ src.gitpath, 'add' ,  src.vpath ],
365              [ src.gitpath, 'commit' ,    {  message: "Attribute Changed :" + src.vpath} ]
366         );
367  
368     
369     },
370     
371     onMoved : function(src,dest)
372     { 
373         this.parsePath(src);
374         this.parsePath(dest);
375         
376         if (src.gitpath != dest.gitpath) {
377             this.onDeleted(src);
378             this.onCreated(dest);
379             this.onChangedDoneHint(dest);
380             return;
381         }
382         // needs to handle move to/from unsupported types..
383         
384         if (this.shouldIgnore(src)) {
385             return;
386         }
387         if (this.shouldIgnore(dest)) {
388             return;
389         }
390         this.lastAdd = new Date();
391         this.queue.push( 
392            // [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
393              [ src.gitpath, 'add',    dest.vpath ],
394              [ src.gitpath, 'rm',    src.vpath ],
395              
396             [ src.gitpath, 'commit' , 
397                 { message:   'MOVED ' + src.vpath +' to ' + dest.vpath}
398             ]
399         );
400          
401     }
402           
403     
404 });
405  
406