summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/xdg-app-builtins-install.c8
-rw-r--r--app/xdg-app-builtins-update.c11
-rw-r--r--common/xdg-app-dir.c234
-rw-r--r--common/xdg-app-dir.h10
-rw-r--r--doc/xdg-app-install.xml9
-rw-r--r--doc/xdg-app-update.xml10
-rw-r--r--lib/xdg-app-installation.c14
-rw-r--r--lib/xdg-app-installed-ref-private.h1
-rw-r--r--lib/xdg-app-installed-ref.c27
-rw-r--r--lib/xdg-app-installed-ref.h13
10 files changed, 305 insertions, 32 deletions
diff --git a/app/xdg-app-builtins-install.c b/app/xdg-app-builtins-install.c
index 73ec2bc..e8634a6 100644
--- a/app/xdg-app-builtins-install.c
+++ b/app/xdg-app-builtins-install.c
@@ -36,6 +36,7 @@
static char *opt_arch;
static char **opt_gpg_file;
+static char **opt_subpaths;
static gboolean opt_no_pull;
static gboolean opt_no_deploy;
static gboolean opt_runtime;
@@ -50,6 +51,7 @@ static GOptionEntry options[] = {
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, "Look for app with the specified name", },
{ "bundle", 0, 0, G_OPTION_ARG_NONE, &opt_bundle, "Install from local bundle file", },
{ "gpg-file", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_gpg_file, "Check bundle signatures with GPG key from FILE (- for stdin)", "FILE" },
+ { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only install this subpath", "path" },
{ NULL }
};
@@ -286,7 +288,7 @@ xdg_app_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
if (!opt_no_pull)
{
- if (!xdg_app_dir_pull (dir, repository, ref, NULL,
+ if (!xdg_app_dir_pull (dir, repository, ref, opt_subpaths, NULL,
cancellable, error))
return FALSE;
}
@@ -306,6 +308,10 @@ xdg_app_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro
if (!xdg_app_dir_set_origin (dir, ref, repository, cancellable, error))
goto out;
+ if (!xdg_app_dir_set_subpaths (dir, ref, (const char **)opt_subpaths,
+ cancellable, error))
+ goto out;
+
if (!xdg_app_dir_deploy (dir, ref, NULL, cancellable, error))
goto out;
diff --git a/app/xdg-app-builtins-update.c b/app/xdg-app-builtins-update.c
index 5903973..15a1475 100644
--- a/app/xdg-app-builtins-update.c
+++ b/app/xdg-app-builtins-update.c
@@ -33,6 +33,7 @@
static char *opt_arch;
static char *opt_commit;
+static char **opt_subpaths;
static gboolean opt_force_remove;
static gboolean opt_no_pull;
static gboolean opt_no_deploy;
@@ -49,6 +50,7 @@ static GOptionEntry options[] = {
{ "runtime", 0, 0, G_OPTION_ARG_NONE, &opt_runtime, "Look for runtime with the specified name", },
{ "app", 0, 0, G_OPTION_ARG_NONE, &opt_app, "Look for app with the specified name", },
{ "appstream", 0, 0, G_OPTION_ARG_NONE, &opt_appstream, "Update appstream for remote", },
+ { "subpath", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &opt_subpaths, "Only update this subpath", "path" },
{ NULL }
};
@@ -75,6 +77,7 @@ do_update (XdgAppDir* dir,
{
g_autofree char *ref = NULL;
g_autofree char *repository = NULL;
+ g_auto(GStrv) subpaths = NULL;
gboolean was_updated = FALSE;
gboolean is_app;
g_auto(GLnxLockFile) lock = GLNX_LOCK_FILE_INIT;
@@ -92,10 +95,14 @@ do_update (XdgAppDir* dir,
if (repository == NULL)
return FALSE;
+ subpaths = xdg_app_dir_get_subpaths (dir, ref, cancellable, error);
+ if (subpaths == NULL)
+ return FALSE;
+
if (!opt_no_pull)
{
- if (!xdg_app_dir_pull (dir, repository, ref, NULL,
- cancellable, error))
+ if (!xdg_app_dir_pull (dir, repository, ref, opt_subpaths ? opt_subpaths : subpaths,
+ NULL, cancellable, error))
return FALSE;
}
diff --git a/common/xdg-app-dir.c b/common/xdg-app-dir.c
index 6d3ce82..6cb2672 100644
--- a/common/xdg-app-dir.c
+++ b/common/xdg-app-dir.c
@@ -521,6 +521,80 @@ xdg_app_dir_set_origin (XdgAppDir *self,
return TRUE;
}
+char **
+xdg_app_dir_get_subpaths (XdgAppDir *self,
+ const char *ref,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GFile) deploy_base = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autofree char *data = NULL;
+ g_autoptr(GError) my_error = NULL;
+ g_autoptr(GPtrArray) subpaths = NULL;
+ g_auto(GStrv) lines = NULL;
+ int i;
+
+ deploy_base = xdg_app_dir_get_deploy_dir (self, ref);
+ if (!g_file_query_exists (deploy_base, cancellable))
+ {
+ xdg_app_fail (error, "%s is not installed", ref);
+ return NULL;
+ }
+
+ file = g_file_get_child (deploy_base, "subpaths");
+ if (!g_file_load_contents (file, cancellable, &data, NULL, NULL, &my_error))
+ {
+ if (g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
+ data = g_strdup ("");
+ else
+ g_propagate_error (error, g_steal_pointer (&my_error));
+
+ return NULL;
+ }
+
+ lines = g_strsplit (data, "\n", 0);
+
+ subpaths = g_ptr_array_new ();
+ for (i = 0; lines[i] != NULL; i++)
+ {
+ lines[i] = g_strstrip (lines[i]);
+ if (lines[i][0] == '/')
+ g_ptr_array_add (subpaths, g_strdup (lines[i]));
+ }
+
+ g_ptr_array_add (subpaths, NULL);
+ return (char **)g_ptr_array_free (subpaths, FALSE);
+}
+
+gboolean
+xdg_app_dir_set_subpaths (XdgAppDir *self,
+ const char *ref,
+ const char **subpaths,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_autoptr(GFile) deploy_base = NULL;
+ g_autoptr(GFile) file = NULL;
+ g_autofree char *data = NULL;
+
+ deploy_base = xdg_app_dir_get_deploy_dir (self, ref);
+ if (!g_file_query_exists (deploy_base, cancellable))
+ {
+ xdg_app_fail (error, "%s is not installed", ref);
+ return FALSE;
+ }
+
+ data = g_strjoinv ("\n", (char **)subpaths);
+
+ file = g_file_get_child (deploy_base, "subpaths");
+ if (!g_file_replace_contents (file, data, strlen (data), NULL, FALSE,
+ G_FILE_CREATE_NONE, NULL, cancellable, error))
+ return FALSE;
+
+ return TRUE;
+}
+
gboolean
xdg_app_dir_ensure_path (XdgAppDir *self,
GCancellable *cancellable,
@@ -690,7 +764,7 @@ xdg_app_dir_update_appstream (XdgAppDir *self,
if (!ostree_repo_resolve_rev (self->repo, remote_and_branch, TRUE, &old_checksum, error))
return FALSE;
- if (!xdg_app_dir_pull (self, remote, branch, progress,
+ if (!xdg_app_dir_pull (self, remote, branch, NULL, progress,
cancellable, error))
return FALSE;
@@ -785,10 +859,45 @@ xdg_app_dir_update_appstream (XdgAppDir *self,
return TRUE;
}
+/* This is a copy of ostree_repo_pull_one_dir that always disables
+ static deltas if subdir is used */
+static gboolean
+repo_pull_one_dir (OstreeRepo *self,
+ const char *remote_name,
+ const char *dir_to_pull,
+ char **refs_to_fetch,
+ OstreeRepoPullFlags flags,
+ OstreeAsyncProgress *progress,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariantBuilder builder;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (dir_to_pull)
+ {
+ g_variant_builder_add (&builder, "{s@v}", "subdir",
+ g_variant_new_variant (g_variant_new_string (dir_to_pull)));
+ g_variant_builder_add (&builder, "{s@v}", "disable-static-deltas",
+ g_variant_new_variant (g_variant_new_boolean (TRUE)));
+ }
+
+ g_variant_builder_add (&builder, "{s@v}", "flags",
+ g_variant_new_variant (g_variant_new_int32 (flags)));
+ if (refs_to_fetch)
+ g_variant_builder_add (&builder, "{s@v}", "refs",
+ g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch, -1)));
+
+ return ostree_repo_pull_with_options (self, remote_name, g_variant_builder_end (&builder),
+ progress, cancellable, error);
+}
+
+
gboolean
xdg_app_dir_pull (XdgAppDir *self,
const char *repository,
const char *ref,
+ char **subpaths,
OstreeAsyncProgress *progress,
GCancellable *cancellable,
GError **error)
@@ -825,13 +934,46 @@ xdg_app_dir_pull (XdgAppDir *self,
refs[0] = ref;
refs[1] = NULL;
- if (!ostree_repo_pull (self->repo, repository,
- (char **)refs, OSTREE_REPO_PULL_FLAGS_NONE,
- progress,
- cancellable, error))
+ if (subpaths == NULL || subpaths[0] == NULL)
{
- g_prefix_error (error, "While pulling %s from remote %s: ", ref, repository);
- goto out;
+ if (!ostree_repo_pull (self->repo, repository,
+ (char **)refs, OSTREE_REPO_PULL_FLAGS_NONE,
+ progress,
+ cancellable, error))
+ {
+ g_prefix_error (error, "While pulling %s from remote %s: ", ref, repository);
+ goto out;
+ }
+ }
+ else
+ {
+ int i;
+
+ if (!repo_pull_one_dir (self->repo, repository,
+ "/metadata",
+ (char **)refs, OSTREE_REPO_PULL_FLAGS_NONE,
+ progress,
+ cancellable, error))
+ {
+ g_prefix_error (error, "While pulling %s from remote %s, metadata: ",
+ ref, repository);
+ goto out;
+ }
+
+ for (i = 0; subpaths[i] != NULL; i++)
+ {
+ g_autofree char *subpath = g_build_filename ("/files", subpaths[i], NULL);
+ if (!repo_pull_one_dir (self->repo, repository,
+ subpath,
+ (char **)refs, OSTREE_REPO_PULL_FLAGS_NONE,
+ progress,
+ cancellable, error))
+ {
+ g_prefix_error (error, "While pulling %s from remote %s, subpath %s: ",
+ ref, repository, subpaths[i]);
+ goto out;
+ }
+ }
}
ret = TRUE;
@@ -1916,6 +2058,7 @@ xdg_app_dir_deploy (XdgAppDir *self,
g_autoptr(GFile) export = NULL;
g_autoptr(OstreeAsyncProgress) progress = NULL;
g_autoptr(GKeyFile) keyfile = NULL;
+ g_auto(GStrv) subpaths = NULL;
if (!xdg_app_dir_ensure_repo (self, cancellable, error))
return FALSE;
@@ -1969,20 +2112,73 @@ xdg_app_dir_deploy (XdgAppDir *self,
if (file_info == NULL)
return FALSE;
- if (!ostree_repo_checkout_tree (self->repo,
- OSTREE_REPO_CHECKOUT_MODE_USER,
- OSTREE_REPO_CHECKOUT_OVERWRITE_NONE,
- checkoutdir,
- OSTREE_REPO_FILE (root), file_info,
- cancellable, error))
+ subpaths = xdg_app_dir_get_subpaths (self, ref, cancellable, error);
+ if (subpaths == NULL)
+ return FALSE;
+
+ if (*subpaths == NULL)
{
- g_autofree char *rootpath = NULL;
- g_autofree char *checkoutpath = NULL;
+ if (!ostree_repo_checkout_tree (self->repo,
+ OSTREE_REPO_CHECKOUT_MODE_USER,
+ OSTREE_REPO_CHECKOUT_OVERWRITE_NONE,
+ checkoutdir,
+ OSTREE_REPO_FILE (root), file_info,
+ cancellable, error))
+ {
+ g_autofree char *rootpath = NULL;
+ g_autofree char *checkoutpath = NULL;
- rootpath = g_file_get_path (root);
- checkoutpath = g_file_get_path (checkoutdir);
- g_prefix_error (error, "While trying to checkout %s into %s: ", rootpath, checkoutpath);
- return FALSE;
+ rootpath = g_file_get_path (root);
+ checkoutpath = g_file_get_path (checkoutdir);
+ g_prefix_error (error, "While trying to checkout %s into %s: ", rootpath, checkoutpath);
+ return FALSE;
+ }
+ }
+ else
+ {
+ OstreeRepoCheckoutOptions options = { 0, };
+ g_autofree char *checkoutdirpath = g_file_get_path (checkoutdir);
+ g_autoptr(GFile) files = g_file_get_child (checkoutdir, "files");
+ int i;
+
+ if (!g_file_make_directory_with_parents (files, cancellable, error))
+ return FALSE;
+
+ options.mode = OSTREE_REPO_CHECKOUT_MODE_USER;
+ options.overwrite_mode = OSTREE_REPO_CHECKOUT_OVERWRITE_UNION_FILES;
+ options.subpath = "/metadata";
+
+ access ("checkout metadata", 0);
+ if (!ostree_repo_checkout_tree_at (self->repo, &options,
+ AT_FDCWD, checkoutdirpath,
+ checksum,
+ cancellable, error))
+ {
+ g_prefix_error (error, "While trying to checkout metadata subpath: ");
+ return FALSE;
+ }
+
+ for (i = 0; subpaths[i] != NULL; i++)
+ {
+ g_autofree char *subpath = g_build_filename ("/files", subpaths[i], NULL);
+ g_autofree char *dstpath = g_build_filename (checkoutdirpath, "/files", subpaths[i], NULL);
+ g_autofree char *dstpath_parent = g_path_get_dirname (dstpath);
+ if (g_mkdir_with_parents (dstpath_parent, 0755))
+ {
+ glnx_set_error_from_errno (error);
+ return FALSE;
+ }
+
+ options.subpath = subpath;
+ if (!ostree_repo_checkout_tree_at (self->repo, &options,
+ AT_FDCWD, dstpath,
+ checksum,
+ cancellable, error))
+ {
+ g_prefix_error (error, "While trying to checkout metadata subpath: ");
+ return FALSE;
+ }
+ }
}
dotref = g_file_resolve_relative_path (checkoutdir, "files/.ref");
diff --git a/common/xdg-app-dir.h b/common/xdg-app-dir.h
index 8d73df1..6319921 100644
--- a/common/xdg-app-dir.h
+++ b/common/xdg-app-dir.h
@@ -88,6 +88,15 @@ gboolean xdg_app_dir_set_origin (XdgAppDir *self,
const char *remote,
GCancellable *cancellable,
GError **error);
+char ** xdg_app_dir_get_subpaths (XdgAppDir *self,
+ const char *ref,
+ GCancellable *cancellable,
+ GError **error);
+gboolean xdg_app_dir_set_subpaths (XdgAppDir *self,
+ const char *ref,
+ const char **subpaths,
+ GCancellable *cancellable,
+ GError **error);
GFile * xdg_app_dir_get_exports_dir (XdgAppDir *self);
GFile * xdg_app_dir_get_removed_dir (XdgAppDir *self);
GFile * xdg_app_dir_get_if_deployed (XdgAppDir *self,
@@ -144,6 +153,7 @@ gboolean xdg_app_dir_update_appstream(XdgAppDir *self,
gboolean xdg_app_dir_pull (XdgAppDir *self,
const char *repository,
const char *ref,
+ char **subpaths,
OstreeAsyncProgress *progress,
GCancellable *cancellable,
GError **error);
diff --git a/doc/xdg-app-install.xml b/doc/xdg-app-install.xml
index d15016f..0803a9c 100644
--- a/doc/xdg-app-install.xml
+++ b/doc/xdg-app-install.xml
@@ -105,6 +105,15 @@
</varlistentry>
<varlistentry>
+ <term><option>--subpath=PATH</option></term>
+
+ <listitem><para>
+ Install only a subpath of the ref. This is mainly used to install a subset of locales.
+ This can be added multiple times to install multiple subpaths.,
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--no-deploy</option></term>
<listitem><para>
diff --git a/doc/xdg-app-update.xml b/doc/xdg-app-update.xml
index f665160..8c29342 100644
--- a/doc/xdg-app-update.xml
+++ b/doc/xdg-app-update.xml
@@ -112,6 +112,16 @@
</varlistentry>
<varlistentry>
+ <term><option>--subpath=PATH</option></term>
+
+ <listitem><para>
+ Install only a subpath of the ref. This is mainly used to install a subset of locales.
+ This can be added multiple times to install multiple subpaths.
+ If this is not specified the subpaths specified at install time are reused.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--commit=COMMIT</option></term>
<listitem><para>
diff --git a/lib/xdg-app-installation.c b/lib/xdg-app-installation.c
index 3ca83b5..0219be4 100644
--- a/lib/xdg-app-installation.c
+++ b/lib/xdg-app-installation.c
@@ -290,6 +290,7 @@ get_ref (XdgAppInstallation *self,
g_autoptr(GFile) deploy_subdir = NULL;
g_autofree char *deploy_path = NULL;
g_autofree char *latest_commit = NULL;
+ g_auto(GStrv) subpaths = NULL;
gboolean is_current = FALSE;
guint64 installed_size = 0;
@@ -297,6 +298,8 @@ get_ref (XdgAppInstallation *self,
origin = xdg_app_dir_get_origin (priv->dir, full_ref, NULL, NULL);
commit = xdg_app_dir_read_active (priv->dir, full_ref, cancellable);
+ subpaths = xdg_app_dir_get_subpaths (priv->dir, full_ref, cancellable, NULL);
+
deploy_dir = xdg_app_dir_get_deploy_dir (priv->dir, full_ref);
if (deploy_dir && commit)
{
@@ -323,7 +326,7 @@ get_ref (XdgAppInstallation *self,
return xdg_app_installed_ref_new (full_ref,
commit,
latest_commit,
- origin,
+ origin, subpaths,
deploy_path,
installed_size,
is_current);
@@ -992,7 +995,7 @@ xdg_app_installation_install (XdgAppInstallation *self,
g_object_set_data (G_OBJECT (ostree_progress), "last_progress", GUINT_TO_POINTER(0));
}
- if (!xdg_app_dir_pull (dir_clone, remote_name, ref,
+ if (!xdg_app_dir_pull (dir_clone, remote_name, ref, NULL,
ostree_progress, cancellable, error))
goto out;
@@ -1088,6 +1091,7 @@ xdg_app_installation_update (XdgAppInstallation *self,
XdgAppInstalledRef *result = NULL;
gboolean was_updated = FALSE;
g_auto(GLnxLockFile) lock = GLNX_LOCK_FILE_INIT;
+ g_auto(GStrv) subpaths = NULL;
ref = xdg_app_compose_ref (kind == XDG_APP_REF_KIND_APP, name, branch, arch, error);
if (ref == NULL)
@@ -1106,6 +1110,10 @@ xdg_app_installation_update (XdgAppInstallation *self,
if (remote_name == NULL)
return NULL;
+ subpaths = xdg_app_dir_get_subpaths (priv->dir, ref, cancellable, error);
+ if (subpaths == NULL)
+ return FALSE;
+
/* Pull, prune, etc are not threadsafe, so we work on a copy */
dir_clone = xdg_app_dir_clone (priv->dir);
@@ -1122,7 +1130,7 @@ xdg_app_installation_update (XdgAppInstallation *self,
if ((flags & XDG_APP_UPDATE_FLAGS_NO_PULL) == 0)
{
- if (!xdg_app_dir_pull (dir_clone, remote_name, ref,
+ if (!xdg_app_dir_pull (dir_clone, remote_name, ref, subpaths,
ostree_progress, cancellable, error))
goto out;
}
diff --git a/lib/xdg-app-installed-ref-private.h b/lib/xdg-app-installed-ref-private.h
index c192aa6..3b7bb59 100644
--- a/lib/xdg-app-installed-ref-private.h
+++ b/lib/xdg-app-installed-ref-private.h
@@ -32,6 +32,7 @@ XdgAppInstalledRef *xdg_app_installed_ref_new (const char *full_ref,
const char *commit,
const char *latest_commit,
const char *origin,
+ char **subpaths,
const char *deploy_dir,
guint64 installed_size,
gboolean current);
diff --git a/lib/xdg-app-installed-ref.c b/lib/xdg-app-installed-ref.c
index da29742..853dc7b 100644
--- a/lib/xdg-app-installed-ref.c
+++ b/lib/xdg-app-installed-ref.c
@@ -44,6 +44,7 @@ struct _XdgAppInstalledRefPrivate
char *origin;
char *latest_commit;
char *deploy_dir;
+ char **subpaths;
guint64 installed_size;
};
@@ -56,7 +57,8 @@ enum {
PROP_ORIGIN,
PROP_LATEST_COMMIT,
PROP_DEPLOY_DIR,
- PROP_INSTALLED_SIZE
+ PROP_INSTALLED_SIZE,
+ PROP_SUBPATHS
};
static void
@@ -67,6 +69,7 @@ xdg_app_installed_ref_finalize (GObject *object)
g_free (priv->origin);
g_free (priv->deploy_dir);
+ g_strfreev (priv->subpaths);
G_OBJECT_CLASS (xdg_app_installed_ref_parent_class)->finalize (object);
}
@@ -105,6 +108,11 @@ xdg_app_installed_ref_set_property (GObject *object,
priv->deploy_dir = g_value_dup_string (value);
break;
+ case PROP_SUBPATHS:
+ g_clear_pointer (&priv->subpaths, g_strfreev);
+ priv->subpaths = g_strdupv (g_value_get_boxed (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -142,6 +150,10 @@ xdg_app_installed_ref_get_property (GObject *object,
g_value_set_string (value, priv->deploy_dir);
break;
+ case PROP_SUBPATHS:
+ g_value_set_boxed (value, priv->subpaths);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -192,6 +204,13 @@ xdg_app_installed_ref_class_init (XdgAppInstalledRefClass *klass)
"Where the application is installed",
NULL,
G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SUBPATHS,
+ g_param_spec_boxed ("subpaths",
+ "",
+ "",
+ G_TYPE_STRV,
+ G_PARAM_READWRITE));
}
static void
@@ -319,6 +338,7 @@ xdg_app_installed_ref_new (const char *full_ref,
const char *commit,
const char *latest_commit,
const char *origin,
+ char **subpaths,
const char *deploy_dir,
guint64 installed_size,
gboolean is_current)
@@ -332,6 +352,10 @@ xdg_app_installed_ref_new (const char *full_ref,
if (strcmp (parts[0], "app") != 0)
kind = XDG_APP_REF_KIND_RUNTIME;
+ /* Canonicalize the "no subpaths" case */
+ if (subpaths && *subpaths == NULL)
+ subpaths = NULL;
+
ref = g_object_new (XDG_APP_TYPE_INSTALLED_REF,
"kind", kind,
"name", parts[1],
@@ -340,6 +364,7 @@ xdg_app_installed_ref_new (const char *full_ref,
"commit", commit,
"latest-commit", latest_commit,
"origin", origin,
+ "subpaths", subpaths,
"is-current", is_current,
"installed-size", installed_size,
"deploy-dir", deploy_dir,
diff --git a/lib/xdg-app-installed-ref.h b/lib/xdg-app-installed-ref.h
index 624bf8a..3fdf069 100644
--- a/lib/xdg-app-installed-ref.h
+++ b/lib/xdg-app-installed-ref.h
@@ -48,12 +48,13 @@ typedef struct {
G_DEFINE_AUTOPTR_CLEANUP_FUNC(XdgAppInstalledRef, g_object_unref)
#endif
-XDG_APP_EXTERN const char *xdg_app_installed_ref_get_origin (XdgAppInstalledRef *self);
-XDG_APP_EXTERN guint64 xdg_app_installed_ref_get_installed_size (XdgAppInstalledRef *self);
-XDG_APP_EXTERN const char *xdg_app_installed_ref_get_deploy_dir (XdgAppInstalledRef *self);
-XDG_APP_EXTERN const char *xdg_app_installed_ref_get_latest_commit (XdgAppInstalledRef *self);
-XDG_APP_EXTERN gboolean xdg_app_installed_ref_get_is_current (XdgAppInstalledRef *self);
-XDG_APP_EXTERN GBytes *xdg_app_installed_ref_load_metadata (XdgAppInstalledRef *self,
+XDG_APP_EXTERN const char *xdg_app_installed_ref_get_origin (XdgAppInstalledRef *self);
+XDG_APP_EXTERN const char **xdg_app_installed_ref_get_subpaths (XdgAppInstalledRef *self);
+XDG_APP_EXTERN guint64 xdg_app_installed_ref_get_installed_size (XdgAppInstalledRef *self);
+XDG_APP_EXTERN const char *xdg_app_installed_ref_get_deploy_dir (XdgAppInstalledRef *self);
+XDG_APP_EXTERN const char *xdg_app_installed_ref_get_latest_commit (XdgAppInstalledRef *self);
+XDG_APP_EXTERN gboolean xdg_app_installed_ref_get_is_current (XdgAppInstalledRef *self);
+XDG_APP_EXTERN GBytes *xdg_app_installed_ref_load_metadata (XdgAppInstalledRef *self,
GCancellable *cancellable,
GError **error);