1 //<Script type="text/javascript">
6 * Projects can only contain one directory... - it can import other projects..(later)
8 * we need to sort out that - paths is currently a key/value array..
10 * currently we store projects in ~/.Builder/{md5}.json
11 - then for Gtk projects we have a file config1.builder - which contains dependancies, and a list of files for each target
12 (for builder it's ended up in src/Builder/config1.builder? by accident.
13 - should really support something like
14 roobuilder --build {path_to_cfg} {target} - or local directory if not set..
15 roobuilder --build-errors {path_to_cfg} {target} - or local directory if not set..
20 should really store project data in the directory of the project?
24 // List of projects - just an array of paths in .Builder/Projects.json
26 // .roobuilder.jcfg << hidden file with project details?
35 public errordomain Error {
43 // static array of all projects.
44 private Gee.ArrayList<Project> projects;
48 public bool projects_loaded = false;
52 public abstract class Project : Object {
54 public signal void on_changed ();
57 //public string fn = ""; // just a md5...
61 return GLib.Path.get_basename(path);
67 public string path = "";
68 private Gee.ArrayList<JsRender.JsRender> sub_paths;
70 private Gee.HashMap<string,JsRender.JsRender> files ; // contains full list of files.
74 //public Json.Object json_project_data;
76 public Palete.Palete palete;
78 private bool is_scanned = false;
79 public Gee.HashMap<string,Palete.GirObject> gir_cache = null; // used by Gir ??? is this used by Roo?
80 public Palete.ValaCompileRequest last_request = null;
82 protected Project (string path) {
85 //this.json_project_data = new Json.Object();
87 this.is_scanned = false;
88 this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
89 this.files = new Gee.HashMap<string,JsRender.JsRender>();
90 //XObject.extend(this, cfg);
101 public static void loadAll(bool force = false)
103 if (projects_loaded && !force) {
107 var dirname = GLib.Environment.get_home_dir() + "/.Builder";
108 var dir = File.new_for_path(dirname);
109 if (!dir.query_exists()) {
111 dir.make_directory();
112 } catch(GLib.Error e) {
113 GLib.error("could not make builder directory");
117 projects = new Gee.ArrayList<Project>();
120 if (FileUtils.test(dirname + "/Projects.list", GLib.FileTest.IS_REGULAR)) {
122 projects_loaded = true;
125 convertOldProjects(); // this saves..
126 foreach(var p in projects) {
129 projects_loaded = true;
133 public static void remove(Project p) {
139 public static void saveProjectList()
141 var f = new Json.Object();
142 foreach(var p in projects) {
143 f.set_string_member(p.path, p.xtype);
146 var generator = new Json.Generator ();
147 var root = new Json.Node(Json.NodeType.OBJECT);
149 generator.set_root (root);
150 generator.pretty = true;
151 generator.indent = 4;
153 var data = generator.to_data (null);
154 var dirname = GLib.Environment.get_home_dir() + "/.Builder";
155 GLib.debug("Write new Project list\n %s", data);
159 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);
160 FileUtils.set_contents(dirname + "/Projects.list", data, data.length);
161 } catch (GLib.Error e) {
162 GLib.error("failed to save file %s", e.message);
169 public static void convertOldProjects()
172 var dirname = GLib.Environment.get_home_dir() + "/.Builder";
173 var dir = File.new_for_path(dirname);
175 var file_enum = dir.enumerate_children(
176 GLib.FileAttribute.STANDARD_DISPLAY_NAME,
177 GLib.FileQueryInfoFlags.NONE,
182 while ((next_file = file_enum.next_file(null)) != null) {
183 var fn = next_file.get_display_name();
184 if (!Regex.match_simple("\\.json$", fn)) {
187 Project.factoryFromFileOld(dirname + "/" + fn);
189 } catch(GLib.Error e) {
190 GLib.warning("oops - something went wrong scanning the projects\n");
192 GLib.debug("Loaded all old Projects - saving");
193 Project.saveProjectList();
197 public static Gee.ArrayList<Project> allProjectsByName()
204 public static Project? getProjectByName(string name)
207 foreach (var p in projects) {
208 if (p.name == name) {
216 public static Project? getProjectByPath(string path)
219 foreach (var p in projects) {
220 if (p.path == path) {
228 public static string listAllToString()
234 all.sort((fa,fb) => {
235 return ((Project)fa).name.collate(((Project)fb).name);
239 var iter = all.list_iterator();
240 var ret = "ID\tName\tDirectory\n";
241 while (iter.next()) {
242 ret += "%s\t%s\n".printf(
256 public static void loadIntoStore(GLib.ListStore st)
259 foreach (var p in projects) {
268 static void loadProjectList()
271 var dirname = GLib.Environment.get_home_dir() + "/.Builder";
273 projects = new Gee.ArrayList<Project>();
275 var pa = new Json.Parser();
277 pa.load_from_file(dirname + "/Projects.list");
278 } catch (GLib.Error e) {
279 GLib.error("could not load json file %s", e.message);
281 var node = pa.get_root();
282 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
283 GLib.error( dirname + "/Projects.list - invalid format?");
288 var obj = node.get_object ();
289 obj.foreach_member((sobj, key, val) => {
290 GLib.debug("read ProjectList %s: %s", key, val.get_string());
291 // facotry adds project!
293 Project.factory(val.get_string(), key );
294 } catch (GLib.Error e ) {
295 GLib.debug("error createing project %s", e.message);
303 // load project data from project file.
304 public static void factoryFromFileOld(string jsonfile)
307 GLib.debug("parse %s", jsonfile);
309 var pa = new Json.Parser();
311 pa.load_from_file(jsonfile);
312 } catch (GLib.Error e) {
313 GLib.error("could not load json file %s", e.message);
315 var node = pa.get_root();
318 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
319 GLib.debug("SKIP " + jsonfile + " - invalid format?");
323 var obj = node.get_object ();
324 var xtype = obj.get_string_member("xtype");
327 var paths = obj.get_object_member("paths");
330 paths.foreach_member((sobj, key, val) => {
337 if (fpath.length < 0 || !FileUtils.test(fpath,FileTest.IS_DIR)) {
343 proj = factory(xtype, fpath);
345 GLib.debug("Skip file - invalid file type");
349 //proj.json_project_data = obj; // store the original object...
351 //proj.fn = Path.get_basename(jsonfile).split(".")[0];
356 proj.name = obj.get_string_member("name");
358 // used to load paths..
359 //proj.initSubDirectories();
362 //proj.initDatabase();
364 GLib.debug("Add Project %s", proj.name);
372 public static Project factory(string xtype, string path) throws Error
375 // check to see if it's already loaded..
377 foreach(var p in projects) {
378 if (p.path == path) {
386 var ret = new Gtk(path);
391 var ret = new Roo(path);
396 // return new Flutter(path);
398 throw new Error.INVALID_TYPE("invalid project type");
413 //var dirname = GLib.Environment.get_home_dir() + "/.Builder";
415 var s = this.toJSON();
416 GLib.debug("Save Project %s\n%s", this.name, s);
418 //FileUtils.set_contents(dirname + "/" + this.fn + ".json", s, s.length);
419 FileUtils.set_contents(this.path + "/.roobuilder.jcfg", s, s.length);
420 } catch (GLib.Error e) {
421 GLib.error("failed to save file %s", e.message);
429 public string toJSON( )
432 var obj = new Json.Object();
433 obj.set_string_member("xtype", this.xtype);
438 var generator = new Json.Generator ();
439 var root = new Json.Node(Json.NodeType.OBJECT);
440 root.init_object(obj);
441 generator.set_root (root);
443 generator.pretty = true;
444 generator.indent = 4;
447 return generator.to_data (null);
452 // used to check what type a project might be..
454 public static string peekProjectType(string fn)
456 var pa = new Json.Parser();
458 pa.load_from_file(fn);
459 } catch (GLib.Error e) {
460 GLib.debug("could not load json file %s", e.message);
464 var node = pa.get_root();
466 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
467 GLib.debug("SKIP %s/.roobuilder.jcfg - invalid format?",fn);
471 var obj = node.get_object ();
473 var xtype = obj.get_string_member("xtype");
474 return xtype == null ? "" : xtype;
479 // this will do a full scan - should only be done on viewing project..
480 // not initial load.. - may take time.
484 if (this.is_scanned) {
487 GLib.debug("load is_scanned = false");
489 if (FileUtils.test(this.path + "/.roobuilder.jcfg", FileTest.EXISTS)) {
491 var pa = new Json.Parser();
493 pa.load_from_file(this.path + "/.roobuilder.jcfg");
494 } catch (GLib.Error e) {
495 GLib.error("could not load json file %s", e.message);
497 var node = pa.get_root();
500 if (node == null || node.get_node_type () != Json.NodeType.OBJECT) {
501 GLib.debug("SKIP %s/.roobuilder.jcfg - invalid format?",this.path);
505 var obj = node.get_object ();
509 // used to load paths..
510 this.sub_paths = new Gee.ArrayList<JsRender.JsRender>();
511 this.files = new Gee.HashMap<string,JsRender.JsRender>();
512 this.loadSubDirectories("", 0);
515 this.is_scanned = true; // loaded.. dont need to do it again..
516 GLib.debug("load is_scanned = true");
520 public abstract void loadJson(Json.Object obj);
521 public abstract void saveJson(Json.Object obj);
525 public string firstPath()
527 var iter = this.paths.map_iterator();
528 while (iter.next()) {
529 return iter.get_key();
535 public bool hasPath(string path)
537 var iter = this.paths.map_iterator();
538 while (iter.next()) {
539 if (iter.get_key() == path) {
548 // returns the first path
549 public string getName()
551 var iter = this.paths.map_iterator();
552 while (iter.next()) {
553 return GLib.Path.get_basename(iter.get_key());
560 public Gee.ArrayList<JsRender.JsRender> sortedFiles()
562 var files = new Gee.ArrayList<JsRender.JsRender>();
564 var fiter = this.files.map_iterator();
565 while(fiter.next()) {
566 files.add(fiter.get_value());
568 files.sort((fa,fb) => {
569 return ((JsRender.JsRender)fa).name.collate(((JsRender.JsRender)fb).name);
578 public string listAllFilesToString()
581 var iter = this.sortedFiles().list_iterator();
582 var ret = "ID\tName\tDirectory\n";
583 while (iter.next()) {
584 ret += "%s\n".printf(
600 public JsRender.JsRender? getByName(string name)
602 foreach(var f in this.files.values) {
603 if (f.name == name) {
609 // this get's a file using the full path ( replaces vala->bjs if they exist);
611 public JsRender.JsRender? getByPath(string path)
614 // keys are not paths...
615 foreach(var f in this.files.values) {
616 GLib.debug("check %s = %s ? %s", path, f.path, f.targetName());
617 if (f.path == path || f.targetName() == path) {
624 public JsRender.JsRender? getById(string id)
626 foreach(var f in this.files.values) {
634 // name should include extension.
636 public JsRender.JsRender? newFile (string xtype, string sub_dir, string name)
639 var fp = this.path + (sub_dir.length > 0 ? "/" : "") + sub_dir;
640 if (this.files.has_key(fp + "/" + name)) {
645 var ret = JsRender.JsRender.factory(xtype,
649 this.files.set(fp + "/" + name , ret);
651 } catch (JsRender.Error e) {
652 GLib.error("failed to create file %s", e.message);
657 public JsRender.JsRender loadFileOnly (string path)
661 return JsRender.JsRender.factory(xt, this, path);
662 } catch (JsRender.Error e) {
663 GLib.error("failed to create file %s", e.message);
669 public JsRender.JsRender create(string filename)
671 var ret = this.loadFileOnly(filename);
678 private void loadSubDirectories(string subdir, int dp)
681 //print("Project.Base: Running scandir on " + dir +"\n");
682 if (dp > 5) { // no more than 5 deep?
685 if (subdir == "build") { // cmake!
689 if (subdir == "autom4te.cache") { // automake?
692 if (subdir == "debian") { // debian!?
697 var dir = this.path + (subdir.length > 0 ? "/" : "") + subdir;
700 GLib.debug("Project %s Scan Dir: %s", this.name, dir);
701 var jsDir = new JsRender.Dir(this, dir);
702 this.sub_paths.add(jsDir); // might be ''...
705 // this should be done async -- but since we are getting the proto up ...
706 var other_files = new Gee.ArrayList<string>();
707 var bjs_files = new Gee.ArrayList<string>();
708 var vala_files = new Gee.ArrayList<string>();
709 var subs = new Gee.ArrayList<string>();
712 var f = File.new_for_path(dir);
714 var file_enum = f.enumerate_children(GLib.FileAttribute.STANDARD_DISPLAY_NAME, GLib.FileQueryInfoFlags.NONE, null);
718 while ((next_file = file_enum.next_file(null)) != null) {
719 var fn = next_file.get_display_name();
722 //print("trying" + dir + "/" + fn +"\n");
724 if (fn[0] == '.') { // skip hidden
728 if (FileUtils.test(dir + "/" + fn, GLib.FileTest.IS_DIR)) {
729 subs.add(dir + "/" + fn);
732 if (Regex.match_simple("\\.(o|cache|gif|jpg|png|gif|out|stamp|~)$", fn)) { // object..
735 if (Regex.match_simple("^(config1.builder|a.out|stamp-h1|depcomp|config.log|config.status)$", fn)) { // object..
740 if (Regex.match_simple("\\.vala$", fn)) {
743 //print("no a bjs\n");
746 if (!Regex.match_simple("\\.bjs$", fn)) {
748 //print("no a bjs\n");
751 bjs_files.add(fn.substring(0, fn.length-4));
754 var el = JsRender.JsRender.factory(xt,this, dir + "/" + fn);
755 this.files.set( dir + "/" + fn, el);
756 jsDir.childfiles.append(el);
763 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
764 } catch (GLib.Error e) {
765 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
768 foreach(var fn in other_files) {
769 var dpos = fn.last_index_of(".");
770 var without_ext = fn.substring(0, dpos);
771 if (bjs_files.contains(without_ext)) { // will remove vala and c.
774 // c with a vala - skip
775 if (Regex.match_simple("\\.c$", fn) && vala_files.contains(without_ext + ".vala")) {
778 // Makefile (only allow am files at present.
779 if (without_ext == "Makefile") {
780 if (!Regex.match_simple("\\.am$", fn)) {
784 if (without_ext == "configure") {
785 if (!Regex.match_simple("\\.ac$", fn)) {
794 //GLib.debug("Could have added %s/%s", dir, fn);
796 var el = JsRender.JsRender.factory("PlainFile",this, dir + "/" + fn);
797 this.files.set( dir + "/" + fn, el);
798 jsDir.childfiles.append(el);
799 } catch (JsRender.Error e) {
800 GLib.warning("Project::scanDirs failed : " + e.message + "\n");
804 foreach (var sd in subs) {
805 this.loadSubDirectories(sd.substring(this.path.length+1), dp+1);
811 // calle dfrom new file dialog
812 // add files to dires
816 public void addFile(JsRender.JsRender pfile)
817 { // add a single file, and trigger changed.
819 if (pfile.xtype == "Gtk" || pfile.xtype == "Roo" ) {
820 this.files.set(pfile.path, pfile); // duplicate check
822 if (pfile.xtype == "Gtk" && pfile.build_module != "") {
824 var gfile = (JsRender.Gtk) pfile;
825 gfile.updateCompileGroup("", pfile.build_module);
829 var sp = this.findDir(pfile.dir);
830 sp.childfiles.append(pfile);
838 public void deleteFile(JsRender.JsRender file)
840 if (file.xtype =="Dir") {
843 var sp = this.findDir(file.dir);
844 for(var i =0;i < sp.childfiles.n_items; i++) {
845 var jf = (JsRender.JsRender) sp.childfiles.get_item(i);
846 if (jf.path == file.path) {
847 sp.childfiles.remove(i);
851 if (this.files.has_key(file.path)) {
852 this.files.unset(file.path);
862 // but do not add it to our list.!!!
863 public void makeProjectSubdir(string name)
865 var dir = File.new_for_path(this.path + "/" + name);
866 if (FileUtils.test(this.path + "/" + name, FileTest.EXISTS)) {
871 dir.make_directory();
872 } catch (GLib.Error e) {
873 GLib.error("Failed to make directory %s", this.path + "/" + name);
877 public void createDir(string subdir) // add a single dir, and trigger changed.
879 if (subdir.strip() == "" || this.subpathsContains(subdir)) {
882 var dir= File.new_for_path(this.path + "/" + subdir);
884 if (!dir.query_exists()) {
888 dir.make_directory();
889 } catch (GLib.Error e) {
890 GLib.error("Failed to make directory %s", this.path + "/" + name);
894 this.sub_paths.add(new JsRender.Dir(this,this.path + "/" + subdir));
895 this.on_changed(); // not sure if it's needed - adding a dir doesnt really change much.
898 // this store is used in the icon view ?? do we need to store and update it?
899 public void loadFilesIntoStore(GLib.ListStore ls)
902 //GLib.debug("Load files (into grid) %s", this.name);
903 foreach(var f in this.files.values) {
904 // GLib.debug("Add file %s", f.name);
905 if (f.xtype == "PlainFile") {
912 public void loadDirsIntoStore(GLib.ListStore ls)
915 foreach(var f in this.sub_paths) {
916 //GLib.debug("Add %s", f.name);
922 public bool subpathsContains(string subpath)
924 foreach(var sp in this.sub_paths) {
926 if (sp.path == this.path + "/" + subpath) {
933 public void loadDirsToStringList( global::Gtk.StringList sl)
936 while (sl.get_n_items() > 0) {
940 foreach(var sp in this.sub_paths) {
942 sl.append( sp.path == this.path ? "/" : sp.path.substring(this.path.length));
947 public JsRender.Dir? findDir(string path) {
949 foreach(var jdir in this.sub_paths) {
950 if (path == jdir.path) {
951 return (JsRender.Dir)jdir;
957 public string[] pathsMatching(string name, bool full_path)
961 foreach(var jdir in this.sub_paths) {
965 if (Path.get_basename (jdir.path) == name) {
966 GLib.debug("pathsMatching %s\n", jdir.path);
967 ret += full_path ? jdir.path : jdir.relpath;
974 public Gee.ArrayList<string> readArray(Json.Array ar)
976 var ret = new Gee.ArrayList<string>();
977 for(var i =0; i< ar.get_length(); i++) {
978 var add = ar.get_string_element(i);
979 if (ret.contains(add)) {
989 public abstract void initDatabase();
990 public abstract void initialize(); // for new projects (make dirs?);