[gnome-builder] util: add non-canonical relative path helper



commit 1b7114b77c22aea9651a438865d25f4a884641ad
Author: Christian Hergert <chergert redhat com>
Date:   Mon Dec 4 16:54:37 2017 -0800

    util: add non-canonical relative path helper
    
    There may be some cases where we need to get a non-canonical path relative
    to a given directory. This tries to handle that by resolving relative paths
    from the base file and returning a path with a number of ../ in them.
    
    The driving force for this is that gdb seems to want paths like this in
    some cases.

 src/libide/util/ide-glib.c |   82 ++++++++++++++++++++++++++++++++++++++++++++
 src/libide/util/ide-glib.h |   22 ++++++-----
 src/tests/meson.build      |    6 +++
 src/tests/test-ide-glib.c  |   44 +++++++++++++++++++++++
 4 files changed, 144 insertions(+), 10 deletions(-)
---
diff --git a/src/libide/util/ide-glib.c b/src/libide/util/ide-glib.c
index bd46505..c41cadc 100644
--- a/src/libide/util/ide-glib.c
+++ b/src/libide/util/ide-glib.c
@@ -18,6 +18,8 @@
 
 #define G_LOG_DOMAIN "ide-glib"
 
+#include <string.h>
+
 #include "config.h"
 
 #include "util/ide-glib.h"
@@ -181,3 +183,83 @@ ide_gettext (const gchar *message)
     return g_dgettext (GETTEXT_PACKAGE, message);
   return NULL;
 }
+
+/**
+ * ide_g_file_get_uncanonical_relative_path:
+ * @file: a #GFile
+ * @other: a #GFile with a common ancestor to @file
+ *
+ * This function is similar to g_file_get_relative_path() except that
+ * @file and @other only need to have a shared common ancestor.
+ *
+ * This is useful if you must use a relative path instead of the absolute,
+ * canonical path.
+ *
+ * This is being implemented for use when communicating to GDB. When that
+ * becomes unnecessary, this should no longer be used.
+ *
+ * Returns: (nullable): A relative path, or %NULL if no common ancestor was
+ *   found for the relative path.
+ *
+ * Since: 3.28
+ */
+gchar *
+ide_g_file_get_uncanonical_relative_path (GFile *file,
+                                          GFile *other)
+{
+  g_autoptr(GFile) ancestor = NULL;
+  g_autoptr(GString) relatives = NULL;
+  g_autofree gchar *scheme = NULL;
+  g_autofree gchar *path = NULL;
+  g_autofree gchar *suffix = NULL;
+
+  g_return_val_if_fail (G_IS_FILE (file), NULL);
+  g_return_val_if_fail (G_IS_FILE (other), NULL);
+
+  /* Nothing for matching files */
+  if (file == other || g_file_equal (file, other))
+    return NULL;
+
+  /* Make sure we're working with files of the same type */
+  if (G_OBJECT_TYPE (file) != G_OBJECT_TYPE (other))
+    return NULL;
+
+  /* Already descendant, just give the actual path */
+  if (g_file_has_prefix (other, file))
+    return g_file_get_path (other);
+
+  relatives = g_string_new ("/");
+
+  /* Find the common ancestor */
+  ancestor = g_object_ref (file);
+  while (ancestor != NULL &&
+         !g_file_has_prefix (other, ancestor) &&
+         !g_file_equal (other, ancestor))
+    {
+      g_autoptr(GFile) parent = g_file_get_parent (ancestor);
+
+      /* We reached the root, nothing more to do */
+      if (g_file_equal (parent, ancestor))
+        return NULL;
+
+      g_string_append_len (relatives, "../", strlen ("../"));
+
+      g_clear_object (&ancestor);
+      ancestor = g_steal_pointer (&parent);
+    }
+
+  g_assert (G_IS_FILE (ancestor));
+  g_assert (g_file_has_prefix (other, ancestor));
+  g_assert (g_file_has_prefix (file, ancestor));
+
+  path = g_file_get_path (file);
+  suffix = g_file_get_relative_path (ancestor, other);
+
+  if (path == NULL)
+    path = g_strdup ("/");
+
+  if (suffix == NULL)
+    suffix = g_strdup ("/");
+
+  return g_build_filename (path, relatives->str, suffix, NULL);
+}
diff --git a/src/libide/util/ide-glib.h b/src/libide/util/ide-glib.h
index 53a0a80..ccda75b 100644
--- a/src/libide/util/ide-glib.h
+++ b/src/libide/util/ide-glib.h
@@ -22,15 +22,17 @@
 
 G_BEGIN_DECLS
 
