[gnome-builder] triplet: create IdeTriplet to represent a machine architecture/vendor/system/os



commit 6f0b2a99609403bb1b0b3e010c2d5e3298f3344f
Author: Corentin Noël <corentin noel collabora co uk>
Date:   Thu Mar 29 16:46:22 2018 +0100

    triplet: create IdeTriplet to represent a machine architecture/vendor/system/os
    
    This avoids the creation of three properties everywhere and is more
    future-proof (It already supports the quadruplets but can be extended as
    needed).  This also avoid string duplication in every classes.

 src/libide/buildsystem/ide-build-pipeline.c        | 125 ++-----
 src/libide/buildsystem/ide-build-pipeline.h        | 199 ++++++-----
 src/libide/devices/ide-device-info.c               | 169 ++++-----
 src/libide/devices/ide-device-info.h               |  31 +-
 src/libide/devices/ide-device-manager.c            |   7 +-
 src/libide/ide.h                                   |   1 +
 src/libide/local/ide-local-device.c                | 133 ++-----
 src/libide/util/ide-triplet.c                      | 386 +++++++++++++++++++++
 src/libide/util/ide-triplet.h                      |  66 ++++
 src/libide/util/meson.build                        |   2 +
 .../autotools/ide-autotools-pipeline-addin.c       |   6 +-
 src/plugins/cargo/cargo_plugin.py                  |   2 +-
 src/plugins/deviced/gbp-deviced-deploy-strategy.c  |   8 +-
 src/plugins/deviced/gbp-deviced-device.c           |  31 +-
 src/plugins/flatpak/gbp-flatpak-runtime-provider.c |   4 +-
 src/plugins/flatpak/gbp-flatpak-util.c             |   6 +-
 src/plugins/npm/npm_plugin.py                      |   2 +-
 src/plugins/qemu/gbp-qemu-device-provider.c        |   4 +-
 18 files changed, 733 insertions(+), 449 deletions(-)
---
diff --git a/src/libide/buildsystem/ide-build-pipeline.c b/src/libide/buildsystem/ide-build-pipeline.c
index b890cf1b4..aa56c2411 100644
--- a/src/libide/buildsystem/ide-build-pipeline.c
+++ b/src/libide/buildsystem/ide-build-pipeline.c
@@ -177,10 +177,7 @@ struct _IdeBuildPipeline
    * the pipeline addins may want to use to tweak how the execute
    * the build.
    */
-  gchar *arch;
-  gchar *kernel;
-  gchar *system;
-  gchar *system_type;
+  IdeTriplet *host_triplet;
 
   /*
    * This is an array of PipelineEntry, which contain information we
@@ -1179,23 +1176,27 @@ void
 _ide_build_pipeline_set_device_info (IdeBuildPipeline *self,
                                      IdeDeviceInfo    *info)
 {
+  IdeTriplet *triplet;
+
   IDE_ENTRY;
 
   g_assert (IDE_IS_BUILD_PIPELINE (self));
   g_assert (IDE_IS_DEVICE_INFO (info));
 
-  g_clear_pointer (&self->arch, g_free);
-  g_clear_pointer (&self->kernel, g_free);
-  g_clear_pointer (&self->system, g_free);
-  g_clear_pointer (&self->system_type, g_free);
+  triplet = ide_device_info_get_host_triplet (info);
+
+  if (triplet != self->host_triplet)
+    {
+      g_clear_pointer (&self->host_triplet, ide_triplet_unref);
+      self->host_triplet = triplet ? ide_triplet_ref (triplet) : NULL;
+    }
 
-  g_object_get (info,
-                "arch", &self->arch,
-                "kernel", &self->kernel,
-                "system", &self->system,
-                NULL);
+  if (self->host_triplet == NULL)
+    self->host_triplet = ide_triplet_new_from_system ();
 
-  self->system_type = ide_create_host_triplet (self->arch, self->kernel, self->system);
+  g_debug ("Pipeline [%p] host is now %s",
+           self,
+           ide_triplet_get_full_name (self->host_triplet));
 
   IDE_EXIT;
 }
@@ -1323,10 +1324,7 @@ ide_build_pipeline_finalize (GObject *object)
   g_clear_object (&self->runtime);
   g_clear_object (&self->configuration);
   g_clear_pointer (&self->pipeline, g_array_unref);
-  g_clear_pointer (&self->arch, g_free);
-  g_clear_pointer (&self->kernel, g_free);
-  g_clear_pointer (&self->system, g_free);
-  g_clear_pointer (&self->system_type, g_free);
+  g_clear_pointer (&self->host_triplet, ide_triplet_unref);
   g_clear_pointer (&self->srcdir, g_free);
   g_clear_pointer (&self->builddir, g_free);
   g_clear_pointer (&self->errfmts, g_array_unref);
@@ -1380,6 +1378,9 @@ ide_build_pipeline_initable_init (GInitable     *initable,
   g_assert (IDE_IS_CONFIGURATION (self->configuration));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
 
+  g_debug ("initializing build pipeline with device %s",
+           G_OBJECT_TYPE_NAME (self->device));
+
   if (self->runtime == NULL)
     {
       g_set_error_literal (error,
@@ -3775,84 +3776,24 @@ ide_build_pipeline_get_device (IdeBuildPipeline *self)
 }
 
 /**
- * ide_build_pipeline_get_arch:
- * @self: a #IdeBuildPipeline
- *
- * Gets the architecture that the pipeline is building for, once that has
- * been discovered from the device.
- *
- * Returns: (nullable): a string describing the architecture, or %NULL
- *
- * Since: 3.28
- */
-const gchar *
-ide_build_pipeline_get_arch (IdeBuildPipeline *self)
-{
-  g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), NULL);
-
-  return self->arch;
-}
-
-/**
- * ide_build_pipeline_get_kernel:
- * @self: a #IdeBuildPipeline
- *
- * Gets the kernel that the pipeline is building for, once that has
- * been discovered from the device.
- *
- * Returns: (nullable): a string describing the kernel, or %NULL
- *
- * Since: 3.28
- */
-const gchar *
-ide_build_pipeline_get_kernel (IdeBuildPipeline *self)
-{
-  g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), NULL);
-
-  return self->kernel;
-}
-
-/**
- * ide_build_pipeline_get_system:
- * @self: a #IdeBuildPipeline
- *
- * Gets the system portion of the host tripet that the pipeline is
- * building for, once that has been discovered from the device.
- *
- * For Linux based devices, this will generally be "gnu".
- *
- * Returns: (nullable): a string describing the device system, or %NULL
- *
- * Since: 3.28
- */
-const gchar *
-ide_build_pipeline_get_system (IdeBuildPipeline *self)
-{
-  g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), NULL);
-
-  return self->system;
-}
-
-/**
- * ide_build_pipeline_get_system_type:
+ * ide_build_pipeline_get_host_triplet:
  * @self: a #IdeBuildPipeline
  *
- * Gets the combination of arch-kernel-system, sometimes referred to as
- * the "host triplet".
+ * Gets the architecture, kernel, and system that the pipeline is building for,
+ * once that has been discovered from the device.
  *
- * For Linux based devices, this will generally be something like
- * "x86_64-linux-gnu".
+ * Returns: (nullable) (transfer full): an #IdeTriplet describing the system
+ *   where the compiled application will run, or %NULL if that is not yet
+ *   known.
  *
- * Returns: a string describing the device
- *
- * Since: 3.28
+ * Since: 3.30
  */
-const gchar *
-ide_build_pipeline_get_system_type (IdeBuildPipeline *self)
+IdeTriplet *
+ide_build_pipeline_get_host_triplet (IdeBuildPipeline *self)
 {
   g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), NULL);
 
