Monitor.vala
[gitlive] / Monitor.vala
1 //<Script type="text/javascript">
2 //var Gio     = imports.gi.Gio;
3 //var GLib    = imports.gi.GLib;
4
5 //var XObject = imports.XObject.XObject;
6 //var File    = imports.File.File;
7
8 /// # valac  --pkg gio-2.0  --pkg posix Monitor.vala -o /tmp/Monitor
9
10  
11 //using Gee; // for array list?
12
13 static int main (string[] args) {
14     // A reference to our file
15     //var file = File.new_for_path ("data.txt");
16     MainLoop loop = new MainLoop ();
17     print("starting");
18     var m = new Monitor();
19     
20     m.add("/home/alan/gitlive");
21     m.start();
22     loop.run ();
23
24     return 0;
25
26 }
27
28
29 public class  MonitorNamePathDir {
30     
31     public string name;
32     public string path;
33     public string dir;
34     
35     public MonitorNamePathDir(string name, string path, string dir)
36     {
37         this.name = name;
38         this.path = path;
39         this.dir = dir;
40         
41     }
42 }
43
44
45
46 public delegate void onEventHander (FileMonitor fm, File f_orig, File of_orig, FileMonitorEvent event_type);
47
48
49 /**
50  * Monitor class - handles monitor managment for a large tree...
51  *
52  *
53  * This 
54  * 
55  * usage : 
56  * x = new Monitor({
57      change : function () {
58          * ....
59          *}
60   }
61  * x.add('/somepath')
62  * x.stop() // stops all scanning.
63  * x.play(); // starts the scanning
64  * 
65  * 
66  * 
67  * 
68  */
69  
70 public class Monitor : Object
71 {
72
73
74
75     public Monitor()
76     {
77        
78      
79         this.monitors = new Array<FileMonitor> ();
80         this.top = new Array<string> ();
81         this.paused = false;
82     }
83      
84     public Array<FileMonitor> monitors;// Array of MonitorNamePathDirileMonitors
85     public Array<string> top; // list of top level directories..
86     public bool paused;
87     /**
88      * add a directory or file to monitor
89      */
90     public void add (string add)
91     {
92         this.top.append_val(add);
93     }
94     /**
95      * start monitoring
96      */
97     public void start()
98     {
99         for(int i = 0; i < this.top.length ; i++) {
100             this.monitor(this.top.index(i), ( fm,  f_orig,  of_orig,  event_type) => {
101                 this.onEvent (fm,  f_orig,  of_orig,  event_type ) ;
102                 } );
103         }
104     }
105     /**
106      * stop / pause monitoring
107      * 
108      */
109     public void stop()
110     {
111         
112         for(int i = 0; i < this.monitors.length ; i++) {
113             this.monitors.index(i).cancel();
114         } 
115         this.monitors = new Array<FileMonitor>(); // clean /destroy/ kill old?
116     }
117     /**
118      * pause monitoring - without changing what's monitored 
119      */
120     public void pause()
121     {
122         this.paused = true;
123     }
124     /**
125      * resume monitoring - without changing what's monitored 
126      */
127     public void resume()
128     {
129         this.paused = false;
130     }
131     /**
132      * monitor a file or directory (privatish)
133      *
134      * initially called with ~/gitlive  null 0 (effectvely)
135      * 
136      * 
137      */
138     public void monitor(string path, onEventHander fn , int depth = 0)
139     {
140          
141         print("ADD: " + path + "\n");
142         
143         //depth = typeof(depth) == 'number'  ? depth *1 : 0;
144         depth = depth > 0  ? depth *1 : 0;
145         
146         
147         //fn = fn || function (fm, f, of, event_type, uh) {
148         //    _this.onEvent(fm, f, of, event_type, uh);
149         //}
150        
151           
152         var f = File.new_for_path(path);
153             //var cancel = new Gio.Cancellable ();
154         if (depth > 0) { 
155   
156             try {
157   
158                  var fm = f.monitor(FileMonitorFlags.SEND_MOVED,null); //Gio.FileMonitorFlags.SEND_MOVED
159  
160                  fm.changed.connect( ( fm,  f_orig,  of_orig,  event_type) => {
161                         //if (fn) {
162                             fn (fm,  f_orig,  of_orig,  event_type ) ;
163                            // return;
164                         //}
165                         //this.onEvent (fm,  f_orig,  of_orig,  event_type ) ;
166                 });
167                 this.monitors.append_val(fm);
168
169             } catch (Error e) {
170                 // FIXME -- show error? do nothing..            
171             }
172             // print("ADD path " + depth + ' ' + path);
173         }
174         // iterate children?
175         // - this is not used.
176         //if (GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR) && this.initRepo) {
177             
178         //    this.initRepo(path);
179         //}
180         FileEnumerator file_enum;
181         try {      
182             file_enum = f.enumerate_children(
183                FileAttribute.STANDARD_DISPLAY_NAME + "," +   FileAttribute.STANDARD_TYPE,
184                0, // FileQueryInfoFlags.NONE,
185                null);
186         } catch (Error e) {
187             // FIXME - show error..
188             return;
189         }
190         FileInfo next_file;
191         
192         while (true) {
193             try {        
194                 next_file = file_enum.next_file(null);
195             } catch (Error e) {
196                 break;
197             }
198             if (next_file == null) {
199                 break;
200             }
201             //print("got a file " + next_file.sudo () + '?=' + Gio.FileType.DIRECTORY);
202             
203             if (next_file.get_file_type() != FileType.DIRECTORY) {
204                 next_file = null;
205                 continue;
206             }
207             
208             if (next_file.get_file_type() ==FileType.SYMBOLIC_LINK) {
209                 next_file = null;
210                 continue;
211             }
212             
213             if (next_file.get_display_name()[0] == '.') {
214                 next_file = null;
215                 continue;
216             }
217             var sp = path+"/"+next_file.get_display_name();
218             // skip modules.
219             //print("got a file : " + sp);
220          
221             next_file = null;
222             
223             
224             
225             this.monitor(sp, fn, depth + 1);
226             
227         }
228         try {
229             file_enum.close(null);
230         } catch(Error e) {
231             // ignore?
232         }
233     }
234     
235     
236     
237     public File realpath(File file)
238     {
239         if (file != null) {
240             return file;
241         }
242         
243         if (FileUtils.test(file.get_path(), FileTest.EXISTS)) {
244             var rp = Posix.realpath(file.get_path());
245             return File.new_for_path(rp);  
246             
247         }
248         // file does not currently exist..
249         // check parent.
250         
251 // FIX ME - string split?/? 
252         var bn = file.get_basename();
253         var ar =  file.get_path().split("/");
254         ar.resize(ar.length-1);
255         var dirname = string.joinv("/",ar );
256         var rp = Posix.realpath(dirname);
257         return File.new_for_path(rp + "/" + bn);
258         
259     }
260    
261     
262     
263      
264     public void onEvent(FileMonitor fm, File f_orig, File of_orig, FileMonitorEvent event_type)
265     {
266         if (this.paused) {
267             return;
268         }
269         print("onEvent");
270         var f = this.realpath(f_orig);
271         
272         var of = this.realpath(of_orig);
273  
274         
275  
276         MonitorNamePathDir src = new MonitorNamePathDir( f.get_basename(), f.get_path() , Path.get_dirname(f.get_path()));
277         MonitorNamePathDir dest = null;
278         
279         if (of != null) {
280             dest = new MonitorNamePathDir( of.get_basename(), of.get_path(),  Path.get_dirname(of.get_path()));
281             
282         }
283         //string event_name = "UKNOWN";
284         
285         
286         // extract the event names ... - not sure if introspection is feasible in vala..
287         //for(var i in Gio.FileMonitorEvent) {
288          //    if (Gio.FileMonitorEvent[i] == event_type) {
289          //        event_name = i;
290          //    }
291          //}
292         
293
294
295
296         //print (JSON.stringify([event_name , f.get_path(), of ? of.get_path() : false ] ));
297         //print ("got src: " + src.toString());
298         //print ("got event: " + src.toString());
299         try {
300                 
301             switch(event_type) {
302                 case FileMonitorEvent.CHANGED:
303                     this.onChanged(src);
304                     return; // ingore thise?? -wait for changes_done_htin?
305                     
306                 case FileMonitorEvent.CHANGES_DONE_HINT:
307                     this.onChangesDoneHint(src);
308                     return;
309                     
310                 case FileMonitorEvent.DELETED:
311                     this.onDeleted(src);
312                     return;
313                     
314                 case FileMonitorEvent.CREATED:
315                     this.onCreated(src);
316                     return;
317                 
318                 case FileMonitorEvent.ATTRIBUTE_CHANGED: // eg. chmod/chatt
319                     this.onAttributeChanged(src);
320                     return;
321                 
322                 case FileMonitorEvent.MOVED: // eg. chmod/chatt
323                     this.onMoved(src,dest);
324                     return; 
325                 
326                 // rest are mount related - not really relivant.. maybe add later..
327             } 
328         } catch(Error e) {
329             print(e.message);
330         }
331         
332     }
333     
334     /** override these to do stuff.. */
335     public void initRepo(MonitorNamePathDir src) { } // called on startup at the top level repo dir.
336     public void onChanged(MonitorNamePathDir src) { }
337     public void onChangesDoneHint(MonitorNamePathDir src) { }
338     public void onDeleted(MonitorNamePathDir src) { }
339     public void onCreated(MonitorNamePathDir src) { }
340     public void onAttributeChanged(MonitorNamePathDir src) { }
341     public void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest) { }
342           
343     
344 }
345  
346  
347
348
349
350
351