core: Make commit always operate on directory contents, not file list

This simplifies things significantly, at some cost in flexibility.
We'll later add the ability to e.g. filter out files by regular
expression.
This commit is contained in:
Colin Walters 2011-11-27 18:03:05 -05:00
parent b296dc4efc
commit 7e32bc6cd7
5 changed files with 245 additions and 677 deletions

View File

@ -698,7 +698,7 @@ ostree_repo_load_variant_checked (OstreeRepo *self,
static gboolean
import_directory_meta (OstreeRepo *self,
const char *path,
GFile *f,
GVariant **out_variant,
GChecksum **out_checksum,
GError **error)
@ -706,11 +706,8 @@ import_directory_meta (OstreeRepo *self,
gboolean ret = FALSE;
GChecksum *ret_checksum = NULL;
GVariant *dirmeta = NULL;
GFile *f = NULL;
GFileInfo *f_info = NULL;
f = ot_gfile_new_for_path (path);
f_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, error);
@ -725,12 +722,17 @@ import_directory_meta (OstreeRepo *self,
goto out;
ret = TRUE;
if (out_variant)
{
*out_variant = dirmeta;
dirmeta = NULL;
}
if (out_checksum)
{
*out_checksum = ret_checksum;
ret_checksum = NULL;
}
out:
g_clear_object (&f);
g_clear_object (&f_info);
if (ret_checksum)
g_checksum_free (ret_checksum);
@ -951,56 +953,6 @@ ostree_repo_store_packfile (OstreeRepo *self,
return ret;
}
typedef struct _ParsedTreeData ParsedTreeData;
typedef struct _ParsedDirectoryData ParsedDirectoryData;
static void parsed_tree_data_free (ParsedTreeData *pdata);
struct _ParsedDirectoryData {
ParsedTreeData *tree_data;
char *metadata_sha256;
GVariant *meta_data;
};
static void
parsed_directory_data_free (ParsedDirectoryData *pdata)
{
if (pdata == NULL)
return;
parsed_tree_data_free (pdata->tree_data);
g_free (pdata->metadata_sha256);
ot_clear_gvariant (&pdata->meta_data);
g_free (pdata);
}
struct _ParsedTreeData {
GHashTable *files; /* char* filename -> char* checksum */
GHashTable *directories; /* char* dirname -> ParsedDirectoryData* */
};
static ParsedTreeData *
parsed_tree_data_new (void)
{
ParsedTreeData *ret = g_new0 (ParsedTreeData, 1);
ret->files = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)g_free);
ret->directories = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free,
(GDestroyNotify)parsed_directory_data_free);
return ret;
}
static void
parsed_tree_data_free (ParsedTreeData *pdata)
{
if (pdata == NULL)
return;
g_hash_table_destroy (pdata->files);
g_hash_table_destroy (pdata->directories);
g_free (pdata);
}
static GVariant *
create_empty_gvariant_dict (void)
{
@ -1009,315 +961,6 @@ create_empty_gvariant_dict (void)
return g_variant_builder_end (&builder);
}
static gboolean
import_parsed_tree (OstreeRepo *self,
ParsedTreeData *tree,
GChecksum **out_checksum,
GError **error)
{
gboolean ret = FALSE;
GVariant *serialized_tree = NULL;
gboolean builders_initialized = FALSE;
GVariantBuilder files_builder;
GVariantBuilder dirs_builder;
GHashTableIter hash_iter;
GSList *sorted_filenames = NULL;
GSList *iter;
gpointer key, value;
g_variant_builder_init (&files_builder, G_VARIANT_TYPE ("a(ss)"));
g_variant_builder_init (&dirs_builder, G_VARIANT_TYPE ("a(sss)"));
builders_initialized = TRUE;
g_hash_table_iter_init (&hash_iter, tree->files);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *name = key;
sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
}
sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
for (iter = sorted_filenames; iter; iter = iter->next)
{
const char *name = iter->data;
const char *value;
value = g_hash_table_lookup (tree->files, name);
g_variant_builder_add (&files_builder, "(ss)", name, value);
}
g_slist_free (sorted_filenames);
sorted_filenames = NULL;
g_hash_table_iter_init (&hash_iter, tree->directories);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *name = key;
sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
}
sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
for (iter = sorted_filenames; iter; iter = iter->next)
{
const char *name = iter->data;
GChecksum *dir_checksum = NULL;
ParsedDirectoryData *dir;
dir = g_hash_table_lookup (tree->directories, name);
if (!import_parsed_tree (self, dir->tree_data, &dir_checksum, error))
goto out;
g_variant_builder_add (&dirs_builder, "(sss)",
name, g_checksum_get_string (dir_checksum), dir->metadata_sha256);
g_checksum_free (dir_checksum);
}
g_slist_free (sorted_filenames);
sorted_filenames = NULL;
serialized_tree = g_variant_new ("(u@a{sv}@a(ss)@a(sss))",
GUINT32_TO_BE (0),
create_empty_gvariant_dict (),
g_variant_builder_end (&files_builder),
g_variant_builder_end (&dirs_builder));
builders_initialized = FALSE;
g_variant_ref_sink (serialized_tree);
if (!import_gvariant_object (self, OSTREE_SERIALIZED_TREE_VARIANT, serialized_tree, out_checksum, error))
goto out;
ret = TRUE;
out:
g_slist_free (sorted_filenames);
if (builders_initialized)
{
g_variant_builder_clear (&files_builder);
g_variant_builder_clear (&dirs_builder);
}
ot_clear_gvariant (&serialized_tree);
return ret;
}
static gboolean
check_path (const char *filename,
GError **error)
{
gboolean ret = FALSE;
if (!*filename)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid empty filename");
goto out;
}
if (strcmp (filename, ".") == 0)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Self-reference '.' in filename '%s' not allowed (yet)", filename);
goto out;
}
if (ot_util_filename_has_dotdot (filename))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Path uplink '..' in filename '%s' not allowed (yet)", filename);
goto out;
}
if (g_path_is_absolute (filename))
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Absolute filename '%s' not allowed (yet)", filename);
goto out;
}
ret = TRUE;
out:
return ret;
}
static gboolean
add_one_directory_to_tree_and_import (OstreeRepo *self,
const char *basename,
const char *abspath,
ParsedTreeData *tree,
ParsedDirectoryData **dir, /*inout*/
GError **error)
{
gboolean ret = FALSE;
GVariant *dirmeta = NULL;
GChecksum *dir_meta_checksum = NULL;
ParsedDirectoryData *dir_value = *dir;
g_assert (tree != NULL);
if (!import_directory_meta (self, abspath, &dirmeta, &dir_meta_checksum, error))
goto out;
if (dir_value)
{
ot_clear_gvariant (&dir_value->meta_data);
dir_value->meta_data = dirmeta;
}
else
{
dir_value = g_new0 (ParsedDirectoryData, 1);
dir_value->tree_data = parsed_tree_data_new ();
dir_value->metadata_sha256 = g_strdup (g_checksum_get_string (dir_meta_checksum));
dir_value->meta_data = dirmeta;
g_hash_table_insert (tree->directories, g_strdup (basename), dir_value);
}
ret = TRUE;
*dir = dir_value;
out:
if (dir_meta_checksum)
g_checksum_free (dir_meta_checksum);
return ret;
}
static gboolean
add_one_file_to_tree_and_import (OstreeRepo *self,
const char *basename,
const char *abspath,
ParsedTreeData *tree,
GError **error)
{
gboolean ret = FALSE;
GChecksum *checksum = NULL;
gboolean did_exist;
GFile *f = NULL;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_assert (tree != NULL);
f = ot_gfile_new_for_path (abspath);
if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_FILE, &checksum, NULL, error))
goto out;
if (!ostree_repo_store_object_trusted (self, f, g_checksum_get_string (checksum),
OSTREE_OBJECT_TYPE_FILE, FALSE, &did_exist, error))
goto out;
g_hash_table_replace (tree->files, g_strdup (basename),
g_strdup (g_checksum_get_string (checksum)));
ret = TRUE;
out:
g_clear_object (&f);
if (checksum)
g_checksum_free (checksum);
return ret;
}
static gboolean
add_one_path_to_tree_and_import (OstreeRepo *self,
const char *base,
const char *filename,
ParsedTreeData *tree,
GError **error)
{
gboolean ret = FALSE;
GPtrArray *components = NULL;
struct stat stbuf;
char *component_abspath = NULL;
ParsedTreeData *current_tree = tree;
const char *component = NULL;
const char *file_sha1;
char *abspath = NULL;
ParsedDirectoryData *dir;
int i;
gboolean is_directory;
if (!check_path (filename, error))
goto out;
abspath = g_build_filename (base, filename, NULL);
if (lstat (abspath, &stbuf) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
is_directory = S_ISDIR(stbuf.st_mode);
if (components)
g_ptr_array_free (components, TRUE);
components = ot_util_path_split (filename);
g_assert (components->len > 0);
current_tree = tree;
for (i = 0; i < components->len; i++)
{
component = components->pdata[i];
g_free (component_abspath);
component_abspath = ot_util_path_join_n (base, components, i);
file_sha1 = g_hash_table_lookup (current_tree->files, component);
dir = g_hash_table_lookup (current_tree->directories, component);
g_assert_cmpstr (component, !=, ".");
if (i < components->len - 1)
{
if (file_sha1 != NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Encountered non-directory '%s' in '%s'",
component,
filename);
goto out;
}
/* Implicitly add intermediate directories */
if (!add_one_directory_to_tree_and_import (self, component,
component_abspath, current_tree, &dir,
error))
goto out;
g_assert (dir != NULL);
current_tree = dir->tree_data;
}
else if (is_directory)
{
if (file_sha1 != NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"File '%s' can't be overwritten by directory",
filename);
goto out;
}
if (!add_one_directory_to_tree_and_import (self, component,
abspath, current_tree, &dir,
error))
goto out;
}
else
{
g_assert (!is_directory);
if (dir != NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"File '%s' can't be overwritten by directory",
filename);
goto out;
}
if (!add_one_file_to_tree_and_import (self, component, abspath,
current_tree, error))
goto out;
}
}
ret = TRUE;
out:
if (components)
g_ptr_array_unref (components);
g_free (component_abspath);
g_free (abspath);
return ret;
}
gboolean
ostree_repo_write_ref (OstreeRepo *self,
const char *remote,
@ -1349,18 +992,18 @@ ostree_repo_write_ref (OstreeRepo *self,
}
static gboolean
commit_parsed_tree (OstreeRepo *self,
import_commit (OstreeRepo *self,
const char *branch,
const char *parent,
const char *subject,
const char *body,
GVariant *metadata,
ParsedDirectoryData *root,
GChecksum *root_contents_checksum,
GChecksum *root_metadata_checksum,
GChecksum **out_commit,
GError **error)
{
gboolean ret = FALSE;
GChecksum *root_checksum = NULL;
GChecksum *ret_commit = NULL;
GVariant *commit = NULL;
GDateTime *now = NULL;
@ -1368,9 +1011,6 @@ commit_parsed_tree (OstreeRepo *self,
g_assert (branch != NULL);
g_assert (subject != NULL);
if (!import_parsed_tree (self, root->tree_data, &root_checksum, error))
goto out;
now = g_date_time_new_now_utc ();
commit = g_variant_new ("(u@a{sv}ssstss)",
GUINT32_TO_BE (OSTREE_COMMIT_VERSION),
@ -1378,8 +1018,8 @@ commit_parsed_tree (OstreeRepo *self,
parent ? parent : "",
subject, body ? body : "",
GUINT64_TO_BE (g_date_time_to_unix (now)),
g_checksum_get_string (root_checksum),
root->metadata_sha256);
g_checksum_get_string (root_contents_checksum),
g_checksum_get_string (root_metadata_checksum));
g_variant_ref_sink (commit);
if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
commit, &ret_commit, error))
@ -1389,10 +1029,14 @@ commit_parsed_tree (OstreeRepo *self,
goto out;
ret = TRUE;
if (out_commit)
{
*out_commit = ret_commit;
ret_commit = NULL;
}
out:
if (root_checksum)
g_checksum_free (root_checksum);
if (ret_commit)
g_checksum_free (ret_commit);
ot_clear_gvariant (&commit);
if (now)
g_date_time_unref (now);
@ -1400,60 +1044,201 @@ commit_parsed_tree (OstreeRepo *self,
}
static gboolean
import_root (OstreeRepo *self,
const char *base,
ParsedDirectoryData **out_root,
import_directory_recurse (OstreeRepo *self,
GFile *base,
GFile *dir,
GChecksum **out_contents_checksum,
GChecksum **out_metadata_checksum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
ParsedDirectoryData *ret_root = NULL;
GVariant *root_metadata = NULL;
GChecksum *root_meta_checksum = NULL;
GError *temp_error = NULL;
GChecksum *ret_metadata_checksum = NULL;
GChecksum *ret_contents_checksum = NULL;
GFileEnumerator *dir_enum = NULL;
GFileInfo *child_info = NULL;
GFile *child = NULL;
GHashTable *file_checksums = NULL;
GHashTable *dir_metadata_checksums = NULL;
GHashTable *dir_contents_checksums = NULL;
GChecksum *child_file_checksum = NULL;
gboolean did_exist;
gboolean builders_initialized = FALSE;
GVariantBuilder files_builder;
GVariantBuilder dirs_builder;
GHashTableIter hash_iter;
GSList *sorted_filenames = NULL;
GSList *iter;
GVariant *serialized_tree = NULL;
gpointer key, value;
if (!import_directory_meta (self, base, &root_metadata, &root_meta_checksum, error))
if (!import_directory_meta (self, dir, NULL, &ret_metadata_checksum, error))
goto out;
ret_root = g_new0 (ParsedDirectoryData, 1);
ret_root->tree_data = parsed_tree_data_new ();
ret_root->meta_data = root_metadata;
root_metadata = NULL;
ret_root->metadata_sha256 = g_strdup (g_checksum_get_string (root_meta_checksum));
dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
file_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
dir_metadata_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
dir_contents_checksums = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify)g_free, (GDestroyNotify)g_free);
while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name = g_file_info_get_name (child_info);
g_clear_object (&child);
child = g_file_get_child (dir, name);
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
{
GChecksum *child_dir_metadata_checksum;
GChecksum *child_dir_contents_checksum;
if (!import_directory_recurse (self, base, child, &child_dir_contents_checksum,
&child_dir_metadata_checksum, cancellable, error))
goto out;
g_hash_table_replace (dir_contents_checksums, g_strdup (name),
g_strdup (g_checksum_get_string (child_dir_contents_checksum)));
g_hash_table_replace (dir_metadata_checksums, g_strdup (name),
g_strdup (g_checksum_get_string (child_dir_metadata_checksum)));
g_checksum_free (child_dir_contents_checksum);
g_checksum_free (child_dir_metadata_checksum);
}
else
{
if (child_file_checksum)
g_checksum_free (child_file_checksum);
if (!ostree_checksum_file (child, OSTREE_OBJECT_TYPE_FILE, &child_file_checksum, cancellable, error))
goto out;
if (!ostree_repo_store_object_trusted (self, child, g_checksum_get_string (child_file_checksum),
OSTREE_OBJECT_TYPE_FILE, FALSE, &did_exist, error))
goto out;
g_hash_table_replace (file_checksums, g_strdup (name),
g_strdup (g_checksum_get_string (child_file_checksum)));
}
g_clear_object (&child_info);
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
g_variant_builder_init (&files_builder, G_VARIANT_TYPE ("a(ss)"));
g_variant_builder_init (&dirs_builder, G_VARIANT_TYPE ("a(sss)"));
builders_initialized = TRUE;
g_hash_table_iter_init (&hash_iter, file_checksums);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *name = key;
sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
}
sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
for (iter = sorted_filenames; iter; iter = iter->next)
{
const char *name = iter->data;
const char *value;
value = g_hash_table_lookup (file_checksums, name);
g_variant_builder_add (&files_builder, "(ss)", name, value);
}
g_slist_free (sorted_filenames);
sorted_filenames = NULL;
g_hash_table_iter_init (&hash_iter, dir_metadata_checksums);
while (g_hash_table_iter_next (&hash_iter, &key, &value))
{
const char *name = key;
sorted_filenames = g_slist_prepend (sorted_filenames, (char*)name);
}
sorted_filenames = g_slist_sort (sorted_filenames, (GCompareFunc)strcmp);
for (iter = sorted_filenames; iter; iter = iter->next)
{
const char *name = iter->data;
g_variant_builder_add (&dirs_builder, "(sss)",
name,
g_hash_table_lookup (dir_contents_checksums, name),
g_hash_table_lookup (dir_metadata_checksums, name));
}
g_slist_free (sorted_filenames);
sorted_filenames = NULL;
serialized_tree = g_variant_new ("(u@a{sv}@a(ss)@a(sss))",
GUINT32_TO_BE (0),
create_empty_gvariant_dict (),
g_variant_builder_end (&files_builder),
g_variant_builder_end (&dirs_builder));
builders_initialized = FALSE;
g_variant_ref_sink (serialized_tree);
if (!import_gvariant_object (self, OSTREE_SERIALIZED_TREE_VARIANT, serialized_tree, &ret_contents_checksum, error))
goto out;
*out_metadata_checksum = ret_metadata_checksum;
ret_metadata_checksum = NULL;
*out_contents_checksum = ret_contents_checksum;
ret_contents_checksum = NULL;
ret = TRUE;
*out_root = ret_root;
ret_root = NULL;
out:
ot_clear_gvariant (&root_metadata);
if (root_meta_checksum)
g_checksum_free (root_meta_checksum);
parsed_directory_data_free (ret_root);
g_clear_object (&dir_enum);
g_clear_object (&child);
g_clear_object (&child_info);
g_hash_table_destroy (file_checksums);
g_hash_table_destroy (dir_metadata_checksums);
g_hash_table_destroy (dir_contents_checksums);
if (ret_metadata_checksum)
g_checksum_free (ret_metadata_checksum);
if (ret_contents_checksum)
g_checksum_free (ret_contents_checksum);
if (child_file_checksum)
g_checksum_free (child_file_checksum);
g_slist_free (sorted_filenames);
if (builders_initialized)
{
g_variant_builder_clear (&files_builder);
g_variant_builder_clear (&dirs_builder);
}
ot_clear_gvariant (&serialized_tree);
return ret;
}
gboolean
ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
ostree_repo_commit (OstreeRepo *self,
const char *branch,
const char *parent,
const char *subject,
const char *body,
GVariant *metadata,
const char *base,
int fd,
char separator,
GFile *dir,
GChecksum **out_commit,
GCancellable *cancellable,
GError **error)
{
OstreeRepoPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE;
ParsedDirectoryData *root = NULL;
GChecksum *ret_commit_checksum = NULL;
GUnixInputStream *in = NULL;
GDataInputStream *datain = NULL;
char *filename = NULL;
gsize filename_len;
GError *temp_error = NULL;
GVariant *root_metadata = NULL;
GChecksum *root_meta_checksum = NULL;
GChecksum *root_metadata_checksum = NULL;
GChecksum *root_contents_checksum = NULL;
char *current_head = NULL;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
@ -1465,39 +1250,14 @@ ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
if (parent == NULL)
parent = branch;
/* We're overwriting the tree */
if (!import_root (self, base, &root, error))
goto out;
if (!ostree_repo_resolve_rev (self, parent, TRUE, &current_head, error))
goto out;
in = (GUnixInputStream*)g_unix_input_stream_new (fd, FALSE);
datain = g_data_input_stream_new ((GInputStream*)in);
if (!import_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
goto out;
while ((filename = g_data_input_stream_read_upto (datain, &separator, 1,
&filename_len, NULL, &temp_error)) != NULL)
{
if (!g_data_input_stream_read_byte (datain, NULL, &temp_error))
{
if (temp_error != NULL)
{
g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
goto out;
}
}
if (!add_one_path_to_tree_and_import (self, base, filename, root->tree_data, error))
goto out;
g_free (filename);
filename = NULL;
}
if (filename == NULL && temp_error != NULL)
{
g_propagate_prefixed_error (error, temp_error, "%s", "While reading filelist: ");
goto out;
}
if (!commit_parsed_tree (self, branch, current_head, subject, body, metadata,
root, &ret_commit_checksum, error))
if (!import_commit (self, branch, current_head, subject, body, metadata,
root_contents_checksum, root_metadata_checksum, &ret_commit_checksum, error))
goto out;
ret = TRUE;
@ -1507,13 +1267,10 @@ ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
if (ret_commit_checksum)
g_checksum_free (ret_commit_checksum);
g_free (current_head);
ot_clear_gvariant (&root_metadata);
if (root_meta_checksum)
g_checksum_free (root_meta_checksum);
g_clear_object (&datain);
g_clear_object (&in);
g_free (filename);
parsed_directory_data_free (root);
if (root_metadata_checksum)
g_checksum_free (root_metadata_checksum);
if (root_contents_checksum)
g_checksum_free (root_contents_checksum);
return ret;
}

View File

@ -110,16 +110,15 @@ gboolean ostree_repo_load_variant_checked (OstreeRepo *self,
GVariant **out_variant,
GError **error);
gboolean ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
gboolean ostree_repo_commit (OstreeRepo *self,
const char *branch,
const char *parent,
const char *subject,
const char *body,
GVariant *metadata,
const char *base,
int fd,
char separator,
GFile *base,
GChecksum **out_commit,
GCancellable *cancellable,
GError **error);
gboolean ostree_repo_checkout (OstreeRepo *self,

View File

@ -29,10 +29,6 @@
#include <glib/gi18n.h>
static gboolean separator_null;
static int from_fd = -1;
static gboolean from_stdin;
static char *from_file;
static char *metadata_text_path;
static char *metadata_bin_path;
static char *subject;
@ -47,159 +43,22 @@ static GOptionEntry options[] = {
{ "metadata-variant", 0, 0, G_OPTION_ARG_FILENAME, &metadata_bin_path, "File containing serialized variant, in host endianness", "path" },
{ "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" },
{ "from-fd", 0, 0, G_OPTION_ARG_INT, &from_fd, "Read new tree files from fd", "file descriptor" },
{ "from-stdin", 0, 0, G_OPTION_ARG_NONE, &from_stdin, "Read new tree files from stdin", "file descriptor" },
{ "from-file", 0, 0, G_OPTION_ARG_FILENAME, &from_file, "Read new tree files from another file", "path" },
{ "separator-null", 0, 0, G_OPTION_ARG_NONE, &separator_null, "", "Use '\\0' as filename separator, as with find -print0" },
{ NULL }
};
typedef struct {
GFile *dir;
char separator;
GOutputStream *out;
GCancellable *cancellable;
} FindThreadData;
static gboolean
find (const char *basepath,
GFile *dir,
char separator,
GOutputStream *out,
GCancellable *cancellable,
GError **error);
static gboolean
find_write_child (const char *basepath,
GFile *dir,
char separator,
GOutputStream *out,
GFileInfo *finfo,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
guint32 type;
const char *name;
char buf[1];
const char *child_path = NULL;
GString *child_trimmed_path = NULL;
GFile *child = NULL;
gsize bytes_written;
type = g_file_info_get_attribute_uint32 (finfo, "standard::type");
name = g_file_info_get_attribute_byte_string (finfo, "standard::name");
child = g_file_get_child (dir, name);
if (type == G_FILE_TYPE_DIRECTORY)
{
if (!find (basepath, child, separator, out, cancellable, error))
goto out;
}
child_path = ot_gfile_get_path_cached (child);
child_trimmed_path = g_string_new (child_path + strlen (basepath));
if (!*(child_trimmed_path->str))
{
/* do nothing - we implicitly add the root . */
}
else
{
g_assert (*(child_trimmed_path->str) == '/');
g_string_insert_c (child_trimmed_path, 0, '.');
if (!g_output_stream_write_all (out, child_trimmed_path->str, child_trimmed_path->len,
&bytes_written, cancellable, error))
goto out;
buf[0] = separator;
if (!g_output_stream_write_all (out, buf, 1, &bytes_written,
cancellable, error))
goto out;
}
ret = TRUE;
out:
g_string_free (child_trimmed_path, TRUE);
child_trimmed_path = NULL;
child_path = NULL;
g_clear_object (&child);
return ret;
}
static gboolean
find (const char *basepath,
GFile *dir,
char separator,
GOutputStream *out,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GError *temp_error = NULL;
GFileEnumerator *enumerator = NULL;
GFileInfo *finfo = NULL;
enumerator = g_file_enumerate_children (dir, "standard::type,standard::name",
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
if (!enumerator)
goto out;
while ((finfo = g_file_enumerator_next_file (enumerator, cancellable, error)) != NULL)
{
if (!find_write_child (basepath, dir, separator, out, finfo, cancellable, error))
goto out;
g_clear_object (&finfo);
}
if (temp_error)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&finfo);
g_clear_object (&enumerator);
return ret;
}
static gpointer
find_thread (gpointer data)
{
FindThreadData *tdata = data;
GError *error = NULL;
const char *path;
path = ot_gfile_get_path_cached (tdata->dir);
if (!find (path, tdata->dir, tdata->separator, tdata->out,
tdata->cancellable, &error))
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
g_clear_object (&(tdata->dir));
g_clear_object (&(tdata->out));
return NULL;
}
gboolean
ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
OstreeRepo *repo = NULL;
char *dir = NULL;
char *dirpath = NULL;
GFile *dir = NULL;
GChecksum *commit_checksum = NULL;
char separator;
GVariant *metadata = NULL;
GMappedFile *metadata_mappedf = NULL;
GFile *metadata_f = NULL;
gboolean temp_fd = -1;
int pipefd[2] = { -1, -1 };
GOutputStream *out = NULL;
FindThreadData fdata;
context = g_option_context_new ("[DIR] - Commit a new revision");
g_option_context_add_main_entries (context, options, NULL);
@ -208,22 +67,22 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
goto out;
if (argc > 1)
dir = g_strdup (argv[1]);
dirpath = g_strdup (argv[1]);
else
dir = g_get_current_dir ();
dirpath = g_get_current_dir ();
if (g_str_has_suffix (dir, "/"))
dir[strlen (dir) - 1] = '\0';
if (g_str_has_suffix (dirpath, "/"))
dirpath[strlen (dirpath) - 1] = '\0';
separator = separator_null ? '\0' : '\n';
if (!*dir)
if (!*dirpath)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid empty directory");
goto out;
}
dir = ot_gfile_new_for_path (dirpath);
if (metadata_text_path || metadata_bin_path)
{
metadata_mappedf = g_mapped_file_new (metadata_text_path ? metadata_text_path : metadata_bin_path, FALSE, error);
@ -266,62 +125,15 @@ ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **er
goto out;
}
if (!(from_file || from_fd >= 0 || from_stdin))
{
/* We're using the current directory */
}
if (from_stdin)
from_fd = 0;
else if (from_file)
{
temp_fd = ot_util_open_file_read (from_file, error);
if (temp_fd < 0)
{
g_prefix_error (error, "Failed to open '%s': ", from_file);
goto out;
}
from_fd = temp_fd;
}
else
{
if (pipe (pipefd) < 0)
{
ot_util_set_error_from_errno (error, errno);
goto out;
}
out = (GOutputStream*)g_unix_output_stream_new (pipefd[1], TRUE);
from_fd = pipefd[0];
fdata.dir = ot_gfile_new_for_path (dir);
fdata.separator = separator;
fdata.out = out;
fdata.cancellable = NULL;
if (g_thread_create_full (find_thread, &fdata, 0, FALSE, FALSE, G_THREAD_PRIORITY_NORMAL, error) == NULL)
goto out;
out = NULL;
}
if (!ostree_repo_commit_from_filelist_fd (repo, branch, parent, subject, body, metadata,
dir, from_fd, separator,
&commit_checksum, error))
if (!ostree_repo_commit (repo, branch, parent, subject, body, metadata,
dir, &commit_checksum, NULL, error))
goto out;
ret = TRUE;
g_print ("%s\n", g_checksum_get_string (commit_checksum));
out:
g_clear_object (&out);
if (temp_fd >= 0)
(void)close (temp_fd);
if (pipefd[0] > 0)
(void) close (pipefd[0]);
if (pipefd[1] > 0)
(void) close (pipefd[1]);
g_free (dir);
g_free (dirpath);
g_clear_object (&dir);
if (metadata_mappedf)
g_mapped_file_unref (metadata_mappedf);
if (context)

View File

@ -71,8 +71,8 @@ mkdir -p another/nested/tree
echo anotherone > another/nested/tree/1
echo whee2 > another/whee
# FIXME - remove grep for .
find | grep -v '^\.$' | $OSTREE commit -b test2 -s "From find" --from-stdin
echo "ok stdin commit"
$OSTREE commit -b test2 -s "Another commit"
echo "ok commit"
cd ${test_tmpdir}
$OSTREE checkout test2 $test_tmpdir/checkout-test2-3

View File

@ -35,7 +35,7 @@ echo 'an ELF file' > usr/lib/libfoo.so
mkdir -p usr/share
echo 'some data' > usr/share/foo.data
find | grep -v '^\.$' | $OSTREE commit -b artifact-libfoo-runtime -s 'Build 12345 of libfoo' --from-stdin
$OSTREE commit -b artifact-libfoo-runtime -s 'Build 12345 of libfoo'
cd "${test_tmpdir}"
mkdir artifact-libfoo-devel
@ -45,7 +45,7 @@ echo 'a header' > usr/include/foo.h
mkdir -p usr/share/doc
echo 'some documentation' > usr/share/doc/foo.txt
find | grep -v '^\.$' | $OSTREE commit -b artifact-libfoo-devel -s 'Build 12345 of libfoo' --from-stdin
$OSTREE commit -b artifact-libfoo-devel -s 'Build 12345 of libfoo'
cd "${test_tmpdir}"
mkdir artifact-barapp
@ -53,7 +53,7 @@ cd artifact-barapp
mkdir -p usr/bin
echo 'another ELF file' > usr/bin/bar
find | grep -v '^\.$' | $OSTREE commit -b artifact-barapp -s 'Build 42 of barapp' --from-stdin
$OSTREE commit -b artifact-barapp -s 'Build 42 of barapp'
echo 'ok artifacts committed'