try fix
[gitlive] /
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 * The aims of this
12 * A) have a gitlive branch - where all our commits go.. - so they can be replicated on the server 
13 * B) HEAD branch - where things get merged to..
14 *    -- eventually on closing issues..
15 *    -- currently when we switch from one feature to another..
16 *
17 * CURRENT HEAD?   
18 * git log -n 1
19 * --pretty=format:%H BRANCHNAME
20
21 *
22 * Notes on feature branch implementation
23 * We need to add a gitlive branch on the remote server..
24 *   git push origin origin:refs/heads/gitlive 
25 *   git checkout --track -b gitlive origin/gitlive << means pull will use both branches..
26 *
27 *
28 * On our feature tree..  
29 *   git push origin origin:refs/heads/feature_2
30
31 * we clone directory into gitlive_feature/XXXXX
32 *     git branch issue_XXX
33 *     git checkout issue_XXX
34 *    
35 * run this on the feature branch it merges and commits..
36 *  git pull origin master << or gitlive..
37 *  
38 *
39 * Standard change file (same bug as before..)
40 *   cd gitlive
41 *     commit etc.. (with bug no..)
42 *   cd featuredir
43 *     git pull origin gitlive
44 *     git push
45 *   cd gitlive
46 *     git push
47 *     
48 *  Change to new bug number..
49 *  cd featuredir
50 *    git checkout -b master origin/master
51 *    git checkout master <<< make sure
52 *    git pull --squash origin gitlive
53 *    git commit -m 'done with old bug number'
54 *    git push
55 *  cd gitlive
56 *    git push
57 *  cd featuredir
58 *     git push origin origin:refs/heads/feature_XXX
59 *     git checkout feature_XXX
60 *   cd gitlive
61 *     commit etc. (with new bug number) 
62 *    cd featuredir
63 *     git pull origin gitlive
64 *     git push
65 *   cd gitlive
66 *     git push
67
68 */
69
70 GI      = imports.gi.GIRepository
71 GLib        = imports.gi.GLib;
72
73 print(JSON.stringify(GI, null,4));
74 // we add this in, as it appears to get lost sometimes if we set it using the ENV. variable in builder.sh
75 GI.IRepository.prepend_search_path(GLib.get_home_dir() + '/.Builder/girepository-1.1');
76
77 Gio         = imports.gi.Gio;
78 Gtk         = imports.gi.Gtk;
79 Notify      = imports.gi.Notify;
80
81 Spawn       = imports.Spawn;
82 Git         = imports.Git;
83 StatusIcon  = imports.StatusIcon.StatusIcon;
84 Monitor     = imports.Monitor.Monitor;
85
86
87 //File = imports[__script_path__+'/../introspection-doc-generator/File.js'].File
88 Gtk.init (null, null);
89
90 var gitlive = GLib.get_home_dir() + "/gitlive";
91
92 if (!GLib.file_test(gitlive, GLib.FileTest.IS_DIR)) {
93     var msg = new Gtk.MessageDialog({message_type:
94         Gtk.MessageType.INFO, buttons : Gtk.ButtonsType.OK, text: "GIT Live - ~/gitlive does not exist."});
95     msg.run();
96     msg.destroy();
97     
98     Seed.quit();
99 }
100
101  
102 var monitor = new Monitor({
103     /**
104      *
105      * queue objects
106      *  action: 'add' | rm | update
107      *  repo : 'gitlive'
108      *  file : XXXXX
109      *
110      * 
111      *
112      */
113     action_queue : [],
114     queueRunning : false,
115      
116     start: function()
117     {
118         var _this = this;
119         this.lastAdd = new Date();
120          
121         // start monitoring first..
122         Monitor.prototype.start.call(this);
123         
124         // then start our queue runner..
125         GLib.timeout_add(GLib.PRIORITY_LOW, 500, function() {
126             //TIMEOUT", _this.action_queue.length , _this.queueRunning].join(', '));
127             if (!_this.action_queue.length || _this.queueRunning) {
128                 return 1;
129             }
130             var last = Math.floor(((new Date()) - this.lastAdd) / 100);
131             if (last < 4) { // wait 1/2 a seconnd before running.
132                 return 1;
133             }
134             _this.runQueue();
135             return 1;
136         },null,null);
137         
138         
139         var notification = new Notify.Notification({
140             summary: "Git Live",
141             body : gitlive + "\nMonitoring " + this.monitors.length + " Directories"
142         });
143
144         notification.set_timeout(2000);
145         notification.show();   
146     },
147     /**
148      * run the queue.
149      * - pulls the items off the queue 
150      *    (as commands run concurrently and new items may get added while it's running)
151      * - runs the queue items
152      * - pushes upstream.
153      * 
154      */
155     runQueue: function()
156     {
157         this.queueRunning = true;
158         var cmds = [];
159         //this.queue.forEach(function (q) {
160         //    cmds.push(q);
161         //});
162         
163         this.action_queue.forEach(function (q) {
164             cmds.push(q);
165         });
166         //this.queue = []; // empty queue!
167         this.action_queue = [];
168         var success = [];
169         var failure = [];
170         var repos = [];
171         var done = [];
172         
173         function readResult(sp) {
174             switch (sp.result * 1) {
175                 case 0: // success:
176                     success.push(sp.args.join(' '));
177                     if (sp.output.length) success.push(sp.output + '');
178                   // if (sp.stderr.length) success.push(sp.stderr + '');
179                     break;
180                 default: 
181                     failure.push(sp.args.join(' '));
182                     if (sp.output.length) failure.push(sp.output);
183                     if (sp.stderr.length) failure.push(sp.stderr);
184                     break;
185             }
186         }
187             
188         cmds.forEach(function(cmd) {
189             // prevent duplicate calls..
190             if (done.indexOf(JSON.stringify(cmd)) > -1) {
191                 return;
192             }
193             done.push(JSON.stringify(cmd));
194             // --- we keep a list of repositories that will be pushed to at the end..
195             
196             if (repos.indexOf(cmd.repo) < 0) {
197                 repos.push(cmd.repo);
198                 //    Git.run(cmd.repos , 'pull'); // pull before we push!
199             }
200             
201             var gp  = gitlive + '/' + cmd.repo;
202             
203             switch( cmd.action ) {
204                 case 'add':
205                     readResult(Git.run(gp, 'add',  cmd.file ));
206                     readResult(Git.run(gp, 'commit',  cmd.file, { message: cmd.file}  ));
207                     break;
208                     
209                 case 'rm':
210                     readResult(Git.run(gp, 'rm',  cmd.file ));
211                     readResult(Git.run(gp, 'commit',  { all: true, message: cmd.file}  ));
212                     break;
213                      
214                 case 'update':
215                     readResult(Git.run(gp, 'commit', cmd.file  , {   message: cmd.file}  ));
216                     break;
217                     
218                 case 'mv':
219                     readResult(Git.run(gp, 'mv', cmd.file , cmd.target));
220                     readResult(Git.run(gp, 'commit', cmd.file  , cmd.target,
221                             {   message: 'MOVED ' + cmd.file +' to ' + cmd.target }  ));
222                     break; 
223             }
224             
225             
226             
227         });
228          
229         // push upstream.
230         repos.forEach(function(r) {
231             var sp = Git.run(gitlive + '/' +r , 'push', { all: true } );
232             if (sp.length) {
233                 success.push(sp);
234             }
235             
236         });
237         
238         if (success.length) {
239             print(success.join("\n"));
240             var notification = new Notify.Notification({
241                 summary: "Git Live Commited",
242                 body : success.join("\n")
243                 
244             });
245
246             notification.set_timeout(2000);
247             notification.show();   
248         }
249         if (failure.length) {
250         
251             var notification = new Notify.Notification({
252                 summary: "Git Live ERROR!!",
253                 body : failure.join("\n")
254                 
255             });
256
257             notification.set_timeout(5000); // show errros for longer
258             notification.show();   
259         }
260         this.queueRunning = false;
261     },
262     
263     shouldIgnore: function(f)
264     {
265         if (f.name[0] == '.') {
266             // except!
267             if (f.name == '.htaccess') {
268                 return false;
269             }
270             
271             return true;
272         }
273         if (f.name.match(/~$/)) {
274             return true;
275         }
276         // ignore anything in top level!!!!
277         if (!f.vpath.length) {
278             return true;
279         }
280         
281         return false;
282         
283     },
284     
285     /**
286      * set gitpath and vpath
287      * 
288      * 
289      */
290     
291     parsePath: function(f)
292     {
293            
294         var vpath_ar = f.path.substring(gitlive.length +1).split('/');
295         f.repo = vpath_ar.shift();
296         f.gitpath = gitlive + '/' + f.repo;
297         f.vpath =  vpath_ar.join('/');
298         
299         
300     },
301     
302     just_created : {},
303       
304     onChanged : function(src) 
305     { 
306         return; // always ignore this..?
307         //this.parsePath(src);
308     },
309     
310     /**
311      *  results in  git add  + git commit..
312      *  
313      *
314      *
315      */
316     
317     onChangesDoneHint : function(src) 
318     { 
319         this.parsePath(src);
320         if (this.shouldIgnore(src)) {
321             return;
322         }
323         
324         var add_it = false;
325         if (typeof(this.just_created[src.path]) !='undefined') {
326             delete this.just_created[src.path];
327             this.lastAdd = new Date();
328             //this.queue.push( 
329             //    [ src.gitpath,  'add', src.vpath ],
330             //    [ src.gitpath,  'commit',  src.vpath, { message: src.vpath} ] 
331             //    
332             //);
333             this.action_queue.push({
334                 action: 'add',
335                 repo : src.repo,
336                 file : src.vpath
337             });
338             
339             
340          
341             return;
342         }
343         this.lastAdd = new Date();
344         //this.queue.push( 
345         //    [ src.gitpath,  'add', src.vpath ],
346         //    [ src.gitpath,  'commit', src.vpath, {  message: src.vpath} ]
347         //
348         //);
349         
350         this.action_queue.push({
351             action: 'add',
352             repo : src.repo,
353             file : src.vpath
354         });
355         
356
357     },
358     onDeleted : function(src) 
359     { 
360         this.parsePath(src);
361         if (this.shouldIgnore(src)) {
362             return;
363         }
364         // should check if monitor needs removing..
365         // it should also check if it was a directory.. - so we dont have to commit all..
366         
367         this.lastAdd = new Date();
368         //this.queue.push( 
369         //    [ src.gitpath, 'rm' , src.vpath ],
370         //    [ src.gitpath, 'commit', { all: true, message: src.vpath} ]
371         //    
372         //);
373         this.action_queue.push({
374             action: 'rm',
375             repo : src.repo,
376             file : src.vpath
377         });
378         
379     },
380     onCreated : function(src) 
381     { 
382         this.parsePath(src);
383         if (this.shouldIgnore(src)) {
384             return;
385         }
386         
387         if (!GLib.file_test(src.path, GLib.FileTest.IS_DIR)) {
388             this.just_created[src.path] = true;
389             return; // we do not handle file create flags... - use done hint.
390         }
391         // director has bee created
392         this.monitor(src.path);
393         
394         /*
395           since git does not really handle directory adds...
396          
397         this.lastAdd = new Date();
398         this.action_queue.push({
399             action: 'add',
400             repo : src.repo,
401             file : src.vpath
402         });
403         
404         this.queue.push( 
405             [ src.gitpath, 'add' , src.vpath,  { all: true } ],
406             [ src.gitpath, 'commit' , { all: true, message: src.vpath} ]
407             
408         );
409         */
410         
411         
412     },
413     onAttributeChanged : function(src) { 
414         this.parsePath(src);
415         if (this.shouldIgnore(src)) {
416             return;
417         }
418         this.lastAdd = new Date();
419         
420         
421         //this.queue.push( 
422        //     [ src.gitpath, 'commit' ,  src.vpath, { message: src.vpath} ]
423        // );
424         this.action_queue.push({
425             action: 'update',
426             repo : src.repo,
427             file : src.vpath
428         });
429  
430     
431     },
432     
433     onMoved : function(src,dest)
434     { 
435         this.parsePath(src);
436         this.parsePath(dest);
437         
438         if (src.gitpath != dest.gitpath) {
439             this.onDeleted(src);
440             this.onCreated(dest);
441             this.onChangedDoneHint(dest);
442             return;
443         }
444         // needs to handle move to/from unsupported types..
445         
446         if (this.shouldIgnore(src)) {
447             return;
448         }
449         if (this.shouldIgnore(dest)) {
450             return;
451         }
452         this.lastAdd = new Date();
453        // this.queue.push( 
454        //     [ src.gitpath, 'mv',  '-k', src.vpath, dest.vpath ],
455        //     [ src.gitpath, 'commit' ,  src.vpath, dest.vpath ,
456        //         { message:   'MOVED ' + src.vpath +' to ' + dest.vpath} ]
457        // );
458         
459         this.action_queue.push({
460             action: 'mv',
461             repo : src.repo,
462             file : src.vpath,
463             target : dest.vpath
464             
465         });
466         
467     }
468           
469     
470 });
471  
472  
473   
474
475 function errorDialog(data) {
476     var msg = new Gtk.MessageDialog({
477             message_type: Gtk.MessageType.ERROR, 
478             buttons : Gtk.ButtonsType.OK, 
479             text: data
480     });
481     msg.run();
482     msg.destroy();
483 }
484
485  
486
487
488
489 //
490 // need a better icon...
491
492
493 StatusIcon.init();   
494
495
496 Notify.init("gitlive");
497
498 monitor.add(GLib.get_home_dir() + "/gitlive");
499 monitor.start();
500 Gtk.main();
501 //icon.signal["activate"].connect(on_left_click);
502