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