-const gchar *ide_gettext                         (const gchar    *message);
-void         ide_g_task_return_boolean_from_main (GTask          *task,
-                                                  gboolean        value);
-void         ide_g_task_return_int_from_main     (GTask          *task,
-                                                  gint            value);
-void         ide_g_task_return_pointer_from_main (GTask          *task,
-                                                  gpointer        value,
-                                                  GDestroyNotify  notify);
-void         ide_g_task_return_error_from_main   (GTask          *task,
-                                                  GError         *error);
+const gchar *ide_gettext                              (const gchar    *message);
+void         ide_g_task_return_boolean_from_main      (GTask          *task,
+                                                       gboolean        value);
+void         ide_g_task_return_int_from_main          (GTask          *task,
+                                                       gint            value);
+void         ide_g_task_return_pointer_from_main      (GTask          *task,
+                                                       gpointer        value,
+                                                       GDestroyNotify  notify);
+void         ide_g_task_return_error_from_main        (GTask          *task,
+                                                       GError         *error);
+gchar       *ide_g_file_get_uncanonical_relative_path (GFile          *file,
+                                                       GFile          *other);
 
 G_END_DECLS
diff --git a/src/tests/meson.build b/src/tests/meson.build
index 8e407d5..177a839 100644
--- a/src/tests/meson.build
+++ b/src/tests/meson.build
@@ -159,3 +159,9 @@ test_snippet_parser = executable('test-snippet-parser',
 #  env: ide_test_env,
 #)
 
+
+test_ide_glib = executable('test-ide-glib', 'test-ide-glib.c',
+  c_args: ide_test_cflags,
+  dependencies: [ ide_test_deps ],
+)
+test('test-ide-glib', test_ide_glib, env: ide_test_env)
diff --git a/src/tests/test-ide-glib.c b/src/tests/test-ide-glib.c
new file mode 100644
index 0000000..5c95170
--- /dev/null
+++ b/src/tests/test-ide-glib.c
@@ -0,0 +1,44 @@
+#include <ide.h>
+
+#include "util/ide-glib.h"
+
+static void
+test_uncanonical_file (void)
+{
+  static const struct {
+    const gchar *file;
+    const gchar *other;
+    const gchar *result;
+  } tests[] = {
+    { 
"/home/alberto/.var/app/org.gnome.Builder/cache/gnome-builder/projects/gtask-example/builds/org.gnome.Gtask-Example.json-0601fcfb2fbf01231dd228e0b218301c589ae573-local-flatpak-org.gnome.Platform-x86_64-master",
+      "/home/alberto/Projects/gtask-example/src/main.c",
+      
"/home/alberto/.var/app/org.gnome.Builder/cache/gnome-builder/projects/gtask-example/builds/org.gnome.Gtask-Example.json-0601fcfb2fbf01231dd228e0b218301c589ae573-local-flatpak-org.gnome.Platform-x86_64-master/../../../../../../../../../Projects/gtask-example/src/main.c"
 },
+    { "/home/xtian/foo",
+      "/home/xtian/foo/bar",
+      "/home/xtian/foo/bar" },
+    { "/home/xtian/foo",
+      "/home/xtian/bar",
+      "/home/xtian/foo/../bar" },
+    { "/home/xtian/foo",
+      "/",
+      "/home/xtian/foo/../../../" },
+  };
+
+  for (guint i = 0; i < G_N_ELEMENTS (tests); i++)
+    {
+      g_autoptr(GFile) file = g_file_new_for_path (tests[i].file);
+      g_autoptr(GFile) other = g_file_new_for_path (tests[i].other);
+      g_autofree gchar *result = ide_g_file_get_uncanonical_relative_path (file, other);
+
+      g_assert_cmpstr (tests[i].result, ==, result);
+    }
+}
+
+gint
+main (gint argc,
+      gchar *argv[])
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_add_func ("/Ide/GLib/uncanonical-file", test_uncanonical_file);
+  return g_test_run ();
+}


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