gitlive.js
[gitlive] / gitlive.js
1 #!/usr/bin/seed
2 ///<script type="text/javascript">
3 /**
4 * Git Live
5
6 * inotify hooks for ~/gitlive
7 * that commit and push any changes made.
8 * Bit like a revision controled backed up file system!?
9
10
11 */
12 GI      = imports.gi.GIRepository;
13 Gio      = imports.gi.Gio;
14 GLib      = imports.gi.GLib;
15 Gtk      = imports.gi.Gtk;
16 Notify = imports.gi.Notify;
17
18 Spawn = imports.Spawn;
19 Git = imports.Git;
20 StatusIcon = imports.StatusIcon.StatusIcon;
21 Monitor = imports.Monitor.Monitor;
22
23
24 //File = imports[__script_path__+'/../introspection-doc-generator/File.js'].File
25 Gtk.init (null, null);
26  
27 var gitlive = GLib.get_home_dir() + "/gitlive";
28
29 if (!GLib.file_test(gitlive, GLib.FileTest.IS_DIR)) {
30     var msg = new Gtk.MessageDialog({message_type:
31         Gtk.MessageType.INFO, buttons : Gtk.ButtonsType.OK, text: "GIT Live - ~/gitlive does not exist."});
32     msg.run();
33     msg.destroy();
34     
35     Seed.quit();
36 }
37
38  
39 var monitor = new Monitor({
40     
41     queue : [],
42     queueRunning : false,
43     nqv : false, // temp var while I switch to queued version.
44     
45     start: function() {
46         var _this = this;
47         this.lastAdd = new Date();
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         Monitor.prototype.start.call(this);
63         var notification = new Notify.Notification({
64             summary: "Git Live",
65             body : gitlive + "\nMonitoring " + this.monitors.length + " Directories"
66         });
67
68         notification.set_timeout(500);
69         notification.show();   
70         
71     },
72     /**
73      * run the queue.
74      * - pulls the items off the queue 
75      *    (as commands run concurrently and new items may get added while it's running)
76      * - runs the queue items
77      * - pushes upstream.
78      * 
79      */
80     runQueue: function()
81     {
82         this.queueRunning = true;
83         var cmds = [];
84         this.queue.forEach(function (q) {
85             cmds.push(q);
86         });
87         this.queue = []; // empty queue!
88         
89         var success = [];
90         var failure = [];
91         var repos = [];
92         cmds.forEach(function(cmd) {
93             if (repos.indexOf(cmd[0]) < 0) {
94                 repos.push(cmd[0]);
95             }
96             var sp = Git.run.apply(Git,cmd);
97             
98             success.push([cmd[1],cmd[2]].join(' '));
99             if (sp.length) {
100                 success.push(sp);
101             }
102              
103             /*
104             switch (sp.result) {
105                 case 0: // success:
106                     success.push(sp.args.join(' '));
107                     success.push(sp.output);
108                     break;
109                 default: 
110                     failure.push(sp.args.join(' '));
111                     failure.push(sp.output);
112                     failure.push(sp.stderr);
113                     break;
114             }
115             */
116              
117         });
118         // push upstream.
119         repos.forEach(function(r) {
120             var sp = Git.run(r , 'push', { all: true } );
121             if (sp.length) {
122                 success.push(sp);
123             }
124             
125         });
126         
127         if (success.length) {
128         
129             var notification = new Notify.Notification({
130                 summary: "Git Live Commited",
131                 body : success.join("\n")
132                 
133             });
134
135             notification.set_timeout(500);
136             notification.show();   
137         }
138         if (failure.length) {
139         
140             var notification = new Notify.Notification({
141                 summary: "Git Live ERROR!!",
142                 body : failure.join("\n")
143                 
144             });
145
146             notification.set_timeout(500);
147             notification.show();   
148         }
149         this.queueRunning = false;
150     },
151     
152     shouldIgnore: function(f)
153     {
154         if (f.name[0] == '.') {
155             // except!
156             if (f.name == '.htaccess') {
157                 return false;
158             }
159             
160             return true;
161         }
162         if (f.name.match(/~$/)) {
163             return true;
164         }
165         // ignore anything in top level!!!!
166         if (!f.vpath.length) {
167             return true;
168         }
169         
170         return false;
171         
172     },
173     
174     parsePath: function(f) {
175            
176         var vpath_ar = f.path.substring(gitlive.length +1).split('/');
177         
178         f.gitpath = gitlive + '/' + vpath_ar.shift();
179         f.vpath =  vpath_ar.join('/');
180         
181         
182     },
183     
184     just_created : {},
185       
186     onChanged : function(src) 
187     { 
188         return; // always ignore this..?
189         //this.parsePath(src);
190     },
191     onChangesDoneHint : function(src) 
192     { 
193         this.parsePath(src);
194         if (this.shouldIgnore(src)) {
195             return;
196         }
197         
198         var add_it = false;
199         if (typeof(this.just_created[src.path]) !='undefined') {
200             delete this.just_created[src.path];
201             this.lastAdd = new Date();
202             this.queue.push( 
203                 [ src.gitpath,  'add', src.vpath ],
204                 [ src.gitpath,  'commit',  src.vpath, { message: src.vpath} ] 
205                 
206             );
207             if (this.nqv) {
208                 
209                 Git.run(src.gitpath, 'add', src.vpath);
210                 var sp = Git.run(src.gitpath, 'commit', { all: true, message: src.vpath});
211                 Git.run(src.gitpath , 'push', { all: true } );
212                 notify(src.name,"CHANGED", sp);
213             }
214             return;
215         }
216         this.lastAdd = new Date();
217         this.queue.push( 
218             [ src.gitpath,  'add', src.vpath ],
219             [ src.gitpath,  'commit', src.vpath, {  message: src.vpath} ]
220
221             
222         );
223         if (this.nqv) {
224             var sp = Git.run(src.gitpath, 'commit', { all: true, message: src.vpath});
225             Git.run(src.gitpath , 'push', '--all' );
226             notify(src.name,"CHANGED", sp);
227         }
228
229     },
230     onDeleted : function(src) 
231     { 
232         this.parsePath(src);
233         if (this.shouldIgnore(src)) {
234             return;
235         }
236         // should check if monitor needs removing..
237         // it should also check if it was a directory.. - so we dont have to commit all..
238         
239         this.lastAdd = new Date();
240         this.queue.push( 
241             [ src.gitpath, 'rm' , src.vpath ],
242             [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
243             
244         );
245         if (!this.nqv) {
246             return;
247         }
248         
249         var sp = Git.run(src.gitpath,'rm' , src.vpath);
250         Git.run(src.gitpath , 'push', { all: true } );
251         if (sp.status !=0) {
252             notify(src.name,"DELETED", sp);
253             return;
254         }
255         sp = Git.run(src.gitpath,'commit' ,{ all: true, message: src.vpath});
256         Git.run(src.gitpath , 'push',{ all: true });
257         notify(src.name,"DELETED", sp);
258         return;
259         
260     },
261     onCreated : function(src) 
262     { 
263         this.parsePath(src);
264         if (this.shouldIgnore(src)) {
265             return;
266         }
267         
268         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
269             this.just_created[src.path] = true;
270             return; // we do not handle file create flags... - use done hint.
271         }
272         // director has bee created
273         this.monitor(src.path);
274         this.lastAdd = new Date();
275         this.queue.push( 
276             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
277             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
278             
279         );
280         if (!this.nqv) {
281             return;
282         }
283         var sp = Git.run(src.gitpath, 'add', src.vpath);
284         Git.run(src.gitpath , 'push', { all: true } );
285
286         if (sp.status !=0) {
287             notify(src.path,"CREATED", sp);
288             return;
289         }
290         //uh.call(fm,f,of, event_type);
291         sp = Git.run(src.gitpath,'commit' , { all: true, message: src.vpath});
292         Git.run(src.gitpath , 'push', { all: true } );
293         notify(src.path,"CREATED", sp);
294         return;
295         
296     },
297     onAttributeChanged : function(src) { 
298         this.parsePath(src);
299         if (this.shouldIgnore(src)) {
300             return;
301         }
302         this.lastAdd = new Date();
303         this.queue.push( 
304             [ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
305         );
306         if (!this.nqv) {
307             return;
308         }
309         var sp = Git.run(src.gitpath, 'commit',{ all: true, message: src.vpath});
310         Git.run(src.gitpath , 'push', { all: true } );
311         notify(src.path,"ATTRIBUTE_CHANGED", sp);
312         return;
313     
314     },
315     
316     onMoved : function(src,dest)
317     { 
318         this.parsePath(src);
319         this.parsePath(dest);
320         
321         if (src.gitpath != dest.gitpath) {
322             this.onDeleted(src);
323             this.onCreated(dest);
324             this.onChangedDoneHint(dest);
325             return;
326         }
327         // needs to handle move to/from unsupported types..
328         
329         if (this.shouldIgnore(src)) {
330             return;
331         }
332         if (this.shouldIgnore(dest)) {
333             return;
334         }
335         this.lastAdd = new Date();
336         this.queue.push( 
337             [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
338             [ src.gitpath, 'commit' ,  src.vpath, dest.vpath ,
339                 { message:   'MOVED ' + src.vpath +' to ' + dest.vpath} ]
340         );
341         
342         if (!this.nqv) {
343             return;
344         }
345         
346         var sp = Git.run(src.gitpath,  'mv',  '-k', src.vpath, dest.vpath);
347         if (sp.status !=0) {
348             notify(dest.path,"MOVED", sp);
349             return;
350         }
351         sp = Git.run(src.gitpath,'commit' , { all: true, message:   'MOVED ' + src.vpath +' to ' + dest.vpath} );
352         Git.run(src.gitpath , 'push', { all: true } );
353         notify(src.path,"MOVED", sp);
354         
355     }
356           
357     
358 });
359  
360  
361  
362
363 function notify(fn, act , sp)
364 {
365     var sum = act + " " + fn;
366     
367     var notification = new Notify.Notification({
368         summary: sum,
369                 body : sp
370         });
371
372     notification.set_timeout(500);
373     notification.show();
374 }
375
376
377
378   
379
380 function errorDialog(data) {
381     var msg = new Gtk.MessageDialog({
382             message_type: Gtk.MessageType.ERROR, 
383             buttons : Gtk.ButtonsType.OK, 
384             text: data
385     });
386     msg.run();
387     msg.destroy();
388 }
389
390  
391
392
393
394 //
395 // need a better icon...
396
397 StatusIcon.init(); 
398 Notify.init("gitlive");
399 monitor.add(GLib.get_home_dir() + "/gitlive");
400 monitor.start();
401 Gtk.main();
402 //icon.signal["activate"].connect(on_left_click);
403