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