libostree: Split off -refs.c
Continuing to break up ostree-repo.c.
This commit is contained in:
parent
3b6a94d272
commit
cb6b69616c
|
|
@ -33,6 +33,7 @@ libostree_la_SOURCES = src/libostree/ostree.h \
|
||||||
src/libostree/ostree-repo.c \
|
src/libostree/ostree-repo.c \
|
||||||
src/libostree/ostree-repo-checkout.c \
|
src/libostree/ostree-repo-checkout.c \
|
||||||
src/libostree/ostree-repo-libarchive.c \
|
src/libostree/ostree-repo-libarchive.c \
|
||||||
|
src/libostree/ostree-repo-refs.c \
|
||||||
src/libostree/ostree-repo.h \
|
src/libostree/ostree-repo.h \
|
||||||
src/libostree/ostree-repo-private.h \
|
src/libostree/ostree-repo-private.h \
|
||||||
src/libostree/ostree-repo-file.c \
|
src/libostree/ostree-repo-file.c \
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,670 @@
|
||||||
|
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Colin Walters <walters@verbum.org>
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*
|
||||||
|
* Author: Colin Walters <walters@verbum.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "ostree-repo-private.h"
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
add_ref_to_set (const char *remote,
|
||||||
|
GFile *base,
|
||||||
|
GFile *child,
|
||||||
|
GHashTable *refs,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
char *contents;
|
||||||
|
char *relpath;
|
||||||
|
gsize len;
|
||||||
|
GString *refname;
|
||||||
|
|
||||||
|
if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_strchomp (contents);
|
||||||
|
|
||||||
|
refname = g_string_new ("");
|
||||||
|
if (remote)
|
||||||
|
{
|
||||||
|
g_string_append (refname, remote);
|
||||||
|
g_string_append_c (refname, ':');
|
||||||
|
}
|
||||||
|
relpath = g_file_get_relative_path (base, child);
|
||||||
|
g_string_append (refname, relpath);
|
||||||
|
g_free (relpath);
|
||||||
|
|
||||||
|
g_hash_table_insert (refs, g_string_free (refname, FALSE), contents);
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
write_checksum_file (GFile *parentdir,
|
||||||
|
const char *name,
|
||||||
|
const char *sha256,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gsize bytes_written;
|
||||||
|
int i;
|
||||||
|
gs_unref_object GFile *parent = NULL;
|
||||||
|
gs_unref_object GFile *child = NULL;
|
||||||
|
gs_unref_object GOutputStream *out = NULL;
|
||||||
|
gs_unref_ptrarray GPtrArray *components = NULL;
|
||||||
|
|
||||||
|
if (!ostree_validate_checksum_string (sha256, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (ostree_validate_checksum_string (name, NULL))
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Rev name '%s' looks like a checksum", name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ot_util_path_split_validate (name, &components, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (components->len == 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Invalid empty ref name");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent = g_object_ref (parentdir);
|
||||||
|
for (i = 0; i+1 < components->len; i++)
|
||||||
|
{
|
||||||
|
child = g_file_get_child (parent, (char*)components->pdata[i]);
|
||||||
|
|
||||||
|
if (!gs_file_ensure_directory (child, FALSE, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_clear_object (&parent);
|
||||||
|
parent = child;
|
||||||
|
child = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
child = g_file_get_child (parent, components->pdata[components->len - 1]);
|
||||||
|
if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, NULL, error)) == NULL)
|
||||||
|
goto out;
|
||||||
|
if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, NULL, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, NULL, error))
|
||||||
|
goto out;
|
||||||
|
if (!g_output_stream_close (out, NULL, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_rev_file (OstreeRepo *self,
|
||||||
|
GFile *f,
|
||||||
|
char **sha256,
|
||||||
|
GError **error) G_GNUC_UNUSED;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
parse_rev_file (OstreeRepo *self,
|
||||||
|
GFile *f,
|
||||||
|
char **sha256,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GError *temp_error = NULL;
|
||||||
|
gs_free char *rev = NULL;
|
||||||
|
|
||||||
|
if ((rev = gs_file_load_contents_utf8 (f, NULL, &temp_error)) == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (rev == NULL)
|
||||||
|
{
|
||||||
|
if (g_error_matches (temp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
|
||||||
|
{
|
||||||
|
g_clear_error (&temp_error);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_propagate_error (error, temp_error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_strchomp (rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_str_has_prefix (rev, "ref: "))
|
||||||
|
{
|
||||||
|
gs_unref_object GFile *ref = NULL;
|
||||||
|
char *ref_sha256;
|
||||||
|
gboolean subret;
|
||||||
|
|
||||||
|
ref = g_file_resolve_relative_path (self->local_heads_dir, rev + 5);
|
||||||
|
subret = parse_rev_file (self, ref, &ref_sha256, error);
|
||||||
|
|
||||||
|
if (!subret)
|
||||||
|
{
|
||||||
|
g_free (ref_sha256);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (rev);
|
||||||
|
rev = ref_sha256;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!ostree_validate_checksum_string (rev, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ot_transfer_out_value(sha256, &rev);
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
find_ref_in_remotes (OstreeRepo *self,
|
||||||
|
const char *rev,
|
||||||
|
GFile **out_file,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_object GFileEnumerator *dir_enum = NULL;
|
||||||
|
gs_unref_object GFile *ret_file = NULL;
|
||||||
|
|
||||||
|
dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
NULL, error);
|
||||||
|
if (!dir_enum)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
GFileInfo *file_info;
|
||||||
|
GFile *child;
|
||||||
|
if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
|
||||||
|
NULL, error))
|
||||||
|
goto out;
|
||||||
|
if (file_info == NULL)
|
||||||
|
break;
|
||||||
|
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
g_clear_object (&ret_file);
|
||||||
|
ret_file = g_file_resolve_relative_path (child, rev);
|
||||||
|
if (!g_file_query_exists (ret_file, NULL))
|
||||||
|
g_clear_object (&ret_file);
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_file, &ret_file);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
resolve_refspec (OstreeRepo *self,
|
||||||
|
const char *remote,
|
||||||
|
const char *ref,
|
||||||
|
gboolean allow_noent,
|
||||||
|
char **out_rev,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
resolve_refspec_fallback (OstreeRepo *self,
|
||||||
|
const char *remote,
|
||||||
|
const char *ref,
|
||||||
|
gboolean allow_noent,
|
||||||
|
char **out_rev,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_free char *ret_rev = NULL;
|
||||||
|
|
||||||
|
if (self->parent_repo)
|
||||||
|
{
|
||||||
|
if (!resolve_refspec (self->parent_repo, remote, ref,
|
||||||
|
allow_noent, &ret_rev, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (!allow_noent)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Refspec '%s%s%s' not found",
|
||||||
|
remote ? remote : "",
|
||||||
|
remote ? ":" : "",
|
||||||
|
ref);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_rev, &ret_rev);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
resolve_refspec (OstreeRepo *self,
|
||||||
|
const char *remote,
|
||||||
|
const char *ref,
|
||||||
|
gboolean allow_noent,
|
||||||
|
char **out_rev,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
__attribute__((unused)) GCancellable *cancellable = NULL;
|
||||||
|
GError *temp_error = NULL;
|
||||||
|
gs_free char *tmp = NULL;
|
||||||
|
gs_free char *tmp2 = NULL;
|
||||||
|
gs_free char *ret_rev = NULL;
|
||||||
|
gs_unref_object GFile *child = NULL;
|
||||||
|
gs_unref_object GFile *origindir = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (ref != NULL, FALSE);
|
||||||
|
|
||||||
|
/* We intentionally don't allow a ref that looks like a checksum */
|
||||||
|
if (ostree_validate_checksum_string (ref, NULL))
|
||||||
|
{
|
||||||
|
ret_rev = g_strdup (ref);
|
||||||
|
}
|
||||||
|
else if (remote != NULL)
|
||||||
|
{
|
||||||
|
child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s",
|
||||||
|
remote, ref);
|
||||||
|
if (!g_file_query_exists (child, NULL))
|
||||||
|
g_clear_object (&child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child = g_file_resolve_relative_path (self->local_heads_dir, ref);
|
||||||
|
|
||||||
|
if (!g_file_query_exists (child, NULL))
|
||||||
|
{
|
||||||
|
g_clear_object (&child);
|
||||||
|
|
||||||
|
child = g_file_resolve_relative_path (self->remote_heads_dir, ref);
|
||||||
|
|
||||||
|
if (!g_file_query_exists (child, NULL))
|
||||||
|
{
|
||||||
|
g_clear_object (&child);
|
||||||
|
|
||||||
|
if (!find_ref_in_remotes (self, ref, &child, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child)
|
||||||
|
{
|
||||||
|
if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL)
|
||||||
|
{
|
||||||
|
g_propagate_error (error, temp_error);
|
||||||
|
g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_strchomp (ret_rev);
|
||||||
|
if (!ostree_validate_checksum_string (ret_rev, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!resolve_refspec_fallback (self, remote, ref, allow_noent,
|
||||||
|
&ret_rev, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ot_transfer_out_value (out_rev, &ret_rev);
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_resolve_rev (OstreeRepo *self,
|
||||||
|
const char *refspec,
|
||||||
|
gboolean allow_noent,
|
||||||
|
char **out_rev,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_free char *ret_rev = NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail (refspec != NULL, FALSE);
|
||||||
|
|
||||||
|
if (ostree_validate_checksum_string (refspec, NULL))
|
||||||
|
{
|
||||||
|
ret_rev = g_strdup (refspec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (g_str_has_suffix (refspec, "^"))
|
||||||
|
{
|
||||||
|
gs_free char *parent_refspec = NULL;
|
||||||
|
gs_free char *parent_rev = NULL;
|
||||||
|
gs_unref_variant GVariant *commit = NULL;
|
||||||
|
gs_unref_variant GVariant *parent_csum_v = NULL;
|
||||||
|
|
||||||
|
parent_refspec = g_strdup (refspec);
|
||||||
|
parent_refspec[strlen(parent_refspec) - 1] = '\0';
|
||||||
|
|
||||||
|
if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev,
|
||||||
|
&commit, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_variant_get_child (commit, 1, "@ay", &parent_csum_v);
|
||||||
|
if (g_variant_n_children (parent_csum_v) == 0)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||||
|
"Commit %s has no parent", parent_rev);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ret_rev = ostree_checksum_from_bytes_v (parent_csum_v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gs_free char *remote = NULL;
|
||||||
|
gs_free char *ref = NULL;
|
||||||
|
|
||||||
|
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!resolve_refspec (self, remote, ref, allow_noent,
|
||||||
|
&ret_rev, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_rev, &ret_rev);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
enumerate_refs_recurse (OstreeRepo *repo,
|
||||||
|
const char *remote,
|
||||||
|
GFile *base,
|
||||||
|
GFile *dir,
|
||||||
|
GHashTable *refs,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_object GFileEnumerator *enumerator = NULL;
|
||||||
|
|
||||||
|
enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
|
cancellable, error);
|
||||||
|
if (!enumerator)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
GFileInfo *file_info = NULL;
|
||||||
|
GFile *child = NULL;
|
||||||
|
|
||||||
|
if (!gs_file_enumerator_iterate (enumerator, &file_info, &child,
|
||||||
|
NULL, error))
|
||||||
|
goto out;
|
||||||
|
if (file_info == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
||||||
|
{
|
||||||
|
if (!add_ref_to_set (remote, base, child, refs,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_list_refs (OstreeRepo *repo,
|
||||||
|
const char *refspec_prefix,
|
||||||
|
GHashTable **out_all_refs,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_hashtable GHashTable *ret_all_refs = NULL;
|
||||||
|
gs_free char *remote = NULL;
|
||||||
|
gs_free char *ref_prefix = NULL;
|
||||||
|
|
||||||
|
ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||||
|
|
||||||
|
if (refspec_prefix)
|
||||||
|
{
|
||||||
|
gs_unref_object GFile *dir = NULL;
|
||||||
|
gs_unref_object GFile *child = NULL;
|
||||||
|
gs_unref_object GFileInfo *info = NULL;
|
||||||
|
|
||||||
|
if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (remote)
|
||||||
|
dir = g_file_get_child (repo->remote_heads_dir, remote);
|
||||||
|
else
|
||||||
|
dir = g_object_ref (repo->local_heads_dir);
|
||||||
|
|
||||||
|
child = g_file_resolve_relative_path (dir, ref_prefix);
|
||||||
|
if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
|
||||||
|
&info, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (info)
|
||||||
|
{
|
||||||
|
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
|
||||||
|
{
|
||||||
|
if (!enumerate_refs_recurse (repo, remote, child, child,
|
||||||
|
ret_all_refs,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!add_ref_to_set (remote, dir, child, ret_all_refs,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gs_unref_object GFileEnumerator *remote_enumerator = NULL;
|
||||||
|
|
||||||
|
if (!enumerate_refs_recurse (repo, NULL, repo->local_heads_dir, repo->local_heads_dir,
|
||||||
|
ret_all_refs,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
remote_enumerator = g_file_enumerate_children (repo->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
|
||||||
|
0,
|
||||||
|
cancellable, error);
|
||||||
|
|
||||||
|
while (TRUE)
|
||||||
|
{
|
||||||
|
GFileInfo *info;
|
||||||
|
GFile *child;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
if (!info)
|
||||||
|
break;
|
||||||
|
|
||||||
|
name = g_file_info_get_name (info);
|
||||||
|
if (!enumerate_refs_recurse (repo, name, child, child,
|
||||||
|
ret_all_refs,
|
||||||
|
cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
ot_transfer_out_value (out_all_refs, &ret_all_refs);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
write_ref_summary (OstreeRepo *self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
GHashTableIter hash_iter;
|
||||||
|
gpointer key, value;
|
||||||
|
gsize bytes_written;
|
||||||
|
gs_unref_hashtable GHashTable *all_refs = NULL;
|
||||||
|
gs_unref_object GFile *summary_path = NULL;
|
||||||
|
gs_unref_object GOutputStream *out = NULL;
|
||||||
|
gs_free char *buf = NULL;
|
||||||
|
|
||||||
|
if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
summary_path = g_file_resolve_relative_path (ostree_repo_get_path (self),
|
||||||
|
"refs/summary");
|
||||||
|
|
||||||
|
out = (GOutputStream*) g_file_replace (summary_path, NULL, FALSE, 0, cancellable, error);
|
||||||
|
if (!out)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&hash_iter, all_refs);
|
||||||
|
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||||
|
{
|
||||||
|
const char *name = key;
|
||||||
|
const char *sha256 = value;
|
||||||
|
|
||||||
|
g_free (buf);
|
||||||
|
buf = g_strdup_printf ("%s %s\n", sha256, name);
|
||||||
|
if (!g_output_stream_write_all (out, buf, strlen (buf), &bytes_written, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_output_stream_close (out, cancellable, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_write_ref (OstreeRepo *self,
|
||||||
|
const char *remote,
|
||||||
|
const char *name,
|
||||||
|
const char *rev,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_unref_object GFile *dir = NULL;
|
||||||
|
|
||||||
|
if (remote == NULL)
|
||||||
|
dir = g_object_ref (self->local_heads_dir);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dir = g_file_get_child (self->remote_heads_dir, remote);
|
||||||
|
|
||||||
|
if (rev != NULL)
|
||||||
|
{
|
||||||
|
if (!gs_file_ensure_directory (dir, FALSE, NULL, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rev == NULL)
|
||||||
|
{
|
||||||
|
gs_unref_object GFile *child = g_file_resolve_relative_path (dir, name);
|
||||||
|
|
||||||
|
if (g_file_query_exists (child, NULL))
|
||||||
|
{
|
||||||
|
if (!gs_file_unlink (child, NULL, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!write_checksum_file (dir, name, rev, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (rev != NULL)
|
||||||
|
{
|
||||||
|
if (self->mode == OSTREE_REPO_MODE_ARCHIVE
|
||||||
|
|| self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
||||||
|
{
|
||||||
|
if (!write_ref_summary (self, NULL, error))
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
ostree_repo_write_refspec (OstreeRepo *self,
|
||||||
|
const char *refspec,
|
||||||
|
const char *rev,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
gs_free char *remote = NULL;
|
||||||
|
gs_free char *ref = NULL;
|
||||||
|
|
||||||
|
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (!ostree_repo_write_ref (self, remote, ref, rev, error))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
@ -186,361 +186,6 @@ ostree_repo_new (GFile *path)
|
||||||
{
|
{
|
||||||
return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
|
return g_object_new (OSTREE_TYPE_REPO, "path", path, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
parse_rev_file (OstreeRepo *self,
|
|
||||||
GFile *f,
|
|
||||||
char **sha256,
|
|
||||||
GError **error) G_GNUC_UNUSED;
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
parse_rev_file (OstreeRepo *self,
|
|
||||||
GFile *f,
|
|
||||||
char **sha256,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
GError *temp_error = NULL;
|
|
||||||
gs_free char *rev = NULL;
|
|
||||||
|
|
||||||
if ((rev = gs_file_load_contents_utf8 (f, NULL, &temp_error)) == NULL)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (rev == NULL)
|
|
||||||
{
|
|
||||||
if (g_error_matches (temp_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
|
|
||||||
{
|
|
||||||
g_clear_error (&temp_error);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_propagate_error (error, temp_error);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
g_strchomp (rev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_str_has_prefix (rev, "ref: "))
|
|
||||||
{
|
|
||||||
gs_unref_object GFile *ref = NULL;
|
|
||||||
char *ref_sha256;
|
|
||||||
gboolean subret;
|
|
||||||
|
|
||||||
ref = g_file_resolve_relative_path (self->local_heads_dir, rev + 5);
|
|
||||||
subret = parse_rev_file (self, ref, &ref_sha256, error);
|
|
||||||
|
|
||||||
if (!subret)
|
|
||||||
{
|
|
||||||
g_free (ref_sha256);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_free (rev);
|
|
||||||
rev = ref_sha256;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!ostree_validate_checksum_string (rev, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ot_transfer_out_value(sha256, &rev);
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
find_ref_in_remotes (OstreeRepo *self,
|
|
||||||
const char *rev,
|
|
||||||
GFile **out_file,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_object GFileEnumerator *dir_enum = NULL;
|
|
||||||
gs_unref_object GFile *ret_file = NULL;
|
|
||||||
|
|
||||||
dir_enum = g_file_enumerate_children (self->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
|
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
|
||||||
NULL, error);
|
|
||||||
if (!dir_enum)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
GFileInfo *file_info;
|
|
||||||
GFile *child;
|
|
||||||
if (!gs_file_enumerator_iterate (dir_enum, &file_info, &child,
|
|
||||||
NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (file_info == NULL)
|
|
||||||
break;
|
|
||||||
if (g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
g_clear_object (&ret_file);
|
|
||||||
ret_file = g_file_resolve_relative_path (child, rev);
|
|
||||||
if (!g_file_query_exists (ret_file, NULL))
|
|
||||||
g_clear_object (&ret_file);
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
ot_transfer_out_value (out_file, &ret_file);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
resolve_refspec (OstreeRepo *self,
|
|
||||||
const char *remote,
|
|
||||||
const char *ref,
|
|
||||||
gboolean allow_noent,
|
|
||||||
char **out_rev,
|
|
||||||
GError **error);
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
resolve_refspec_fallback (OstreeRepo *self,
|
|
||||||
const char *remote,
|
|
||||||
const char *ref,
|
|
||||||
gboolean allow_noent,
|
|
||||||
char **out_rev,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_free char *ret_rev = NULL;
|
|
||||||
|
|
||||||
if (self->parent_repo)
|
|
||||||
{
|
|
||||||
if (!resolve_refspec (self->parent_repo, remote, ref,
|
|
||||||
allow_noent, &ret_rev, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if (!allow_noent)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Refspec '%s%s%s' not found",
|
|
||||||
remote ? remote : "",
|
|
||||||
remote ? ":" : "",
|
|
||||||
ref);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
ot_transfer_out_value (out_rev, &ret_rev);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
resolve_refspec (OstreeRepo *self,
|
|
||||||
const char *remote,
|
|
||||||
const char *ref,
|
|
||||||
gboolean allow_noent,
|
|
||||||
char **out_rev,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
__attribute__((unused)) GCancellable *cancellable = NULL;
|
|
||||||
GError *temp_error = NULL;
|
|
||||||
gs_free char *tmp = NULL;
|
|
||||||
gs_free char *tmp2 = NULL;
|
|
||||||
gs_free char *ret_rev = NULL;
|
|
||||||
gs_unref_object GFile *child = NULL;
|
|
||||||
gs_unref_object GFile *origindir = NULL;
|
|
||||||
|
|
||||||
g_return_val_if_fail (ref != NULL, FALSE);
|
|
||||||
|
|
||||||
/* We intentionally don't allow a ref that looks like a checksum */
|
|
||||||
if (ostree_validate_checksum_string (ref, NULL))
|
|
||||||
{
|
|
||||||
ret_rev = g_strdup (ref);
|
|
||||||
}
|
|
||||||
else if (remote != NULL)
|
|
||||||
{
|
|
||||||
child = ot_gfile_resolve_path_printf (self->remote_heads_dir, "%s/%s",
|
|
||||||
remote, ref);
|
|
||||||
if (!g_file_query_exists (child, NULL))
|
|
||||||
g_clear_object (&child);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
child = g_file_resolve_relative_path (self->local_heads_dir, ref);
|
|
||||||
|
|
||||||
if (!g_file_query_exists (child, NULL))
|
|
||||||
{
|
|
||||||
g_clear_object (&child);
|
|
||||||
|
|
||||||
child = g_file_resolve_relative_path (self->remote_heads_dir, ref);
|
|
||||||
|
|
||||||
if (!g_file_query_exists (child, NULL))
|
|
||||||
{
|
|
||||||
g_clear_object (&child);
|
|
||||||
|
|
||||||
if (!find_ref_in_remotes (self, ref, &child, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (child)
|
|
||||||
{
|
|
||||||
if ((ret_rev = gs_file_load_contents_utf8 (child, NULL, &temp_error)) == NULL)
|
|
||||||
{
|
|
||||||
g_propagate_error (error, temp_error);
|
|
||||||
g_prefix_error (error, "Couldn't open ref '%s': ", gs_file_get_path_cached (child));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_strchomp (ret_rev);
|
|
||||||
if (!ostree_validate_checksum_string (ret_rev, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!resolve_refspec_fallback (self, remote, ref, allow_noent,
|
|
||||||
&ret_rev, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ot_transfer_out_value (out_rev, &ret_rev);
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
ostree_repo_resolve_rev (OstreeRepo *self,
|
|
||||||
const char *refspec,
|
|
||||||
gboolean allow_noent,
|
|
||||||
char **out_rev,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_free char *ret_rev = NULL;
|
|
||||||
|
|
||||||
g_return_val_if_fail (refspec != NULL, FALSE);
|
|
||||||
|
|
||||||
if (ostree_validate_checksum_string (refspec, NULL))
|
|
||||||
{
|
|
||||||
ret_rev = g_strdup (refspec);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (g_str_has_suffix (refspec, "^"))
|
|
||||||
{
|
|
||||||
gs_free char *parent_refspec = NULL;
|
|
||||||
gs_free char *parent_rev = NULL;
|
|
||||||
gs_unref_variant GVariant *commit = NULL;
|
|
||||||
gs_unref_variant GVariant *parent_csum_v = NULL;
|
|
||||||
|
|
||||||
parent_refspec = g_strdup (refspec);
|
|
||||||
parent_refspec[strlen(parent_refspec) - 1] = '\0';
|
|
||||||
|
|
||||||
if (!ostree_repo_resolve_rev (self, parent_refspec, allow_noent, &parent_rev, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT, parent_rev,
|
|
||||||
&commit, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_variant_get_child (commit, 1, "@ay", &parent_csum_v);
|
|
||||||
if (g_variant_n_children (parent_csum_v) == 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Commit %s has no parent", parent_rev);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ret_rev = ostree_checksum_from_bytes_v (parent_csum_v);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gs_free char *remote = NULL;
|
|
||||||
gs_free char *ref = NULL;
|
|
||||||
|
|
||||||
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!resolve_refspec (self, remote, ref, allow_noent,
|
|
||||||
&ret_rev, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
ot_transfer_out_value (out_rev, &ret_rev);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
write_checksum_file (GFile *parentdir,
|
|
||||||
const char *name,
|
|
||||||
const char *sha256,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gsize bytes_written;
|
|
||||||
int i;
|
|
||||||
gs_unref_object GFile *parent = NULL;
|
|
||||||
gs_unref_object GFile *child = NULL;
|
|
||||||
gs_unref_object GOutputStream *out = NULL;
|
|
||||||
gs_unref_ptrarray GPtrArray *components = NULL;
|
|
||||||
|
|
||||||
if (!ostree_validate_checksum_string (sha256, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (ostree_validate_checksum_string (name, NULL))
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Rev name '%s' looks like a checksum", name);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ot_util_path_split_validate (name, &components, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (components->len == 0)
|
|
||||||
{
|
|
||||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
|
||||||
"Invalid empty ref name");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
parent = g_object_ref (parentdir);
|
|
||||||
for (i = 0; i+1 < components->len; i++)
|
|
||||||
{
|
|
||||||
child = g_file_get_child (parent, (char*)components->pdata[i]);
|
|
||||||
|
|
||||||
if (!gs_file_ensure_directory (child, FALSE, NULL, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_clear_object (&parent);
|
|
||||||
parent = child;
|
|
||||||
child = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
child = g_file_get_child (parent, components->pdata[components->len - 1]);
|
|
||||||
if ((out = (GOutputStream*)g_file_replace (child, NULL, FALSE, 0, NULL, error)) == NULL)
|
|
||||||
goto out;
|
|
||||||
if (!g_output_stream_write_all (out, sha256, strlen (sha256), &bytes_written, NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (!g_output_stream_write_all (out, "\n", 1, &bytes_written, NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (!g_output_stream_close (out, NULL, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ostree_repo_get_config:
|
* ostree_repo_get_config:
|
||||||
* @self:
|
* @self:
|
||||||
|
|
@ -1752,297 +1397,6 @@ create_empty_gvariant_dict (void)
|
||||||
return g_variant_builder_end (&builder);
|
return g_variant_builder_end (&builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
|
||||||
add_ref_to_set (const char *remote,
|
|
||||||
GFile *base,
|
|
||||||
GFile *child,
|
|
||||||
GHashTable *refs,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
char *contents;
|
|
||||||
char *relpath;
|
|
||||||
gsize len;
|
|
||||||
GString *refname;
|
|
||||||
|
|
||||||
if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_strchomp (contents);
|
|
||||||
|
|
||||||
refname = g_string_new ("");
|
|
||||||
if (remote)
|
|
||||||
{
|
|
||||||
g_string_append (refname, remote);
|
|
||||||
g_string_append_c (refname, ':');
|
|
||||||
}
|
|
||||||
relpath = g_file_get_relative_path (base, child);
|
|
||||||
g_string_append (refname, relpath);
|
|
||||||
g_free (relpath);
|
|
||||||
|
|
||||||
g_hash_table_insert (refs, g_string_free (refname, FALSE), contents);
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
enumerate_refs_recurse (OstreeRepo *repo,
|
|
||||||
const char *remote,
|
|
||||||
GFile *base,
|
|
||||||
GFile *dir,
|
|
||||||
GHashTable *refs,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_object GFileEnumerator *enumerator = NULL;
|
|
||||||
|
|
||||||
enumerator = g_file_enumerate_children (dir, OSTREE_GIO_FAST_QUERYINFO,
|
|
||||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
|
||||||
cancellable, error);
|
|
||||||
if (!enumerator)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
GFileInfo *file_info = NULL;
|
|
||||||
GFile *child = NULL;
|
|
||||||
|
|
||||||
if (!gs_file_enumerator_iterate (enumerator, &file_info, &child,
|
|
||||||
NULL, error))
|
|
||||||
goto out;
|
|
||||||
if (file_info == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
|
|
||||||
{
|
|
||||||
if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR)
|
|
||||||
{
|
|
||||||
if (!add_ref_to_set (remote, base, child, refs,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
ostree_repo_list_refs (OstreeRepo *repo,
|
|
||||||
const char *refspec_prefix,
|
|
||||||
GHashTable **out_all_refs,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_hashtable GHashTable *ret_all_refs = NULL;
|
|
||||||
gs_free char *remote = NULL;
|
|
||||||
gs_free char *ref_prefix = NULL;
|
|
||||||
|
|
||||||
ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
||||||
|
|
||||||
if (refspec_prefix)
|
|
||||||
{
|
|
||||||
gs_unref_object GFile *dir = NULL;
|
|
||||||
gs_unref_object GFile *child = NULL;
|
|
||||||
gs_unref_object GFileInfo *info = NULL;
|
|
||||||
|
|
||||||
if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (remote)
|
|
||||||
dir = g_file_get_child (repo->remote_heads_dir, remote);
|
|
||||||
else
|
|
||||||
dir = g_object_ref (repo->local_heads_dir);
|
|
||||||
|
|
||||||
child = g_file_resolve_relative_path (dir, ref_prefix);
|
|
||||||
if (!ot_gfile_query_info_allow_noent (child, OSTREE_GIO_FAST_QUERYINFO, 0,
|
|
||||||
&info, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (info)
|
|
||||||
{
|
|
||||||
if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY)
|
|
||||||
{
|
|
||||||
if (!enumerate_refs_recurse (repo, remote, child, child,
|
|
||||||
ret_all_refs,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!add_ref_to_set (remote, dir, child, ret_all_refs,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
gs_unref_object GFileEnumerator *remote_enumerator = NULL;
|
|
||||||
|
|
||||||
if (!enumerate_refs_recurse (repo, NULL, repo->local_heads_dir, repo->local_heads_dir,
|
|
||||||
ret_all_refs,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
remote_enumerator = g_file_enumerate_children (repo->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO,
|
|
||||||
0,
|
|
||||||
cancellable, error);
|
|
||||||
|
|
||||||
while (TRUE)
|
|
||||||
{
|
|
||||||
GFileInfo *info;
|
|
||||||
GFile *child;
|
|
||||||
const char *name;
|
|
||||||
|
|
||||||
if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
if (!info)
|
|
||||||
break;
|
|
||||||
|
|
||||||
name = g_file_info_get_name (info);
|
|
||||||
if (!enumerate_refs_recurse (repo, name, child, child,
|
|
||||||
ret_all_refs,
|
|
||||||
cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
ot_transfer_out_value (out_all_refs, &ret_all_refs);
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
write_ref_summary (OstreeRepo *self,
|
|
||||||
GCancellable *cancellable,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
GHashTableIter hash_iter;
|
|
||||||
gpointer key, value;
|
|
||||||
gsize bytes_written;
|
|
||||||
gs_unref_hashtable GHashTable *all_refs = NULL;
|
|
||||||
gs_unref_object GFile *summary_path = NULL;
|
|
||||||
gs_unref_object GOutputStream *out = NULL;
|
|
||||||
gs_free char *buf = NULL;
|
|
||||||
|
|
||||||
if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
summary_path = g_file_resolve_relative_path (ostree_repo_get_path (self),
|
|
||||||
"refs/summary");
|
|
||||||
|
|
||||||
out = (GOutputStream*) g_file_replace (summary_path, NULL, FALSE, 0, cancellable, error);
|
|
||||||
if (!out)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
g_hash_table_iter_init (&hash_iter, all_refs);
|
|
||||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
|
||||||
{
|
|
||||||
const char *name = key;
|
|
||||||
const char *sha256 = value;
|
|
||||||
|
|
||||||
g_free (buf);
|
|
||||||
buf = g_strdup_printf ("%s %s\n", sha256, name);
|
|
||||||
if (!g_output_stream_write_all (out, buf, strlen (buf), &bytes_written, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!g_output_stream_close (out, cancellable, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
ostree_repo_write_ref (OstreeRepo *self,
|
|
||||||
const char *remote,
|
|
||||||
const char *name,
|
|
||||||
const char *rev,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_unref_object GFile *dir = NULL;
|
|
||||||
|
|
||||||
if (remote == NULL)
|
|
||||||
dir = g_object_ref (self->local_heads_dir);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dir = g_file_get_child (self->remote_heads_dir, remote);
|
|
||||||
|
|
||||||
if (rev != NULL)
|
|
||||||
{
|
|
||||||
if (!gs_file_ensure_directory (dir, FALSE, NULL, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rev == NULL)
|
|
||||||
{
|
|
||||||
gs_unref_object GFile *child = g_file_resolve_relative_path (dir, name);
|
|
||||||
|
|
||||||
if (g_file_query_exists (child, NULL))
|
|
||||||
{
|
|
||||||
if (!gs_file_unlink (child, NULL, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!write_checksum_file (dir, name, rev, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (rev != NULL)
|
|
||||||
{
|
|
||||||
if (self->mode == OSTREE_REPO_MODE_ARCHIVE
|
|
||||||
|| self->mode == OSTREE_REPO_MODE_ARCHIVE_Z2)
|
|
||||||
{
|
|
||||||
if (!write_ref_summary (self, NULL, error))
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
ostree_repo_write_refspec (OstreeRepo *self,
|
|
||||||
const char *refspec,
|
|
||||||
const char *rev,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
gboolean ret = FALSE;
|
|
||||||
gs_free char *remote = NULL;
|
|
||||||
gs_free char *ref = NULL;
|
|
||||||
|
|
||||||
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (!ostree_repo_write_ref (self, remote, ref, rev, error))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ret = TRUE;
|
|
||||||
out:
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
ostree_repo_stage_commit (OstreeRepo *self,
|
ostree_repo_stage_commit (OstreeRepo *self,
|
||||||
const char *branch,
|
const char *branch,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue