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