-  return self->system_type;
+  return ide_triplet_ref (self->host_triplet);
 }
 
 /**
@@ -3862,17 +3803,17 @@ ide_build_pipeline_get_system_type (IdeBuildPipeline *self)
  * Checks to see if the pipeline is building for the native architecture,
  * kernel, and system of the host.
  *
- * This is equivalent to checking if ide_get_system_type() matches the host
- * triplet (arch, kernel, system) properties of the pipeline.
+ * This is equivalent to checking if ide_get_system_type() matches the
+ * device-triplet property of the pipeline.
  *
- * Returns: %TRUE if this is a native build, otherwise %FALSE.
+ * Returns: %TRUE if this is a native build, otherwise %FALSE
  */
 gboolean
 ide_build_pipeline_is_native (IdeBuildPipeline *self)
 {
   g_return_val_if_fail (IDE_IS_BUILD_PIPELINE (self), FALSE);
 
-  return g_strcmp0 (self->system_type, ide_get_system_type ()) == 0;
+  return ide_triplet_is_system (self->host_triplet);
 }
 
 /**
diff --git a/src/libide/buildsystem/ide-build-pipeline.h b/src/libide/buildsystem/ide-build-pipeline.h
index a506d7b8b..09434d7fc 100644
--- a/src/libide/buildsystem/ide-build-pipeline.h
+++ b/src/libide/buildsystem/ide-build-pipeline.h
@@ -29,6 +29,7 @@
 #include "config/ide-configuration.h"
 #include "runtimes/ide-runtime.h"
 #include "subprocess/ide-subprocess-launcher.h"
+#include "util/ide-triplet.h"
 
 G_BEGIN_DECLS
 
@@ -59,137 +60,131 @@ IDE_AVAILABLE_IN_ALL
 G_DECLARE_FINAL_TYPE (IdeBuildPipeline, ide_build_pipeline, IDE, BUILD_PIPELINE, IdeObject)
 
 IDE_AVAILABLE_IN_3_28
-gboolean               ide_build_pipeline_is_ready            (IdeBuildPipeline       *self);
+gboolean               ide_build_pipeline_is_ready                (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_get_busy            (IdeBuildPipeline       *self);
+gboolean               ide_build_pipeline_get_busy                (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-IdeConfiguration      *ide_build_pipeline_get_configuration   (IdeBuildPipeline       *self);
+IdeConfiguration      *ide_build_pipeline_get_configuration       (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_3_28
-IdeDevice             *ide_build_pipeline_get_device          (IdeBuildPipeline       *self);
+IdeDevice             *ide_build_pipeline_get_device              (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_3_28
-IdeRuntime            *ide_build_pipeline_get_runtime         (IdeBuildPipeline       *self);
+IdeRuntime            *ide_build_pipeline_get_runtime             (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-const gchar           *ide_build_pipeline_get_builddir        (IdeBuildPipeline       *self);
+const gchar           *ide_build_pipeline_get_builddir            (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-const gchar           *ide_build_pipeline_get_srcdir          (IdeBuildPipeline       *self);
-IDE_AVAILABLE_IN_3_28
-const gchar           *ide_build_pipeline_get_arch            (IdeBuildPipeline       *self);
-IDE_AVAILABLE_IN_3_28
-const gchar           *ide_build_pipeline_get_kernel          (IdeBuildPipeline       *self);
-IDE_AVAILABLE_IN_3_28
-const gchar           *ide_build_pipeline_get_system          (IdeBuildPipeline       *self);
-IDE_AVAILABLE_IN_3_28
-const gchar           *ide_build_pipeline_get_system_type     (IdeBuildPipeline       *self);
+const gchar           *ide_build_pipeline_get_srcdir              (IdeBuildPipeline       *self);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet            *ide_build_pipeline_get_host_triplet        (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-gchar                 *ide_build_pipeline_get_message         (IdeBuildPipeline       *self);
+gchar                 *ide_build_pipeline_get_message             (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-IdeBuildPhase          ide_build_pipeline_get_phase           (IdeBuildPipeline       *self);
+IdeBuildPhase          ide_build_pipeline_get_phase               (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_get_can_export      (IdeBuildPipeline       *self);
+gboolean               ide_build_pipeline_get_can_export          (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_3_28
-VtePty                *ide_build_pipeline_get_pty             (IdeBuildPipeline       *self);
+VtePty                *ide_build_pipeline_get_pty                 (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_ALL
-IdeSubprocessLauncher *ide_build_pipeline_create_launcher     (IdeBuildPipeline       *self,
-                                                               GError                **error);
+IdeSubprocessLauncher *ide_build_pipeline_create_launcher         (IdeBuildPipeline       *self,
+                                                                   GError                **error);
 IDE_AVAILABLE_IN_ALL
-gchar                 *ide_build_pipeline_build_srcdir_path   (IdeBuildPipeline       *self,
-                                                               const gchar            *first_part,
-                                                               ...) G_GNUC_NULL_TERMINATED;
+gchar                 *ide_build_pipeline_build_srcdir_path       (IdeBuildPipeline       *self,
+                                                                   const gchar            *first_part,
+                                                                   ...) G_GNUC_NULL_TERMINATED;
 IDE_AVAILABLE_IN_ALL
-gchar                 *ide_build_pipeline_build_builddir_path (IdeBuildPipeline       *self,
-                                                               const gchar            *first_part,
-                                                               ...) G_GNUC_NULL_TERMINATED;
+gchar                 *ide_build_pipeline_build_builddir_path     (IdeBuildPipeline       *self,
+                                                                   const gchar            *first_part,
+                                                                   ...) G_GNUC_NULL_TERMINATED;
 IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_invalidate_phase    (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phases);
+void                   ide_build_pipeline_invalidate_phase        (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phases);
 IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_request_phase       (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase);
+gboolean               ide_build_pipeline_request_phase           (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase);
 IDE_AVAILABLE_IN_ALL
-guint                  ide_build_pipeline_connect             (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase,
-                                                               gint                    priority,
-                                                               IdeBuildStage          *stage);
+guint                  ide_build_pipeline_connect                 (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase,
+                                                                   gint                    priority,
+                                                                   IdeBuildStage          *stage);
 IDE_AVAILABLE_IN_ALL
-guint                  ide_build_pipeline_connect_launcher    (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase,
-                                                               gint                    priority,
-                                                               IdeSubprocessLauncher  *launcher);
+guint                  ide_build_pipeline_connect_launcher        (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase,
+                                                                   gint                    priority,
+                                                                   IdeSubprocessLauncher  *launcher);
 IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_disconnect          (IdeBuildPipeline       *self,
-                                                               guint                   stage_id);
+void                   ide_build_pipeline_disconnect              (IdeBuildPipeline       *self,
+                                                                   guint                   stage_id);
 IDE_AVAILABLE_IN_ALL
-IdeBuildStage         *ide_build_pipeline_get_stage_by_id     (IdeBuildPipeline       *self,
-                                                               guint                   stage_id);
+IdeBuildStage         *ide_build_pipeline_get_stage_by_id         (IdeBuildPipeline       *self,
+                                                                   guint                   stage_id);
 IDE_AVAILABLE_IN_ALL
-guint                  ide_build_pipeline_add_log_observer    (IdeBuildPipeline       *self,
-                                                               IdeBuildLogObserver     observer,
-                                                               gpointer                observer_data,
-                                                               GDestroyNotify          
observer_data_destroy);
+guint                  ide_build_pipeline_add_log_observer        (IdeBuildPipeline       *self,
+                                                                   IdeBuildLogObserver     observer,
+                                                                   gpointer                observer_data,
+                                                                   GDestroyNotify          
observer_data_destroy);
 IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_remove_log_observer (IdeBuildPipeline       *self,
-                                                               guint                   observer_id);
+gboolean               ide_build_pipeline_remove_log_observer     (IdeBuildPipeline       *self,
+                                                                   guint                   observer_id);
 IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_emit_diagnostic     (IdeBuildPipeline       *self,
-                                                               IdeDiagnostic          *diagnostic);
+void                   ide_build_pipeline_emit_diagnostic         (IdeBuildPipeline       *self,
+                                                                   IdeDiagnostic          *diagnostic);
 IDE_AVAILABLE_IN_ALL
-guint                  ide_build_pipeline_add_error_format    (IdeBuildPipeline       *self,
-                                                               const gchar            *regex,
-                                                               GRegexCompileFlags      flags);
+guint                  ide_build_pipeline_add_error_format        (IdeBuildPipeline       *self,
+                                                                   const gchar            *regex,
+                                                                   GRegexCompileFlags      flags);
 IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_remove_error_format (IdeBuildPipeline       *self,
-                                                               guint                   error_format_id);
+gboolean               ide_build_pipeline_remove_error_format     (IdeBuildPipeline       *self,
+                                                                   guint                   error_format_id);
 IDE_AVAILABLE_IN_3_28
-void                   ide_build_pipeline_build_async         (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase,
-                                                               GCancellable           *cancellable,
-                                                               GAsyncReadyCallback     callback,
-                                                               gpointer                user_data);
+void                   ide_build_pipeline_build_async             (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase,
+                                                                   GCancellable           *cancellable,
+                                                                   GAsyncReadyCallback     callback,
+                                                                   gpointer                user_data);
 IDE_AVAILABLE_IN_3_28
-gboolean               ide_build_pipeline_build_finish        (IdeBuildPipeline       *self,
-                                                               GAsyncResult           *result,
-                                                               GError                **error);
-IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_execute_async       (IdeBuildPipeline       *self,
-                                                               GCancellable           *cancellable,
-                                                               GAsyncReadyCallback     callback,
-                                                               gpointer                user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_execute_finish      (IdeBuildPipeline       *self,
-                                                               GAsyncResult           *result,
-                                                               GError                **error);
-IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_foreach_stage       (IdeBuildPipeline       *self,
-                                                               GFunc                   stage_callback,
-                                                               gpointer                user_data);
-IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_clean_async         (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase,
-                                                               GCancellable           *cancellable,
-                                                               GAsyncReadyCallback     callback,
-                                                               gpointer                user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_clean_finish        (IdeBuildPipeline       *self,
-                                                               GAsyncResult           *result,
-                                                               GError                **error);
-IDE_AVAILABLE_IN_ALL
-void                   ide_build_pipeline_rebuild_async       (IdeBuildPipeline       *self,
-                                                               IdeBuildPhase           phase,
-                                                               GCancellable           *cancellable,
-                                                               GAsyncReadyCallback     callback,
-                                                               gpointer                user_data);
-IDE_AVAILABLE_IN_ALL
-gboolean               ide_build_pipeline_rebuild_finish      (IdeBuildPipeline       *self,
-                                                               GAsyncResult           *result,
-                                                               GError                **error);
+gboolean               ide_build_pipeline_build_finish            (IdeBuildPipeline       *self,
+                                                                   GAsyncResult           *result,
+                                                                   GError                **error);
+IDE_AVAILABLE_IN_ALL
+void                   ide_build_pipeline_execute_async           (IdeBuildPipeline       *self,
+                                                                   GCancellable           *cancellable,
+                                                                   GAsyncReadyCallback     callback,
+                                                                   gpointer                user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean               ide_build_pipeline_execute_finish          (IdeBuildPipeline       *self,
+                                                                   GAsyncResult           *result,
+                                                                   GError                **error);
+IDE_AVAILABLE_IN_ALL
+void                   ide_build_pipeline_foreach_stage           (IdeBuildPipeline       *self,
+                                                                   GFunc                   stage_callback,
+                                                                   gpointer                user_data);
+IDE_AVAILABLE_IN_ALL
+void                   ide_build_pipeline_clean_async             (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase,
+                                                                   GCancellable           *cancellable,
+                                                                   GAsyncReadyCallback     callback,
+                                                                   gpointer                user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean               ide_build_pipeline_clean_finish            (IdeBuildPipeline       *self,
+                                                                   GAsyncResult           *result,
+                                                                   GError                **error);
+IDE_AVAILABLE_IN_ALL
+void                   ide_build_pipeline_rebuild_async           (IdeBuildPipeline       *self,
+                                                                   IdeBuildPhase           phase,
+                                                                   GCancellable           *cancellable,
+                                                                   GAsyncReadyCallback     callback,
+                                                                   gpointer                user_data);
+IDE_AVAILABLE_IN_ALL
+gboolean               ide_build_pipeline_rebuild_finish          (IdeBuildPipeline       *self,
+                                                                   GAsyncResult           *result,
+                                                                   GError                **error);
 IDE_AVAILABLE_IN_3_28
-void                   ide_build_pipeline_attach_pty          (IdeBuildPipeline       *self,
-                                                               IdeSubprocessLauncher  *launcher);
+void                   ide_build_pipeline_attach_pty              (IdeBuildPipeline       *self,
+                                                                   IdeSubprocessLauncher  *launcher);
 IDE_AVAILABLE_IN_3_28
-gboolean               ide_build_pipeline_has_configured      (IdeBuildPipeline       *self);
+gboolean               ide_build_pipeline_has_configured          (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_3_28
-IdeBuildPhase          ide_build_pipeline_get_requested_phase (IdeBuildPipeline       *self);
+IdeBuildPhase          ide_build_pipeline_get_requested_phase     (IdeBuildPipeline       *self);
 IDE_AVAILABLE_IN_3_28
-gboolean               ide_build_pipeline_is_native           (IdeBuildPipeline       *self);
+gboolean               ide_build_pipeline_is_native               (IdeBuildPipeline       *self);
 
 G_END_DECLS
diff --git a/src/libide/devices/ide-device-info.c b/src/libide/devices/ide-device-info.c
index cf23585e6..0785e52bf 100644
--- a/src/libide/devices/ide-device-info.c
+++ b/src/libide/devices/ide-device-info.c
@@ -30,9 +30,7 @@
 struct _IdeDeviceInfo
 {
   GObject parent_instance;
-  gchar *arch;
-  gchar *kernel;
-  gchar *system;
+  IdeTriplet *host_triplet;
   IdeDeviceKind kind;
 };
 
@@ -40,10 +38,8 @@ G_DEFINE_TYPE (IdeDeviceInfo, ide_device_info, G_TYPE_OBJECT)
 
 enum {
   PROP_0,
-  PROP_ARCH,
-  PROP_KERNEL,
   PROP_KIND,
-  PROP_SYSTEM,
+  PROP_HOST_TRIPLET,
   N_PROPS
 };
 
@@ -54,9 +50,7 @@ ide_device_info_finalize (GObject *object)
 {
   IdeDeviceInfo *self = (IdeDeviceInfo *)object;
 
-  g_clear_pointer (&self->arch, g_free);
-  g_clear_pointer (&self->kernel, g_free);
-  g_clear_pointer (&self->system, g_free);
+  g_clear_pointer (&self->host_triplet, ide_triplet_unref);
 
   G_OBJECT_CLASS (ide_device_info_parent_class)->finalize (object);
 }
@@ -71,20 +65,12 @@ ide_device_info_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_ARCH:
-      g_value_set_string (value, ide_device_info_get_arch (self));
-      break;
-
-    case PROP_KERNEL:
-      g_value_set_string (value, ide_device_info_get_kernel (self));
-      break;
-
     case PROP_KIND:
       g_value_set_enum (value, ide_device_info_get_kind (self));
       break;
 
-    case PROP_SYSTEM:
-      g_value_set_string (value, ide_device_info_get_system (self));
+    case PROP_HOST_TRIPLET:
+      g_value_set_boxed (value, ide_device_info_get_host_triplet (self));
       break;
 
     default:
@@ -102,20 +88,12 @@ ide_device_info_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_ARCH:
-      ide_device_info_set_arch (self, g_value_get_string (value));
-      break;
-
-    case PROP_KERNEL:
-      ide_device_info_set_kernel (self, g_value_get_string (value));
-      break;
-
     case PROP_KIND:
       ide_device_info_set_kind (self, g_value_get_enum (value));
       break;
 
-    case PROP_SYSTEM:
-      ide_device_info_set_system (self, g_value_get_string (value));
+    case PROP_HOST_TRIPLET:
+      ide_device_info_set_host_triplet (self, g_value_get_boxed (value));
       break;
 
     default:
@@ -133,20 +111,6 @@ ide_device_info_class_init (IdeDeviceInfoClass *klass)
   object_class->get_property = ide_device_info_get_property;
   object_class->set_property = ide_device_info_set_property;
 
-  properties [PROP_ARCH] =
-    g_param_spec_string ("arch",
-                         "Arch",
-                         "The architecture of the device, such as x86_64",
-                         arch,
-                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
-
-  properties [PROP_KERNEL] =
-    g_param_spec_string ("kernel",
-                         "Kernel",
-                         "The operating system kernel, such as Linux",
-                         NULL,
-                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
-
   properties [PROP_KIND] =
     g_param_spec_enum ("kind",
                        "Kind",
@@ -155,12 +119,12 @@ ide_device_info_class_init (IdeDeviceInfoClass *klass)
                        IDE_DEVICE_KIND_COMPUTER,
                        G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
-  properties [PROP_SYSTEM] =
-    g_param_spec_string ("system",
-                         "System",
-                         "The system kind, such as 'gnu'",
-                         NULL,
-                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+  properties [PROP_HOST_TRIPLET] =
+    g_param_spec_boxed ("host-triplet",
+                        "Host Triplet",
+                        "The #IdeTriplet object holding all the configuration name values",
+                        IDE_TYPE_TRIPLET,
+                        G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
@@ -168,7 +132,7 @@ ide_device_info_class_init (IdeDeviceInfoClass *klass)
 static void
 ide_device_info_init (IdeDeviceInfo *self)
 {
-  self->arch = ide_get_system_arch ();
+  self->host_triplet = ide_triplet_new_from_system ();
 }
 
 IdeDeviceInfo *
@@ -177,30 +141,14 @@ ide_device_info_new (void)
   return g_object_new (IDE_TYPE_DEVICE_INFO, NULL);
 }
 
-const gchar *
-ide_device_info_get_arch (IdeDeviceInfo *self)
-{
-  g_return_val_if_fail (IDE_IS_DEVICE_INFO (self), NULL);
-
-  return self->arch;
-}
-
-const gchar *
-ide_device_info_get_kernel (IdeDeviceInfo *self)
-{
-  g_return_val_if_fail (IDE_IS_DEVICE_INFO (self), NULL);
-
-  return self->kernel;
-}
-
-const gchar *
-ide_device_info_get_system (IdeDeviceInfo *self)
-{
-  g_return_val_if_fail (IDE_IS_DEVICE_INFO (self), NULL);
-
-  return self->system;
-}
-
+/**
+ * ide_device_info_get_kind:
+ * @self: An #IdeDeviceInfo
+ *
+ * Get the #IdeDeviceKind of the device describing the type of device @self refers to
+ *
+ * Returns: An #IdeDeviceKind.
+ */
 IdeDeviceKind
 ide_device_info_get_kind (IdeDeviceInfo *self)
 {
@@ -209,34 +157,14 @@ ide_device_info_get_kind (IdeDeviceInfo *self)
   return self->kind;
 }
 
