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         if (f.name[0] == '.') {
233             // except!
234             if (f.name == '.htaccess') {
235                 return false;
236             }
237             
238             return true;
239         }
240         if (f.name.match(/~$/)) {
241             return true;
242         }
243         // ignore anything in top level!!!!
244         if (!f.vpath.length) {
245             return true;
246         }
247         
248         return false;
249     },
250     
251     /**
252      * parsePath:
253      * Fill in gitlive, vpath and repo  
254      * 
255      */
256     parsePath: function(f)
257     {
258            
259         var vpath_ar = f.path.substring(this.gitlive.length +1).split('/');
260         
261         f.gitpath = this.gitlive + '/' + vpath_ar.shift();
262         f.vpath =  vpath_ar.join('/');
263         //f.repo = new imports.Scm.Git.Repo({ repopath: f.gitpath })
264         
265         
266     },
267     
268     just_created : {},
269       
270     onChanged : function(src) 
271     { 
272         return; // always ignore this..?
273         //this.parsePath(src);
274     },
275     
276     
277     
278     
279     /**
280      *  results in  git add  + git commit..
281      *
282      */
283     onChangesDoneHint : function(src) 
284     { 
285         this.parsePath(src);
286         if (this.shouldIgnore(src)) {
287             return;
288         }
289         
290        
291         var add_it = false;
292         if (typeof(this.just_created[src.path]) !='undefined') {
293             delete this.just_created[src.path];
294             this.lastAdd = new Date();
295             this.queue.push( 
296                 [ src.gitpath,  'add', src.vpath ],
297                 [ src.gitpath,  'commit',    { message: src.vpath} ] 
298                 
299             );
300          
301             return;
302         }
303         this.lastAdd = new Date();
304         this.queue.push( 
305             [ src.gitpath,  'add', src.vpath ],
306             [ src.gitpath,  'commit',  {  message: src.vpath} ]
307
308             
309         );
310     },
311     onDeleted : function(src) 
312     { 
313         this.parsePath(src);
314         if (this.shouldIgnore(src)) {
315             return;
316         }
317         // should check if monitor needs removing..
318         // it should also check if it was a directory.. - so we dont have to commit all..
319         
320         this.lastAdd = new Date();
321         this.queue.push( 
322             [ src.gitpath, 'rm' , src.vpath ],
323             [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
324             
325         );
326     
327         
328     },
329     onCreated : function(src) 
330     { 
331         this.parsePath(src);
332         if (this.shouldIgnore(src)) {
333             return;
334         }
335         
336         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
337             this.just_created[src.path] = true;
338             return; // we do not handle file create flags... - use done hint.
339         }
340         // director has bee created
341         this.monitor(src.path);
342         this.lastAdd = new Date();
343         this.queue.push( 
344             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
345             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
346             
347         );
348         
349         
350     },
351     onAttributeChanged : function(src) { 
352         this.parsePath(src);
353         if (this.shouldIgnore(src)) {
354             return;
355         }
356         this.lastAdd = new Date();
357         this.queue.push(
358                         
359             //[ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
360             [ src.gitpath, 'add' ,  src.vpath ],
361              [ src.gitpath, 'commit' ,    {  message: "Attribute Changed :" + src.vpath} ]
362         );
363  
364     
365     },
366     
367     onMoved : function(src,dest)
368     { 
369         this.parsePath(src);
370         this.parsePath(dest);
371         
372         if (src.gitpath != dest.gitpath) {
373             this.onDeleted(src);
374             this.onCreated(dest);
375             this.onChangedDoneHint(dest);
376             return;
377         }
378         // needs to handle move to/from unsupported types..
379         
380         if (this.shouldIgnore(src)) {
381             return;
382         }
383         if (this.shouldIgnore(dest)) {
384             return;
385         }
386         this.lastAdd = new Date();
387         this.queue.push( 
388            // [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
389              [ src.gitpath, 'add',    dest.vpath ],
390              [ src.gitpath, 'rm',    src.vpath ],
391              
392             [ src.gitpath, 'commit' , 
393                 { message:   'MOVED ' + src.vpath +' to ' + dest.vpath}
394             ]
395         );
396          
397     }
398           
399     
400 });
401  
402