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