-void
-ide_device_info_set_arch (IdeDeviceInfo *self,
-                          const gchar   *arch)
-{
-  g_return_if_fail (IDE_IS_DEVICE_INFO (self));
-
-  if (g_strcmp0 (arch, self->arch) != 0)
-    {
-      g_free (self->arch);
-      self->arch = g_strdup (arch);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ARCH]);
-    }
-}
-
-void
-ide_device_info_set_kernel (IdeDeviceInfo *self,
-                            const gchar   *kernel)
-{
-  g_return_if_fail (IDE_IS_DEVICE_INFO (self));
-
-  if (g_strcmp0 (kernel, self->kernel) != 0)
-    {
-      g_free (self->kernel);
-      self->kernel = g_strdup (kernel);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_KERNEL]);
-    }
-}
 
+/**
+ * ide_device_info_set_kind:
+ * @self: An #IdeDeviceInfo
+ * @kind: An #IdeDeviceKind
+ *
+ * Set the #IdeDeviceKind of the device describing the type of device @self refers to
+ */
 void
 ide_device_info_set_kind (IdeDeviceInfo *self,
                           IdeDeviceKind  kind)
@@ -250,16 +178,43 @@ ide_device_info_set_kind (IdeDeviceInfo *self,
     }
 }
 
+/**
+ * ide_device_info_get_host_triplet:
+ * @self: An #IdeDeviceInfo
+ *
+ * Get the #IdeTriplet object describing the configuration name
+ * of the Device (its architecture…)
+ *
+ * Returns: (transfer none) (nullable): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_device_info_get_host_triplet (IdeDeviceInfo *self)
+{
+  g_return_val_if_fail (IDE_IS_DEVICE_INFO (self), NULL);
+
+  return self->host_triplet;
+}
+
+/**
+ * ide_device_info_set_host_triplet:
+ * @self: An #IdeDeviceInfo
+ *
+ * Set the #IdeTriplet object describing the configuration name
+ *
+ * Since: 3.30
+ */
 void
