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