commit - 3235492e3fcec3882427de904e5be159b6380edf
commit + b00d56cde51fc646b2b3055ff80e6f5b2b8cccb1
blob - a55e7d9e6f0317755b1aa6df1c5f7673ad9a6e0c
blob + 41ca7c9696379c1899dc721f39eb4c60a8f672df
--- got/got.c
+++ got/got.c
__dead void usage(void);
__dead void usage_checkout(void);
__dead void usage_log(void);
+__dead void usage_diff(void);
const struct got_error* cmd_checkout(int, char *[]);
const struct got_error* cmd_log(int, char *[]);
+const struct got_error* cmd_diff(int, char *[]);
const struct got_error* cmd_status(int, char *[]);
struct cmd got_commands[] = {
"check out a new work tree from a repository" },
{ "log", cmd_log, usage_log,
"show repository history" },
+ { "diff", cmd_diff, usage_diff,
+ "compare files and directories" },
#ifdef notyet
{ "status", cmd_status, usage_status,
"show modification status of files" },
free(id);
got_repo_close(repo);
return error;
+}
+
+__dead void
+usage_diff(void)
+{
+ fprintf(stderr, "usage: %s diff repository-path object1 object2\n",
+ getprogname());
+ exit(1);
+}
+
+static const struct got_error *
+diff_blobs(struct got_object *obj1, struct got_object *obj2,
+ struct got_repository *repo)
+{
+ const struct got_error *err;
+ struct got_blob_object *blob1 = NULL, *blob2 = NULL;
+
+ err = got_object_blob_open(&blob1, repo, obj1, 8192);
+ if (err)
+ goto done;
+ err = got_object_blob_open(&blob2, repo, obj2, 81992);
+ if (err)
+ goto done;
+
+ err = got_diff_blob(blob1, blob2, NULL, NULL, stdout);
+done:
+ if (blob1)
+ got_object_blob_close(blob1);
+ if (blob2)
+ got_object_blob_close(blob2);
+ return err;
+}
+
+static const struct got_error *
+diff_trees(struct got_object *obj1, struct got_object *obj2,
+ struct got_repository *repo)
+{
+ const struct got_error *err;
+ struct got_tree_object *tree1 = NULL, *tree2 = NULL;
+
+ err = got_object_tree_open(&tree1, repo, obj1);
+ if (err)
+ goto done;
+ err = got_object_tree_open(&tree2, repo, obj2);
+ if (err)
+ goto done;
+
+ err = got_diff_tree(tree1, tree2, repo, stdout);
+done:
+ if (tree1)
+ got_object_tree_close(tree1);
+ if (tree2)
+ got_object_tree_close(tree2);
+ return err;
}
+static const struct got_error *
+diff_commits(struct got_object *obj1, struct got_object *obj2,
+ struct got_repository *repo)
+{
+ const struct got_error *err;
+ struct got_commit_object *commit1 = NULL, *commit2 = NULL;
+ struct got_object *tree_obj1 = NULL, *tree_obj2 = NULL;
+
+ err = got_object_commit_open(&commit1, repo, obj1);
+ if (err)
+ goto done;
+ err = got_object_commit_open(&commit2, repo, obj2);
+ if (err)
+ goto done;
+
+ err = got_object_open(&tree_obj1, repo, commit1->tree_id);
+ if (err)
+ goto done;
+ err = got_object_open(&tree_obj2, repo, commit2->tree_id);
+ if (err)
+ goto done;
+
+ err = diff_trees(tree_obj1, tree_obj2, repo);
+done:
+ if (tree_obj1)
+ got_object_close(tree_obj1);
+ if (tree_obj2)
+ got_object_close(tree_obj2);
+ if (commit1)
+ got_object_commit_close(commit1);
+ if (commit2)
+ got_object_commit_close(commit2);
+ return err;
+
+}
+
+const struct got_error *
+cmd_diff(int argc, char *argv[])
+{
+ const struct got_error *error;
+ struct got_repository *repo = NULL;
+ struct got_object_id *id1 = NULL, *id2 = NULL;
+ struct got_object *obj1 = NULL, *obj2 = NULL;
+ char *repo_path = NULL;
+ char *obj_id_str1 = NULL, *obj_id_str2 = NULL;
+ int ch;
+
+#ifndef PROFILE
+ if (pledge("stdio rpath wpath cpath", NULL) == -1)
+ err(1, "pledge");
+#endif
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0) {
+ usage_diff(); /* TODO show local worktree changes */
+ } else if (argc == 3) {
+ repo_path = argv[0];
+ obj_id_str1 = argv[1];
+ obj_id_str2 = argv[2];
+ } else
+ usage_diff();
+
+ error = got_repo_open(&repo, repo_path);
+ if (error != NULL)
+ goto done;
+
+ error = got_object_open_by_id_str(&obj1, repo, obj_id_str1);
+ if (error == NULL) {
+ id1 = got_object_get_id(obj1);
+ if (id1 == NULL)
+ error = got_error_from_errno();
+ }
+ if (error != NULL)
+ goto done;
+
+ error = got_object_open_by_id_str(&obj2, repo, obj_id_str2);
+ if (error == NULL) {
+ id2 = got_object_get_id(obj2);
+ if (id2 == NULL)
+ error = got_error_from_errno();
+ }
+ if (error != NULL)
+ goto done;
+
+ if (got_object_get_type(obj1) != got_object_get_type(obj2)) {
+ error = got_error(GOT_ERR_OBJ_TYPE);
+ goto done;
+ }
+
+ switch (got_object_get_type(obj1)) {
+ case GOT_OBJ_TYPE_BLOB:
+ error = diff_blobs(obj1, obj2, repo);
+ break;
+ case GOT_OBJ_TYPE_TREE:
+ error = diff_trees(obj1, obj2, repo);
+ break;
+ case GOT_OBJ_TYPE_COMMIT:
+ error = diff_commits(obj1, obj2, repo);
+ break;
+ default:
+ error = got_error(GOT_ERR_OBJ_TYPE);
+ }
+
+done:
+ if (obj1)
+ got_object_close(obj1);
+ if (obj2)
+ got_object_close(obj2);
+ if (id1)
+ free(id1);
+ if (id2)
+ free(id2);
+ if (repo)
+ got_repo_close(repo);
+ return error;
+}
+
#ifdef notyet
const struct got_error *
cmd_status(int argc __unused, char *argv[] __unused)