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); g_free (dest_path);
return ret; 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 gboolean
ostree_repo_read_commit (OstreeRepo *self, ostree_repo_read_commit (OstreeRepo *self,
const char *rev, const char *rev,
@ -2959,39 +2645,3 @@ ostree_repo_read_commit (OstreeRepo *self,
g_clear_object (&ret_root); g_clear_object (&ret_root);
return ret; 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, GCancellable *cancellable,
GError **error); 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, typedef void (*OstreeRepoObjectIter) (OstreeRepo *self,
const char *checksum, const char *checksum,
OstreeObjectType type, OstreeObjectType type,

View File

@ -61,11 +61,343 @@ parse_file_or_commit (OstreeRepo *repo,
return ret; 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 gboolean
ostree_builtin_diff (int argc, char **argv, GFile *repo_path, GError **error) ostree_builtin_diff (int argc, char **argv, GFile *repo_path, GError **error)
{ {
GOptionContext *context;
gboolean ret = FALSE; gboolean ret = FALSE;
GOptionContext *context;
GCancellable *cancellable = NULL;
OstreeRepo *repo = NULL; OstreeRepo *repo = NULL;
char *src_prev = NULL; char *src_prev = NULL;
const char *src; 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 ("."); 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; goto out;
if (!parse_file_or_commit (repo, target, &targetf, NULL, error)) if (!parse_file_or_commit (repo, target, &targetf, cancellable, error))
goto out; goto out;
if (!ostree_repo_diff (repo, srcf, targetf, &modified, &removed, &added, NULL, error)) 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 (!diff_dirs (srcf, targetf, modified, removed, added, cancellable, error))
goto out; goto out;
for (i = 0; i < modified->len; i++) 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)); g_print ("M %s\n", ot_gfile_get_path_cached (diff->src));
} }
for (i = 0; i < removed->len; i++) for (i = 0; i < removed->len; i++)