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