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