1 /* ide-config.c
2  *
3  * Copyright 2016-2019 Christian Hergert <chergert@redhat.com>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  * SPDX-License-Identifier: GPL-3.0-or-later
19  */
20 
21 #define G_LOG_DOMAIN "ide-config"
22 
23 #include "config.h"
24 
25 #include <string.h>
26 
27 #include "ide-config-manager.h"
28 #include "ide-config-private.h"
29 #include "ide-config.h"
30 #include "ide-foundry-enums.h"
31 #include "ide-foundry-compat.h"
32 #include "ide-runtime-manager.h"
33 #include "ide-runtime.h"
34 #include "ide-toolchain-manager.h"
35 #include "ide-toolchain.h"
36 
37 typedef struct
38 {
39   gchar          *app_id;
40   gchar         **build_commands;
41   gchar          *config_opts;
42   gchar          *display_name;
43   gchar          *id;
44   gchar         **post_install_commands;
45   gchar          *prefix;
46   gchar          *run_opts;
47   gchar          *runtime_id;
48   gchar          *toolchain_id;
49   gchar          *prepend_path;
50   gchar          *append_path;
51   GHashTable     *pipeline_args;
52 
53   GFile          *build_commands_dir;
54 
55   IdeEnvironment *environment;
56   IdeEnvironment *runtime_environment;
57 
58   GHashTable     *internal;
59 
60   gint            parallelism;
61   guint           sequence;
62 
63   guint           block_changed;
64 
65   guint           dirty : 1;
66   guint           debug : 1;
67   guint           has_attached : 1;
68   guint           prefix_set : 1;
69 
70   /*
71    * This is used to determine if we can make progress building
72    * with this configuration. When runtimes are added/removed, the
73    * IdeConfig:ready property will be notified.
74    */
75   guint           runtime_ready : 1;
76 
77   IdeBuildLocality locality : 3;
78 } IdeConfigPrivate;
79 
80 G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (IdeConfig, ide_config, IDE_TYPE_OBJECT)
81 
82 enum {
83   PROP_0,
84   PROP_PREPEND_PATH,
85   PROP_APPEND_PATH,
86   PROP_APP_ID,
87   PROP_BUILD_COMMANDS,
88   PROP_BUILD_COMMANDS_DIR,
89   PROP_CONFIG_OPTS,
90   PROP_DEBUG,
91   PROP_DIRTY,
92   PROP_DISPLAY_NAME,
93   PROP_ENVIRON,
94   PROP_ID,
95   PROP_LOCALITY,
96   PROP_PARALLELISM,
97   PROP_POST_INSTALL_COMMANDS,
98   PROP_PREFIX,
99   PROP_PREFIX_SET,
100   PROP_READY,
101   PROP_RUNTIME,
102   PROP_RUNTIME_ID,
103   PROP_TOOLCHAIN_ID,
104   PROP_TOOLCHAIN,
105   PROP_RUN_OPTS,
106   N_PROPS
107 };
108 
109 enum {
110   CHANGED,
111   N_SIGNALS
112 };
113 
114 static GParamSpec *properties [N_PROPS];
115 static guint signals [N_SIGNALS];
116 
117 static void
_value_free(gpointer data)118 _value_free (gpointer data)
119 {
120   GValue *value = data;
121 
122   if (value != NULL)
123     {
124       g_value_unset (value);
125       g_slice_free (GValue, value);
126     }
127 }
128 
129 static GValue *
_value_new(GType type)130 _value_new (GType type)
131 {
132   GValue *value;
133 
134   value = g_slice_new0 (GValue);
135   g_value_init (value, type);
136 
137   return value;
138 }
139 
140 static void
ide_config_block_changed(IdeConfig * self)141 ide_config_block_changed (IdeConfig *self)
142 {
143   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
144 
145   g_assert (IDE_IS_CONFIG (self));
146 
147   priv->block_changed++;
148 }
149 
150 static void
ide_config_unblock_changed(IdeConfig * self)151 ide_config_unblock_changed (IdeConfig *self)
152 {
153   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
154 
155   g_assert (IDE_IS_CONFIG (self));
156 
157   priv->block_changed--;
158 }
159 
160 static void
ide_config_emit_changed(IdeConfig * self)161 ide_config_emit_changed (IdeConfig *self)
162 {
163   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
164 
165   g_assert (IDE_IS_CONFIG (self));
166 
167   if (priv->block_changed == 0)
168     g_signal_emit (self, signals [CHANGED], 0);
169 }
170 
171 static IdeRuntime *
ide_config_real_get_runtime(IdeConfig * self)172 ide_config_real_get_runtime (IdeConfig *self)
173 {
174   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
175 
176   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
177 
178   if (priv->runtime_id != NULL)
179     {
180       g_autoptr(IdeContext) context = NULL;
181       g_autoptr(IdeRuntimeManager) runtime_manager = NULL;
182 
183       /* We might be in a thread, ref objects */
184       context = ide_object_ref_context (IDE_OBJECT (self));
185       runtime_manager = ide_object_get_child_typed (IDE_OBJECT (context), IDE_TYPE_RUNTIME_MANAGER);
186 
187       return ide_runtime_manager_get_runtime (runtime_manager, priv->runtime_id);
188     }
189 
190   return NULL;
191 }
192 
193 static void
ide_config_set_id(IdeConfig * self,const gchar * id)194 ide_config_set_id (IdeConfig   *self,
195                    const gchar *id)
196 {
197   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
198 
199   g_return_if_fail (IDE_IS_CONFIG (self));
200   g_return_if_fail (id != NULL);
201 
202   if (g_strcmp0 (id, priv->id) != 0)
203     {
204       g_free (priv->id);
205       priv->id = g_strdup (id);
206       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ID]);
207     }
208 }
209 
210 static void
ide_config_runtime_manager_items_changed(IdeConfig * self,guint position,guint added,guint removed,IdeRuntimeManager * runtime_manager)211 ide_config_runtime_manager_items_changed (IdeConfig         *self,
212                                           guint              position,
213                                           guint              added,
214                                           guint              removed,
215                                           IdeRuntimeManager *runtime_manager)
216 {
217   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
218   IdeRuntime *runtime;
219   gboolean runtime_ready;
220 
221   g_assert (IDE_IS_CONFIG (self));
222 
223   if (ide_object_in_destruction (IDE_OBJECT (self)))
224     return;
225 
226   g_assert (IDE_IS_RUNTIME_MANAGER (runtime_manager));
227 
228   runtime = ide_runtime_manager_get_runtime (runtime_manager, priv->runtime_id);
229   runtime_ready = !!runtime;
230 
231   if (!priv->runtime_ready && runtime_ready)
232     ide_runtime_prepare_configuration (runtime, self);
233 
234   if (runtime_ready != priv->runtime_ready)
235     {
236       priv->runtime_ready = runtime_ready;
237       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_READY]);
238     }
239 }
240 
241 static void
ide_config_environment_changed(IdeConfig * self,IdeEnvironment * environment)242 ide_config_environment_changed (IdeConfig      *self,
243                                 IdeEnvironment *environment)
244 {
245   IDE_ENTRY;
246 
247   g_assert (IDE_IS_CONFIG (self));
248   g_assert (IDE_IS_ENVIRONMENT (environment));
249 
250   if (ide_object_in_destruction (IDE_OBJECT (self)))
251     return;
252 
253   ide_config_set_dirty (self, TRUE);
254   ide_config_emit_changed (self);
255 
256   IDE_EXIT;
257 }
258 
259 static void
ide_config_runtime_environment_changed(IdeConfig * self,IdeEnvironment * environment)260 ide_config_runtime_environment_changed (IdeConfig      *self,
261                                         IdeEnvironment *environment)
262 {
263   IDE_ENTRY;
264 
265   g_assert (IDE_IS_CONFIG (self));
266   g_assert (IDE_IS_ENVIRONMENT (environment));
267 
268   if (ide_object_in_destruction (IDE_OBJECT (self)))
269     return;
270 
271   ide_config_set_dirty (self, TRUE);
272   ide_config_emit_changed (self);
273 
274   IDE_EXIT;
275 }
276 
277 static void
ide_config_real_set_runtime(IdeConfig * self,IdeRuntime * runtime)278 ide_config_real_set_runtime (IdeConfig  *self,
279                              IdeRuntime *runtime)
280 {
281   const gchar *runtime_id = "host";
282 
283   g_assert (IDE_IS_CONFIG (self));
284   g_assert (!runtime || IDE_IS_RUNTIME (runtime));
285 
286   if (runtime != NULL)
287     runtime_id = ide_runtime_get_id (runtime);
288 
289   ide_config_set_runtime_id (self, runtime_id);
290 }
291 
292 static gchar *
ide_config_repr(IdeObject * object)293 ide_config_repr (IdeObject *object)
294 {
295   IdeConfig *self = (IdeConfig *)object;
296   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
297 
298   g_assert (IDE_IS_MAIN_THREAD ());
299   g_assert (IDE_IS_CONFIG (self));
300 
301   return g_strdup_printf ("%s id=\"%s\" name=\"%s\" runtime=\"%s\"",
302                           G_OBJECT_TYPE_NAME (self),
303                           priv->id,
304                           priv->display_name,
305                           priv->runtime_id);
306 }
307 
308 static void
ide_config_finalize(GObject * object)309 ide_config_finalize (GObject *object)
310 {
311   IdeConfig *self = (IdeConfig *)object;
312   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
313 
314   g_clear_object (&priv->build_commands_dir);
315   g_clear_object (&priv->environment);
316   g_clear_object (&priv->runtime_environment);
317 
318   g_clear_pointer (&priv->build_commands, g_strfreev);
319   g_clear_pointer (&priv->internal, g_hash_table_unref);
320   g_clear_pointer (&priv->pipeline_args, g_hash_table_unref);
321   g_clear_pointer (&priv->config_opts, g_free);
322   g_clear_pointer (&priv->display_name, g_free);
323   g_clear_pointer (&priv->id, g_free);
324   g_clear_pointer (&priv->post_install_commands, g_strfreev);
325   g_clear_pointer (&priv->prefix, g_free);
326   g_clear_pointer (&priv->runtime_id, g_free);
327   g_clear_pointer (&priv->app_id, g_free);
328   g_clear_pointer (&priv->toolchain_id, g_free);
329   g_clear_pointer (&priv->prepend_path, g_free);
330   g_clear_pointer (&priv->append_path, g_free);
331 
332   G_OBJECT_CLASS (ide_config_parent_class)->finalize (object);
333 }
334 
335 static void
ide_config_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)336 ide_config_get_property (GObject    *object,
337                          guint       prop_id,
338                          GValue     *value,
339                          GParamSpec *pspec)
340 {
341   IdeConfig *self = IDE_CONFIG (object);
342 
343   switch (prop_id)
344     {
345     case PROP_CONFIG_OPTS:
346       g_value_set_string (value, ide_config_get_config_opts (self));
347       break;
348 
349     case PROP_BUILD_COMMANDS:
350       g_value_set_boxed (value, ide_config_get_build_commands (self));
351       break;
352 
353     case PROP_BUILD_COMMANDS_DIR:
354       g_value_set_object (value, ide_config_get_build_commands_dir (self));
355       break;
356 
357     case PROP_DEBUG:
358       g_value_set_boolean (value, ide_config_get_debug (self));
359       break;
360 
361     case PROP_DIRTY:
362       g_value_set_boolean (value, ide_config_get_dirty (self));
363       break;
364 
365     case PROP_DISPLAY_NAME:
366       g_value_set_string (value, ide_config_get_display_name (self));
367       break;
368 
369     case PROP_ENVIRON:
370       g_value_set_boxed (value, ide_config_get_environ (self));
371       break;
372 
373     case PROP_ID:
374       g_value_set_string (value, ide_config_get_id (self));
375       break;
376 
377     case PROP_PARALLELISM:
378       g_value_set_int (value, ide_config_get_parallelism (self));
379       break;
380 
381     case PROP_READY:
382       g_value_set_boolean (value, ide_config_get_ready (self));
383       break;
384 
385     case PROP_POST_INSTALL_COMMANDS:
386       g_value_set_boxed (value, ide_config_get_post_install_commands (self));
387       break;
388 
389     case PROP_PREFIX:
390       g_value_set_string (value, ide_config_get_prefix (self));
391       break;
392 
393     case PROP_RUNTIME:
394       g_value_set_object (value, ide_config_get_runtime (self));
395       break;
396 
397     case PROP_RUNTIME_ID:
398       g_value_set_string (value, ide_config_get_runtime_id (self));
399       break;
400 
401     case PROP_TOOLCHAIN:
402       g_value_take_object (value, ide_config_get_toolchain (self));
403       break;
404 
405     case PROP_TOOLCHAIN_ID:
406       g_value_set_string (value, ide_config_get_toolchain_id (self));
407       break;
408 
409     case PROP_RUN_OPTS:
410       g_value_set_string (value, ide_config_get_run_opts (self));
411       break;
412 
413     case PROP_APP_ID:
414       g_value_set_string (value, ide_config_get_app_id (self));
415       break;
416 
417     case PROP_PREPEND_PATH:
418       g_value_set_string (value, ide_config_get_prepend_path (self));
419       break;
420 
421     case PROP_APPEND_PATH:
422       g_value_set_string (value, ide_config_get_append_path (self));
423       break;
424 
425     case PROP_LOCALITY:
426       g_value_set_flags (value, ide_config_get_locality (self));
427       break;
428 
429     default:
430       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
431     }
432 }
433 
434 static void
ide_config_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)435 ide_config_set_property (GObject      *object,
436                          guint         prop_id,
437                          const GValue *value,
438                          GParamSpec   *pspec)
439 {
440   IdeConfig *self = IDE_CONFIG (object);
441 
442   switch (prop_id)
443     {
444     case PROP_CONFIG_OPTS:
445       ide_config_set_config_opts (self, g_value_get_string (value));
446       break;
447 
448     case PROP_BUILD_COMMANDS:
449       ide_config_set_build_commands (self, g_value_get_boxed (value));
450       break;
451 
452     case PROP_BUILD_COMMANDS_DIR:
453       ide_config_set_build_commands_dir (self, g_value_get_object (value));
454       break;
455 
456     case PROP_DEBUG:
457       ide_config_set_debug (self, g_value_get_boolean (value));
458       break;
459 
460     case PROP_DIRTY:
461       ide_config_set_dirty (self, g_value_get_boolean (value));
462       break;
463 
464     case PROP_DISPLAY_NAME:
465       ide_config_set_display_name (self, g_value_get_string (value));
466       break;
467 
468     case PROP_ID:
469       ide_config_set_id (self, g_value_get_string (value));
470       break;
471 
472     case PROP_POST_INSTALL_COMMANDS:
473       ide_config_set_post_install_commands (self, g_value_get_boxed (value));
474       break;
475 
476     case PROP_PREFIX:
477       ide_config_set_prefix (self, g_value_get_string (value));
478       break;
479 
480     case PROP_PARALLELISM:
481       ide_config_set_parallelism (self, g_value_get_int (value));
482       break;
483 
484     case PROP_RUNTIME:
485       ide_config_set_runtime (self, g_value_get_object (value));
486       break;
487 
488     case PROP_RUNTIME_ID:
489       ide_config_set_runtime_id (self, g_value_get_string (value));
490       break;
491 
492     case PROP_TOOLCHAIN:
493       ide_config_set_toolchain (self, g_value_get_object (value));
494       break;
495 
496     case PROP_TOOLCHAIN_ID:
497       ide_config_set_toolchain_id (self, g_value_get_string (value));
498       break;
499 
500     case PROP_RUN_OPTS:
501       ide_config_set_run_opts (self, g_value_get_string (value));
502       break;
503 
504     case PROP_APP_ID:
505       ide_config_set_app_id (self, g_value_get_string (value));
506       break;
507 
508     case PROP_PREPEND_PATH:
509       ide_config_set_prepend_path (self, g_value_get_string (value));
510       break;
511 
512     case PROP_APPEND_PATH:
513       ide_config_set_append_path (self, g_value_get_string (value));
514       break;
515 
516     case PROP_LOCALITY:
517       ide_config_set_locality (self, g_value_get_flags (value));
518       break;
519 
520     default:
521       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
522     }
523 }
524 
525 static void
ide_config_class_init(IdeConfigClass * klass)526 ide_config_class_init (IdeConfigClass *klass)
527 {
528   GObjectClass *object_class = G_OBJECT_CLASS (klass);
529   IdeObjectClass *i_object_class = IDE_OBJECT_CLASS (klass);
530 
531   object_class->finalize = ide_config_finalize;
532   object_class->get_property = ide_config_get_property;
533   object_class->set_property = ide_config_set_property;
534 
535   i_object_class->repr = ide_config_repr;
536 
537   klass->get_runtime = ide_config_real_get_runtime;
538   klass->set_runtime = ide_config_real_set_runtime;
539 
540   properties [PROP_PREPEND_PATH] =
541     g_param_spec_string ("prepend-path",
542                          "Prepend Path",
543                          "Prepend to PATH environment variable",
544                          NULL,
545                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
546 
547   properties [PROP_APPEND_PATH] =
548     g_param_spec_string ("append-path",
549                          "Append Path",
550                          "Append to PATH environment variable",
551                          NULL,
552                          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
553 
554   properties [PROP_BUILD_COMMANDS] =
555     g_param_spec_boxed ("build-commands",
556                         "Build commands",
557                         "Build commands",
558                         G_TYPE_STRV,
559                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
560 
561   properties [PROP_BUILD_COMMANDS_DIR] =
562     g_param_spec_object ("build-commands-dir",
563                         "Build commands Dir",
564                         "Directory to run build commands from",
565                         G_TYPE_FILE,
566                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
567 
568   properties [PROP_CONFIG_OPTS] =
569     g_param_spec_string ("config-opts",
570                          "Config Options",
571                          "Parameters to bootstrap the project",
572                          NULL,
573                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
574 
575   properties [PROP_DEBUG] =
576     g_param_spec_boolean ("debug",
577                           "Debug",
578                           "Debug",
579                           TRUE,
580                           (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
581 
582   properties [PROP_DIRTY] =
583     g_param_spec_boolean ("dirty",
584                           "Dirty",
585                           "If the configuration has been changed.",
586                           FALSE,
587                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
588 
589   properties [PROP_DISPLAY_NAME] =
590     g_param_spec_string ("display-name",
591                          "Display Name",
592                          "Display Name",
593                          NULL,
594                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
595 
596   properties [PROP_ENVIRON] =
597     g_param_spec_boxed ("environ",
598                         "Environ",
599                         "Environ",
600                         G_TYPE_STRV,
601                         (G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
602 
603   properties [PROP_ID] =
604     g_param_spec_string ("id",
605                          "Id",
606                          "Id",
607                          NULL,
608                          (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
609 
610   properties [PROP_PARALLELISM] =
611     g_param_spec_int ("parallelism",
612                       "Parallelism",
613                       "Parallelism",
614                       -1,
615                       G_MAXINT,
616                       -1,
617                       (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
618 
619   properties [PROP_POST_INSTALL_COMMANDS] =
620     g_param_spec_boxed ("post-install-commands",
621                         "Post install commands",
622                         "Post install commands",
623                         G_TYPE_STRV,
624                         (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
625 
626   properties [PROP_PREFIX] =
627     g_param_spec_string ("prefix",
628                          "Prefix",
629                          "Prefix",
630                          NULL,
631                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
632 
633   properties [PROP_PREFIX_SET] =
634     g_param_spec_boolean ("prefix-set",
635                           "Prefix Set",
636                           "If Prefix is Set or not (meaning default)",
637                           FALSE,
638                           (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
639 
640   properties [PROP_READY] =
641     g_param_spec_boolean ("ready",
642                           "Ready",
643                           "If the configuration can be used for building",
644                           FALSE,
645                           (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
646 
647   properties [PROP_RUN_OPTS] =
648     g_param_spec_string ("run-opts",
649                          "Run Options",
650                          "The options for running the target application",
651                          NULL,
652                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
653 
654   properties [PROP_RUNTIME] =
655     g_param_spec_object ("runtime",
656                          "Runtime",
657                          "Runtime",
658                          IDE_TYPE_RUNTIME,
659                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
660 
661   properties [PROP_RUNTIME_ID] =
662     g_param_spec_string ("runtime-id",
663                          "Runtime Id",
664                          "The identifier of the runtime",
665                          "host",
666                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
667 
668   properties [PROP_TOOLCHAIN] =
669     g_param_spec_object ("toolchain",
670                          "Toolchain",
671                          "Toolchain",
672                          IDE_TYPE_TOOLCHAIN,
673                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
674 
675   properties [PROP_TOOLCHAIN_ID] =
676     g_param_spec_string ("toolchain-id",
677                          "Toolchain Id",
678                          "The identifier of the toolchain",
679                          "default",
680                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
681 
682   properties [PROP_APP_ID] =
683     g_param_spec_string ("app-id",
684                          "App ID",
685                          "The application ID (such as org.gnome.Builder)",
686                          NULL,
687                          (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS));
688 
689   properties [PROP_LOCALITY] =
690     g_param_spec_flags ("locality",
691                         "Locality",
692                         "Where the build may occur",
693                         IDE_TYPE_BUILD_LOCALITY,
694                         IDE_BUILD_LOCALITY_DEFAULT,
695                         G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
696 
697   g_object_class_install_properties (object_class, N_PROPS, properties);
698 
699   signals [CHANGED] =
700     g_signal_new ("changed",
701                   G_TYPE_FROM_CLASS (klass),
702                   G_SIGNAL_RUN_LAST,
703                   0, NULL, NULL, NULL, G_TYPE_NONE, 0);
704 }
705 
706 static void
ide_config_init(IdeConfig * self)707 ide_config_init (IdeConfig *self)
708 {
709   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
710   g_autoptr(IdeEnvironment) env = ide_environment_new ();
711   g_autoptr(IdeEnvironment) rt_env = ide_environment_new ();
712 
713   priv->runtime_id = g_strdup ("host");
714   priv->toolchain_id = g_strdup ("default");
715   priv->debug = TRUE;
716   priv->parallelism = -1;
717   priv->locality = IDE_BUILD_LOCALITY_DEFAULT;
718   priv->internal = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, _value_free);
719   priv->pipeline_args = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_strfreev);
720 
721   ide_config_set_environment (self, env);
722   ide_config_set_runtime_environment (self, rt_env);
723 }
724 
725 /**
726  * ide_config_get_app_id:
727  * @self: An #IdeConfig
728  *
729  * Gets the application ID for the configuration.
730  *
731  * Returns: (transfer none) (nullable): A string.
732  *
733  * Since: 3.32
734  */
735 const gchar *
ide_config_get_app_id(IdeConfig * self)736 ide_config_get_app_id (IdeConfig *self)
737 {
738   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
739 
740   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
741 
742   return priv->app_id;
743 }
744 
745 void
ide_config_set_app_id(IdeConfig * self,const gchar * app_id)746 ide_config_set_app_id (IdeConfig   *self,
747                        const gchar *app_id)
748 {
749   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
750 
751   g_return_if_fail (IDE_IS_CONFIG (self));
752 
753   if (priv->app_id != app_id)
754     {
755       g_free (priv->app_id);
756       priv->app_id = g_strdup (app_id);
757       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_APP_ID]);
758     }
759 }
760 
761 const gchar *
ide_config_get_runtime_id(IdeConfig * self)762 ide_config_get_runtime_id (IdeConfig *self)
763 {
764   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
765 
766   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
767 
768   return priv->runtime_id;
769 }
770 
771 void
ide_config_set_runtime_id(IdeConfig * self,const gchar * runtime_id)772 ide_config_set_runtime_id (IdeConfig   *self,
773                            const gchar *runtime_id)
774 {
775   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
776 
777   g_return_if_fail (IDE_IS_CONFIG (self));
778 
779   if (runtime_id == NULL)
780     runtime_id = "host";
781 
782   if (g_strcmp0 (runtime_id, priv->runtime_id) != 0)
783     {
784       priv->runtime_ready = FALSE;
785       g_free (priv->runtime_id);
786       priv->runtime_id = g_strdup (runtime_id);
787 
788       ide_config_set_dirty (self, TRUE);
789 
790       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNTIME_ID]);
791       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUNTIME]);
792 
793       if (priv->has_attached)
794         {
795           IdeRuntimeManager *runtime_manager;
796           IdeContext *context;
797 
798           g_assert (IDE_IS_MAIN_THREAD ());
799 
800           context = ide_object_get_context (IDE_OBJECT (self));
801           runtime_manager = ide_runtime_manager_from_context (context);
802           ide_config_runtime_manager_items_changed (self, 0, 0, 0, runtime_manager);
803 
804           ide_config_emit_changed (self);
805         }
806     }
807 }
808 
809 /**
810  * ide_config_get_toolchain_id:
811  * @self: An #IdeConfig
812  *
813  * Gets the toolchain id for the configuration.
814  *
815  * Returns: (transfer none) (nullable): The id of an #IdeToolchain or %NULL
816  *
817  * Since: 3.32
818  */
819 const gchar *
ide_config_get_toolchain_id(IdeConfig * self)820 ide_config_get_toolchain_id (IdeConfig *self)
821 {
822   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
823 
824   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
825 
826   return priv->toolchain_id;
827 }
828 
829 /**
830  * ide_config_set_toolchain_id:
831  * @self: An #IdeConfig
832  * @toolchain_id: The id of an #IdeToolchain
833  *
834  * Sets the toolchain id for the configuration.
835  *
836  * Since: 3.32
837  */
838 void
ide_config_set_toolchain_id(IdeConfig * self,const gchar * toolchain_id)839 ide_config_set_toolchain_id (IdeConfig   *self,
840                              const gchar *toolchain_id)
841 {
842   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
843 
844   g_return_if_fail (IDE_IS_CONFIG (self));
845 
846   if (toolchain_id == NULL)
847     toolchain_id = "default";
848 
849   if (g_strcmp0 (toolchain_id, priv->toolchain_id) != 0)
850     {
851       g_free (priv->toolchain_id);
852       priv->toolchain_id = g_strdup (toolchain_id);
853 
854       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TOOLCHAIN_ID]);
855       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_TOOLCHAIN]);
856 
857       ide_config_set_dirty (self, TRUE);
858       ide_config_emit_changed (self);
859     }
860 }
861 
862 /**
863  * ide_config_get_runtime:
864  * @self: An #IdeConfig
865  *
866  * Gets the runtime for the configuration.
867  *
868  * Returns: (transfer none) (nullable): An #IdeRuntime
869  *
870  * Since: 3.32
871  */
872 IdeRuntime *
ide_config_get_runtime(IdeConfig * self)873 ide_config_get_runtime (IdeConfig *self)
874 {
875   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
876 
877   return IDE_CONFIG_GET_CLASS (self)->get_runtime (self);
878 }
879 
880 void
ide_config_set_runtime(IdeConfig * self,IdeRuntime * runtime)881 ide_config_set_runtime (IdeConfig  *self,
882                         IdeRuntime *runtime)
883 {
884   g_return_if_fail (IDE_IS_CONFIG (self));
885   g_return_if_fail (!runtime || IDE_IS_RUNTIME (runtime));
886 
887   IDE_CONFIG_GET_CLASS (self)->set_runtime (self, runtime);
888 }
889 
890 /**
891  * ide_config_get_toolchain:
892  * @self: An #IdeConfig
893  *
894  * Gets the toolchain for the configuration.
895  *
896  * Returns: (transfer full) (nullable): An #IdeToolchain
897  *
898  * Since: 3.32
899  */
900 IdeToolchain *
ide_config_get_toolchain(IdeConfig * self)901 ide_config_get_toolchain (IdeConfig *self)
902 {
903   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
904 
905   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
906 
907   if (priv->toolchain_id != NULL)
908     {
909       IdeContext *context = ide_object_get_context (IDE_OBJECT (self));
910       IdeToolchainManager *toolchain_manager = ide_toolchain_manager_from_context (context);
911       g_autoptr (IdeToolchain) toolchain = ide_toolchain_manager_get_toolchain (toolchain_manager, priv->toolchain_id);
912 
913       if (toolchain != NULL)
914         return g_steal_pointer (&toolchain);
915     }
916 
917   return NULL;
918 }
919 
920 /**
921  * ide_config_set_toolchain:
922  * @self: An #IdeConfig
923  * @toolchain: (nullable): An #IdeToolchain or %NULL to use the default one
924  *
925  * Sets the toolchain for the configuration.
926  *
927  * Since: 3.32
928  */
929 void
ide_config_set_toolchain(IdeConfig * self,IdeToolchain * toolchain)930 ide_config_set_toolchain (IdeConfig    *self,
931                           IdeToolchain *toolchain)
932 {
933   const gchar *toolchain_id = "default";
934 
935   g_return_if_fail (IDE_IS_CONFIG (self));
936   g_return_if_fail (!toolchain || IDE_IS_TOOLCHAIN (toolchain));
937 
938   if (toolchain != NULL)
939     toolchain_id = ide_toolchain_get_id (toolchain);
940 
941   ide_config_set_toolchain_id (self, toolchain_id);
942 }
943 
944 /**
945  * ide_config_get_environ:
946  * @self: An #IdeConfig
947  *
948  * Gets the environment to use when spawning processes.
949  *
950  * Returns: (transfer full): An array of key=value environment variables.
951  *
952  * Since: 3.32
953  */
954 gchar **
ide_config_get_environ(IdeConfig * self)955 ide_config_get_environ (IdeConfig *self)
956 {
957   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
958 
959   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
960 
961   return ide_environment_get_environ (priv->environment);
962 }
963 
964 const gchar *
ide_config_getenv(IdeConfig * self,const gchar * key)965 ide_config_getenv (IdeConfig   *self,
966                    const gchar *key)
967 {
968   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
969 
970   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
971   g_return_val_if_fail (key != NULL, NULL);
972 
973   return ide_environment_getenv (priv->environment, key);
974 }
975 
976 void
ide_config_setenv(IdeConfig * self,const gchar * key,const gchar * value)977 ide_config_setenv (IdeConfig   *self,
978                    const gchar *key,
979                    const gchar *value)
980 {
981   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
982 
983   g_return_if_fail (IDE_IS_CONFIG (self));
984   g_return_if_fail (key != NULL);
985 
986   ide_environment_setenv (priv->environment, key, value);
987 }
988 
989 const gchar *
ide_config_get_id(IdeConfig * self)990 ide_config_get_id (IdeConfig *self)
991 {
992   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
993 
994   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
995 
996   return priv->id;
997 }
998 
999 const gchar *
ide_config_get_prefix(IdeConfig * self)1000 ide_config_get_prefix (IdeConfig *self)
1001 {
1002   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1003 
1004   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1005 
1006   return priv->prefix;
1007 }
1008 
1009 void
ide_config_set_prefix(IdeConfig * self,const gchar * prefix)1010 ide_config_set_prefix (IdeConfig   *self,
1011                        const gchar *prefix)
1012 {
1013   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1014 
1015   g_return_if_fail (IDE_IS_CONFIG (self));
1016 
1017   if (g_strcmp0 (prefix, priv->prefix) != 0)
1018     {
1019       g_free (priv->prefix);
1020       priv->prefix = g_strdup (prefix);
1021       priv->prefix_set = TRUE;
1022       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PREFIX]);
1023       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PREFIX_SET]);
1024       ide_config_set_dirty (self, TRUE);
1025     }
1026 }
1027 
1028 gint
ide_config_get_parallelism(IdeConfig * self)1029 ide_config_get_parallelism (IdeConfig *self)
1030 {
1031   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1032 
1033   g_return_val_if_fail (IDE_IS_CONFIG (self), -1);
1034 
1035   if (priv->parallelism == -1)
1036     {
1037       g_autoptr(GSettings) settings = g_settings_new ("org.gnome.builder.build");
1038 
1039       return g_settings_get_int (settings, "parallel");
1040     }
1041 
1042   return priv->parallelism;
1043 }
1044 
1045 void
ide_config_set_parallelism(IdeConfig * self,gint parallelism)1046 ide_config_set_parallelism (IdeConfig *self,
1047                             gint       parallelism)
1048 {
1049   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1050 
1051   g_return_if_fail (IDE_IS_CONFIG (self));
1052   g_return_if_fail (parallelism >= -1);
1053 
1054   if (parallelism != priv->parallelism)
1055     {
1056       priv->parallelism = parallelism;
1057       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PARALLELISM]);
1058     }
1059 }
1060 
1061 gboolean
ide_config_get_debug(IdeConfig * self)1062 ide_config_get_debug (IdeConfig *self)
1063 {
1064   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1065 
1066   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1067 
1068   return priv->debug;
1069 }
1070 
1071 void
ide_config_set_debug(IdeConfig * self,gboolean debug)1072 ide_config_set_debug (IdeConfig *self,
1073                       gboolean   debug)
1074 {
1075   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1076 
1077   g_return_if_fail (IDE_IS_CONFIG (self));
1078 
1079   debug = !!debug;
1080 
1081   if (debug != priv->debug)
1082     {
1083       priv->debug = debug;
1084       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DEBUG]);
1085       ide_config_set_dirty (self, TRUE);
1086     }
1087 }
1088 
1089 const gchar *
ide_config_get_display_name(IdeConfig * self)1090 ide_config_get_display_name (IdeConfig *self)
1091 {
1092   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1093 
1094   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1095 
1096   return priv->display_name;
1097 }
1098 
1099 void
ide_config_set_display_name(IdeConfig * self,const gchar * display_name)1100 ide_config_set_display_name (IdeConfig   *self,
1101                              const gchar *display_name)
1102 {
1103   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1104 
1105   g_return_if_fail (IDE_IS_CONFIG (self));
1106 
1107   if (g_strcmp0 (display_name, priv->display_name) != 0)
1108     {
1109       g_free (priv->display_name);
1110       priv->display_name = g_strdup (display_name);
1111       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DISPLAY_NAME]);
1112       ide_config_emit_changed (self);
1113     }
1114 }
1115 
1116 gboolean
ide_config_get_dirty(IdeConfig * self)1117 ide_config_get_dirty (IdeConfig *self)
1118 {
1119   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1120 
1121   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1122 
1123   return priv->dirty;
1124 }
1125 
1126 void
ide_config_set_dirty(IdeConfig * self,gboolean dirty)1127 ide_config_set_dirty (IdeConfig *self,
1128                       gboolean   dirty)
1129 {
1130   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1131 
1132   IDE_ENTRY;
1133 
1134   g_return_if_fail (IDE_IS_CONFIG (self));
1135 
1136   if (priv->block_changed)
1137     IDE_EXIT;
1138 
1139   dirty = !!dirty;
1140 
1141   if (dirty != priv->dirty)
1142     {
1143       priv->dirty = dirty;
1144       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DIRTY]);
1145     }
1146 
1147   if (dirty)
1148     {
1149       /*
1150        * Emit the changed signal so that the configuration manager
1151        * can queue a writeback of the configuration. If we are
1152        * clearing the dirty bit, then we don't need to do this.
1153        */
1154       priv->sequence++;
1155       IDE_TRACE_MSG ("configuration set dirty with sequence %u", priv->sequence);
1156       ide_config_emit_changed (self);
1157     }
1158 
1159   IDE_EXIT;
1160 }
1161 
1162 /**
1163  * ide_config_get_environment:
1164  *
1165  * Returns: (transfer none): An #IdeEnvironment.
1166  *
1167  * Since: 3.32
1168  */
1169 IdeEnvironment *
ide_config_get_environment(IdeConfig * self)1170 ide_config_get_environment (IdeConfig *self)
1171 {
1172   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1173 
1174   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1175 
1176   return priv->environment;
1177 }
1178 
1179 void
ide_config_set_environment(IdeConfig * self,IdeEnvironment * environment)1180 ide_config_set_environment (IdeConfig      *self,
1181                             IdeEnvironment *environment)
1182 {
1183   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1184 
1185   g_return_if_fail (IDE_IS_CONFIG (self));
1186   g_return_if_fail (!environment || IDE_IS_ENVIRONMENT (environment));
1187 
1188   if (priv->environment != environment)
1189     {
1190       if (priv->environment != NULL)
1191         {
1192           g_signal_handlers_disconnect_by_func (priv->environment,
1193                                                 G_CALLBACK (ide_config_environment_changed),
1194                                                 self);
1195           g_clear_object (&priv->environment);
1196         }
1197 
1198       if (environment != NULL)
1199         {
1200           priv->environment = g_object_ref (environment);
1201           g_signal_connect_object (priv->environment,
1202                                    "changed",
1203                                    G_CALLBACK (ide_config_environment_changed),
1204                                    self,
1205                                    G_CONNECT_SWAPPED);
1206         }
1207 
1208       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ENVIRON]);
1209     }
1210 }
1211 
1212 /**
1213  * ide_config_get_runtime_environment:
1214  *
1215  * Returns: (transfer none): An #IdeEnvironment.
1216  *
1217  * Since: 3.40
1218  */
1219 IdeEnvironment *
ide_config_get_runtime_environment(IdeConfig * self)1220 ide_config_get_runtime_environment (IdeConfig *self)
1221 {
1222   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1223 
1224   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1225 
1226   return priv->runtime_environment;
1227 }
1228 
1229 void
ide_config_set_runtime_environment(IdeConfig * self,IdeEnvironment * environment)1230 ide_config_set_runtime_environment (IdeConfig      *self,
1231                                     IdeEnvironment *environment)
1232 {
1233   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1234 
1235   g_return_if_fail (IDE_IS_CONFIG (self));
1236   g_return_if_fail (!environment || IDE_IS_ENVIRONMENT (environment));
1237 
1238   if (priv->runtime_environment != environment)
1239     {
1240       if (priv->runtime_environment != NULL)
1241         {
1242           g_signal_handlers_disconnect_by_func (priv->runtime_environment,
1243                                                 G_CALLBACK (ide_config_runtime_environment_changed),
1244                                                 self);
1245           g_clear_object (&priv->runtime_environment);
1246         }
1247 
1248       if (environment != NULL)
1249         {
1250           priv->runtime_environment = g_object_ref (environment);
1251           g_signal_connect_object (priv->runtime_environment,
1252                                    "changed",
1253                                    G_CALLBACK (ide_config_runtime_environment_changed),
1254                                    self,
1255                                    G_CONNECT_SWAPPED);
1256         }
1257     }
1258 }
1259 
1260 const gchar *
ide_config_get_config_opts(IdeConfig * self)1261 ide_config_get_config_opts (IdeConfig *self)
1262 {
1263   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1264 
1265   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1266 
1267   return priv->config_opts;
1268 }
1269 
1270 void
ide_config_set_config_opts(IdeConfig * self,const gchar * config_opts)1271 ide_config_set_config_opts (IdeConfig   *self,
1272                             const gchar *config_opts)
1273 {
1274   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1275 
1276   g_return_if_fail (IDE_IS_CONFIG (self));
1277 
1278   if (g_strcmp0 (config_opts, priv->config_opts) != 0)
1279     {
1280       g_free (priv->config_opts);
1281       priv->config_opts = g_strdup (config_opts);
1282       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CONFIG_OPTS]);
1283       ide_config_set_dirty (self, TRUE);
1284     }
1285 }
1286 
1287 const gchar * const *
ide_config_get_build_commands(IdeConfig * self)1288 ide_config_get_build_commands (IdeConfig *self)
1289 {
1290   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1291 
1292   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1293 
1294   return (const gchar * const *)priv->build_commands;
1295 }
1296 
1297 void
ide_config_set_build_commands(IdeConfig * self,const gchar * const * build_commands)1298 ide_config_set_build_commands (IdeConfig           *self,
1299                                const gchar * const *build_commands)
1300 {
1301   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1302 
1303   g_return_if_fail (IDE_IS_CONFIG (self));
1304 
1305   if (priv->build_commands != (gchar **)build_commands)
1306     {
1307       g_strfreev (priv->build_commands);
1308       priv->build_commands = g_strdupv ((gchar **)build_commands);
1309       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_COMMANDS]);
1310     }
1311 }
1312 
1313 const gchar * const *
ide_config_get_post_install_commands(IdeConfig * self)1314 ide_config_get_post_install_commands (IdeConfig *self)
1315 {
1316   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1317 
1318   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1319 
1320   return (const gchar * const *)priv->post_install_commands;
1321 }
1322 
1323 void
ide_config_set_post_install_commands(IdeConfig * self,const gchar * const * post_install_commands)1324 ide_config_set_post_install_commands (IdeConfig           *self,
1325                                       const gchar * const *post_install_commands)
1326 {
1327   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1328 
1329   g_return_if_fail (IDE_IS_CONFIG (self));
1330 
1331   if (priv->post_install_commands != (gchar **)post_install_commands)
1332     {
1333       g_strfreev (priv->post_install_commands);
1334       priv->post_install_commands = g_strdupv ((gchar **)post_install_commands);
1335       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_POST_INSTALL_COMMANDS]);
1336     }
1337 }
1338 
1339 /**
1340  * ide_config_get_sequence:
1341  * @self: An #IdeConfig
1342  *
1343  * This returns a sequence number for the configuration. This is useful
1344  * for build systems that want to clear the "dirty" bit on the configuration
1345  * so that they need not bootstrap a second time. This should be done by
1346  * checking the sequence number before executing the bootstrap, and only
1347  * cleared if the sequence number matches after performing the bootstrap.
1348  * This indicates no changes have been made to the configuration in the
1349  * mean time.
1350  *
1351  * Returns: A monotonic sequence number.
1352  *
1353  * Since: 3.32
1354  */
1355 guint
ide_config_get_sequence(IdeConfig * self)1356 ide_config_get_sequence (IdeConfig *self)
1357 {
1358   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1359 
1360   g_return_val_if_fail (IDE_IS_CONFIG (self), 0);
1361 
1362   return priv->sequence;
1363 }
1364 
1365 static GValue *
ide_config_reset_internal_value(IdeConfig * self,const gchar * key,GType type)1366 ide_config_reset_internal_value (IdeConfig   *self,
1367                                  const gchar *key,
1368                                  GType        type)
1369 {
1370   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1371   GValue *v;
1372 
1373   g_assert (IDE_IS_CONFIG (self));
1374   g_assert (key != NULL);
1375   g_assert (type != G_TYPE_INVALID);
1376 
1377   v = g_hash_table_lookup (priv->internal, key);
1378 
1379   if (v == NULL)
1380     {
1381       v = _value_new (type);
1382       g_hash_table_insert (priv->internal, g_strdup (key), v);
1383     }
1384   else
1385     {
1386       g_value_unset (v);
1387       g_value_init (v, type);
1388     }
1389 
1390   return v;
1391 }
1392 
1393 const gchar *
ide_config_get_internal_string(IdeConfig * self,const gchar * key)1394 ide_config_get_internal_string (IdeConfig   *self,
1395                                 const gchar *key)
1396 {
1397   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1398   const GValue *v;
1399 
1400   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1401   g_return_val_if_fail (key != NULL, NULL);
1402 
1403   v = g_hash_table_lookup (priv->internal, key);
1404 
1405   if (v != NULL && G_VALUE_HOLDS_STRING (v))
1406     return g_value_get_string (v);
1407 
1408   return NULL;
1409 }
1410 
1411 void
ide_config_set_internal_string(IdeConfig * self,const gchar * key,const gchar * value)1412 ide_config_set_internal_string (IdeConfig   *self,
1413                                 const gchar *key,
1414                                 const gchar *value)
1415 {
1416   GValue *v;
1417 
1418   g_return_if_fail (IDE_IS_CONFIG (self));
1419   g_return_if_fail (key != NULL);
1420 
1421   v = ide_config_reset_internal_value (self, key, G_TYPE_STRING);
1422   g_value_set_string (v, value);
1423 }
1424 
1425 const gchar * const *
ide_config_get_internal_strv(IdeConfig * self,const gchar * key)1426 ide_config_get_internal_strv (IdeConfig   *self,
1427                               const gchar *key)
1428 {
1429   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1430   const GValue *v;
1431 
1432   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1433   g_return_val_if_fail (key != NULL, NULL);
1434 
1435   v = g_hash_table_lookup (priv->internal, key);
1436 
1437   if (v != NULL && G_VALUE_HOLDS (v, G_TYPE_STRV))
1438     return g_value_get_boxed (v);
1439 
1440   return NULL;
1441 }
1442 
1443 void
ide_config_set_internal_strv(IdeConfig * self,const gchar * key,const gchar * const * value)1444 ide_config_set_internal_strv (IdeConfig           *self,
1445                               const gchar         *key,
1446                               const gchar * const *value)
1447 {
1448   GValue *v;
1449 
1450   g_return_if_fail (IDE_IS_CONFIG (self));
1451   g_return_if_fail (key != NULL);
1452 
1453   v = ide_config_reset_internal_value (self, key, G_TYPE_STRV);
1454   g_value_set_boxed (v, value);
1455 }
1456 
1457 gboolean
ide_config_get_internal_boolean(IdeConfig * self,const gchar * key)1458 ide_config_get_internal_boolean (IdeConfig   *self,
1459                                  const gchar *key)
1460 {
1461   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1462   const GValue *v;
1463 
1464   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1465   g_return_val_if_fail (key != NULL, FALSE);
1466 
1467   v = g_hash_table_lookup (priv->internal, key);
1468 
1469   if (v != NULL && G_VALUE_HOLDS_BOOLEAN (v))
1470     return g_value_get_boolean (v);
1471 
1472   return FALSE;
1473 }
1474 
1475 void
ide_config_set_internal_boolean(IdeConfig * self,const gchar * key,gboolean value)1476 ide_config_set_internal_boolean (IdeConfig   *self,
1477                                  const gchar *key,
1478                                  gboolean     value)
1479 {
1480   GValue *v;
1481 
1482   g_return_if_fail (IDE_IS_CONFIG (self));
1483   g_return_if_fail (key != NULL);
1484 
1485   v = ide_config_reset_internal_value (self, key, G_TYPE_BOOLEAN);
1486   g_value_set_boolean (v, value);
1487 }
1488 
1489 gint
ide_config_get_internal_int(IdeConfig * self,const gchar * key)1490 ide_config_get_internal_int (IdeConfig   *self,
1491                              const gchar *key)
1492 {
1493   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1494   const GValue *v;
1495 
1496   g_return_val_if_fail (IDE_IS_CONFIG (self), -1);
1497   g_return_val_if_fail (key != NULL, -1);
1498 
1499   v = g_hash_table_lookup (priv->internal, key);
1500 
1501   if (v != NULL && G_VALUE_HOLDS_INT (v))
1502     return g_value_get_int (v);
1503 
1504   return 0;
1505 }
1506 
1507 void
ide_config_set_internal_int(IdeConfig * self,const gchar * key,gint value)1508 ide_config_set_internal_int (IdeConfig   *self,
1509                              const gchar *key,
1510                              gint         value)
1511 {
1512   GValue *v;
1513 
1514   g_return_if_fail (IDE_IS_CONFIG (self));
1515   g_return_if_fail (key != NULL);
1516 
1517   v = ide_config_reset_internal_value (self, key, G_TYPE_INT);
1518   g_value_set_int (v, value);
1519 }
1520 
1521 gint64
ide_config_get_internal_int64(IdeConfig * self,const gchar * key)1522 ide_config_get_internal_int64 (IdeConfig *self,
1523                                       const gchar      *key)
1524 {
1525   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1526   const GValue *v;
1527 
1528   g_return_val_if_fail (IDE_IS_CONFIG (self), -1);
1529   g_return_val_if_fail (key != NULL, -1);
1530 
1531   v = g_hash_table_lookup (priv->internal, key);
1532 
1533   if (v != NULL && G_VALUE_HOLDS_INT64 (v))
1534     return g_value_get_int64 (v);
1535 
1536   return 0;
1537 }
1538 
1539 void
ide_config_set_internal_int64(IdeConfig * self,const gchar * key,gint64 value)1540 ide_config_set_internal_int64 (IdeConfig   *self,
1541                                const gchar *key,
1542                                gint64       value)
1543 {
1544   GValue *v;
1545 
1546   g_return_if_fail (IDE_IS_CONFIG (self));
1547   g_return_if_fail (key != NULL);
1548 
1549   v = ide_config_reset_internal_value (self, key, G_TYPE_INT64);
1550   g_value_set_int64 (v, value);
1551 }
1552 
1553 /**
1554  * ide_config_get_internal_object:
1555  * @self: An #IdeConfig
1556  * @key: The key to get
1557  *
1558  * Gets the value associated with @key if it is a #GObject.
1559  *
1560  * Returns: (nullable) (transfer none) (type GObject.Object): a #GObject or %NULL.
1561  *
1562  * Since: 3.32
1563  */
1564 gpointer
ide_config_get_internal_object(IdeConfig * self,const gchar * key)1565 ide_config_get_internal_object (IdeConfig   *self,
1566                                 const gchar *key)
1567 {
1568   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1569   const GValue *v;
1570 
1571   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1572   g_return_val_if_fail (key != NULL, NULL);
1573 
1574   v = g_hash_table_lookup (priv->internal, key);
1575 
1576   if (v != NULL && G_VALUE_HOLDS_OBJECT (v))
1577     return g_value_get_object (v);
1578 
1579   return NULL;
1580 }
1581 
1582 /**
1583  * ide_config_set_internal_object:
1584  * @self: an #IdeConfig
1585  * @key: the key to set
1586  * @instance: (type GObject.Object) (nullable): a #GObject or %NULL
1587  *
1588  * Sets the value for @key to @instance.
1589  *
1590  * Since: 3.32
1591  */
1592 void
ide_config_set_internal_object(IdeConfig * self,const gchar * key,gpointer instance)1593 ide_config_set_internal_object (IdeConfig   *self,
1594                                 const gchar *key,
1595                                 gpointer     instance)
1596 {
1597   GValue *v;
1598   GType type;
1599 
1600   g_return_if_fail (IDE_IS_CONFIG (self));
1601   g_return_if_fail (key != NULL);
1602 
1603   if (instance != NULL)
1604     type = G_OBJECT_TYPE (instance);
1605   else
1606     type = G_TYPE_OBJECT;
1607 
1608   v = ide_config_reset_internal_value (self, key, type);
1609   g_value_set_object (v, instance);
1610 }
1611 
1612 /**
1613  * ide_config_get_ready:
1614  * @self: An #IdeConfig
1615  *
1616  * Determines if the configuration is ready for use.
1617  *
1618  * Returns: %TRUE if the configuration is ready for use.
1619  *
1620  * Since: 3.32
1621  */
1622 gboolean
ide_config_get_ready(IdeConfig * self)1623 ide_config_get_ready (IdeConfig *self)
1624 {
1625   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1626 
1627   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1628 
1629   return priv->runtime_ready;
1630 }
1631 
1632 gboolean
ide_config_supports_runtime(IdeConfig * self,IdeRuntime * runtime)1633 ide_config_supports_runtime (IdeConfig  *self,
1634                              IdeRuntime *runtime)
1635 {
1636   gboolean ret = TRUE;
1637 
1638   IDE_ENTRY;
1639 
1640   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1641   g_return_val_if_fail (IDE_IS_RUNTIME (runtime), FALSE);
1642 
1643   if (IDE_CONFIG_GET_CLASS (self)->supports_runtime)
1644     ret = IDE_CONFIG_GET_CLASS (self)->supports_runtime (self, runtime);
1645 
1646   IDE_RETURN (ret);
1647 }
1648 
1649 /**
1650  * ide_config_get_run_opts:
1651  * @self: a #IdeConfig
1652  *
1653  * Gets the command line options to use when running the target application.
1654  * The result should be parsed with g_shell_parse_argv() to convert the run
1655  * options to an array suitable for use in argv.
1656  *
1657  * Returns: (transfer none) (nullable): A string containing the run options
1658  *   or %NULL if none have been set.
1659  *
1660  * Since: 3.32
1661  */
1662 const gchar *
ide_config_get_run_opts(IdeConfig * self)1663 ide_config_get_run_opts (IdeConfig *self)
1664 {
1665   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1666 
1667   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1668 
1669   return priv->run_opts;
1670 }
1671 
1672 /**
1673  * ide_config_set_run_opts:
1674  * @self: a #IdeConfig
1675  * @run_opts: (nullable): the run options for the target application
1676  *
1677  * Sets the run options to use when running the target application.
1678  * See ide_config_get_run_opts() for more information.
1679  *
1680  * Since: 3.32
1681  */
1682 void
ide_config_set_run_opts(IdeConfig * self,const gchar * run_opts)1683 ide_config_set_run_opts (IdeConfig   *self,
1684                          const gchar *run_opts)
1685 {
1686   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1687 
1688   g_return_if_fail (IDE_IS_CONFIG (self));
1689 
1690   if (g_strcmp0 (run_opts, priv->run_opts) != 0)
1691     {
1692       g_free (priv->run_opts);
1693       priv->run_opts = g_strdup (run_opts);
1694       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_RUN_OPTS]);
1695     }
1696 }
1697 
1698 const gchar *
ide_config_get_prepend_path(IdeConfig * self)1699 ide_config_get_prepend_path (IdeConfig *self)
1700 {
1701   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1702 
1703   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1704 
1705   return priv->prepend_path;
1706 }
1707 
1708 void
ide_config_set_prepend_path(IdeConfig * self,const gchar * prepend_path)1709 ide_config_set_prepend_path (IdeConfig   *self,
1710                              const gchar *prepend_path)
1711 {
1712   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1713 
1714   g_return_if_fail (IDE_IS_CONFIG (self));
1715 
1716   if (g_strcmp0 (priv->prepend_path, prepend_path) != 0)
1717     {
1718       g_free (priv->prepend_path);
1719       priv->prepend_path = g_strdup (prepend_path);
1720       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PREPEND_PATH]);
1721     }
1722 }
1723 
1724 const gchar *
ide_config_get_append_path(IdeConfig * self)1725 ide_config_get_append_path (IdeConfig *self)
1726 {
1727   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1728 
1729   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1730 
1731   return priv->append_path;
1732 }
1733 
1734 void
ide_config_set_append_path(IdeConfig * self,const gchar * append_path)1735 ide_config_set_append_path (IdeConfig   *self,
1736                             const gchar *append_path)
1737 {
1738   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1739 
1740   g_return_if_fail (IDE_IS_CONFIG (self));
1741 
1742   if (g_strcmp0 (priv->append_path, append_path) != 0)
1743     {
1744       g_free (priv->append_path);
1745       priv->append_path = g_strdup (append_path);
1746       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_APPEND_PATH]);
1747     }
1748 }
1749 
1750 void
ide_config_apply_path(IdeConfig * self,IdeSubprocessLauncher * launcher)1751 ide_config_apply_path (IdeConfig             *self,
1752                        IdeSubprocessLauncher *launcher)
1753 {
1754   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1755 
1756   g_return_if_fail (IDE_IS_CONFIG (self));
1757   g_return_if_fail (IDE_IS_SUBPROCESS_LAUNCHER (launcher));
1758 
1759   if (priv->prepend_path != NULL)
1760     ide_subprocess_launcher_prepend_path (launcher, priv->prepend_path);
1761 
1762   if (priv->append_path != NULL)
1763     ide_subprocess_launcher_append_path (launcher, priv->append_path);
1764 }
1765 
1766 IdeBuildLocality
ide_config_get_locality(IdeConfig * self)1767 ide_config_get_locality (IdeConfig *self)
1768 {
1769   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1770 
1771   g_return_val_if_fail (IDE_IS_CONFIG (self), 0);
1772 
1773   return priv->locality;
1774 }
1775 
1776 void
ide_config_set_locality(IdeConfig * self,IdeBuildLocality locality)1777 ide_config_set_locality (IdeConfig        *self,
1778                          IdeBuildLocality  locality)
1779 {
1780   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1781 
1782   g_return_if_fail (IDE_IS_CONFIG (self));
1783   g_return_if_fail (locality > 0);
1784   g_return_if_fail (locality <= IDE_BUILD_LOCALITY_DEFAULT);
1785 
1786   if (priv->locality != locality)
1787     {
1788       priv->locality = locality;
1789       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LOCALITY]);
1790     }
1791 }
1792 
1793 /**
1794  * ide_config_get_build_commands_dir:
1795  * @self: a #IdeConfig
1796  *
1797  * Returns: (transfer none) (nullable): a #GFile or %NULL
1798  *
1799  * Since: 3.32
1800  */
1801 GFile *
ide_config_get_build_commands_dir(IdeConfig * self)1802 ide_config_get_build_commands_dir (IdeConfig *self)
1803 {
1804   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1805 
1806   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1807 
1808   return priv->build_commands_dir;
1809 }
1810 
1811 void
ide_config_set_build_commands_dir(IdeConfig * self,GFile * build_commands_dir)1812 ide_config_set_build_commands_dir (IdeConfig *self,
1813                                    GFile     *build_commands_dir)
1814 {
1815   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1816 
1817   g_return_if_fail (IDE_IS_CONFIG (self));
1818   g_return_if_fail (!build_commands_dir || G_IS_FILE (build_commands_dir));
1819 
1820   if (g_set_object (&priv->build_commands_dir, build_commands_dir))
1821     g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_BUILD_COMMANDS_DIR]);
1822 }
1823 
1824 void
_ide_config_attach(IdeConfig * self)1825 _ide_config_attach (IdeConfig *self)
1826 {
1827   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1828   IdeRuntimeManager *runtime_manager;
1829   IdeContext *context;
1830 
1831   g_return_if_fail (IDE_IS_MAIN_THREAD ());
1832   g_return_if_fail (IDE_IS_CONFIG (self));
1833   g_return_if_fail (priv->has_attached == FALSE);
1834 
1835   priv->has_attached = TRUE;
1836 
1837   /*
1838    * We don't start monitoring changed events until we've gotten back
1839    * to the main loop (in case of threaded loaders) which happens from
1840    * the point where the configuration is added to the config manager.
1841    */
1842 
1843   if (!(context = ide_object_get_context (IDE_OBJECT (self))))
1844     {
1845       g_critical ("Attempt to register configuration without a context");
1846       return;
1847     }
1848 
1849   runtime_manager = ide_runtime_manager_from_context (context);
1850 
1851   g_signal_connect_object (runtime_manager,
1852                            "items-changed",
1853                            G_CALLBACK (ide_config_runtime_manager_items_changed),
1854                            self,
1855                            G_CONNECT_SWAPPED);
1856 
1857   /* Update the runtime and potentially set prefix, but do not emit changed */
1858   ide_config_block_changed (self);
1859   ide_config_runtime_manager_items_changed (self, 0, 0, 0, runtime_manager);
1860   ide_config_unblock_changed (self);
1861 }
1862 
1863 gboolean
ide_config_get_prefix_set(IdeConfig * self)1864 ide_config_get_prefix_set (IdeConfig *self)
1865 {
1866   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1867 
1868   g_return_val_if_fail (IDE_IS_CONFIG (self), FALSE);
1869 
1870   return priv->prefix_set;
1871 }
1872 
1873 void
ide_config_set_prefix_set(IdeConfig * self,gboolean prefix_set)1874 ide_config_set_prefix_set (IdeConfig *self,
1875                            gboolean   prefix_set)
1876 {
1877   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1878 
1879   g_return_if_fail (IDE_IS_CONFIG (self));
1880 
1881   prefix_set = !!prefix_set;
1882 
1883   if (prefix_set != priv->prefix_set)
1884     {
1885       priv->prefix_set = prefix_set;
1886       g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PREFIX_SET]);
1887     }
1888 }
1889 
1890 /**
1891  * ide_config_get_extensions:
1892  * @self: a #IdeConfig
1893  *
1894  * Gets the known SDK extensions that will be used when building the project.
1895  * Implementing this in your configuration backend allows plugins to know if
1896  * additional binaries will be available to the build system.
1897  *
1898  * Returns: (not nullable) (transfer full) (element-type Ide.Runtime): an array
1899  *   of #IdeRuntime for the runtime extensions for the configuration.
1900  *
1901  * Since: 3.34
1902  */
1903 GPtrArray *
ide_config_get_extensions(IdeConfig * self)1904 ide_config_get_extensions (IdeConfig *self)
1905 {
1906   GPtrArray *ret = NULL;
1907 
1908   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1909 
1910   if (IDE_CONFIG_GET_CLASS (self)->get_extensions)
1911    ret = IDE_CONFIG_GET_CLASS (self)->get_extensions (self);
1912 
1913   if (ret == NULL)
1914     ret = g_ptr_array_new ();
1915 
1916   return g_steal_pointer (&ret);
1917 }
1918 
1919 const gchar * const *
ide_config_get_args_for_phase(IdeConfig * self,IdePipelinePhase phase)1920 ide_config_get_args_for_phase (IdeConfig        *self,
1921                                IdePipelinePhase  phase)
1922 {
1923   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1924   const gchar * const *args;
1925 
1926   g_return_val_if_fail (IDE_IS_CONFIG (self), NULL);
1927 
1928   args = g_hash_table_lookup (priv->pipeline_args, GINT_TO_POINTER (phase));
1929   return args;
1930 }
1931 
1932 void
ide_config_set_args_for_phase(IdeConfig * self,IdePipelinePhase phase,const gchar * const * args)1933 ide_config_set_args_for_phase (IdeConfig           *self,
1934                                IdePipelinePhase     phase,
1935                                const gchar * const *args)
1936 {
1937   IdeConfigPrivate *priv = ide_config_get_instance_private (self);
1938 
1939   g_return_if_fail (IDE_IS_CONFIG (self));
1940 
1941   g_hash_table_insert (priv->pipeline_args, GINT_TO_POINTER (phase), g_strdupv ((gchar **)args));
1942 }
1943