[gnome-builder] util: add non-canonical relative path helper
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder] util: add non-canonical relative path helper
- Date: Tue, 5 Dec 2017 00:55:09 +0000 (UTC)
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]