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