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