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