test-AL0LMY.vala.c
[roobuilder] / src / Project / Gtk.vala
1 //<Script type="text/javascript">
2 /**
3  * Gtk projects - normally vala based now..
4  * 
5  * should have a few extra features..
6  * 
7  * like:
8  *   compile flags etc..
9  *   different versions (eg. different files can compile different versions - eg. for testing.
10  *   
11  * If we model this like adjuta - then we would need a 'project' file that is actually in 
12  * the directory somewhere... - and is revision controlled etc..
13  * 
14  * builder.config ??
15  * 
16  * 
17  * 
18  * 
19  */
20  
21
22 namespace Project 
23 {
24         static int gtk_id = 1;
25  
26
27         public class Gtk : Project
28         {
29                 /**
30                 * Gir cache - it's local as we might want clear it if we modify the packages...
31                 *
32                 */
33                 public Gee.HashMap<string,Palete.Gir> gir_cache = null;
34                 public bool gir_cache_loaded = false;
35  
36           
37                 public Gtk(string path) {
38                   
39                   
40                         base(path);
41                         this.palete = new Palete.Gtk(this);
42                         
43                         this.gir_cache = new Gee.HashMap<string,Palete.Gir>();
44                         this.xtype = "Gtk";
45                         var gid = "project-gtk-%d".printf(gtk_id++);
46                         this.id = gid;
47                         try {
48                                 this.loadConfig();
49                         } catch (GLib.Error e )  {
50                                 // is tihs ok?
51                         }
52                 
53                 }
54                 public Gee.HashMap<string,GtkValaSettings> compilegroups;
55                 
56                 public void loadConfig() throws GLib.Error 
57                 {
58                         // load a builder.config JSON file.
59                         // 
60                         this.compilegroups = new  Gee.HashMap<string,GtkValaSettings>();
61                         
62                         
63                         var fn = this.firstPath() + "/config1.builder";
64                         GLib.debug("load: " + fn );
65                         
66                         if (!FileUtils.test(fn, FileTest.EXISTS)) {
67                                 this.compilegroups.set("_default_", new GtkValaSettings("_default_") );
68                                 return;
69                         }
70
71                         var pa = new Json.Parser();
72                         pa.load_from_file(fn);
73                         var node = pa.get_root();
74
75                         // should be an array really.
76                         if (node.get_node_type () != Json.NodeType.ARRAY) {
77                                 throw new Error.INVALID_FORMAT ("Unexpected element type %s", node.type_name ());
78                         }
79                         
80                         var obj = node.get_array ();
81                         for(var i= 0;i<obj.get_length();i++) {
82                                 var el = obj.get_object_element(i);
83                                 var vs = new GtkValaSettings.from_json(el);
84                 if (vs == null) {
85                     print("problem loading json file");
86                     continue;
87                 }
88                                 if (vs.name != "_default_") {
89                                         vs.parent = this.compilegroups.get("_default_");
90                                 }
91                                 this.compilegroups.set(vs.name,vs);
92                         }
93                         GLib.debug("%s\n",this.configToString ());
94                         
95                 }
96                 public string configToString()
97                 {
98                         var ar = new Json.Array();
99                         var iter = this.compilegroups.map_iterator();
100                         while(iter.next()) {
101                                  
102                                 ar.add_object_element(iter.get_value().toJson());
103                         }
104
105                         var generator = new Json.Generator ();
106                         generator.indent = 4;
107                         generator.pretty = true;
108                         var node = new Json.Node(Json.NodeType.ARRAY);
109                         node.set_array(ar);
110                         generator.set_root(node);
111                         return generator.to_data(null);
112                 }
113                 
114                 public void writeConfig()
115                 {
116                         var fn = this.firstPath() + "/config1.builder";
117                         GLib.debug("write: " + fn );
118
119                          
120                         var f = GLib.File.new_for_path(fn);
121                         var data_out = new GLib.DataOutputStream(
122                                         f.replace(null, false, GLib.FileCreateFlags.NONE, null)
123                         );
124                         data_out.put_string(this.configToString(), null);
125                         data_out.close(null);
126                         this.gir_cache_loaded = false; // force a reload.
127                         return ;
128                          
129                 }
130                 /**
131                  *  perhaps we should select the default in the window somewhere...
132                  */ 
133                 public string firstBuildModule()
134                 {
135                         var iter = this.compilegroups.map_iterator();
136                         while(iter.next()) {
137                                  
138                                  if (iter.get_value().name == "_default_") {
139                                          continue;
140                                  }
141                                  
142                                  return iter.get_value().name;
143                         }
144                         return "";
145                 }
146                 
147                 
148                 public string relPath(string target)
149                 {
150                         var basename = this.firstPath();
151                         // eg. base = /home/xxx/fred/blogs
152                         // target = /home/xxx/fred/jones
153                         
154                         // this does not work correctly...
155                         var bb = basename;
156                         var prefix = "";
157                         while (true) {
158                                 if (    bb.length < target.length &&
159                                         target.substring(0, bb.length) == bb) {
160                                         
161                                         return prefix + target.substring(bb.length );
162                                 }
163                                 if (bb.length < 1) {
164                                         throw new Error.INVALID_FORMAT ("Could not work out relative path %s to %s",
165                                                                         basename, target);
166                                 }
167                                 bb = GLib.Path.get_dirname(bb);
168                                 prefix += "../";
169                                 
170                         }
171          
172                 }
173                 /**
174                  * get a list of files for a folder..
175                  * 
176                  * - in the project manager this has to list all possible compilable 
177                  *   files  - eg. exclue XXX.vala.c or XXX.c with the same name as 
178                  *   a vala file (so to ignore the generated files)
179                  * 
180                  * - for the editor navigation - this should exclude all files that
181                  *   are vala based on a bjs file..
182                  *  
183                  */
184                 
185                 public Gee.ArrayList<string> filesAll(string in_path,bool abspath = true)
186                 {
187                         var ret =  new Gee.ArrayList<string>();
188                         
189                         var dirname = this.resolve_path(
190                                 this.resolve_path_combine_path(this.firstPath(),in_path));
191                         
192                         GLib.debug("SCAN %s", dirname);
193                                 // scan the directory for files -- ending with vala || c
194                         
195
196                         var dir = File.new_for_path(dirname);
197                         if (!dir.query_exists()) {
198                                 GLib.debug("SCAN %s - skip - does not exist\n", dirname);
199                                 return ret;
200                         }
201                         var pathprefix = abspath ? dirname : in_path;
202            
203                         try {
204                                 var file_enum = dir.enumerate_children(
205                                         "standard::*", 
206                                         GLib.FileQueryInfoFlags.NONE, 
207                                         null
208                                 );
209                 
210                  
211                                 FileInfo next_file; 
212                                 while ((next_file = file_enum.next_file(null)) != null) {
213                                         var fn = next_file.get_display_name();
214                                         
215                                         if (next_file.get_file_type () == GLib.FileType.DIRECTORY) {
216                                          
217                                                 GLib.debug("SKIP %s not regular  ", fn);
218                                                 continue;
219                                         }
220                                         if (!Regex.match_simple("^text", next_file.get_content_type())) {
221                                                 continue;
222                                         }
223                                         GLib.debug("SCAN ADD %s : %s", fn, next_file.get_content_type());
224                                         ret.add(pathprefix + "/" + fn);
225                                          
226                                         // any other valid types???
227                                 
228                                 }
229                                 
230                         } catch(Error e) {
231                                 GLib.warning("oops - something went wrong scanning the projects\n");
232                         }       
233                         
234                         return ret;
235                 }
236                 
237                 public Gee.ArrayList<string> filesForCompile(string in_path, bool abspath = true)
238                 {
239                         var allfiles = this.filesAll(in_path,abspath);
240                         var ret =  new Gee.ArrayList<string>();
241                         
242                         
243                         for (var i = 0; i < allfiles.size; i ++) {
244                                 var fn = allfiles.get(i);
245                                 try {
246                                         if (Regex.match_simple("\\.vala$", fn)) {
247                                                 ret.add( fn);
248                                                 continue;
249                                         }
250                                         // vala.c -- ignore..
251                                         if (Regex.match_simple("\\.vala\\.c$", fn)) {
252                                                 continue;
253                                         }
254                                         // not a c file...
255                                         if (!Regex.match_simple("\\.c$", fn)) {
256                                                 continue;
257                                         }
258                                         
259                                         // is the c file the same as a vala file...
260                                         
261                                          
262                                         
263                                         var vv = (new Regex("\\.c$")).replace( fn, fn.length, 0, ".vala");
264                                 
265                                         
266                                                 
267                                         if (allfiles.index_of( vv) > -1) {
268                                                 continue;
269                                         }
270                                         // add the 'c' file..
271                                         ret.add(fn);
272                                 } catch (Error e) {
273                                         continue;
274                                 }
275                         }
276                         // sort.
277                         ret.sort((fa,fb) => {
278                                 return ((string)fa).collate((string) fb);
279                         });
280                         return ret;
281                         
282                 }
283                 
284                 public Gee.ArrayList<string> filesForOpen(string in_path)
285                 {
286                         var allfiles = this.filesAll(in_path);
287                         var ret =  new Gee.ArrayList<string>();
288                         GLib.debug("SCAN %s - %d files",in_path, allfiles.size);
289                         
290                         for (var i = 0; i < allfiles.size; i ++) {
291                                 var fn = allfiles.get(i);
292                                 var bn  = GLib.Path.get_basename(fn);
293                                 try {
294                                         
295                                         if (Regex.match_simple("\\.vala\\.c$", fn)) {
296                                                 GLib.debug("SKIP %s - vala.c",fn);
297
298                                                 continue;
299                                         }
300                                         
301                                         if (Regex.match_simple("\\.bjs$", fn)) {
302                                                 GLib.debug("SKIP %s - .bjs",fn);
303                                                 continue;
304                                         }
305                                         
306                                         if (Regex.match_simple("\\~$", fn)) {
307                                                 GLib.debug("SKIP %s - ~",fn);
308                                                 continue;
309                                         }
310                                         if (Regex.match_simple("\\.stamp$", fn)) {
311                                                 GLib.debug("SKIP %s - .o",fn);
312                                                 continue;
313                                         }
314                                         if ("stamp-h1" == bn) {
315                                                 GLib.debug("SKIP %s - .o",fn);
316                                                 continue;
317                                         }
318                                         
319                                         // confgure.am
320                                         if ("config.h" == bn || "config.h.in" == bn || "config.log" == bn  || "configure" == bn ) {
321                                                 if (allfiles.index_of( in_path +"/configure.ac") > -1) {
322                                                         continue;
323                                                 }
324                                         }
325                                         // makefile
326                                         if ("Makefile" == bn || "Makefile.in" == bn ) {
327                                                 if (allfiles.index_of( in_path +"/Makefile.am") > -1) {
328                                                         continue;
329                                                 }
330                                         }
331                                         
332                                         if (Regex.match_simple("^\\.", bn)) {
333                                                 GLib.debug("SKIP %s - hidden",fn);
334                                                 continue;
335                                         }
336                                         if (Regex.match_simple("\\.vala$", fn)) {
337                                                 var vv = (new Regex("\\.vala$")).replace( fn, fn.length, 0, ".bjs");
338                                                 if (allfiles.index_of( vv) > -1) {
339                                                         GLib.debug("SKIP %s - .vala (got bjs)",fn);
340                                                         continue;
341                                                 }
342                                                 GLib.debug("ADD %s",fn);
343                                                 ret.add( fn);
344                                                 continue;
345                                         }
346                                         // vala.c -- ignore..
347                                         
348                                         // not a c file...
349                                         if (Regex.match_simple("\\.c$", fn)) {
350                                                 
351                                                 var vv = (new Regex("\\.c$")).replace( fn, fn.length, 0, ".vala");
352                                                 if (allfiles.index_of( vv) > -1) {
353                                                         GLib.debug("SKIP %s - .c (got vala)",fn);
354                                                         continue;
355                                                 }
356                                                 GLib.debug("ADD %s",fn);                                                
357                                                 ret.add( fn);
358                                                 continue;
359                                         }
360                                         
361                                         if (GLib.Path.get_basename( fn) == "config1.builder") {
362                                                 continue;
363                                         }
364                                         // not .c / not .vala /not .bjs.. -- other type of file..
365                                         // allow ???
366                                         GLib.debug("ADD %s",fn);
367                                         // add the 'c' file..
368                                         ret.add(fn);
369                                 } catch (Error e) {
370                                         GLib.debug("Exception %s",e.message);
371                                         continue;
372                                 }
373                         }
374                         // sort.
375                         ret.sort((fa,fb) => {
376                                 return ((string)fa).collate((string) fb);
377                         });
378                         return ret;
379                         
380                 }
381                 
382                 
383                  
384  
385
386                 public   string  resolve_path_combine_path(string first, string second)
387                 {
388                         string ret = first;
389                         if (first.length > 0 && second.length > 0 && !first.has_suffix("/") && !second.has_prefix("/"))
390                         {
391                                 ret += "/";
392                         }
393                         //print("combined path = %s",  ret + second);
394                         return ret + second;
395                 }
396                 public   string  resolve_path_times(string part, int times, string? clue = null)
397                 {
398                         string ret = "";
399                         for (int i = 0; i < times; i++)
400                         {
401                                 if (clue != null && i > 0)
402                                 {
403                                         ret += clue;
404                                 }
405                                 ret += part;
406                         }
407                         return ret;
408                 }
409                 public   string resolve_path(string _path, string? relative = null)
410                 {
411                         string path = _path;
412                         if (relative != null)
413                         {
414                                 path = this.resolve_path_combine_path(path, relative);
415                         }
416                         string[] parts = path.split("/");
417                         string[] ret = {};
418                         int relative_parts = 0;
419                                         
420                         foreach (var part in parts)
421                         {
422                                 if (part.length < 1 || part == ".")
423                                 {
424                                         continue;
425                                 }
426                                 
427                                 if (part == "..")
428                                 {
429                                         if (ret.length > 0)
430                                         {
431                                                 ret = ret[0: ret.length -1];
432                                         }
433                                         else
434                                         {
435                                                 relative_parts++;
436                                         }
437                                         continue;
438                                 }
439                                 
440                                 ret += part;
441                         }
442                         
443                         path =  this.resolve_path_combine_path(this.resolve_path_times("..", relative_parts, "/"), string.joinv("/", ret));
444                         if (_path.has_prefix("/"))
445                         {
446                                 path = "/" + path;
447                         }
448                         return path;
449                 }
450                 
451                 public string[] vapidirs()
452                 {
453                         string[] ret = {};
454                         var sources = this.compilegroups.get("_default_").sources;
455                         for(var i =0; i< sources.size; i++) {
456                                 
457                                 var path = this.resolve_path( this.firstPath(), sources.get(i));
458                                 
459                                 if (Path.get_basename (path) == "vapi") {
460                                         GLib.debug("Adding VAPIDIR: %s\n", path);
461                                         ret += path;
462                                 }
463                                 
464                         }
465                         return ret;
466                         
467                 }
468                 public string[] sourcedirs()
469                 {
470                         string[] ret = {};
471                         var sources = this.compilegroups.get("_default_").sources;
472                         ret += this.firstPath();  
473                         for(var i =0; i< sources.size; i++) {
474                                 
475                                 var path = this.resolve_path( this.firstPath(), sources.get(i));
476                                 if (path == this.firstPath()) {
477                                         continue;
478                                 }
479                                 if (Path.get_basename (path) == "vapi") {
480                                         continue;
481                 
482                                 }
483                 //                      GLib.debug("Adding VAPIDIR: %s\n", path);
484                                 ret += path;            
485                         }
486                         return ret;
487                         
488                 }       
489
490         }
491         // an object describing a build config (or generic ...)
492         public class GtkValaSettings : Object {
493                 public string name;
494                 public GtkValaSettings? parent;
495                 
496                 public string compile_flags; // generic to all.
497                 public Gee.ArrayList<string> packages; // list of packages?? some might be genericly named?
498                 public Gee.ArrayList<string> sources; // list of files+dirs (relative to project)
499                 public string target_bin;
500
501                 public string execute_args;
502                 
503                 
504                 public GtkValaSettings(string name) 
505                 {
506                         this.name = name;
507                         this.compile_flags = "";
508                         this.target_bin = "";
509                         this.packages = new Gee.ArrayList<string>();
510                         this.sources = new Gee.ArrayList<string>();
511                         this.execute_args = "";
512                                 
513                 }
514                 
515                 
516                 public GtkValaSettings.from_json(Json.Object el) {
517
518                         
519                         this.name = el.get_string_member("name");
520                         this.compile_flags = el.get_string_member("compile_flags");
521                         if ( el.has_member("execute_args")) {
522                                 this.execute_args = el.get_string_member("execute_args");
523                         } else {
524                                 this.execute_args = "";
525                         }
526                         this.target_bin = el.get_string_member("target_bin");
527                         // sources and packages.
528                         this.sources = this.readArray(el.get_array_member("sources"));
529                         this.packages = this.readArray(el.get_array_member("packages"));
530
531                 }
532                 
533                 // why not array of strings?
534                 
535                 public Gee.ArrayList<string> readArray(Json.Array ar) 
536                 {
537                         var ret = new Gee.ArrayList<string>();
538                         for(var i =0; i< ar.get_length(); i++) {
539                                 ret.add(ar.get_string_element(i));
540                         }
541                         return ret;
542                 }
543                 
544                 public Json.Object toJson()
545                 {
546                         var ret = new Json.Object();
547                         ret.set_string_member("name", this.name);
548                         ret.set_string_member("compile_flags", this.compile_flags);
549                         ret.set_string_member("execute_args", this.execute_args);
550                         ret.set_string_member("target_bin", this.target_bin);
551                         ret.set_array_member("sources", this.writeArray(this.sources));
552                         ret.set_array_member("packages", this.writeArray(this.packages));
553                         return ret;
554                 }
555                 public Json.Array writeArray(Gee.ArrayList<string> ar) {
556                         var ret = new Json.Array();
557                         for(var i =0; i< ar.size; i++) {
558                                 ret.add_string_element(ar.get(i));
559                         }
560                         return ret;
561                 }
562                 
563                 
564         }
565  
566    
567 }