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