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