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