revert code that did not affect memory
[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 abstract class gitMonitorBase : Object
72 {
73         public abstract void monitor(string path, int depth = 0);
74
75  
76 public class Monitor : gitMonitorBase
77 {
78
79
80         static int total_monitors = 0;
81     public Monitor()
82     {
83        
84      
85         this.monitors = new Array<FileMonitor> ();
86         this.top = new Array<string> ();
87         this.paused = false;
88     }
89      
90     public Array<FileMonitor> monitors;// Array of MonitorNamePathDirileMonitors
91     public Array<string> top; // list of top level directories..
92     public bool paused;
93     /**
94      * add a directory or file to monitor
95      */
96     public void add (string add)
97     {
98         
99         print("Monitor.add: " + add);
100         this.top.append_val(add);
101     }
102     /**
103      * start monitoring
104      */
105     public void start()
106     {
107         for(int i = 0; i < this.top.length ; i++) {
108             this.monitor(this.top.index(i));
109         }
110     }
111     /**
112      * stop / pause monitoring
113      * 
114      */
115     public void stop()
116     {
117         
118         for(int i = 0; i < this.monitors.length ; i++) {
119             this.monitors.index(i).cancel();
120         } 
121         this.monitors = new Array<FileMonitor>(); // clean /destroy/ kill old?
122     }
123     /**
124      * pause monitoring - without changing what's monitored 
125      */
126     public void pause()
127     {
128         this.paused = true;
129     }
130     /**
131      * resume monitoring - without changing what's monitored 
132      */
133     public void resume()
134     {
135         this.paused = false;
136     }
137     /**
138      * monitor a file or directory (privatish)
139      *
140      * initially called with ~/gitlive  null 0 (effectvely)
141      * 
142      * 
143      */
144     public override void monitor(string path, int depth = 0)
145     {
146          
147         //GLib.debug("ADD: (%d): %s\n", depth, path);
148         
149         //depth = typeof(depth) == 'number'  ? depth *1 : 0;
150         depth = depth > 0  ? depth *1 : 0;
151         
152         
153         //fn = fn || function (fm, f, of, event_type, uh) {
154         //    _this.onEvent(fm, f, of, event_type, uh);
155         //}
156                  
157         var f = File.new_for_path(path);
158             //var cancel = new Gio.Cancellable ();
159         if (depth > 0) { 
160   
161             try {
162                  var fm = f.monitor(FileMonitorFlags.SEND_MOVED + FileMonitorFlags.WATCH_MOVES,null);  
163                  //var fm = f.monitor(FileMonitorFlags.WATCH_MOVES,null);
164  
165                  fm.changed.connect( this.onEvent );
166                 this.monitors.append_val(fm);
167  
168                 
169                 total_monitors++;
170                 GLib.debug("Total Monitors this: %d, All:%d: %s", (int)this.monitors.length, total_monitors, path);
171  
172
173             } catch (Error e) {
174                   GLib.debug("Error adding monitor: %s\n", e.message);
175                   GLib.debug("Try: \n\nsudo su\necho 512 > /proc/sys/fs/inotify/max_user_instances\n");     
176                 // FIXME -- show error? do nothing..            
177             }
178             // print("ADD path " + depth + ' ' + path);
179         }
180         // iterate children?
181         // - this is not used.
182         //if (GLib.file_test(path + '/.git' , GLib.FileTest.IS_DIR) && this.initRepo) {
183             
184         //    this.initRepo(path);
185         //}
186         FileEnumerator file_enum;
187         var cancellable = new Cancellable ();
188         try {      
189             file_enum = f.enumerate_children(
190                FileAttribute.STANDARD_DISPLAY_NAME + "," +   FileAttribute.STANDARD_TYPE,
191                         FileQueryInfoFlags.NOFOLLOW_SYMLINKS,  // FileQueryInfoFlags.NONE,
192                cancellable);
193         } catch (Error e) {
194             // FIXME - show error..
195             return;
196         }
197         FileInfo next_file;
198         
199         while (cancellable.is_cancelled () == false ) {
200             try {
201                 next_file = file_enum .next_file (cancellable);
202             } catch(Error e) {
203                 print(e.message);
204                 break;
205             }
206
207             if (next_file == null) {
208                 break;
209             }
210
211             //print("got a file " + next_file.sudo () + '?=' + Gio.FileType.DIRECTORY);
212
213             if (next_file.get_file_type() != FileType.DIRECTORY) {
214                 next_file = null;
215                 continue;
216             }
217
218
219             //stdout.printf("Monitor.monitor: got file %s : type :%u\n",
220             //        next_file.get_display_name(), next_file.get_file_type());
221
222
223             if (next_file.get_is_symlink()) {
224                 next_file = null;
225                 continue;
226             }
227             
228             if (next_file.get_display_name()[0] == '.') {
229                 next_file = null;
230                 continue;
231             }
232             var sp = path+"/"+next_file.get_display_name();
233             // skip modules.
234             //print("got a file : " + sp);
235          
236             next_file = null;
237             
238             
239             
240             this.monitor(sp, depth + 1);
241             
242         }
243         try {
244             file_enum.close(null);
245         } catch(Error e) {
246             // ignore?
247         }
248     }
249     
250     
251     
252     public File realpath(File file)
253     {
254         if (file != null) {
255             return file;
256         }
257         
258         if (FileUtils.test(file.get_path(), FileTest.EXISTS)) {
259             var rp = Posix.realpath(file.get_path());
260             return File.new_for_path(rp);  
261             
262         }
263         // file does not currently exist..
264         // check parent.
265         
266 // FIX ME - string split?/? 
267         var bn = file.get_basename();
268         var ar =  file.get_path().split("/");
269         ar.resize(ar.length-1);
270         var dirname = string.joinv("/",ar );
271         var rp = Posix.realpath(dirname);
272         return File.new_for_path(rp + "/" + bn);
273         
274     }
275    
276     
277     
278      
279     public void onEvent(File f_orig, File? of_orig, FileMonitorEvent event_type)
280     {
281         if (this.paused) {
282             return;
283         }
284        // print("onEvent\n");
285         var f = this.realpath(f_orig);
286         
287  
288         MonitorNamePathDir src = new MonitorNamePathDir( f.get_basename(), f.get_path() , Path.get_dirname(f.get_path()));
289                 
290         GLib.debug("onEvent src: %s", f.get_path());
291     
292         try {
293                 
294
295             switch(event_type) {
296                 case FileMonitorEvent.CHANGED:
297                     src.action = "changed";
298                     this.onChanged(src);
299                     return; // ingore thise?? -wait for changes_done_htin?
300                     
301                 case FileMonitorEvent.CHANGES_DONE_HINT:
302                     src.action = "changed";
303                     this.onChangesDoneHint(src);
304                     return;
305                     
306                 case FileMonitorEvent.DELETED:
307                     src.action = "rm";
308                     this.onDeleted(src);
309                     return;
310                     
311                 case FileMonitorEvent.CREATED:
312                     src.action = "created";
313                     this.onCreated(src);
314                     return;
315                 
316                 case FileMonitorEvent.ATTRIBUTE_CHANGED: // eg. chmod/chatt
317                     src.action = "attrib";
318                     this.onAttributeChanged(src);
319                     return;
320                 
321                 case FileMonitorEvent.MOVED: // eg. chmod/chatt
322                 case FileMonitorEvent.MOVED_IN: // eg. chmod/chatt
323                 case FileMonitorEvent.MOVED_OUT: // eg. chmod/chatt                                
324                 case FileMonitorEvent.RENAMED: // eg. chmod/chatt                      
325                                         if (of_orig == null) { // move from outside of monitoring?
326                                                 this.onChanged(src);
327                                                 return;
328                                         }
329                                         
330                                         
331                    var of = this.realpath(of_orig);
332                    var   dest = new MonitorNamePathDir(
333                                 of.get_basename(), 
334                                 of.get_path(),  
335                                 Path.get_dirname(of.get_path())
336                     );
337                     
338                                         if (dest == null) {
339                                                 
340                                                 return;
341                                         }
342                     src.action = "moved";
343                     dest.action = "moved";
344                     this.onMoved(src,dest);
345                     return; 
346                     
347  
348                 default:
349                     stdout.printf("event type not handled %u", event_type);
350                     break;
351                 // rest are mount related - not really relivant.. maybe add later..
352             } 
353         } catch(Error e) {
354             print(e.message);
355         }
356         
357     }
358     
359
360     /** override these to do stuff.. */
361     //public void initRepo(MonitorNamePathDir src) { } // called on startup at the top level repo dir.
362     public virtual void  onChanged(MonitorNamePathDir src) { }
363     public virtual void onChangesDoneHint(MonitorNamePathDir src) { }
364     public virtual void onDeleted(MonitorNamePathDir src) { }
365     public virtual void onCreated(MonitorNamePathDir src) { }
366     public virtual void onAttributeChanged(MonitorNamePathDir src) { }
367     public virtual void onMoved(MonitorNamePathDir src,MonitorNamePathDir dest) { }
368           
369     
370 }
371  
372  
373
374
375
376
377