tests/TreeBuilder.vala
[app.Builder.js] / Project / Project.vala
1 //<Script type="text/javascript">
2
3 /**
4  * Project Object
5  * 
6  * Projects can only contain one directory... - it can import other projects..(later)
7  * 
8  * we need to sort out that - paths is currently a key/value array..
9  * 
10  * 
11  * 
12  */
13 namespace Project {
14          public errordomain Error {
15                     INVALID_TYPE,
16                     NEED_IMPLEMENTING,
17                         MISSING_FILE,
18                         INVALID_VALUE
19                 }
20
21         // static array of all projects.
22         public Gee.HashMap<string,Project>  projects;
23         public bool  projects_loaded = false;
24
25         
26         public class Project : Object {
27                 
28                 public signal void on_changed (); 
29         
30                 public string id;
31                 public string fn = ""; // just a md5...
32                 public string name = "";
33                 public string runhtml = "";
34                 public string base_template = "";
35                 public string rootURL = "";
36                 public Gee.HashMap<string,string> paths;
37                 public Gee.HashMap<string,JsRender.JsRender> files ;
38                 //tree : false,
39                 public  string xtype;
40                  
41                 bool is_scanned; 
42            
43                 
44                 public Project (string path) {
45                     
46                         this.name = GLib.Path.get_basename(path); // default..
47
48                         this.is_scanned = false;
49                         this.paths = new Gee.HashMap<string,string>();
50                         this.files = new Gee.HashMap<string,JsRender.JsRender>();
51                         //XObject.extend(this, cfg);
52                         //this.files = { }; 
53                         if (path.length > 0) {
54                                 this.paths.set(path, "dir");
55                         }
56                         
57                     
58                     
59                 }
60
61         
62         
63         
64                 
65                 public static void loadAll(bool force = false)
66                 {
67                         if (projects_loaded && !force) {
68                                 return;
69                         }
70
71                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
72                         var dir = File.new_for_path(dirname);
73                         if (!dir.query_exists()) {
74                                 dir.make_directory();
75                                 return;
76                         }
77                         projects = new  Gee.HashMap<string,Project>();
78                           
79                    
80                         try {
81                                 var file_enum = dir.enumerate_children(
82                                         GLib.FileAttribute.STANDARD_DISPLAY_NAME, 
83                                         GLib.FileQueryInfoFlags.NONE, 
84                                         null
85                                 );
86                         
87                          
88                                 FileInfo next_file; 
89                                 while ((next_file = file_enum.next_file(null)) != null) {
90                                 var fn = next_file.get_display_name();
91                                 if (!Regex.match_simple("\\.json$", fn)) {
92                                         continue;
93                                 }
94                                 factoryFromFile(dirname + "/" + fn);
95                                 }
96                         } catch(Error e) {
97                                 print("oops - something went wrong scanning the projects\n");
98                         }
99                     
100
101                 }
102
103                 public static Gee.ArrayList<Project> allProjectsByName()
104                 {
105                     var ret = new Gee.ArrayList<Project>();
106                     var iter = projects.map_iterator();
107                             while (iter.next()) {
108                                 ret.add(iter.get_value());
109                             }
110                     // fixme -- sort...
111                     return ret;
112                 
113                 }
114
115                 public static Project?  getProject(string name) 
116                 {
117                         if (projects.has_key(name)) {
118                                 return projects.get(name);
119                         }
120                         return null;
121
122                 }
123                 // load project data from project file.
124                 public static void   factoryFromFile(string jsonfile)
125                 {
126                          
127                         print("parse %s\n", jsonfile);
128
129                         var pa = new Json.Parser();
130                         pa.load_from_file(jsonfile);
131                         var node = pa.get_root();
132
133                         
134                         if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
135                                 print("SKIP " + jsonfile + " - invalid format?\n");
136                                 return;
137                         }
138                         
139                         var obj = node.get_object ();
140                         var xtype =  obj.get_string_member("xtype");
141
142                         var proj = factory(xtype, "");
143
144                         proj.fn =  Path.get_basename(jsonfile).split(".")[0];
145
146                         // might not exist?
147
148                         if (obj.has_member("runhtml")) {
149                                 proj.runhtml  = obj.get_string_member("runhtml"); 
150                         }
151                         // might not exist?
152                         if (obj.has_member("base_template")) {
153                                 proj.base_template  = obj.get_string_member("base_template"); 
154                         }
155                         // might not exist?
156                         if (obj.has_member("rootURL")) {
157                                 proj.rootURL  = obj.get_string_member("rootURL"); 
158                         }
159                         
160                         proj.name = obj.get_string_member("name");
161
162                         var paths = obj.get_object_member("paths");
163                         paths.foreach_member((sobj, key, val) => {
164                                 proj.paths.set(key, "dir");
165                         });
166                         projects.set(proj.name,proj);
167                 }
168                 
169                 
170                 public static Project factory(string xtype, string path)
171                 {
172
173                         // check to see if it's already loaded..
174
175                          
176                         var iter = projects.map_iterator();
177                         while (iter.next()) {
178                                 if (iter.get_value().hasPath( path)) {
179                                         return iter.get_value();
180                                  }
181                         }
182
183
184                         switch(xtype) {
185                                 case "Gtk":
186                                         return new Gtk(path);
187                                 case "Roo":
188                                         return new Roo(path);
189                         }
190                         throw new Error.INVALID_TYPE("invalid project type");
191                                 
192                 }
193                  public static void  remove(Project project)
194                 {
195                         // delete the file..
196                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
197                          
198                         FileUtils.unlink(dirname + "/" + project.fn + ".json");
199                         projects.unset(project.name,null);
200                         
201
202                 }
203                  
204
205                 public void save()
206                 {
207                                 // fixme..
208             
209                         if (this.fn.length < 1) {
210                                 // make the filename..
211                                 //var t = new DateTime.now_local ();
212                                 //TimeVal tv;
213                                 //t.to_timeval(out tv);
214                                 //var str = "%l:%l".printf(tv.tv_sec,tv.tv_usec);
215                                 var str = this.firstPath();
216                                 
217                                 this.fn = GLib.Checksum.compute_for_string(GLib.ChecksumType.MD5, str, str.length);
218                         }
219
220                         var dirname = GLib.Environment.get_home_dir() + "/.Builder";
221                         var  s =  this.toJSON(false);
222                         FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);  
223                         
224                         
225                 }
226
227                 
228                 
229                 public string toJSON(bool show_all)
230                 {
231                     
232                         var builder = new Json.Builder ();
233
234                         builder.begin_object ();
235
236                         builder.set_member_name ("name");
237                         builder.add_string_value (this.name);
238
239
240                         builder.set_member_name ("fn");
241                         builder.add_string_value (this.fn);
242
243                         builder.set_member_name ("xtype");
244                         builder.add_string_value (this.xtype);
245
246                         builder.set_member_name ("runhtml");
247                         builder.add_string_value (this.runhtml);
248
249
250                         builder.set_member_name ("rootURL");
251                         builder.add_string_value (this.rootURL);
252                         
253                         builder.set_member_name ("base_template");
254                         builder.add_string_value (this.base_template);                  
255                         // file ??? try/false?
256                         builder.set_member_name ("paths");
257
258
259                         builder.begin_object ();
260
261
262                         var iter = this.paths.map_iterator();
263                         while (iter.next()) {
264                                 builder.set_member_name (iter.get_key());
265                                 builder.add_string_value("path");
266                         }
267                         builder.end_object ();
268                         
269                         if (show_all) {
270                                 builder.set_member_name ("files");
271                                 builder.begin_array ();
272                                 var fiter = this.files.map_iterator();
273                                 while (fiter.next()) {
274                                     builder.add_string_value (fiter.get_key());
275                                 }
276                                 
277                                 
278                                 builder.end_array ();
279                         }
280
281                 
282                         builder.end_object ();
283
284                         var  generator = new Json.Generator ();
285                         var  root = builder.get_root ();
286                         generator.set_root (root);
287                         if (show_all) {
288                                 generator.pretty = true;
289                                 generator.indent = 4;
290                         }
291
292                         return  generator.to_data (null);
293                           
294                       
295                 }
296                 public string firstPath()
297                 {
298                     var iter = this.paths.map_iterator();
299                     while (iter.next()) {
300                         return iter.get_key();
301                     }
302                   
303                     return "";
304                 }
305
306                 public bool hasPath(string path)
307                 {
308                     var iter = this.paths.map_iterator();
309                     while (iter.next()) {
310                         if (iter.get_key() == path) {
311                                 return true;
312                         }
313                     }
314                   
315                     return false;
316                 }
317
318                 
319                 // returns the first path
320                 public string getName()
321                 {
322                     var iter = this.paths.map_iterator();
323                     while (iter.next()) {
324                         return GLib.Path.get_basename(iter.get_key());
325                     }
326                   
327                     return "";
328                 }
329
330                 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
331                 {
332                         var files = new Gee.ArrayList<JsRender.JsRender>();
333
334                         var fiter = this.files.map_iterator();
335                         while(fiter.next()) {
336                                 files.add(fiter.get_value());
337                         }
338                         files.sort((fa,fb) => {
339                                 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
340
341                         });
342                         return files;
343
344                 }
345                 
346          
347                 public JsRender.JsRender? getByName(string name)
348                 {
349                     
350                         var fiter = files.map_iterator();
351                     while(fiter.next()) {
352                      
353                         var f = fiter.get_value();
354                         
355                         
356                         print ("Project.getByName: %s ?= %s\n" ,f.name , name);
357                         if (f.name == name) {
358                             return f;
359                         }
360                     };
361                     return null;
362                 }
363                 
364                 public JsRender.JsRender? getById(string id)
365                 {
366                     
367                         var fiter = files.map_iterator();
368                         while(fiter.next()) {
369                      
370                                 var f = fiter.get_value();
371                                 
372                                 
373                                 //console.log(f.id + '?=' + id);
374                                 if (f.id == id) {
375                                     return f;
376                                 }
377                             };
378                         return null;
379                 }
380
381                 public JsRender.JsRender newFile (string name)
382                 {
383                         var ret =  JsRender.JsRender.factory(this.xtype, 
384                                                          this, 
385                                                          this.firstPath() + "/" + name + ".bjs");
386                         this.addFile(ret);
387                         return ret;
388                 }
389                 
390                 public JsRender.JsRender loadFileOnly (string path)
391                 {
392                     var xt = this.xtype;
393                     return JsRender.JsRender.factory(xt, this, path);
394                     
395                 }
396                 
397                 public JsRender.JsRender create(string filename)
398                 {
399                     var ret = this.loadFileOnly(filename);
400                     ret.save();
401                     this.addFile(ret);
402                     return ret;
403                     
404                 }
405                     
406                      
407                 public void addFile(JsRender.JsRender pfile) { // add a single file, and trigger changed.
408                 
409                 
410                     this.files.set(pfile.path, pfile); // duplicate check?
411                     this.on_changed();
412                 }
413                 
414                 public void add(string path, string type)
415                 {
416                     this.paths.set(path,type);
417                     //Seed.print(" type is '" + type + "'");
418                     if (type == "dir") {
419                         this.scanDir(path);
420                     //    console.dump(this.files);
421                     }
422                     if (type == "file" ) {
423                         
424                         this.files.set(path,this.loadFileOnly( path ));
425                     }
426                     this.on_changed();
427                     
428                 }
429                 public void  scanDirs() // cached version
430                 {
431                     if (this.is_scanned) {
432                                 return;
433                         }
434                         this.scanDirsForce();
435                     //console.dump(this.files);
436                     
437                 }
438                 
439                 public void  scanDirsForce()
440                 {
441                         this.is_scanned = true;  
442                         var iter = this.paths.map_iterator();
443                     while (iter.next()) {
444                                 //print("path: " + iter.get_key() + " : " + iter.get_value() +"\n");
445                         if (iter.get_value() != "dir") {
446                             continue;
447                         }
448                         this.scanDir(iter.get_key());
449                     }
450                     //console.dump(this.files);
451                     
452                 }
453                     // list files.
454                 public void scanDir(string dir, int dp =0 ) 
455                 {
456                     //dp = dp || 0;
457                     //print("Project.Base: Running scandir on " + dir +"\n");
458                     if (dp > 5) { // no more than 5 deep?
459                         return;
460                     }
461                     // this should be done async -- but since we are getting the proto up ...
462                     
463                     var subs = new GLib.List<string>();;            
464                     var f = File.new_for_path(dir);
465                     try {
466                         var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
467                         
468                          
469                         FileInfo next_file; 
470                         while ((next_file = file_enum.next_file(null)) != null) {
471                             var fn = next_file.get_display_name();
472                     
473                              
474                             //print("trying"  + dir + "/" + fn +"\n");
475                             
476                             if (fn[0] == '.') { // skip hidden
477                                 continue;
478                             }
479                             
480                             if (FileUtils.test(dir  + "/" + fn, GLib.FileTest.IS_DIR)) {
481                                 subs.append(dir  + "/" + fn);
482                                 continue;
483                             }
484                             
485                             if (!Regex.match_simple("\\.bjs$", fn)) {
486                                                 //print("no a bjs\n");
487                                 continue;
488                             }
489                             /*
490                             var parent = "";
491                             //if (dp > 0 ) {
492                             
493                             var sp = dir.split("/");
494                             var parent = "";
495                             for (var i = 0; i < sp.length; i++) {
496                                 
497                             }
498                             
499                             /*
500                             sp = sp.splice(sp.length - (dp +1), (dp +1));
501                             parent = sp.join('.');
502                             
503                             
504                             if (typeof(_this.files[dir  + '/' + fn]) != 'undefined') {
505                                 // we already have it..
506                                 _this.files[dir  + '/' + fn].parent = parent;
507                                 return;
508                             }
509                             */
510                             var xt = this.xtype;
511                                         var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
512                             this.files.set( dir + "/" + fn, el);
513                             // parent ?? 
514                             
515                              
516                         }
517                     } catch (Error e) {
518                         print("Project::scanDirs failed : " + e.message + "\n");
519                     } catch (GLib.Error e) {
520                                 print("Project::scanDirs failed : " + e.message + "\n");
521                         }
522                         for (var i = 0; i < subs.length(); i++) {
523                         
524                          this.scanDir(subs.nth_data(i), dp+1);
525                     }
526                     
527                 }
528                   
529         }
530 }
531