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