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
13 GI      = imports.gi.GIRepository
14 GLib        = imports.gi.GLib;
15
16 // we add this in, as it appears to get lost sometimes if we set it using the ENV. variable in builder.sh
17 GI.IRepository.prepend_search_path(GLib.get_home_dir() + '/.Builder/girepository-1.1');
18
19 Gio         = imports.gi.Gio;
20 Gtk         = imports.gi.Gtk;
21 Notify      = imports.gi.Notify;
22
23 Spawn       = imports.Spawn;
24 Git         = imports.Git;
25 StatusIcon  = imports.StatusIcon.StatusIcon;
26 Monitor     = imports.Monitor.Monitor;
27
28
29 //File = imports[__script_path__+'/../introspection-doc-generator/File.js'].File
30 Gtk.init (null, null);
31
32 var gitlive = GLib.get_home_dir() + "/gitlive";
33
34 if (!GLib.file_test(gitlive, GLib.FileTest.IS_DIR)) {
35     var msg = new Gtk.MessageDialog({message_type:
36         Gtk.MessageType.INFO, buttons : Gtk.ButtonsType.OK, text: "GIT Live - ~/gitlive does not exist."});
37     msg.run();
38     msg.destroy();
39     
40     Seed.quit();
41 }
42
43  
44 var monitor = new Monitor({
45     
46     queue : [],
47     queueRunning : false,
48      
49     start: function() {
50         var _this = this;
51         this.lastAdd = new Date();
52          
53         GLib.timeout_add(GLib.PRIORITY_LOW, 500, function() {
54             //TIMEOUT", _this.queue.length , _this.queueRunning].join(', '));
55             if (!_this.queue.length || _this.queueRunning) {
56                 return 1;
57             }
58             var last = Math.floor(((new Date()) - this.lastAdd) / 100);
59             if (last < 4) { // wait 1/2 a seconnd before running.
60                 return 1;
61             }
62             _this.runQueue();
63             return 1;
64         },null,null);
65         
66         Monitor.prototype.start.call(this);
67         var notification = new Notify.Notification({
68             summary: "Git Live",
69             body : gitlive + "\nMonitoring " + this.monitors.length + " Directories"
70         });
71
72         notification.set_timeout(2000);
73         notification.show();   
74     },
75     /**
76      * run the queue.
77      * - pulls the items off the queue 
78      *    (as commands run concurrently and new items may get added while it's running)
79      * - runs the queue items
80      * - pushes upstream.
81      * 
82      */
83     runQueue: function()
84     {
85         this.queueRunning = true;
86         var cmds = [];
87         this.queue.forEach(function (q) {
88             cmds.push(q);
89         });
90         this.queue = []; // empty queue!
91         
92         var success = [];
93         var failure = [];
94         var repos = [];
95         var done = [];
96         cmds.forEach(function(cmd) {
97             // prevent duplicate calls..
98             if (done.indexOf(cmd.join(',')) > -1) {
99                 return;
100             }
101             done.push(cmd.join(','));
102             
103             if (repos.indexOf(cmd[0]) < 0) {
104                 repos.push(cmd[0]);
105                 Git.run(cmd[0] , 'pull'); // pull before we push!
106             }
107             var sp = Git.run.apply(Git,cmd);
108              
109             switch (sp.result * 1) {
110                 case 0: // success:
111                     success.push(sp.args.join(' '));
112                     if (sp.output.length) success.push(sp.output + '');
113                   // if (sp.stderr.length) success.push(sp.stderr + '');
114                     break;
115                 default: 
116                     failure.push(sp.args.join(' '));
117                     if (sp.output.length) failure.push(sp.output);
118                     if (sp.stderr.length) failure.push(sp.stderr);
119                     break;
120             }
121             
122         });
123          
124         // push upstream.
125         repos.forEach(function(r) {
126             var sp = Git.run(r , 'push', { all: true } );
127             if (sp.length) {
128                 success.push(sp);
129             }
130             
131         });
132         
133         if (success.length) {
134             print(success.join("\n"));
135             var notification = new Notify.Notification({
136                 summary: "Git Live Commited",
137                 body : success.join("\n")
138                 
139             });
140
141             notification.set_timeout(2000);
142             notification.show();   
143         }
144         if (failure.length) {
145         
146             var notification = new Notify.Notification({
147                 summary: "Git Live ERROR!!",
148                 body : failure.join("\n")
149                 
150             });
151
152             notification.set_timeout(5000); // show errros for longer
153             notification.show();   
154         }
155         this.queueRunning = false;
156     },
157     
158     shouldIgnore: function(f)
159     {
160         if (f.name[0] == '.') {
161             // except!
162             if (f.name == '.htaccess') {
163                 return false;
164             }
165             
166             return true;
167         }
168         if (f.name.match(/~$/)) {
169             return true;
170         }
171         // ignore anything in top level!!!!
172         if (!f.vpath.length) {
173             return true;
174         }
175         
176         return false;
177         
178     },
179     
180     parsePath: function(f) {
181            
182         var vpath_ar = f.path.substring(gitlive.length +1).split('/');
183         
184         f.gitpath = gitlive + '/' + vpath_ar.shift();
185         f.vpath =  vpath_ar.join('/');
186         
187         
188     },
189     
190     just_created : {},
191       
192     onChanged : function(src) 
193     { 
194         return; // always ignore this..?
195         //this.parsePath(src);
196     },
197     onChangesDoneHint : function(src) 
198     { 
199         this.parsePath(src);
200         if (this.shouldIgnore(src)) {
201             return;
202         }
203         
204         var add_it = false;
205         if (typeof(this.just_created[src.path]) !='undefined') {
206             delete this.just_created[src.path];
207             this.lastAdd = new Date();
208             this.queue.push( 
209                 [ src.gitpath,  'add', src.vpath ],
210                 [ src.gitpath,  'commit',  src.vpath, { message: src.vpath} ] 
211                 
212             );
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        
224
225     },
226     onDeleted : function(src) 
227     { 
228         this.parsePath(src);
229         if (this.shouldIgnore(src)) {
230             return;
231         }
232         // should check if monitor needs removing..
233         // it should also check if it was a directory.. - so we dont have to commit all..
234         
235         this.lastAdd = new Date();
236         this.queue.push( 
237             [ src.gitpath, 'rm' , src.vpath ],
238             [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
239             
240         );
241     
242         
243     },
244     onCreated : function(src) 
245     { 
246         this.parsePath(src);
247         if (this.shouldIgnore(src)) {
248             return;
249         }
250         
251         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
252             this.just_created[src.path] = true;
253             return; // we do not handle file create flags... - use done hint.
254         }
255         // director has bee created
256         this.monitor(src.path);
257         this.lastAdd = new Date();
258         this.queue.push( 
259             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
260             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
261             
262         );
263         
264         
265     },
266     onAttributeChanged : function(src) { 
267         this.parsePath(src);
268         if (this.shouldIgnore(src)) {
269             return;
270         }
271         this.lastAdd = new Date();
272         this.queue.push( 
273             [ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
274         );
275  
276     
277     },
278     
279     onMoved : function(src,dest)
280     { 
281         this.parsePath(src);
282         this.parsePath(dest);
283         
284         if (src.gitpath != dest.gitpath) {
285             this.onDeleted(src);
286             this.onCreated(dest);
287             this.onChangedDoneHint(dest);
288             return;
289         }
290         // needs to handle move to/from unsupported types..
291         
292         if (this.shouldIgnore(src)) {
293             return;
294         }
295         if (this.shouldIgnore(dest)) {
296             return;
297         }
298         this.lastAdd = new Date();
299         this.queue.push( 
300             [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
301             [ src.gitpath, 'commit' ,  src.vpath, dest.vpath ,
302                 { message:   'MOVED ' + src.vpath +' to ' + dest.vpath} ]
303         );
304          
305     }
306           
307     
308 });
309  
310  
311   
312
313 function errorDialog(data) {
314     var msg = new Gtk.MessageDialog({
315             message_type: Gtk.MessageType.ERROR, 
316             buttons : Gtk.ButtonsType.OK, 
317             text: data
318     });
319     msg.run();
320     msg.destroy();
321 }
322
323  
324
325
326
327 //
328 // need a better icon...
329
330
331 StatusIcon.init();   
332
333
334 Notify.init("gitlive");
335
336 monitor.add(GLib.get_home_dir() + "/gitlive");
337 monitor.start();
338 Gtk.main();
339 //icon.signal["activate"].connect(on_left_click);
340