-ide_device_info_set_system (IdeDeviceInfo *self,
-                            const gchar   *system)
+ide_device_info_set_host_triplet (IdeDeviceInfo *self,
+                                  IdeTriplet    *host_triplet)
 {
   g_return_if_fail (IDE_IS_DEVICE_INFO (self));
 
-  if (g_strcmp0 (system, self->system) != 0)
+  if (host_triplet != self->host_triplet)
     {
-      g_free (self->system);
-      self->system = g_strdup (system);
-      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SYSTEM]);
+      g_clear_pointer (&self->host_triplet, ide_triplet_unref);
+      self->host_triplet = host_triplet ? ide_triplet_ref (host_triplet) : NULL;
+      g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HOST_TRIPLET]);
     }
 }
diff --git a/src/libide/devices/ide-device-info.h b/src/libide/devices/ide-device-info.h
index b9385d6f9..698a00bb0 100644
--- a/src/libide/devices/ide-device-info.h
+++ b/src/libide/devices/ide-device-info.h
@@ -22,8 +22,11 @@
 
 #include <gio/gio.h>
 
+#include "ide-types.h"
 #include "ide-version-macros.h"
 
+#include "util/ide-triplet.h"
+
 G_BEGIN_DECLS
 
 typedef enum
@@ -40,26 +43,16 @@ IDE_AVAILABLE_IN_3_28
 G_DECLARE_FINAL_TYPE (IdeDeviceInfo, ide_device_info, IDE, DEVICE_INFO, GObject)
 
 IDE_AVAILABLE_IN_3_28
-IdeDeviceInfo *ide_device_info_new        (void);
-IDE_AVAILABLE_IN_3_28
-IdeDeviceKind  ide_device_info_get_kind   (IdeDeviceInfo *self);
-IDE_AVAILABLE_IN_3_28
-void           ide_device_info_set_kind   (IdeDeviceInfo *self,
-                                           IdeDeviceKind  kind);
-IDE_AVAILABLE_IN_3_28
-const gchar   *ide_device_info_get_kernel (IdeDeviceInfo *self);
-IDE_AVAILABLE_IN_3_28
-void           ide_device_info_set_kernel (IdeDeviceInfo *self,
-                                           const gchar   *kernel);
-IDE_AVAILABLE_IN_3_28
-const gchar   *ide_device_info_get_arch   (IdeDeviceInfo *self);
-IDE_AVAILABLE_IN_3_28
-void           ide_device_info_set_arch   (IdeDeviceInfo *self,
-                                           const gchar   *arch);
+IdeDeviceInfo *ide_device_info_new              (void);
 IDE_AVAILABLE_IN_3_28
-const gchar   *ide_device_info_get_system (IdeDeviceInfo *self);
+IdeDeviceKind  ide_device_info_get_kind         (IdeDeviceInfo *self);
 IDE_AVAILABLE_IN_3_28
-void           ide_device_info_set_system (IdeDeviceInfo *self,
-                                           const gchar   *system);
+void           ide_device_info_set_kind         (IdeDeviceInfo *self,
+                                                 IdeDeviceKind  kind);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet    *ide_device_info_get_host_triplet (IdeDeviceInfo *self);
+IDE_AVAILABLE_IN_3_30
+void           ide_device_info_set_host_triplet (IdeDeviceInfo *self,
+                                                 IdeTriplet    *host_triplet);
 
 G_END_DECLS
diff --git a/src/libide/devices/ide-device-manager.c b/src/libide/devices/ide-device-manager.c
index 4835c3d83..0af4d1985 100644
--- a/src/libide/devices/ide-device-manager.c
+++ b/src/libide/devices/ide-device-manager.c
@@ -367,15 +367,17 @@ static void
 ide_device_manager_add_local (IdeDeviceManager *self)
 {
   g_autoptr(IdeDevice) device = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
   g_autofree gchar *arch = NULL;
   IdeContext *context;
 
   g_return_if_fail (IDE_IS_DEVICE_MANAGER (self));
 
   context = ide_object_get_context (IDE_OBJECT (self));
-
+  triplet = ide_triplet_new_from_system ();
   device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
                          "context", context,
+                         "triplet", triplet,
                          NULL);
   ide_device_manager_provider_device_added_cb (self, device, NULL);
 
