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 static 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]);
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, Callback fn = null, 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                         
148                     }
149                     this.onEvent (fm,  f_orig,  of_orig,  event_type ) ;
150             });
151             this.monitors.add(fm);
152             // print("ADD path " + depth + ' ' + path);
153         }
154         // iterate children?
155         // - this is not used.
156         //if (GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR) && this.initRepo) {
157             
158         //    this.initRepo(path);
159         //}
160         
161        
162          var file_enum = f.enumerate_children(
163             FileAttribute.STANDARD_DISPLAY_NAME + "," +   FileAttribute.STANDARD_TYPE,
164             0, // FileQueryInfoFlags.NONE,
165             null);
166         
167         FileInfo next_file;
168         
169         while ((next_file = file_enum.next_file(null)) != null) {
170          
171             //print("got a file " + next_file.sudo () + '?=' + Gio.FileType.DIRECTORY);
172             
173             if (next_file.get_file_type() != FileType.DIRECTORY) {
174                 next_file = null;
175                 continue;
176             }
177             
178             if (next_file.get_file_type() ==FileType.SYMBOLIC_LINK) {
179                 next_file = null;
180                 continue;
181             }
182             
183             if (next_file.get_display_name()[0] == '.') {
184                 next_file = null;
185                 continue;
186             }
187             var sp = path+"/"+next_file.get_display_name();
188             // skip modules.
189             //print("got a file : " + sp);
190          
191             next_file = null;
192             
193             
194             
195             this.monitor(sp, fn, depth + 1);
196             
197         }
198     
199         file_enum.close(null);
200     }
201     
202     
203     
204     public File realpath(File file)
205     {
206         if (file != null) {
207             return file;
208         }
209         
210         if (FileUtils.test(file.get_path(), FileTest.EXISTS)) {
211             var rp = Posix.realpath(file.get_path());
212             return File.new_for_path(rp);  
213             
214         }
215         // file does not currently exist..
216         // check parent.
217         
218 // FIX ME - string split?/? 
219         var bn = file.get_basename();
220         var ar =  file.get_path().split("/");
221         ar.resize(ar.length-1);
222         var dirname = string.joinv("/",ar );
223         var rp = Posix.realpath(dirname);
224         return File.new_for_path(rp + "/" + bn);
225         
226     }
227    
228     
229     
230      
231     public void onEvent(FileMonitor fm, File f_orig, File of_orig, FileMonitorEvent event_type)
232     {
233         if (this.paused) {
234             return;
235         }
236         
237         var f = this.realpath(f_orig);
238         
239         var of = this.realpath(of_orig);
240  
241         
242  
243         MonitorNamePathDir src = new MonitorNamePathDir( f.get_basename(), f.get_path() , Path.get_dirname(f.get_path()));
244         MonitorNamePathDir dest = null;
245         
246         if (of != null) {
247             dest = new MonitorNamePathDir( of.get_basename(), of.get_path(),  Path.get_dirname(of.get_path()));
248             
249         }
250         //string event_name = "UKNOWN";
251         
252         
253         // extract the event names ... - not sure if introspection is feasible in vala..
254         //for(var i in Gio.FileMonitorEvent) {
255          //    if (Gio.FileMonitorEvent[i] == event_type) {
256          //        event_name = i;
257          //    }
258          //}
259         
260         //print (JSON.stringify([event_name , f.get_path(), of ? of.get_path() : false ] ));
261         //print ("got src: " + src.toString());
262         //print ("got event: " + src.toString());
263         try {
264                 
265             switch(event_type) {
266                 case FileMonitorEvent.CHANGED:
267                     this.onChanged(src);
268                     return; // ingore thise?? -wait for changes_done_htin?
269                     
270                 case FileMonitorEvent.CHANGES_DONE_HINT:
271                     this.onChangesDoneHint(src);
272                     return;
273                     
274                 case FileMonitorEvent.DELETED:
275                     this.onDeleted(src);
276                     return;
277                     
278                 case FileMonitorEvent.CREATED:
279                     this.onCreated(src);
280                     return;
281                 
282                 case FileMonitorEvent.ATTRIBUTE_CHANGED: // eg. chmod/chatt
283                     this.onAttributeChanged(src);
284                     return;
285                 
286                 case FileMonitorEvent.MOVED: // eg. chmod/chatt
287                     this.onMoved(src,dest);
288                     return; 
289                 
290                 // rest are mount related - not really relivant.. maybe add later..
291             } 
292         } catch(Error e) {
293             print(e.message);
294         }
295         
296     }
297     
298     /** override these to do stuff.. */
299     public void initRepo(MonitorNamePathDir src) { } // called on startup at the top level repo dir.
300     public void onChanged(MonitorNamePathDir src) { }
301     public void onChangesDoneHint(MonitorNamePathDir src) { }
302     public void onDeleted(MonitorNamePathDir src) { }
303     public void onCreated(MonitorNamePathDir src) { }
304     public void onAttributeChanged(MonitorNamePathDir src) { }
305     public void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest) { }
306           
307     
308 }
309  
310  
311
312
313
314
315