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 static gboolean
import_directory_meta (OstreeRepo *self, import_directory_meta (OstreeRepo *self,
const char *path, GFile *f,
GVariant **out_variant, GVariant **out_variant,
GChecksum **out_checksum, GChecksum **out_checksum,
GError **error) GError **error)
@ -706,11 +706,8 @@ import_directory_meta (OstreeRepo *self,
gboolean ret = FALSE; gboolean ret = FALSE;
GChecksum *ret_checksum = NULL; GChecksum *ret_checksum = NULL;
GVariant *dirmeta = NULL; GVariant *dirmeta = NULL;
GFile *f = NULL;
GFileInfo *f_info = NULL; GFileInfo *f_info = NULL;
f = ot_gfile_new_for_path (path);
f_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO, f_info = g_file_query_info (f, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
NULL, error); NULL, error);
@ -725,12 +722,17 @@ import_directory_meta (OstreeRepo *self,
goto out; goto out;
ret = TRUE; ret = TRUE;
*out_variant = dirmeta; if (out_variant)
dirmeta = NULL; {
*out_checksum = ret_checksum; *out_variant = dirmeta;
ret_checksum = NULL; dirmeta = NULL;
}
if (out_checksum)
{
*out_checksum = ret_checksum;
ret_checksum = NULL;
}
out: out:
g_clear_object (&f);
g_clear_object (&f_info); g_clear_object (&f_info);
if (ret_checksum) if (ret_checksum)
g_checksum_free (ret_checksum); g_checksum_free (ret_checksum);
@ -951,56 +953,6 @@ ostree_repo_store_packfile (OstreeRepo *self,
return ret; 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 * static GVariant *
create_empty_gvariant_dict (void) create_empty_gvariant_dict (void)
{ {
@ -1009,315 +961,6 @@ create_empty_gvariant_dict (void)
return g_variant_builder_end (&builder); 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 gboolean
ostree_repo_write_ref (OstreeRepo *self, ostree_repo_write_ref (OstreeRepo *self,
const char *remote, const char *remote,
@ -1349,18 +992,18 @@ ostree_repo_write_ref (OstreeRepo *self,
} }
static gboolean static gboolean
commit_parsed_tree (OstreeRepo *self, import_commit (OstreeRepo *self,
const char *branch, const char *branch,
const char *parent, const char *parent,
const char *subject, const char *subject,
const char *body, const char *body,
GVariant *metadata, GVariant *metadata,
ParsedDirectoryData *root, GChecksum *root_contents_checksum,
GChecksum **out_commit, GChecksum *root_metadata_checksum,
GError **error) GChecksum **out_commit,
GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
GChecksum *root_checksum = NULL;
GChecksum *ret_commit = NULL; GChecksum *ret_commit = NULL;
GVariant *commit = NULL; GVariant *commit = NULL;
GDateTime *now = NULL; GDateTime *now = NULL;
@ -1368,9 +1011,6 @@ commit_parsed_tree (OstreeRepo *self,
g_assert (branch != NULL); g_assert (branch != NULL);
g_assert (subject != 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 (); now = g_date_time_new_now_utc ();
commit = g_variant_new ("(u@a{sv}ssstss)", commit = g_variant_new ("(u@a{sv}ssstss)",
GUINT32_TO_BE (OSTREE_COMMIT_VERSION), GUINT32_TO_BE (OSTREE_COMMIT_VERSION),
@ -1378,8 +1018,8 @@ commit_parsed_tree (OstreeRepo *self,
parent ? parent : "", parent ? parent : "",
subject, body ? body : "", subject, body ? body : "",
GUINT64_TO_BE (g_date_time_to_unix (now)), GUINT64_TO_BE (g_date_time_to_unix (now)),
g_checksum_get_string (root_checksum), g_checksum_get_string (root_contents_checksum),
root->metadata_sha256); g_checksum_get_string (root_metadata_checksum));
g_variant_ref_sink (commit); g_variant_ref_sink (commit);
if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT, if (!import_gvariant_object (self, OSTREE_SERIALIZED_COMMIT_VARIANT,
commit, &ret_commit, error)) commit, &ret_commit, error))
@ -1389,10 +1029,14 @@ commit_parsed_tree (OstreeRepo *self,
goto out; goto out;
ret = TRUE; ret = TRUE;
*out_commit = ret_commit; if (out_commit)
{
*out_commit = ret_commit;
ret_commit = NULL;
}
out: out:
if (root_checksum) if (ret_commit)
g_checksum_free (root_checksum); g_checksum_free (ret_commit);
ot_clear_gvariant (&commit); ot_clear_gvariant (&commit);
if (now) if (now)
g_date_time_unref (now); g_date_time_unref (now);
@ -1400,60 +1044,201 @@ commit_parsed_tree (OstreeRepo *self,
} }
static gboolean static gboolean
import_root (OstreeRepo *self, import_directory_recurse (OstreeRepo *self,
const char *base, GFile *base,
ParsedDirectoryData **out_root, GFile *dir,
GError **error) GChecksum **out_contents_checksum,
GChecksum **out_metadata_checksum,
GCancellable *cancellable,
GError **error)
{ {
gboolean ret = FALSE; gboolean ret = FALSE;
ParsedDirectoryData *ret_root = NULL; GError *temp_error = NULL;
GVariant *root_metadata = NULL; GChecksum *ret_metadata_checksum = NULL;
GChecksum *root_meta_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; goto out;
ret_root = g_new0 (ParsedDirectoryData, 1); dir_enum = g_file_enumerate_children ((GFile*)dir, OSTREE_GIO_FAST_QUERYINFO,
ret_root->tree_data = parsed_tree_data_new (); G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
ret_root->meta_data = root_metadata; cancellable,
root_metadata = NULL; error);
ret_root->metadata_sha256 = g_strdup (g_checksum_get_string (root_meta_checksum)); 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; ret = TRUE;
*out_root = ret_root;
ret_root = NULL;
out: out:
ot_clear_gvariant (&root_metadata); g_clear_object (&dir_enum);
if (root_meta_checksum) g_clear_object (&child);
g_checksum_free (root_meta_checksum); g_clear_object (&child_info);
parsed_directory_data_free (ret_root); 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; return ret;
} }
gboolean gboolean
ostree_repo_commit_from_filelist_fd (OstreeRepo *self, ostree_repo_commit (OstreeRepo *self,
const char *branch, const char *branch,
const char *parent, const char *parent,
const char *subject, const char *subject,
const char *body, const char *body,
GVariant *metadata, GVariant *metadata,
const char *base, GFile *dir,
int fd, GChecksum **out_commit,
char separator, GCancellable *cancellable,
GChecksum **out_commit, GError **error)
GError **error)
{ {
OstreeRepoPrivate *priv = GET_PRIVATE (self); OstreeRepoPrivate *priv = GET_PRIVATE (self);
gboolean ret = FALSE; gboolean ret = FALSE;
ParsedDirectoryData *root = NULL;
GChecksum *ret_commit_checksum = NULL; GChecksum *ret_commit_checksum = NULL;
GUnixInputStream *in = NULL; GChecksum *root_metadata_checksum = NULL;
GDataInputStream *datain = NULL; GChecksum *root_contents_checksum = NULL;
char *filename = NULL;
gsize filename_len;
GError *temp_error = NULL;
GVariant *root_metadata = NULL;
GChecksum *root_meta_checksum = NULL;
char *current_head = NULL; char *current_head = NULL;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); 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) if (parent == NULL)
parent = branch; 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)) if (!ostree_repo_resolve_rev (self, parent, TRUE, &current_head, error))
goto out; goto out;
in = (GUnixInputStream*)g_unix_input_stream_new (fd, FALSE); if (!import_directory_recurse (self, dir, dir, &root_contents_checksum, &root_metadata_checksum, cancellable, error))
datain = g_data_input_stream_new ((GInputStream*)in); goto out;
while ((filename = g_data_input_stream_read_upto (datain, &separator, 1, if (!import_commit (self, branch, current_head, subject, body, metadata,
&filename_len, NULL, &temp_error)) != NULL) root_contents_checksum, root_metadata_checksum, &ret_commit_checksum, error))
{
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))
goto out; goto out;
ret = TRUE; ret = TRUE;
@ -1507,13 +1267,10 @@ ostree_repo_commit_from_filelist_fd (OstreeRepo *self,
if (ret_commit_checksum) if (ret_commit_checksum)
g_checksum_free (ret_commit_checksum); g_checksum_free (ret_commit_checksum);
g_free (current_head); g_free (current_head);
ot_clear_gvariant (&root_metadata); if (root_metadata_checksum)
if (root_meta_checksum) g_checksum_free (root_metadata_checksum);
g_checksum_free (root_meta_checksum); if (root_contents_checksum)
g_clear_object (&datain); g_checksum_free (root_contents_checksum);
g_clear_object (&in);
g_free (filename);
parsed_directory_data_free (root);
return ret; return ret;
} }

View File

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

View File

@ -29,10 +29,6 @@
#include <glib/gi18n.h> #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_text_path;
static char *metadata_bin_path; static char *metadata_bin_path;
static char *subject; 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" }, { "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" }, { "branch", 'b', 0, G_OPTION_ARG_STRING, &branch, "Branch", "branch" },
{ "parent", 'p', 0, G_OPTION_ARG_STRING, &parent, "Parent commit", "commit" }, { "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 } { 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 gboolean
ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **error) ostree_builtin_commit (int argc, char **argv, const char *repo_path, GError **error)
{ {
GOptionContext *context; GOptionContext *context;
gboolean ret = FALSE; gboolean ret = FALSE;
OstreeRepo *repo = NULL; OstreeRepo *repo = NULL;
char *dir = NULL; char *dirpath = NULL;
GFile *dir = NULL;
GChecksum *commit_checksum = NULL; GChecksum *commit_checksum = NULL;
char separator; char separator;
GVariant *metadata = NULL; GVariant *metadata = NULL;
GMappedFile *metadata_mappedf = NULL; GMappedFile *metadata_mappedf = NULL;
GFile *metadata_f = 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"); context = g_option_context_new ("[DIR] - Commit a new revision");
g_option_context_add_main_entries (context, options, NULL); 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; goto out;
if (argc > 1) if (argc > 1)
dir = g_strdup (argv[1]); dirpath = g_strdup (argv[1]);
else else
dir = g_get_current_dir (); dirpath = g_get_current_dir ();
if (g_str_has_suffix (dir, "/")) if (g_str_has_suffix (dirpath, "/"))
dir[strlen (dir) - 1] = '\0'; dirpath[strlen (dirpath) - 1] = '\0';
separator = separator_null ? '\0' : '\n'; if (!*dirpath)
if (!*dir)
{ {
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid empty directory"); "Invalid empty directory");
goto out; goto out;
} }
dir = ot_gfile_new_for_path (dirpath);
if (metadata_text_path || metadata_bin_path) if (metadata_text_path || metadata_bin_path)
{ {
metadata_mappedf = g_mapped_file_new (metadata_text_path ? metadata_text_path : metadata_bin_path, FALSE, error); 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; goto out;
} }
if (!(from_file || from_fd >= 0 || from_stdin)) if (!ostree_repo_commit (repo, branch, parent, subject, body, metadata,
{ dir, &commit_checksum, NULL, error))
/* 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))
goto out; goto out;
ret = TRUE; ret = TRUE;
g_print ("%s\n", g_checksum_get_string (commit_checksum)); g_print ("%s\n", g_checksum_get_string (commit_checksum));
out: out:
g_clear_object (&out); g_free (dirpath);
if (temp_fd >= 0) g_clear_object (&dir);
(void)close (temp_fd);
if (pipefd[0] > 0)
(void) close (pipefd[0]);
if (pipefd[1] > 0)
(void) close (pipefd[1]);
g_free (dir);
if (metadata_mappedf) if (metadata_mappedf)
g_mapped_file_unref (metadata_mappedf); g_mapped_file_unref (metadata_mappedf);
if (context) if (context)

View File

@ -71,8 +71,8 @@ mkdir -p another/nested/tree
echo anotherone > another/nested/tree/1 echo anotherone > another/nested/tree/1
echo whee2 > another/whee echo whee2 > another/whee
# FIXME - remove grep for . # FIXME - remove grep for .
find | grep -v '^\.$' | $OSTREE commit -b test2 -s "From find" --from-stdin $OSTREE commit -b test2 -s "Another commit"
echo "ok stdin commit" echo "ok commit"
cd ${test_tmpdir} cd ${test_tmpdir}
$OSTREE checkout test2 $test_tmpdir/checkout-test2-3 $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 mkdir -p usr/share
echo 'some data' > usr/share/foo.data 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}" cd "${test_tmpdir}"
mkdir artifact-libfoo-devel mkdir artifact-libfoo-devel
@ -45,7 +45,7 @@ echo 'a header' > usr/include/foo.h
mkdir -p usr/share/doc mkdir -p usr/share/doc
echo 'some documentation' > usr/share/doc/foo.txt 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}" cd "${test_tmpdir}"
mkdir artifact-barapp mkdir artifact-barapp
@ -53,7 +53,7 @@ cd artifact-barapp
mkdir -p usr/bin mkdir -p usr/bin
echo 'another ELF file' > usr/bin/bar 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' echo 'ok artifacts committed'