@@ -389,9 +391,10 @@ ide_device_manager_add_local (IdeDeviceManager *self)
     {
 #if 0
       g_autoptr(IdeDevice) legacy_device = NULL;
+      g_autoptr(IdeTriplet) legacy_triplet = ide_triplet_new ("i386");
 
       legacy_device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
-                                    "arch", "i386",
+                                    "triplet", legacy_triplet,
                                     "context", context,
                                     NULL);
       ide_device_manager_provider_device_added_cb (self, legacy_device, NULL);
diff --git a/src/libide/ide.h b/src/libide/ide.h
index 83c0c8257..1ec900a6b 100644
--- a/src/libide/ide.h
+++ b/src/libide/ide.h
@@ -196,6 +196,7 @@ G_BEGIN_DECLS
 #include "util/ide-progress.h"
 #include "util/ide-ref-ptr.h"
 #include "util/ide-settings.h"
+#include "util/ide-triplet.h"
 #include "util/ide-uri.h"
 #include "vcs/ide-vcs-config.h"
 #include "vcs/ide-vcs-file-info.h"
diff --git a/src/libide/local/ide-local-device.c b/src/libide/local/ide-local-device.c
index 0977b6bbe..6673c045f 100644
--- a/src/libide/local/ide-local-device.c
+++ b/src/libide/local/ide-local-device.c
@@ -26,23 +26,19 @@
 
 #include "local/ide-local-device.h"
 #include "util/ide-posix.h"
+#include "util/ide-triplet.h"
 #include "threading/ide-task.h"
 
 typedef struct
 {
-  gchar *system_type;
-  gchar *arch;
-  gchar *kernel;
-  gchar *system;
+  IdeTriplet *triplet;
 } IdeLocalDevicePrivate;
 
 G_DEFINE_TYPE_WITH_PRIVATE (IdeLocalDevice, ide_local_device, IDE_TYPE_DEVICE)
 
 enum {
   PROP_0,
-  PROP_ARCH,
-  PROP_KERNEL,
-  PROP_SYSTEM,
+  PROP_TRIPLET,
   N_PROPS
 };
 
