core: Pull diff functionality out into "diff" builtin

There's no good reason for this to be in core when it's only in use by
the diff builtin.
This commit is contained in:
Colin Walters 2012-03-06 09:10:48 -05:00
parent 4db485dd5f
commit 1513f29495
3 changed files with 341 additions and 380 deletions

View File

@ -2620,320 +2620,6 @@ ostree_repo_checkout_tree (OstreeRepo *self,
g_free (dest_path);
return ret;
}
static gboolean
get_file_checksum (GFile *f,
GFileInfo *f_info,
char **out_checksum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GChecksum *tmp_checksum = NULL;
char *ret_checksum = NULL;
if (OSTREE_IS_REPO_FILE (f))
{
ret_checksum = g_strdup (ostree_repo_file_get_checksum ((OstreeRepoFile*)f));
}
else
{
if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_RAW_FILE,
&tmp_checksum, cancellable, error))
goto out;
ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
}
ret = TRUE;
ot_transfer_out_value(out_checksum, &ret_checksum);
out:
ot_clear_checksum (&tmp_checksum);
return ret;
}
OstreeRepoDiffItem *
ostree_repo_diff_item_ref (OstreeRepoDiffItem *diffitem)
{
g_atomic_int_inc (&diffitem->refcount);
return diffitem;
}
void
ostree_repo_diff_item_unref (OstreeRepoDiffItem *diffitem)
{
if (!g_atomic_int_dec_and_test (&diffitem->refcount))
return;
g_clear_object (&diffitem->src);
g_clear_object (&diffitem->target);
g_clear_object (&diffitem->src_info);
g_clear_object (&diffitem->target_info);
g_free (diffitem->src_checksum);
g_free (diffitem->target_checksum);
g_free (diffitem);
}
static OstreeRepoDiffItem *
diff_item_new (GFile *a,
GFileInfo *a_info,
GFile *b,
GFileInfo *b_info,
char *checksum_a,
char *checksum_b)
{
OstreeRepoDiffItem *ret = g_new0 (OstreeRepoDiffItem, 1);
ret->refcount = 1;
ret->src = a ? g_object_ref (a) : NULL;
ret->src_info = a_info ? g_object_ref (a_info) : NULL;
ret->target = b ? g_object_ref (b) : NULL;
ret->target_info = b_info ? g_object_ref (b_info) : b_info;
ret->src_checksum = g_strdup (checksum_a);
ret->target_checksum = g_strdup (checksum_b);
return ret;
}
static gboolean
diff_files (GFile *a,
GFileInfo *a_info,
GFile *b,
GFileInfo *b_info,
OstreeRepoDiffItem **out_item,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char *checksum_a = NULL;
char *checksum_b = NULL;
OstreeRepoDiffItem *ret_item = NULL;
if (!get_file_checksum (a, a_info, &checksum_a, cancellable, error))
goto out;
if (!get_file_checksum (b, b_info, &checksum_b, cancellable, error))
goto out;
if (strcmp (checksum_a, checksum_b) != 0)
{
ret_item = diff_item_new (a, a_info, b, b_info,
checksum_a, checksum_b);
}
ret = TRUE;
ot_transfer_out_value(out_item, &ret_item);
out:
if (ret_item)
ostree_repo_diff_item_unref (ret_item);
g_free (checksum_a);
g_free (checksum_b);
return ret;
}
static gboolean
diff_add_dir_recurse (GFile *d,
GPtrArray *added,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *dir_enum = NULL;
GError *temp_error = NULL;
GFile *child = NULL;
GFileInfo *child_info = NULL;
dir_enum = g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
name = g_file_info_get_name (child_info);
g_clear_object (&child);
child = g_file_get_child (d, name);
g_ptr_array_add (added, g_object_ref (child));
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
{
if (!diff_add_dir_recurse (child, added, cancellable, error))
goto out;
}
g_clear_object (&child_info);
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&child_info);
g_clear_object (&child);
g_clear_object (&dir_enum);
return ret;
}
static gboolean
diff_dirs (GFile *a,
GFile *b,
GPtrArray *modified,
GPtrArray *removed,
GPtrArray *added,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *dir_enum = NULL;
GError *temp_error = NULL;
GFile *child_a = NULL;
GFile *child_b = NULL;
GFileInfo *child_a_info = NULL;
GFileInfo *child_b_info = NULL;
dir_enum = g_file_enumerate_children (a, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_a_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
GFileType child_a_type;
GFileType child_b_type;
name = g_file_info_get_name (child_a_info);
g_clear_object (&child_a);
child_a = g_file_get_child (a, name);
child_a_type = g_file_info_get_file_type (child_a_info);
g_clear_object (&child_b);
child_b = g_file_get_child (b, name);
g_clear_object (&child_b_info);
child_b_info = g_file_query_info (child_b, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
&temp_error);
if (!child_b_info)
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_ptr_array_add (removed, g_object_ref (child_a));
}
else
{
g_propagate_error (error, temp_error);
goto out;
}
}
else
{
child_b_type = g_file_info_get_file_type (child_b_info);
if (child_a_type != child_b_type)
{
OstreeRepoDiffItem *diff_item = diff_item_new (child_a, child_a_info,
child_b, child_b_info, NULL, NULL);
g_ptr_array_add (modified, diff_item);
}
else
{
OstreeRepoDiffItem *diff_item = NULL;
if (!diff_files (child_a, child_a_info, child_b, child_b_info, &diff_item, cancellable, error))
goto out;
if (diff_item)
g_ptr_array_add (modified, diff_item); /* Transfer ownership */
if (child_a_type == G_FILE_TYPE_DIRECTORY)
{
if (!diff_dirs (child_a, child_b, modified,
removed, added, cancellable, error))
goto out;
}
}
}
g_clear_object (&child_a_info);
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
g_clear_object (&dir_enum);
dir_enum = g_file_enumerate_children (b, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_b_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
name = g_file_info_get_name (child_b_info);
g_clear_object (&child_a);
child_a = g_file_get_child (a, name);
g_clear_object (&child_b);
child_b = g_file_get_child (b, name);
g_clear_object (&child_a_info);
child_a_info = g_file_query_info (child_a, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
&temp_error);
if (!child_a_info)
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_ptr_array_add (added, g_object_ref (child_b));
if (g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY)
{
if (!diff_add_dir_recurse (child_b, added, cancellable, error))
goto out;
}
}
else
{
g_propagate_error (error, temp_error);
goto out;
}
}
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&dir_enum);
g_clear_object (&child_a_info);
g_clear_object (&child_b_info);
g_clear_object (&child_a);
g_clear_object (&child_b);
return ret;
}
gboolean
ostree_repo_read_commit (OstreeRepo *self,
const char *rev,
@ -2959,39 +2645,3 @@ ostree_repo_read_commit (OstreeRepo *self,
g_clear_object (&ret_root);
return ret;
}
gboolean
ostree_repo_diff (OstreeRepo *self,
GFile *src,
GFile *target,
GPtrArray **out_modified,
GPtrArray **out_removed,
GPtrArray **out_added,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GPtrArray *ret_modified = NULL;
GPtrArray *ret_removed = NULL;
GPtrArray *ret_added = NULL;
ret_modified = g_ptr_array_new_with_free_func ((GDestroyNotify)ostree_repo_diff_item_unref);
ret_removed = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
ret_added = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
if (!diff_dirs (src, target, ret_modified, ret_removed, ret_added, cancellable, error))
goto out;
ret = TRUE;
ot_transfer_out_value(out_modified, &ret_modified);
ot_transfer_out_value(out_removed, &ret_removed);
ot_transfer_out_value(out_added, &ret_added);
out:
if (ret_modified)
g_ptr_array_free (ret_modified, TRUE);
if (ret_removed)
g_ptr_array_free (ret_removed, TRUE);
if (ret_added)
g_ptr_array_free (ret_added, TRUE);
return ret;
}

View File

@ -220,31 +220,6 @@ gboolean ostree_repo_read_commit (OstreeRepo *self,
GCancellable *cancellable,
GError **error);
typedef struct {
volatile gint refcount;
GFile *src;
GFile *target;
GFileInfo *src_info;
GFileInfo *target_info;
char *src_checksum;
char *target_checksum;
} OstreeRepoDiffItem;
OstreeRepoDiffItem *ostree_repo_diff_item_ref (OstreeRepoDiffItem *diffitem);
void ostree_repo_diff_item_unref (OstreeRepoDiffItem *diffitem);
gboolean ostree_repo_diff (OstreeRepo *self,
GFile *src,
GFile *target,
GPtrArray **out_modified, /* OstreeRepoDiffItem */
GPtrArray **out_removed, /* OstreeRepoDiffItem */
GPtrArray **out_added, /* OstreeRepoDiffItem */
GCancellable *cancellable,
GError **error);
typedef void (*OstreeRepoObjectIter) (OstreeRepo *self,
const char *checksum,
OstreeObjectType type,

View File

@ -61,11 +61,343 @@ parse_file_or_commit (OstreeRepo *repo,
return ret;
}
static gboolean
get_file_checksum (GFile *f,
GFileInfo *f_info,
char **out_checksum,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GChecksum *tmp_checksum = NULL;
char *ret_checksum = NULL;
if (OSTREE_IS_REPO_FILE (f))
{
ret_checksum = g_strdup (ostree_repo_file_get_checksum ((OstreeRepoFile*)f));
}
else
{
if (!ostree_checksum_file (f, OSTREE_OBJECT_TYPE_RAW_FILE,
&tmp_checksum, cancellable, error))
goto out;
ret_checksum = g_strdup (g_checksum_get_string (tmp_checksum));
}
ret = TRUE;
ot_transfer_out_value(out_checksum, &ret_checksum);
out:
ot_clear_checksum (&tmp_checksum);
return ret;
}
typedef struct {
volatile gint refcount;
GFile *src;
GFile *target;
GFileInfo *src_info;
GFileInfo *target_info;
char *src_checksum;
char *target_checksum;
} DiffItem;
DiffItem *diff_item_ref (DiffItem *diffitem);
void diff_item_unref (DiffItem *diffitem);
DiffItem *
diff_item_ref (DiffItem *diffitem)
{
g_atomic_int_inc (&diffitem->refcount);
return diffitem;
}
void
diff_item_unref (DiffItem *diffitem)
{
if (!g_atomic_int_dec_and_test (&diffitem->refcount))
return;
g_clear_object (&diffitem->src);
g_clear_object (&diffitem->target);
g_clear_object (&diffitem->src_info);
g_clear_object (&diffitem->target_info);
g_free (diffitem->src_checksum);
g_free (diffitem->target_checksum);
g_free (diffitem);
}
static DiffItem *
diff_item_new (GFile *a,
GFileInfo *a_info,
GFile *b,
GFileInfo *b_info,
char *checksum_a,
char *checksum_b)
{
DiffItem *ret = g_new0 (DiffItem, 1);
ret->refcount = 1;
ret->src = a ? g_object_ref (a) : NULL;
ret->src_info = a_info ? g_object_ref (a_info) : NULL;
ret->target = b ? g_object_ref (b) : NULL;
ret->target_info = b_info ? g_object_ref (b_info) : b_info;
ret->src_checksum = g_strdup (checksum_a);
ret->target_checksum = g_strdup (checksum_b);
return ret;
}
static gboolean
diff_files (GFile *a,
GFileInfo *a_info,
GFile *b,
GFileInfo *b_info,
DiffItem **out_item,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char *checksum_a = NULL;
char *checksum_b = NULL;
DiffItem *ret_item = NULL;
if (!get_file_checksum (a, a_info, &checksum_a, cancellable, error))
goto out;
if (!get_file_checksum (b, b_info, &checksum_b, cancellable, error))
goto out;
if (strcmp (checksum_a, checksum_b) != 0)
{
ret_item = diff_item_new (a, a_info, b, b_info,
checksum_a, checksum_b);
}
ret = TRUE;
ot_transfer_out_value(out_item, &ret_item);
out:
if (ret_item)
diff_item_unref (ret_item);
g_free (checksum_a);
g_free (checksum_b);
return ret;
}
static gboolean
diff_add_dir_recurse (GFile *d,
GPtrArray *added,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *dir_enum = NULL;
GError *temp_error = NULL;
GFile *child = NULL;
GFileInfo *child_info = NULL;
dir_enum = g_file_enumerate_children (d, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
name = g_file_info_get_name (child_info);
g_clear_object (&child);
child = g_file_get_child (d, name);
g_ptr_array_add (added, g_object_ref (child));
if (g_file_info_get_file_type (child_info) == G_FILE_TYPE_DIRECTORY)
{
if (!diff_add_dir_recurse (child, added, cancellable, error))
goto out;
}
g_clear_object (&child_info);
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&child_info);
g_clear_object (&child);
g_clear_object (&dir_enum);
return ret;
}
static gboolean
diff_dirs (GFile *a,
GFile *b,
GPtrArray *modified,
GPtrArray *removed,
GPtrArray *added,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
GFileEnumerator *dir_enum = NULL;
GError *temp_error = NULL;
GFile *child_a = NULL;
GFile *child_b = NULL;
GFileInfo *child_a_info = NULL;
GFileInfo *child_b_info = NULL;
dir_enum = g_file_enumerate_children (a, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_a_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
GFileType child_a_type;
GFileType child_b_type;
name = g_file_info_get_name (child_a_info);
g_clear_object (&child_a);
child_a = g_file_get_child (a, name);
child_a_type = g_file_info_get_file_type (child_a_info);
g_clear_object (&child_b);
child_b = g_file_get_child (b, name);
g_clear_object (&child_b_info);
child_b_info = g_file_query_info (child_b, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
&temp_error);
if (!child_b_info)
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_ptr_array_add (removed, g_object_ref (child_a));
}
else
{
g_propagate_error (error, temp_error);
goto out;
}
}
else
{
child_b_type = g_file_info_get_file_type (child_b_info);
if (child_a_type != child_b_type)
{
DiffItem *diff_item = diff_item_new (child_a, child_a_info,
child_b, child_b_info, NULL, NULL);
g_ptr_array_add (modified, diff_item);
}
else
{
DiffItem *diff_item = NULL;
if (!diff_files (child_a, child_a_info, child_b, child_b_info, &diff_item, cancellable, error))
goto out;
if (diff_item)
g_ptr_array_add (modified, diff_item); /* Transfer ownership */
if (child_a_type == G_FILE_TYPE_DIRECTORY)
{
if (!diff_dirs (child_a, child_b, modified,
removed, added, cancellable, error))
goto out;
}
}
}
g_clear_object (&child_a_info);
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
g_clear_object (&dir_enum);
dir_enum = g_file_enumerate_children (b, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
error);
if (!dir_enum)
goto out;
while ((child_b_info = g_file_enumerator_next_file (dir_enum, cancellable, &temp_error)) != NULL)
{
const char *name;
name = g_file_info_get_name (child_b_info);
g_clear_object (&child_a);
child_a = g_file_get_child (a, name);
g_clear_object (&child_b);
child_b = g_file_get_child (b, name);
g_clear_object (&child_a_info);
child_a_info = g_file_query_info (child_a, OSTREE_GIO_FAST_QUERYINFO,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable,
&temp_error);
if (!child_a_info)
{
if (g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
{
g_clear_error (&temp_error);
g_ptr_array_add (added, g_object_ref (child_b));
if (g_file_info_get_file_type (child_b_info) == G_FILE_TYPE_DIRECTORY)
{
if (!diff_add_dir_recurse (child_b, added, cancellable, error))
goto out;
}
}
else
{
g_propagate_error (error, temp_error);
goto out;
}
}
}
if (temp_error != NULL)
{
g_propagate_error (error, temp_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&dir_enum);
g_clear_object (&child_a_info);
g_clear_object (&child_b_info);
g_clear_object (&child_a);
g_clear_object (&child_b);
return ret;
}
gboolean
ostree_builtin_diff (int argc, char **argv, GFile *repo_path, GError **error)
{
GOptionContext *context;
gboolean ret = FALSE;
GOptionContext *context;
GCancellable *cancellable = NULL;
OstreeRepo *repo = NULL;
char *src_prev = NULL;
const char *src;
@ -112,17 +444,21 @@ ostree_builtin_diff (int argc, char **argv, GFile *repo_path, GError **error)
cwd = ot_gfile_new_for_path (".");
if (!parse_file_or_commit (repo, src, &srcf, NULL, error))
if (!parse_file_or_commit (repo, src, &srcf, cancellable, error))
goto out;
if (!parse_file_or_commit (repo, target, &targetf, NULL, error))
if (!parse_file_or_commit (repo, target, &targetf, cancellable, error))
goto out;
modified = g_ptr_array_new_with_free_func ((GDestroyNotify)diff_item_unref);
removed = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
added = g_ptr_array_new_with_free_func ((GDestroyNotify)g_object_unref);
if (!ostree_repo_diff (repo, srcf, targetf, &modified, &removed, &added, NULL, error))
if (!diff_dirs (srcf, targetf, modified, removed, added, cancellable, error))
goto out;
for (i = 0; i < modified->len; i++)
{
OstreeRepoDiffItem *diff = modified->pdata[i];
DiffItem *diff = modified->pdata[i];
g_print ("M %s\n", ot_gfile_get_path_cached (diff->src));
}
for (i = 0; i < removed->len; i++)