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