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