@@ -58,9 +54,6 @@ ide_local_device_get_info_async (IdeDevice           *device,
   IdeLocalDevicePrivate *priv = ide_local_device_get_instance_private (self);
   g_autoptr(IdeTask) task = NULL;
   g_autoptr(IdeDeviceInfo) info = NULL;
-  const gchar *system_type = NULL;
-  g_auto(GStrv) parts = NULL;
-  g_autofree gchar *arch = NULL;
 
   g_assert (IDE_IS_LOCAL_DEVICE (self));
   g_assert (!cancellable || G_IS_CANCELLABLE (cancellable));
@@ -69,28 +62,8 @@ ide_local_device_get_info_async (IdeDevice           *device,
   ide_task_set_source_tag (task, ide_local_device_get_info_async);
   ide_task_set_check_cancellable (task, FALSE);
 
-  system_type = ide_get_system_type ();
-  arch = ide_get_system_arch ();
-  parts = g_strsplit (system_type, "-", 3);
-
   info = ide_device_info_new ();
-  ide_device_info_set_arch (info, arch);
-
-  if (parts[1] != NULL)
-    {
-      ide_device_info_set_kernel (info, parts[1]);
-      if (parts[2] != NULL)
-        ide_device_info_set_system (info, parts[2]);
-    }
-
-  /* Now override anything that was specified in the device */
-
-  if (priv->arch != NULL)
-    ide_device_info_set_arch (info, priv->arch);
-  if (priv->kernel != NULL)
-    ide_device_info_set_kernel (info, priv->kernel);
-  if (priv->system != NULL)
-    ide_device_info_set_system (info, priv->system);
+  ide_device_info_set_host_triplet (info, priv->triplet);
 
   ide_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
 }
@@ -117,16 +90,8 @@ ide_local_device_get_property (GObject    *object,
 
   switch (prop_id)
     {
-    case PROP_ARCH:
-      g_value_set_string (value, priv->arch);
-      break;
-
-    case PROP_KERNEL:
-      g_value_set_string (value, priv->kernel);
-      break;
-
-    case PROP_SYSTEM:
-      g_value_set_string (value, priv->system);
+    case PROP_TRIPLET:
+      g_value_set_boxed (value, priv->triplet);
       break;
 
     default:
@@ -145,16 +110,8 @@ ide_local_device_set_property (GObject      *object,
 
   switch (prop_id)
     {
-    case PROP_ARCH:
-      priv->arch = g_value_dup_string (value);
-      break;
-
-    case PROP_KERNEL:
-      priv->kernel = g_value_dup_string (value);
-      break;
-
-    case PROP_SYSTEM:
-      priv->system = g_value_dup_string (value);
+    case PROP_TRIPLET:
+      priv->triplet = g_value_dup_boxed (value);
       break;
 
     default:
@@ -167,44 +124,14 @@ ide_local_device_constructed (GObject *object)
 {
   IdeLocalDevice *self = (IdeLocalDevice *)object;
   IdeLocalDevicePrivate *priv = ide_local_device_get_instance_private (self);
-  g_autofree gchar *arch = NULL;
   g_autofree gchar *name = NULL;
-  g_auto(GStrv) parts = NULL;
-  const gchar *system_type;
 
   g_assert (IDE_IS_LOCAL_DEVICE (self));
 
-  G_OBJECT_CLASS (ide_local_device_parent_class)->constructed (object);
-
-  arch = ide_get_system_arch ();
-  system_type = ide_get_system_type ();
-  parts = g_strsplit (system_type, "-", 3);
+  if (priv->triplet == NULL)
+    priv->triplet = ide_triplet_new_from_system ();
 
-  /* Parse our system type into the 3 pieces. We'll use this
-   * to reconstruct our system_type property in case the caller
-   * changed the arch manually (say from x86_64 to i386).
-   */
-  if (parts[0] != NULL)
-    {
-      if (priv->arch == NULL)
-        priv->arch = g_strdup (parts[0]);
-
-      if (parts[1] != NULL)
-        {
-          if (priv->kernel == NULL)
-            priv->kernel = g_strdup (parts[1]);
-
-          if (parts[2] != NULL)
-            {
-              if (priv->system == NULL)
-                priv->system = g_strdup (parts[2]);
-            }
-        }
-    }
-
-  priv->system_type = g_strdup_printf ("%s-%s-%s", priv->arch, priv->kernel, priv->system);
-
-  if (g_strcmp0 (arch, priv->arch) == 0)
+  if (ide_triplet_is_system (priv->triplet))
     {
       /* translators: %s is replaced with the host name */
       name = g_strdup_printf (_("My Computer (%s)"), g_get_host_name ());
@@ -213,13 +140,16 @@ ide_local_device_constructed (GObject *object)
     }
   else
     {
-      g_autofree gchar *id = g_strdup_printf ("local:%s", priv->arch);
+      const gchar *arch = ide_triplet_get_arch (priv->triplet);
+      g_autofree gchar *id = g_strdup_printf ("local:%s", arch);
 
       /* translators: first %s is replaced with the host name, second with CPU architecture */
-      name = g_strdup_printf (_("My Computer (%s) — %s"), g_get_host_name (), priv->arch);
+      name = g_strdup_printf (_("My Computer (%s) — %s"), g_get_host_name (), arch);
       ide_device_set_display_name (IDE_DEVICE (self), name);
       ide_device_set_id (IDE_DEVICE (self), id);
     }
+
+  G_OBJECT_CLASS (ide_local_device_parent_class)->constructed (object);
 }
 
 static void
@@ -228,10 +158,7 @@ ide_local_device_finalize (GObject *object)
   IdeLocalDevice *self = (IdeLocalDevice *)object;
   IdeLocalDevicePrivate *priv = ide_local_device_get_instance_private (self);
 
-  g_clear_pointer (&priv->arch, g_free);
-  g_clear_pointer (&priv->kernel, g_free);
-  g_clear_pointer (&priv->system, g_free);
-  g_clear_pointer (&priv->system_type, g_free);
+  g_clear_pointer (&priv->triplet, ide_triplet_unref);
 
   G_OBJECT_CLASS (ide_local_device_parent_class)->finalize (object);
 }
@@ -250,26 +177,12 @@ ide_local_device_class_init (IdeLocalDeviceClass *klass)
   device_class->get_info_async = ide_local_device_get_info_async;
   device_class->get_info_finish = ide_local_device_get_info_finish;
 
-  properties [PROP_ARCH] =
-    g_param_spec_string ("arch",
-                         "Arch",
-                         "The architecture of the local device",
-                         NULL,
-                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-  properties [PROP_KERNEL] =
-    g_param_spec_string ("kernel",
-                         "Kernel",
-                         "The kernel of the local device",
-                         NULL,
-                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
-  properties [PROP_SYSTEM] =
-    g_param_spec_string ("system",
-                         "System",
-                         "The system of the local device, such as 'gnu'",
-                         NULL,
-                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+  properties [PROP_TRIPLET] =
+    g_param_spec_boxed ("triplet",
+                        "Triplet",
+                        "The #IdeTriplet object describing the local device configuration name",
+                        IDE_TYPE_TRIPLET,
+                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
 
   g_object_class_install_properties (object_class, N_PROPS, properties);
 }
diff --git a/src/libide/util/ide-triplet.c b/src/libide/util/ide-triplet.c
new file mode 100644
index 000000000..4d302427a
--- /dev/null
+++ b/src/libide/util/ide-triplet.c
@@ -0,0 +1,386 @@
+/* ide-triplet.c
+ *
+ * Copyright (C) 2018 Corentin Noël <corentin noel collabora com>
+ * Copyright (C) 2018 Collabora Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define G_LOG_DOMAIN "ide-triplet"
+
+#include "config.h"
+
+#include "util/ide-triplet.h"
+#include "util/ide-posix.h"
+
+G_DEFINE_BOXED_TYPE (IdeTriplet, ide_triplet, ide_triplet_ref, ide_triplet_unref)
+
+struct _IdeTriplet
+{
+  volatile gint ref_count;
+
+  gchar *full_name;
+  gchar *arch;
+  gchar *vendor;
+  gchar *kernel;
+  gchar *operating_system;
+};
+
+static IdeTriplet *
+_ide_triplet_construct (void)
+{
+  IdeTriplet *self;
+
+  self = g_slice_new0 (IdeTriplet);
+  self->ref_count = 1;
+  self->full_name = NULL;
+  self->arch = NULL;
+  self->vendor = NULL;
+  self->kernel = NULL;
+  self->operating_system = NULL;
+
+  return self;
+}
+
+/**
+ * ide_triplet_new:
+ * @full_name: The complete identifier of the machine
+ *
+ * Creates a new #IdeTriplet from a given identifier. This identifier
+ * can be a simple architecture name, a duet of "arch-kernel" (like "m68k-coff"), a triplet
+ * of "arch-kernel-os" (like "x86_64-linux-gnu") or a quadriplet of "arch-vendor-kernel-os"
+ * (like "i686-pc-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_triplet_new (const gchar *full_name)
+{
+  IdeTriplet *self;
+  g_auto (GStrv) parts = NULL;
+  guint parts_length = 0;
+
+  g_return_val_if_fail (full_name != NULL, NULL);
+
+  self = _ide_triplet_construct ();
+  self->full_name = g_strdup (full_name);
+
+  parts = g_strsplit (full_name, "-", 4);
+  parts_length = g_strv_length (parts);
+  /* Currently they can't have more than 4 parts */
+  if (parts_length >= 4)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->vendor = g_strdup (parts[1]);
+      self->kernel = g_strdup (parts[2]);
+      self->operating_system = g_strdup (parts[3]);
+    }
+  else if (parts_length == 3)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->kernel = g_strdup (parts[1]);
+      self->operating_system = g_strdup (parts[2]);
+    }
+  else if (parts_length == 2)
+    {
+      self->arch = g_strdup (parts[0]);
+      self->kernel = g_strdup (parts[1]);
+    }
+  else if (parts_length == 1)
+    self->arch = g_strdup (parts[0]);
+
+  return self;
+}
+
+/**
+ * ide_triplet_new_from_system:
+ *
+ * Creates a new #IdeTriplet from a the current system information
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_triplet_new_from_system (void)
+{
+  static IdeTriplet *system_triplet;
+
+  if (g_once_init_enter (&system_triplet))
+    g_once_init_leave (&system_triplet, ide_triplet_new (ide_get_system_type ()));
+
+  return ide_triplet_ref (system_triplet);
+}
+
+/**
+ * ide_triplet_new_with_triplet:
+ * @arch: The name of the architecture of the machine (like "x86_64")
+ * @kernel: (nullable): The name of the kernel of the machine (like "linux")
+ * @operating_system: (nullable): The name of the os of the machine
+ * (like "gnuabi64")
+ *
+ * Creates a new #IdeTriplet from a given triplet of "arch-kernel-os"
+ * (like "x86_64-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_triplet_new_with_triplet (const gchar *arch,
+                              const gchar *kernel,
+                              const gchar *operating_system)
+{
+  IdeTriplet *self;
+  g_autofree gchar *full_name = NULL;
+
+  g_return_val_if_fail (arch != NULL, NULL);
+
+  self = _ide_triplet_construct ();
+  self->arch = g_strdup (arch);
+  self->kernel = g_strdup (kernel);
+  self->operating_system = g_strdup (operating_system);
+
+  full_name = g_strdup (arch);
+  if (kernel != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
+    }
+
+  if (operating_system != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
+    }
+
+  self->full_name = g_steal_pointer (&full_name);
+
+  return self;
+}
+
+/**
+ * ide_triplet_new_with_quadruplet:
+ * @arch: The name of the architecture of the machine (like "x86_64")
+ * @vendor: (nullable): The name of the vendor of the machine (like "pc")
+ * @kernel: (nullable): The name of the kernel of the machine (like "linux")
+ * @operating_system: (nullable): The name of the os of the machine (like "gnuabi64")
+ *
+ * Creates a new #IdeTriplet from a given quadruplet of 
+ * "arch-vendor-kernel-os" (like "i686-pc-linux-gnu")
+ *
+ * Returns: (transfer full): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_triplet_new_with_quadruplet (const gchar *arch,
+                                 const gchar *vendor,
+                                 const gchar *kernel,
+                                 const gchar *operating_system)
+{
+  IdeTriplet *self;
+  g_autofree gchar *full_name = NULL;
+
+  g_return_val_if_fail (arch != NULL, NULL);
+
+  if (vendor == NULL)
+    return ide_triplet_new_with_triplet (arch, kernel, operating_system);
+
+  self = _ide_triplet_construct ();
+  self->arch = g_strdup (arch);
+  self->vendor = g_strdup (vendor);
+  self->kernel = g_strdup (kernel);
+  self->operating_system = g_strdup (operating_system);
+
+  full_name = g_strdup_printf ("%s-%s", arch, vendor);
+  if (kernel != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, kernel);
+    }
+
+  if (operating_system != NULL)
+    {
+      g_autofree gchar *start_full_name = full_name;
+      full_name = g_strdup_printf ("%s-%s", start_full_name, operating_system);
+    }
+
+  self->full_name = g_steal_pointer (&full_name);
+
+  return self;
+}
+
+static void
+ide_triplet_finalize (IdeTriplet *self)
+{
+  g_free (self->full_name);
+  g_free (self->arch);
+  g_free (self->vendor);
+  g_free (self->kernel);
+  g_free (self->operating_system);
+  g_slice_free (IdeTriplet, self);
+}
+
+/**
+ * ide_triplet_ref:
+ * @self: An #IdeTriplet
+ *
+ * Increases the reference count of @self
+ *
+ * Returns: (transfer none): An #IdeTriplet.
+ *
+ * Since: 3.30
+ */
+IdeTriplet *
+ide_triplet_ref (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+  g_return_val_if_fail (self->ref_count > 0, NULL);
+
+  g_atomic_int_inc (&self->ref_count);
+
+  return self;
+}
+
+/**
+ * ide_triplet_unref:
+ * @self: An #IdeTriplet
+ *
+ * Decreases the reference count of @self
+ * Once the reference count reaches 0, the object is freed.
+ *
+ * Since: 3.30
+ */
+void
+ide_triplet_unref (IdeTriplet *self)
+{
+  g_return_if_fail (self);
+  g_return_if_fail (self->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&self->ref_count))
+    ide_triplet_finalize (self);
+}
+
+/**
+ * ide_triplet_get_full_name:
+ * @self: An #IdeTriplet
+ *
+ * Gets the full name of the machine configuration name (can be an architecture name,
+ * a duet, a triplet or a quadruplet).
+ *
+ * Returns: (transfer none): The full name of the machine configuration name
+ *
+ * Since: 3.30
+ */
+const gchar *
+ide_triplet_get_full_name (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->full_name;
+}
+
+/**
+ * ide_triplet_get_arch:
+ * @self: An #IdeTriplet
+ *
+ * Gets the architecture name of the machine
+ *
+ * Returns: (transfer none): The architecture name of the machine
+ */
+const gchar *
+ide_triplet_get_arch (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->arch;
+}
+
+/**
+ * ide_triplet_get_vendor:
+ * @self: An #IdeTriplet
+ *
+ * Gets the vendor name of the machine
+ *
+ * Returns: (transfer none) (nullable): The vendor name of the machine
+ *
+ * Since: 3.30
+ */
+const gchar *
+ide_triplet_get_vendor (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->vendor;
+}
+
+/**
+ * ide_triplet_get_kernel:
+ * @self: An #IdeTriplet
+ *
+ * Gets name of the kernel of the machine
+ *
+ * Returns: (transfer none) (nullable): The name of the kernel of the machine
+ *
+ * Since: 3.30
+ */
+const gchar *
+ide_triplet_get_kernel (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->kernel;
+}
+
+/**
+ * ide_triplet_get_operating_system:
+ * @self: An #IdeTriplet
+ *
+ * Gets name of the operating system of the machine
+ *
+ * Returns: (transfer none) (nullable): The name of the operating system of the machine
+ *
+ * Since: 3.30
+ */
+const gchar *
+ide_triplet_get_operating_system (IdeTriplet *self)
+{
+  g_return_val_if_fail (self, NULL);
+
+  return self->operating_system;
+}
+
+
+/**
+ * ide_triplet_is_system:
+ * @self: An #IdeTriplet
+ *
+ * Gets whether this is the same architecture as the system
+ *
+ * Returns: %TRUE if this is the same architecture as the system, %FALSE otherwise
+ *
+ * Since: 3.30
+ */
+gboolean
+ide_triplet_is_system (IdeTriplet *self)
+{
+  g_autofree gchar *system_arch = ide_get_system_arch ();
+
+  g_return_val_if_fail (self, FALSE);
+
+  return g_strcmp0 (self->arch, system_arch) == 0;
+}
diff --git a/src/libide/util/ide-triplet.h b/src/libide/util/ide-triplet.h
new file mode 100644
index 000000000..91553019d
--- /dev/null
+++ b/src/libide/util/ide-triplet.h
@@ -0,0 +1,66 @@
+/* ide-triplet.c
+ *
+ * Copyright (C) 2018 Corentin Noël <corentin noel collabora com>
+ * Copyright (C) 2018 Collabora Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+
+#include "ide-version-macros.h"
+
+G_BEGIN_DECLS
+
+#define IDE_TYPE_TRIPLET (ide_triplet_get_type())
+
+typedef struct _IdeTriplet IdeTriplet;
+
+IDE_AVAILABLE_IN_3_30
+GType         ide_triplet_get_type             (void);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet   *ide_triplet_new                  (const gchar  *full_name);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet   *ide_triplet_new_from_system      (void);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet   *ide_triplet_new_with_triplet     (const gchar  *arch,
+                                                const gchar  *kernel,
+                                                const gchar  *operating_system);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet   *ide_triplet_new_with_quadruplet  (const gchar  *arch,
+                                                const gchar  *vendor,
+                                                const gchar  *kernel,
+                                                const gchar  *operating_system);
+IDE_AVAILABLE_IN_3_30
+IdeTriplet   *ide_triplet_ref                  (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+void          ide_triplet_unref                (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+const gchar  *ide_triplet_get_full_name        (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+const gchar  *ide_triplet_get_arch             (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+const gchar  *ide_triplet_get_vendor           (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+const gchar  *ide_triplet_get_kernel           (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+const gchar  *ide_triplet_get_operating_system (IdeTriplet   *self);
+IDE_AVAILABLE_IN_3_30
+gboolean      ide_triplet_is_system            (IdeTriplet   *self);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (IdeTriplet, ide_triplet_unref)
+
+G_END_DECLS
diff --git a/src/libide/util/meson.build b/src/libide/util/meson.build
index ddba1c9e8..46d0f51c0 100644
--- a/src/libide/util/meson.build
+++ b/src/libide/util/meson.build
@@ -10,6 +10,7 @@ util_headers = [
   'ide-progress.h',
   'ide-ref-ptr.h',
   'ide-settings.h',
+  'ide-triplet.h',
   'ide-uri.h',
 ]
 
@@ -24,6 +25,7 @@ util_sources = [
   'ide-progress.c',
   'ide-ref-ptr.c',
   'ide-settings.c',
+  'ide-triplet.c',
   'ide-uri.c',
 ]
 
diff --git a/src/plugins/autotools/ide-autotools-pipeline-addin.c 
b/src/plugins/autotools/ide-autotools-pipeline-addin.c
index 8a0bb2b1a..ce3853a8a 100644
--- a/src/plugins/autotools/ide-autotools-pipeline-addin.c
+++ b/src/plugins/autotools/ide-autotools-pipeline-addin.c
@@ -168,7 +168,7 @@ register_configure_stage (IdeAutotoolsPipelineAddin  *self,
   IdeConfiguration *configuration;
   g_autofree gchar *configure_path = NULL;
   g_autofree gchar *host_arg = NULL;
-  const gchar *system_type;
+  g_autoptr(IdeTriplet) triplet = NULL;
   const gchar *config_opts;
   const gchar *prefix;
   guint stage_id;
@@ -189,8 +189,8 @@ register_configure_stage (IdeAutotoolsPipelineAddin  *self,
 
   /* --host=triplet */
   configuration = ide_build_pipeline_get_configuration (pipeline);
-  system_type = ide_build_pipeline_get_system_type (pipeline);
-  host_arg = g_strdup_printf ("--host=%s", system_type);
+  triplet = ide_build_pipeline_get_host_triplet (pipeline);
+  host_arg = g_strdup_printf ("--host=%s", ide_triplet_get_full_name (triplet));
   ide_subprocess_launcher_push_argv (launcher, host_arg);
 
   /*
diff --git a/src/plugins/cargo/cargo_plugin.py b/src/plugins/cargo/cargo_plugin.py
index 082fdb0fe..db2565785 100644
--- a/src/plugins/cargo/cargo_plugin.py
+++ b/src/plugins/cargo/cargo_plugin.py
@@ -131,7 +131,7 @@ class CargoPipelineAddin(Ide.Object, Ide.BuildPipelineAddin):
 
         if not pipeline.is_native():
             build_launcher.push_argv('--target')
-            build_launcher.push_argv(pipeline.get_system_type())
+            build_launcher.push_argv(pipeline.get_host_triplet().get_full_name())
 
         if config.props.parallelism > 0:
             build_launcher.push_argv('-j{}'.format(config.props.parallelism))
diff --git a/src/plugins/deviced/gbp-deviced-deploy-strategy.c 
b/src/plugins/deviced/gbp-deviced-deploy-strategy.c
index c3042df10..f7ff757a4 100644
--- a/src/plugins/deviced/gbp-deviced-deploy-strategy.c
+++ b/src/plugins/deviced/gbp-deviced-deploy-strategy.c
@@ -179,6 +179,7 @@ deploy_get_commit_cb (GObject      *object,
   g_autofree gchar *staging_dir = NULL;
   g_autoptr(IdeSubprocess) subprocess = NULL;
   g_autoptr(GError) error = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
   IdeConfiguration *config;
   const gchar *arch;
   const gchar *app_id;
@@ -200,7 +201,8 @@ deploy_get_commit_cb (GObject      *object,
 
   context = ide_object_get_context (IDE_OBJECT (state->pipeline));
   config = ide_build_pipeline_get_configuration (state->pipeline);
-  arch = ide_build_pipeline_get_arch (state->pipeline);
+  triplet = ide_build_pipeline_get_host_triplet (state->pipeline);
+  arch = ide_triplet_get_arch (triplet);
   staging_dir = gbp_flatpak_get_staging_dir (state->pipeline);
   repo_dir = gbp_flatpak_get_repo_dir (context);
   app_id = ide_configuration_get_app_id (config);
@@ -303,6 +305,7 @@ gbp_deviced_deploy_strategy_deploy_async (IdeDeployStrategy     *strategy,
 {
   GbpDevicedDeployStrategy *self = (GbpDevicedDeployStrategy *)strategy;
   g_autoptr(IdeTask) task = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
   IdeConfiguration *config;
   DeployState *state;
   const gchar *app_id;
@@ -320,7 +323,8 @@ gbp_deviced_deploy_strategy_deploy_async (IdeDeployStrategy     *strategy,
 
   config = ide_build_pipeline_get_configuration (pipeline);
   device = ide_build_pipeline_get_device (pipeline);
-  arch = ide_build_pipeline_get_arch (pipeline);
+  triplet = ide_build_pipeline_get_host_triplet (pipeline);
+  arch = ide_triplet_get_arch (triplet);
   app_id = ide_configuration_get_app_id (config);
 
   g_assert (GBP_IS_FLATPAK_MANIFEST (config));
diff --git a/src/plugins/deviced/gbp-deviced-device.c b/src/plugins/deviced/gbp-deviced-device.c
index cc6fd09d7..21ee396c5 100644
--- a/src/plugins/deviced/gbp-deviced-device.c
+++ b/src/plugins/deviced/gbp-deviced-device.c
@@ -149,11 +149,13 @@ gbp_deviced_device_get_info_connect_cb (GObject      *object,
 {
   GbpDevicedDevice *self = (GbpDevicedDevice *)object;
   g_autoptr(IdeDeviceInfo) info = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
   g_autoptr(GError) error = NULL;
   g_autoptr(IdeTask) task = user_data;
   g_autofree gchar *arch = NULL;
   g_autofree gchar *kernel = NULL;
   g_autofree gchar *system = NULL;
+  IdeDeviceKind kind = 0;
   DevdClient *client;
 
   g_assert (GBP_IS_DEVICED_DEVICE (self));
@@ -169,12 +171,31 @@ gbp_deviced_device_get_info_connect_cb (GObject      *object,
   arch = devd_client_get_arch (client);
   kernel = devd_client_get_kernel (client);
   system = devd_client_get_system (client);
+  triplet = ide_triplet_new_with_triplet (arch, kernel, system);
 
-  info = g_object_new (IDE_TYPE_DEVICE_INFO,
-                       "arch", arch,
-                       "kernel", kernel,
-                       "system", system,
-                       NULL);
+  switch (devd_device_get_kind (self->device))
+    {
+    case DEVD_DEVICE_KIND_TABLET:
+      kind = IDE_DEVICE_KIND_TABLET;
+      break;
+
+    case DEVD_DEVICE_KIND_PHONE:
+      kind = IDE_DEVICE_KIND_PHONE;
+      break;
+
+    case DEVD_DEVICE_KIND_MICRO_CONTROLLER:
+      kind = IDE_DEVICE_KIND_MICRO_CONTROLLER;
+      break;
+
+    case DEVD_DEVICE_KIND_COMPUTER:
+    default:
+      kind = IDE_DEVICE_KIND_COMPUTER;
+      break;
+    }
+
+  info = ide_device_info_new ();
+  ide_device_info_set_kind (info, kind);
+  ide_device_info_set_host_triplet (info, triplet);
 
   ide_task_return_pointer (task, g_steal_pointer (&info), g_object_unref);
 }
diff --git a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c 
b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
index 0939d0ec2..e6fd994d9 100644
--- a/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
+++ b/src/plugins/flatpak/gbp-flatpak-runtime-provider.c
@@ -603,6 +603,7 @@ gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
   g_autofree gchar *arch = NULL;
   g_autofree gchar *branch = NULL;
   g_autoptr(IdeTask) task = NULL;
+  g_autoptr(IdeTriplet) triplet = NULL;
   IdeConfiguration *config;
   BootstrapState *state;
   const gchar *runtime_id;
@@ -618,7 +619,8 @@ gbp_flatpak_runtime_provider_bootstrap_async (IdeRuntimeProvider  *provider,
   ide_task_set_source_tag (task, gbp_flatpak_runtime_provider_bootstrap_async);
   ide_task_set_priority (task, G_PRIORITY_LOW);
 
-  build_arch = ide_build_pipeline_get_arch (pipeline);
+  triplet = ide_build_pipeline_get_host_triplet (pipeline);
+  build_arch = ide_triplet_get_arch (triplet);
   config = ide_build_pipeline_get_configuration (pipeline);
   runtime_id = ide_configuration_get_runtime_id (config);
 
diff --git a/src/plugins/flatpak/gbp-flatpak-util.c b/src/plugins/flatpak/gbp-flatpak-util.c
index 16ed191f7..7a25eed0e 100644
--- a/src/plugins/flatpak/gbp-flatpak-util.c
+++ b/src/plugins/flatpak/gbp-flatpak-util.c
@@ -34,7 +34,7 @@ gbp_flatpak_get_staging_dir (IdeBuildPipeline *pipeline)
 {
   g_autofree gchar *branch = NULL;
   g_autofree gchar *name = NULL;
-  const gchar *arch;
+  g_autoptr (IdeTriplet) triplet = NULL;
   IdeContext *context;
   IdeVcs *vcs;
 
@@ -43,8 +43,8 @@ gbp_flatpak_get_staging_dir (IdeBuildPipeline *pipeline)
   context = ide_object_get_context (IDE_OBJECT (pipeline));
   vcs = ide_context_get_vcs (context);
   branch = ide_vcs_get_branch_name (vcs);
-  arch = ide_build_pipeline_get_arch (pipeline);
-  name = g_strdup_printf ("%s-%s", arch, branch);
+  triplet = ide_build_pipeline_get_host_triplet (pipeline);
+  name = g_strdup_printf ("%s-%s", ide_triplet_get_arch (triplet), branch);
 
   g_strdelimit (name, G_DIR_SEPARATOR_S, '-');
 
diff --git a/src/plugins/npm/npm_plugin.py b/src/plugins/npm/npm_plugin.py
index bf4041889..f77a4e187 100644
--- a/src/plugins/npm/npm_plugin.py
+++ b/src/plugins/npm/npm_plugin.py
@@ -104,7 +104,7 @@ class NPMPipelineAddin(Ide.Object, Ide.BuildPipelineAddin):
         fetch_launcher.push_argv(npm)
         if not pipeline.is_native():
             fetch_launcher.push_argv('--arch')
-            fetch_launcher.push_argv(pipeline.get_arch())
+            fetch_launcher.push_argv(pipeline.get_host_triplet().get_arch())
         fetch_launcher.push_argv('install')
         self.track(pipeline.connect_launcher(Ide.BuildPhase.DOWNLOADS, 0, fetch_launcher))
 
diff --git a/src/plugins/qemu/gbp-qemu-device-provider.c b/src/plugins/qemu/gbp-qemu-device-provider.c
index db607b033..6c1f4732c 100644
--- a/src/plugins/qemu/gbp-qemu-device-provider.c
+++ b/src/plugins/qemu/gbp-qemu-device-provider.c
@@ -148,6 +148,7 @@ gbp_qemu_device_provider_load_worker (IdeTask      *task,
           has_flag (contents, len, 'F'))
         {
           g_autoptr(IdeLocalDevice) device = NULL;
+          g_autoptr(IdeTriplet) triplet = NULL;
           g_autofree gchar *display_name = NULL;
 
           IDE_TRACE_MSG ("Discovered QEMU device \"%s\"\n", machines[i].arch);
@@ -157,9 +158,10 @@ gbp_qemu_device_provider_load_worker (IdeTask      *task,
                                           g_get_host_name (),
                                           machines[i].suffix);
 
+          triplet = ide_triplet_new (machines[i].arch);
           device = g_object_new (IDE_TYPE_LOCAL_DEVICE,
                                  "id", machines[i].filename,
-                                 "arch", machines[i].arch,
+                                 "triplet", triplet,
                                  "context", context,
                                  "display-name", display_name,
                                  NULL);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]