mirror of
https://github.com/ostreedev/ostree.git
synced 2025-01-21 22:04:15 +03:00
lib/refs: Add methods for setting/listing collection–refs
These are tuples of (collection ID, ref name) which are a globally-unique form of local ref. They use OstreeCollectionRef as an identifier, and hence need to be accessed using new API, as the existing API uses string identifiers and sometimes accepts refspecs. Remote names are not supported as part an OstreeCollectionRef. Signed-off-by: Philip Withnall <withnall@endlessm.com> Closes: #924 Approved by: cgwalters
This commit is contained in:
parent
4de736fdfa
commit
fbf8df8829
@ -26,4 +26,7 @@ ostree_remote_get_name
|
||||
ostree_repo_get_collection_id
|
||||
ostree_repo_set_collection_id
|
||||
ostree_validate_collection_id
|
||||
ostree_repo_list_collection_refs
|
||||
ostree_repo_set_collection_ref_immediate
|
||||
ostree_repo_transaction_set_collection_ref
|
||||
</SECTION>
|
||||
|
@ -46,6 +46,9 @@ global:
|
||||
ostree_collection_ref_hash;
|
||||
ostree_collection_ref_new;
|
||||
ostree_repo_get_collection_id;
|
||||
ostree_repo_list_collection_refs;
|
||||
ostree_repo_set_collection_id;
|
||||
ostree_repo_set_collection_ref_immediate;
|
||||
ostree_repo_transaction_set_collection_ref;
|
||||
ostree_validate_collection_id;
|
||||
} LIBOSTREE_2017.7_EXPERIMENTAL;
|
||||
|
@ -1347,6 +1347,11 @@ ensure_txn_refs (OstreeRepo *self)
|
||||
{
|
||||
if (self->txn_refs == NULL)
|
||||
self->txn_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
if (self->txn_collection_refs == NULL)
|
||||
self->txn_collection_refs = g_hash_table_new_full (ostree_collection_ref_hash,
|
||||
ostree_collection_ref_equal,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1410,6 +1415,41 @@ ostree_repo_transaction_set_ref (OstreeRepo *self,
|
||||
g_hash_table_replace (self->txn_refs, refspec, g_strdup (checksum));
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_transaction_set_collection_ref:
|
||||
* @self: An #OstreeRepo
|
||||
* @ref: The collection–ref to write
|
||||
* @checksum: (nullable): The checksum to point it to
|
||||
*
|
||||
* If @checksum is not %NULL, then record it as the target of local ref named
|
||||
* @ref.
|
||||
*
|
||||
* Otherwise, if @checksum is %NULL, then record that the ref should
|
||||
* be deleted.
|
||||
*
|
||||
* The change will not be written out immediately, but when the transaction
|
||||
* is completed with ostree_repo_commit_transaction(). If the transaction
|
||||
* is instead aborted with ostree_repo_abort_transaction(), no changes will
|
||||
* be made to the repository.
|
||||
*
|
||||
* Since: 2017.8
|
||||
*/
|
||||
void
|
||||
ostree_repo_transaction_set_collection_ref (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum)
|
||||
{
|
||||
g_return_if_fail (OSTREE_IS_REPO (self));
|
||||
g_return_if_fail (self->in_transaction == TRUE);
|
||||
g_return_if_fail (ref != NULL);
|
||||
g_return_if_fail (checksum == NULL || ostree_validate_checksum_string (checksum, NULL));
|
||||
|
||||
ensure_txn_refs (self);
|
||||
|
||||
g_hash_table_replace (self->txn_collection_refs,
|
||||
ostree_collection_ref_dup (ref), g_strdup (checksum));
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_set_ref_immediate:
|
||||
* @self: An #OstreeRepo
|
||||
@ -1431,7 +1471,40 @@ ostree_repo_set_ref_immediate (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
return _ostree_repo_write_ref (self, remote, ref, checksum,
|
||||
const OstreeCollectionRef _ref = { NULL, (gchar *) ref };
|
||||
return _ostree_repo_write_ref (self, remote, &_ref, checksum,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_set_collection_ref_immediate:
|
||||
* @self: An #OstreeRepo
|
||||
* @ref: The collection–ref to write
|
||||
* @checksum: (nullable): The checksum to point it to, or %NULL to unset
|
||||
* @cancellable: GCancellable
|
||||
* @error: GError
|
||||
*
|
||||
* This is like ostree_repo_transaction_set_collection_ref(), except it may be
|
||||
* invoked outside of a transaction. This is presently safe for the
|
||||
* case where we're creating or overwriting an existing ref.
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE otherwise
|
||||
* Since: 2017.8
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
|
||||
g_return_val_if_fail (ref != NULL, FALSE);
|
||||
g_return_val_if_fail (checksum == NULL || ostree_validate_checksum_string (checksum, NULL), FALSE);
|
||||
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
return _ostree_repo_write_ref (self, NULL, ref, checksum,
|
||||
cancellable, error);
|
||||
}
|
||||
|
||||
@ -1481,6 +1554,11 @@ ostree_repo_commit_transaction (OstreeRepo *self,
|
||||
return FALSE;
|
||||
g_clear_pointer (&self->txn_refs, g_hash_table_destroy);
|
||||
|
||||
if (self->txn_collection_refs)
|
||||
if (!_ostree_repo_update_collection_refs (self, self->txn_collection_refs, cancellable, error))
|
||||
return FALSE;
|
||||
g_clear_pointer (&self->txn_collection_refs, g_hash_table_destroy);
|
||||
|
||||
if (self->commit_stagedir_fd != -1)
|
||||
{
|
||||
(void) close (self->commit_stagedir_fd);
|
||||
@ -1518,6 +1596,7 @@ ostree_repo_abort_transaction (OstreeRepo *self,
|
||||
g_hash_table_remove_all (self->loose_object_devino_hash);
|
||||
|
||||
g_clear_pointer (&self->txn_refs, g_hash_table_destroy);
|
||||
g_clear_pointer (&self->txn_collection_refs, g_hash_table_destroy);
|
||||
|
||||
if (self->commit_stagedir_fd != -1)
|
||||
{
|
||||
|
@ -48,6 +48,8 @@ G_BEGIN_DECLS
|
||||
/* Well-known keys for the additional metadata field in a summary file. */
|
||||
#define OSTREE_SUMMARY_LAST_MODIFIED "ostree.summary.last-modified"
|
||||
#define OSTREE_SUMMARY_EXPIRES "ostree.summary.expires"
|
||||
#define OSTREE_SUMMARY_COLLECTION_ID "ostree.summary.collection-id"
|
||||
#define OSTREE_SUMMARY_COLLECTION_MAP "ostree.summary.collection-map"
|
||||
|
||||
/* Well-known keys for the additional metadata field in a commit in a ref entry
|
||||
* in a summary file. */
|
||||
@ -96,7 +98,8 @@ struct OstreeRepo {
|
||||
GFile *sysroot_dir;
|
||||
char *remotes_config_dir;
|
||||
|
||||
GHashTable *txn_refs;
|
||||
GHashTable *txn_refs; /* (element-type utf8 utf8) */
|
||||
GHashTable *txn_collection_refs; /* (element-type OstreeCollectionRef utf8) */
|
||||
GMutex txn_stats_lock;
|
||||
OstreeRepoTransactionStats txn_stats;
|
||||
|
||||
@ -221,7 +224,13 @@ _ostree_repo_update_refs (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
gboolean
|
||||
_ostree_repo_update_collection_refs (OstreeRepo *self,
|
||||
GHashTable *refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_file_replace_contents (OstreeRepo *self,
|
||||
int dfd,
|
||||
const char *path,
|
||||
@ -230,13 +239,13 @@ _ostree_repo_file_replace_contents (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
gboolean
|
||||
_ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *rev,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
gboolean
|
||||
_ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *rev,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
OstreeRepoFile *
|
||||
_ostree_repo_file_new_for_commit (OstreeRepo *repo,
|
||||
@ -358,6 +367,22 @@ gboolean ostree_repo_set_collection_id (OstreeRepo *self,
|
||||
const gchar *collection_id,
|
||||
GError **error);
|
||||
|
||||
gboolean ostree_repo_list_collection_refs (OstreeRepo *self,
|
||||
const char *match_collection_id,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void ostree_repo_transaction_set_collection_ref (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum);
|
||||
|
||||
gboolean ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#endif /* !OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -312,7 +312,6 @@ ostree_repo_prune (OstreeRepo *self,
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key, value;
|
||||
g_autoptr(GHashTable) objects = NULL;
|
||||
g_autoptr(GHashTable) all_refs = NULL;
|
||||
g_autoptr(GHashTable) reachable = NULL;
|
||||
gboolean refs_only = flags & OSTREE_REPO_PRUNE_FLAGS_REFS_ONLY;
|
||||
|
||||
@ -325,12 +324,34 @@ ostree_repo_prune (OstreeRepo *self,
|
||||
|
||||
if (refs_only)
|
||||
{
|
||||
/* Ignoring collections. */
|
||||
g_autoptr(GHashTable) all_refs = NULL; /* (element-type utf8 utf8) */
|
||||
|
||||
if (!ostree_repo_list_refs (self, NULL, &all_refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, all_refs);
|
||||
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *checksum = value;
|
||||
|
||||
g_debug ("Finding objects to keep for commit %s", checksum);
|
||||
if (!ostree_repo_traverse_commit_union (self, checksum, depth, reachable,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Using collections. */
|
||||
g_autoptr(GHashTable) all_collection_refs = NULL; /* (element-type OstreeChecksumRef utf8) */
|
||||
|
||||
if (!ostree_repo_list_collection_refs (self, NULL, &all_collection_refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, all_collection_refs);
|
||||
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const char *checksum = value;
|
||||
|
@ -20,18 +20,25 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ostree-core-private.h"
|
||||
#include "ostree-repo-private.h"
|
||||
#include "otutil.h"
|
||||
#include "ot-fs-utils.h"
|
||||
|
||||
/* This is polymorphic in @collection_id: if non-%NULL, @refs will be treated as of
|
||||
* type OstreeCollectionRef ↦ checksum. Otherwise, it will be treated as of type
|
||||
* refspec ↦ checksum. */
|
||||
static gboolean
|
||||
add_ref_to_set (const char *remote,
|
||||
const char *collection_id,
|
||||
int base_fd,
|
||||
const char *path,
|
||||
GHashTable *refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (remote == NULL || collection_id == NULL, FALSE);
|
||||
|
||||
gsize len;
|
||||
char *contents = glnx_file_get_contents_utf8_at (base_fd, path, &len, cancellable, error);
|
||||
if (!contents)
|
||||
@ -39,14 +46,21 @@ add_ref_to_set (const char *remote,
|
||||
|
||||
g_strchomp (contents);
|
||||
|
||||
g_autoptr(GString) refname = g_string_new ("");
|
||||
if (remote)
|
||||
if (collection_id == NULL)
|
||||
{
|
||||
g_string_append (refname, remote);
|
||||
g_string_append_c (refname, ':');
|
||||
g_autoptr(GString) refname = g_string_new ("");
|
||||
if (remote)
|
||||
{
|
||||
g_string_append (refname, remote);
|
||||
g_string_append_c (refname, ':');
|
||||
}
|
||||
g_string_append (refname, path);
|
||||
g_hash_table_insert (refs, g_string_free (g_steal_pointer (&refname), FALSE), contents);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_insert (refs, ostree_collection_ref_new (collection_id, path), contents);
|
||||
}
|
||||
g_string_append (refname, path);
|
||||
g_hash_table_insert (refs, g_string_free (g_steal_pointer (&refname), FALSE), contents);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@ -99,6 +113,8 @@ write_checksum_file_at (OstreeRepo *self,
|
||||
|
||||
g_clear_error (&temp_error);
|
||||
|
||||
/* FIXME: Conflict detection needs to be extended to collection–refs
|
||||
* using ostree_repo_list_collection_refs(). */
|
||||
if (!ostree_repo_list_refs (self, name, &refs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
@ -456,6 +472,7 @@ ostree_repo_resolve_rev_ext (OstreeRepo *self,
|
||||
static gboolean
|
||||
enumerate_refs_recurse (OstreeRepo *repo,
|
||||
const char *remote,
|
||||
const char *collection_id,
|
||||
int base_dfd,
|
||||
GString *base_path,
|
||||
int child_dfd,
|
||||
@ -485,14 +502,14 @@ enumerate_refs_recurse (OstreeRepo *repo,
|
||||
{
|
||||
g_string_append_c (base_path, '/');
|
||||
|
||||
if (!enumerate_refs_recurse (repo, remote, base_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (repo, remote, collection_id, base_dfd, base_path,
|
||||
dfd_iter.fd, dent->d_name,
|
||||
refs, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
else if (dent->d_type == DT_REG)
|
||||
{
|
||||
if (!add_ref_to_set (remote, base_dfd, base_path->str, refs,
|
||||
if (!add_ref_to_set (remote, collection_id, base_dfd, base_path->str, refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -554,7 +571,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, cut_prefix ? path : prefix_path, TRUE, &base_fd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, remote, base_fd, base_path,
|
||||
if (!enumerate_refs_recurse (self, remote, NULL, base_fd, base_path,
|
||||
base_fd, cut_prefix ? "." : ref_prefix,
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
@ -566,7 +583,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, prefix_path, TRUE, &prefix_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!add_ref_to_set (remote, prefix_dfd, ref_prefix, ret_all_refs,
|
||||
if (!add_ref_to_set (remote, NULL, prefix_dfd, ref_prefix, ret_all_refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
@ -581,7 +598,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, refs_heads_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, NULL, NULL, refs_heads_dfd, base_path,
|
||||
refs_heads_dfd, ".",
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
@ -607,7 +624,7 @@ _ostree_repo_list_refs_internal (OstreeRepo *self,
|
||||
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &remote_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, dent->d_name, remote_dfd, base_path,
|
||||
if (!enumerate_refs_recurse (self, dent->d_name, NULL, remote_dfd, base_path,
|
||||
remote_dfd, ".",
|
||||
ret_all_refs,
|
||||
cancellable, error))
|
||||
@ -741,16 +758,19 @@ ostree_repo_remote_list_refs (OstreeRepo *self,
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const char *ref,
|
||||
const char *rev,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
_ostree_repo_write_ref (OstreeRepo *self,
|
||||
const char *remote,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *rev,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
glnx_fd_close int dfd = -1;
|
||||
|
||||
if (remote == NULL)
|
||||
g_return_val_if_fail (remote == NULL || ref->collection_id == NULL, FALSE);
|
||||
|
||||
if (remote == NULL &&
|
||||
(ref->collection_id == NULL || g_strcmp0 (ref->collection_id, ostree_repo_get_collection_id (self)) == 0))
|
||||
{
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE,
|
||||
&dfd, error))
|
||||
@ -759,6 +779,29 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (remote == NULL && ref->collection_id != NULL)
|
||||
{
|
||||
glnx_fd_close int refs_mirrors_dfd = -1;
|
||||
|
||||
/* refs/mirrors might not exist in older repositories, so create it. */
|
||||
if (!glnx_shutil_mkdir_p_at_open (self->repo_dir_fd, "refs/mirrors", 0777,
|
||||
&refs_mirrors_dfd, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Opening %s: ", "refs/mirrors");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (rev != NULL)
|
||||
{
|
||||
/* Ensure we have a dir for the collection */
|
||||
if (!glnx_shutil_mkdir_p_at (refs_mirrors_dfd, ref->collection_id, 0777, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
dfd = glnx_opendirat_with_errno (refs_mirrors_dfd, ref->collection_id, TRUE);
|
||||
if (dfd < 0 && (errno != ENOENT || rev != NULL))
|
||||
return glnx_throw_errno_prefix (error, "Opening mirrors/ dir %s", ref->collection_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
glnx_fd_close int refs_remotes_dfd = -1;
|
||||
@ -786,7 +829,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
{
|
||||
if (dfd >= 0)
|
||||
{
|
||||
if (unlinkat (dfd, ref, 0) != 0)
|
||||
if (unlinkat (dfd, ref->ref_name, 0) != 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return glnx_throw_errno (error);
|
||||
@ -795,7 +838,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!write_checksum_file_at (self, dfd, ref, rev, cancellable, error))
|
||||
if (!write_checksum_file_at (self, dfd, ref->ref_name, rev, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@ -807,7 +850,7 @@ _ostree_repo_write_ref (OstreeRepo *self,
|
||||
|
||||
gboolean
|
||||
_ostree_repo_update_refs (OstreeRepo *self,
|
||||
GHashTable *refs,
|
||||
GHashTable *refs, /* (element-type utf8 utf8) */
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
@ -820,15 +863,135 @@ _ostree_repo_update_refs (OstreeRepo *self,
|
||||
const char *refspec = key;
|
||||
const char *rev = value;
|
||||
g_autofree char *remote = NULL;
|
||||
g_autofree char *ref = NULL;
|
||||
g_autofree char *ref_name = NULL;
|
||||
|
||||
if (!ostree_parse_refspec (refspec, &remote, &ref, error))
|
||||
if (!ostree_parse_refspec (refspec, &remote, &ref_name, error))
|
||||
return FALSE;
|
||||
|
||||
if (!_ostree_repo_write_ref (self, remote, ref, rev,
|
||||
const OstreeCollectionRef ref = { NULL, ref_name };
|
||||
if (!_ostree_repo_write_ref (self, remote, &ref, rev,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
_ostree_repo_update_collection_refs (OstreeRepo *self,
|
||||
GHashTable *refs, /* (element-type OstreeCollectionRef utf8) */
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
GHashTableIter hash_iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&hash_iter, refs);
|
||||
while (g_hash_table_iter_next (&hash_iter, &key, &value))
|
||||
{
|
||||
const OstreeCollectionRef *ref = key;
|
||||
const char *rev = value;
|
||||
|
||||
if (!_ostree_repo_write_ref (self, NULL, ref, rev,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* ostree_repo_list_collection_refs:
|
||||
* @self: Repo
|
||||
* @match_collection_id: (nullable): If non-%NULL, only list refs from this collection
|
||||
* @out_all_refs: (out) (element-type OstreeCollectionRef utf8): Mapping from collection–ref to checksum
|
||||
* @cancellable: Cancellable
|
||||
* @error: Error
|
||||
*
|
||||
* List all local and mirrored refs, mapping them to the commit checksums they
|
||||
* currently point to in @out_all_refs. If @match_collection_id is specified,
|
||||
* the results will be limited to those with an equal collection ID.
|
||||
*
|
||||
* #OstreeCollectionRefs are guaranteed to be returned with their collection ID
|
||||
* set to a non-%NULL value; so no refs from `refs/heads` will be listed if no
|
||||
* collection ID is configured for the repository
|
||||
* (ostree_repo_get_collection_id()).
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE otherwise
|
||||
* Since: 2017.8
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_list_collection_refs (OstreeRepo *self,
|
||||
const char *match_collection_id,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (OSTREE_IS_REPO (self), FALSE);
|
||||
g_return_val_if_fail (match_collection_id == NULL ||
|
||||
ostree_validate_collection_id (match_collection_id, NULL), FALSE);
|
||||
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
g_autoptr(GHashTable) ret_all_refs = NULL;
|
||||
|
||||
ret_all_refs = g_hash_table_new_full (ostree_collection_ref_hash,
|
||||
ostree_collection_ref_equal,
|
||||
(GDestroyNotify) ostree_collection_ref_free,
|
||||
g_free);
|
||||
|
||||
g_auto(GLnxDirFdIterator) dfd_iter = { 0, };
|
||||
g_autoptr(GString) base_path = g_string_new ("");
|
||||
|
||||
const gchar *main_collection_id = ostree_repo_get_collection_id (self);
|
||||
|
||||
if (main_collection_id != NULL &&
|
||||
(match_collection_id == NULL || g_strcmp0 (match_collection_id, main_collection_id) == 0))
|
||||
{
|
||||
glnx_fd_close int refs_heads_dfd = -1;
|
||||
|
||||
if (!glnx_opendirat (self->repo_dir_fd, "refs/heads", TRUE, &refs_heads_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, main_collection_id, refs_heads_dfd, base_path,
|
||||
refs_heads_dfd, ".",
|
||||
ret_all_refs, cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_string_truncate (base_path, 0);
|
||||
|
||||
gboolean refs_mirrors_exists = FALSE;
|
||||
if (!ot_dfd_iter_init_allow_noent (self->repo_dir_fd, "refs/mirrors",
|
||||
&dfd_iter, &refs_mirrors_exists, error))
|
||||
return FALSE;
|
||||
|
||||
while (refs_mirrors_exists)
|
||||
{
|
||||
struct dirent *dent;
|
||||
glnx_fd_close int collection_dfd = -1;
|
||||
|
||||
if (!glnx_dirfd_iterator_next_dent_ensure_dtype (&dfd_iter, &dent, cancellable, error))
|
||||
return FALSE;
|
||||
if (!dent)
|
||||
break;
|
||||
|
||||
if (dent->d_type != DT_DIR)
|
||||
continue;
|
||||
|
||||
if (match_collection_id != NULL && g_strcmp0 (match_collection_id, dent->d_name) != 0)
|
||||
continue;
|
||||
|
||||
if (!glnx_opendirat (dfd_iter.fd, dent->d_name, TRUE, &collection_dfd, error))
|
||||
return FALSE;
|
||||
|
||||
if (!enumerate_refs_recurse (self, NULL, dent->d_name, collection_dfd, base_path,
|
||||
collection_dfd, ".",
|
||||
ret_all_refs,
|
||||
cancellable, error))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ot_transfer_out_value (out_all_refs, &ret_all_refs);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -475,6 +475,7 @@ ostree_repo_finalize (GObject *object)
|
||||
if (self->config)
|
||||
g_key_file_free (self->config);
|
||||
g_clear_pointer (&self->txn_refs, g_hash_table_destroy);
|
||||
g_clear_pointer (&self->txn_collection_refs, g_hash_table_destroy);
|
||||
g_clear_error (&self->writable_error);
|
||||
g_clear_pointer (&self->object_sizes, (GDestroyNotify) g_hash_table_unref);
|
||||
g_clear_pointer (&self->dirmeta_cache, (GDestroyNotify) g_hash_table_unref);
|
||||
@ -1703,7 +1704,8 @@ ostree_repo_create (OstreeRepo *self,
|
||||
glnx_fd_close int dfd = -1;
|
||||
struct stat stbuf;
|
||||
const char *state_dirs[] = { "objects", "tmp", "extensions", "state",
|
||||
"refs", "refs/heads", "refs/remotes" };
|
||||
"refs", "refs/heads", "refs/mirrors",
|
||||
"refs/remotes" };
|
||||
|
||||
if (mkdir (repopath, 0755) != 0)
|
||||
{
|
||||
@ -4568,6 +4570,13 @@ summary_add_ref_entry (OstreeRepo *self,
|
||||
*
|
||||
* It is regenerated automatically after a commit if
|
||||
* `core/commit-update-summary` is set.
|
||||
*
|
||||
* If the `core/collection-id` key is set in the configuration, it will be
|
||||
* included as %OSTREE_SUMMARY_COLLECTION_ID in the summary file. Refs from the
|
||||
* `refs/mirrors` directory will be included in the generated summary file,
|
||||
* listed under the %OSTREE_SUMMARY_COLLECTION_MAP key. Collection IDs and refs
|
||||
* in %OSTREE_SUMMARY_COLLECTION_MAP are guaranteed to be in lexicographic
|
||||
* order.
|
||||
*/
|
||||
gboolean
|
||||
ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
@ -4579,21 +4588,26 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
g_variant_dict_init (&additional_metadata_builder, additional_metadata);
|
||||
g_autoptr(GVariantBuilder) refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(s(taya{sv}))"));
|
||||
|
||||
const gchar *main_collection_id = ostree_repo_get_collection_id (self);
|
||||
|
||||
{
|
||||
g_autoptr(GHashTable) refs = NULL;
|
||||
if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs);
|
||||
ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp);
|
||||
|
||||
for (GList *iter = ordered_keys; iter; iter = iter->next)
|
||||
if (main_collection_id == NULL)
|
||||
{
|
||||
const char *ref = iter->data;
|
||||
const char *commit = g_hash_table_lookup (refs, ref);
|
||||
|
||||
if (!summary_add_ref_entry (self, ref, commit, refs_builder, error))
|
||||
g_autoptr(GHashTable) refs = NULL;
|
||||
if (!ostree_repo_list_refs (self, NULL, &refs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
g_autoptr(GList) ordered_keys = g_hash_table_get_keys (refs);
|
||||
ordered_keys = g_list_sort (ordered_keys, (GCompareFunc)strcmp);
|
||||
|
||||
for (GList *iter = ordered_keys; iter; iter = iter->next)
|
||||
{
|
||||
const char *ref = iter->data;
|
||||
const char *commit = g_hash_table_lookup (refs, ref);
|
||||
|
||||
if (!summary_add_ref_entry (self, ref, commit, refs_builder, error))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4640,6 +4654,88 @@ ostree_repo_regenerate_summary (OstreeRepo *self,
|
||||
g_variant_new_uint64 (GUINT64_TO_BE (g_get_real_time () / G_USEC_PER_SEC)));
|
||||
}
|
||||
|
||||
/* Add refs which have a collection specified. ostree_repo_list_collection_refs()
|
||||
* is guaranteed to only return refs which are in refs/mirrors, or those which
|
||||
* are in refs/heads if the repository configuration specifies a collection ID
|
||||
* (which we put in the main refs map, rather than the collection map, for
|
||||
* backwards compatibility). */
|
||||
{
|
||||
g_autoptr(GHashTable) collection_refs = NULL;
|
||||
if (!ostree_repo_list_collection_refs (self, NULL, &collection_refs, cancellable, error))
|
||||
return FALSE;
|
||||
|
||||
gsize collection_map_size = 0;
|
||||
GHashTableIter iter;
|
||||
g_autoptr(GHashTable) collection_map = NULL; /* (element-type utf8 GHashTable) */
|
||||
g_hash_table_iter_init (&iter, collection_refs);
|
||||
collection_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
|
||||
(GDestroyNotify) g_hash_table_unref);
|
||||
|
||||
const OstreeCollectionRef *ref;
|
||||
const char *checksum;
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &ref, (gpointer *) &checksum))
|
||||
{
|
||||
GHashTable *ref_map = g_hash_table_lookup (collection_map, ref->collection_id);
|
||||
|
||||
if (ref_map == NULL)
|
||||
{
|
||||
ref_map = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
|
||||
g_hash_table_insert (collection_map, ref->collection_id, ref_map);
|
||||
}
|
||||
|
||||
g_hash_table_insert (ref_map, ref->ref_name, (gpointer) checksum);
|
||||
}
|
||||
|
||||
g_autoptr(GVariantBuilder) collection_refs_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sa(s(taya{sv}))}"));
|
||||
|
||||
g_autoptr(GList) ordered_collection_ids = g_hash_table_get_keys (collection_map);
|
||||
ordered_collection_ids = g_list_sort (ordered_collection_ids, (GCompareFunc) strcmp);
|
||||
|
||||
for (GList *collection_iter = ordered_collection_ids; collection_iter; collection_iter = collection_iter->next)
|
||||
{
|
||||
const char *collection_id = collection_iter->data;
|
||||
GHashTable *ref_map = g_hash_table_lookup (collection_map, collection_id);
|
||||
|
||||
gboolean is_main_collection_id = (main_collection_id != NULL && g_str_equal (collection_id, main_collection_id));
|
||||
|
||||
if (!is_main_collection_id)
|
||||
{
|
||||
g_variant_builder_open (collection_refs_builder, G_VARIANT_TYPE ("{sa(s(taya{sv}))}"));
|
||||
g_variant_builder_add (collection_refs_builder, "s", collection_id);
|
||||
g_variant_builder_open (collection_refs_builder, G_VARIANT_TYPE ("a(s(taya{sv}))"));
|
||||
}
|
||||
|
||||
g_autoptr(GList) ordered_refs = g_hash_table_get_keys (ref_map);
|
||||
ordered_refs = g_list_sort (ordered_refs, (GCompareFunc) strcmp);
|
||||
|
||||
for (GList *ref_iter = ordered_refs; ref_iter != NULL; ref_iter = ref_iter->next)
|
||||
{
|
||||
const char *ref = ref_iter->data;
|
||||
const char *commit = g_hash_table_lookup (ref_map, ref);
|
||||
GVariantBuilder *builder = is_main_collection_id ? refs_builder : collection_refs_builder;
|
||||
|
||||
if (!summary_add_ref_entry (self, ref, commit, builder, error))
|
||||
return FALSE;
|
||||
|
||||
if (!is_main_collection_id)
|
||||
collection_map_size++;
|
||||
}
|
||||
|
||||
if (!is_main_collection_id)
|
||||
{
|
||||
g_variant_builder_close (collection_refs_builder); /* array */
|
||||
g_variant_builder_close (collection_refs_builder); /* dict entry */
|
||||
}
|
||||
}
|
||||
|
||||
if (main_collection_id != NULL)
|
||||
g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_COLLECTION_ID,
|
||||
g_variant_new_string (main_collection_id));
|
||||
if (collection_map_size > 0)
|
||||
g_variant_dict_insert_value (&additional_metadata_builder, OSTREE_SUMMARY_COLLECTION_MAP,
|
||||
g_variant_builder_end (collection_refs_builder));
|
||||
}
|
||||
|
||||
g_autoptr(GVariant) summary = NULL;
|
||||
{
|
||||
g_autoptr(GVariantBuilder) summary_builder =
|
||||
|
@ -309,6 +309,15 @@ void ostree_repo_transaction_set_ref (OstreeRepo *self,
|
||||
const char *ref,
|
||||
const char *checksum);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_transaction_set_collection_ref (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum);
|
||||
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_set_ref_immediate (OstreeRepo *self,
|
||||
const char *remote,
|
||||
@ -317,6 +326,17 @@ gboolean ostree_repo_set_ref_immediate (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_set_collection_ref_immediate (OstreeRepo *self,
|
||||
const OstreeCollectionRef *ref,
|
||||
const char *checksum,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_has_object (OstreeRepo *self,
|
||||
OstreeObjectType objtype,
|
||||
@ -1068,6 +1088,17 @@ gboolean ostree_repo_pull_with_options (OstreeRepo *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
gboolean ostree_repo_list_collection_refs (OstreeRepo *self,
|
||||
const char *match_collection_id,
|
||||
GHashTable **out_all_refs,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
|
||||
|
||||
_OSTREE_PUBLIC
|
||||
void ostree_repo_pull_default_console_progress_changed (OstreeAsyncProgress *progress,
|
||||
gpointer user_data);
|
||||
|
@ -492,7 +492,7 @@ echo "ok pull-local with --remote arg"
|
||||
cd ${test_tmpdir}
|
||||
${CMD_PREFIX} ostree --repo=repo3 prune
|
||||
find repo3/objects -name '*.commit' > objlist-before-prune
|
||||
rm repo3/refs/heads/* repo3/refs/remotes/* -rf
|
||||
rm repo3/refs/heads/* repo3/refs/mirrors/* repo3/refs/remotes/* -rf
|
||||
${CMD_PREFIX} ostree --repo=repo3 prune --refs-only
|
||||
find repo3/objects -name '*.commit' > objlist-after-prune
|
||||
if cmp -s objlist-before-prune objlist-after-prune; then
|
||||
|
Loading…
x
Reference in New Issue
Block a user