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