Commit Diff


commit - 2f51b5b3dbc9fb8bc58001a3e80bf7b2cdf8c6a2
commit + de18fc635cbce498d8f11d0b994a9de1821760bb
blob - f48a524c2e941f59e208fe7590e665f47e95256a
blob + a39387abda91c220d8e14e5faab47e21bc1396f4
--- got/got.c
+++ got/got.c
@@ -2132,7 +2132,8 @@ cmd_commit(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_worktree_commit(&id, worktree, path, logmsg, repo);
+	error = got_worktree_commit(&id, worktree, path,
+	    "Stefan Sperling <stsp@stsp.name>", NULL, logmsg, repo);
 	if (error)
 		goto done;
 
blob - debcb302f5ffcd4e16b249bb81b570b59be23923
blob + 27d9c4b14fdad4299d1cdd8a2cf811e17f143565
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -171,10 +171,10 @@ const struct got_error *got_worktree_revert(struct got
  * The worktree's base commit will be set to this new commit.
  * Files unaffected by this commit operation will retain their
  * current base commit.
- * A non-empty log message must be specified.
+ * An author and a non-empty log message must be specified.
+ * The name of the committer is optional (may be NULL).
  * If an on-disk path is specified, only commit changes at or within this path.
  */
-const struct got_error *
-got_worktree_commit(struct got_object_id **,
-    struct got_worktree *, const char *, const char *,
-    struct got_repository *);
+const struct got_error *got_worktree_commit(struct got_object_id **,
+    struct got_worktree *, const char *, const char *, const char *,
+    const char *, struct got_repository *);
blob - 4d0047944714aaef7dbd3063372dcb83d7f2bffe
blob + 011e79e1b6f5f62d4fdb6d0658db9c490498352a
--- lib/got_lib_object_create.h
+++ lib/got_lib_object_create.h
@@ -18,3 +18,7 @@ const struct got_error *got_object_blob_create(struct 
     const char *, struct got_repository *);
 const struct got_error *got_object_tree_create(struct got_object_id **,
     struct got_tree_entries *, struct got_repository *);
+const struct got_error *got_object_commit_create(struct got_object_id **,
+    struct got_object_id *, struct got_object_id_queue *, int,
+    const char *, time_t, const char *, time_t, const char *,
+    struct got_repository *);
blob - 8c94148d642736807ad761ea0d23f5284eeee348
blob + 6e0d38934875115a92f1d9ea9e6ce822976910f7
--- lib/object_create.c
+++ lib/object_create.c
@@ -297,7 +297,169 @@ got_object_tree_create(struct got_object_id **id,
 done:
 	free(header);
 	if (treefile && fclose(treefile) != 0 && err == NULL)
+		err = got_error_from_errno();
+	if (err) {
+		free(*id);
+		*id = NULL;
+	}
+	return err;
+}
+
+const struct got_error *
+got_object_commit_create(struct got_object_id **id,
+    struct got_object_id *tree_id, struct got_object_id_queue *parent_ids,
+    int nparents, const char *author, time_t author_time,
+    const char *committer, time_t committer_time,
+    const char *logmsg, struct got_repository *repo)
+{
+	const struct got_error *err = NULL;
+	SHA1_CTX sha1_ctx;
+	char *header = NULL, *tree_str = NULL;
+	char *author_str = NULL, *committer_str = NULL;
+	char *id_str = NULL;
+	size_t headerlen, len = 0, n;
+	FILE *commitfile = NULL;
+	struct got_object_qid *qid;
+
+	*id = NULL;
+
+	SHA1Init(&sha1_ctx);
+
+	if (asprintf(&author_str, "%s%s %lld +0000\n",
+	    GOT_COMMIT_LABEL_AUTHOR, author, author_time) == -1)
+		return got_error_from_errno();
+
+	if (asprintf(&committer_str, "%s%s %lld +0000\n",
+	    GOT_COMMIT_LABEL_COMMITTER, committer ? committer : author,
+	    committer ? committer_time : author_time)
+	    == -1) {
+		err = got_error_from_errno();
+		goto done;
+	}
+
+	len = strlen(GOT_COMMIT_LABEL_TREE) + SHA1_DIGEST_STRING_LENGTH +
+	    nparents *
+	    (strlen(GOT_COMMIT_LABEL_PARENT) + SHA1_DIGEST_STRING_LENGTH) +
+	    + strlen(author_str) + strlen(committer_str) + 2 + strlen(logmsg);
+
+	if (asprintf(&header, "%s %zd", GOT_OBJ_LABEL_COMMIT, len) == -1) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	headerlen = strlen(header) + 1;
+	SHA1Update(&sha1_ctx, header, headerlen);
+
+	commitfile = got_opentemp();
+	if (commitfile == NULL) {
+		err = got_error_from_errno();
+		goto done;
+	}
+
+	n = fwrite(header, 1, headerlen, commitfile);
+	if (n != headerlen) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	err = got_object_id_str(&id_str, tree_id);
+	if (err)
+		goto done;
+	if (asprintf(&tree_str, "%s%s\n", GOT_COMMIT_LABEL_TREE, id_str)
+	    == -1) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	len = strlen(tree_str);
+	SHA1Update(&sha1_ctx, tree_str, len);
+	n = fwrite(tree_str, 1, len, commitfile);
+	if (n != len) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	SIMPLEQ_FOREACH(qid, parent_ids, entry) {
+		char *parent_str = NULL;
+
+		free(id_str);
+
+		err = got_object_id_str(&id_str, qid->id);
+		if (err)
+			goto done;
+		if (asprintf(&parent_str, "%s%s\n", GOT_COMMIT_LABEL_PARENT,
+		    id_str) == -1) {
+			err = got_error_from_errno();
+			goto done;
+		}
+		len = strlen(parent_str);
+		SHA1Update(&sha1_ctx, parent_str, len);
+		n = fwrite(parent_str, 1, len, commitfile);
+		if (n != len) {
+			err = got_ferror(commitfile, GOT_ERR_IO);
+			free(parent_str);
+			goto done;
+		}
+		free(parent_str);
+	}
+
+	len = strlen(author_str);
+	SHA1Update(&sha1_ctx, author_str, len);
+	n = fwrite(author_str, 1, len, commitfile);
+	if (n != len) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	len = strlen(committer_str);
+	SHA1Update(&sha1_ctx, committer_str, len);
+	n = fwrite(committer_str, 1, len, commitfile);
+	if (n != len) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	SHA1Update(&sha1_ctx, "\n", 1);
+	n = fwrite("\n", 1, 1, commitfile);
+	if (n != 1) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	len = strlen(logmsg);
+	SHA1Update(&sha1_ctx, logmsg, len);
+	n = fwrite(logmsg, 1, len, commitfile);
+	if (n != len) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	SHA1Update(&sha1_ctx, "\n", 1);
+	n = fwrite("\n", 1, 1, commitfile);
+	if (n != 1) {
+		err = got_ferror(commitfile, GOT_ERR_IO);
+		goto done;
+	}
+
+	*id = malloc(sizeof(**id));
+	if (*id == NULL) {
 		err = got_error_from_errno();
+		goto done;
+	}
+	SHA1Final((*id)->sha1, &sha1_ctx);
+
+	if (fflush(commitfile) != 0) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	rewind(commitfile);
+
+	err = create_object_file(*id, commitfile, repo);
+done:
+	free(header);
+	free(tree_str);
+	free(author_str);
+	free(committer_str);
+	if (commitfile && fclose(commitfile) != 0 && err == NULL)
+		err = got_error_from_errno();
 	if (err) {
 		free(*id);
 		*id = NULL;
blob - 90a97466396a51ba49e87eb6064fcc811bfb0ddc
blob + 1bd890d5772e107b2e3a9ed899572810e276677d
--- lib/worktree.c
+++ lib/worktree.c
@@ -2598,6 +2598,7 @@ done:
 const struct got_error *
 got_worktree_commit(struct got_object_id **new_commit_id,
     struct got_worktree *worktree, const char *ondisk_path,
+    const char *author, const char *committer,
     const char *logmsg, struct got_repository *repo)
 {
 	const struct got_error *err = NULL, *unlockerr = NULL;
@@ -2608,10 +2609,13 @@ got_worktree_commit(struct got_object_id **new_commit_
 	struct got_commit_object *base_commit = NULL;
 	struct got_tree_object *base_tree = NULL;
 	struct got_object_id *new_tree_id = NULL;
+	struct got_object_id_queue parent_ids;
+	struct got_object_qid *pid = NULL;
 
 	*new_commit_id = NULL;
 
 	TAILQ_INIT(&commitable_paths);
+	SIMPLEQ_INIT(&parent_ids);
 
 	if (ondisk_path) {
 		err = got_path_skip_common_ancestor(&relpath,
@@ -2632,6 +2636,8 @@ got_worktree_commit(struct got_object_id **new_commit_
 	if (err)
 		goto done;
 
+	/* TODO: out-of-dateness check */
+
 	/* TODO: collect commit message if not specified */
 
 	/* Create blobs from added and modified files and record their IDs. */
@@ -2667,8 +2673,13 @@ got_worktree_commit(struct got_object_id **new_commit_
 	if (err)
 		goto done;
 
-	/* TODO: Write new commit. */
-
+	err = got_object_qid_alloc(&pid, worktree->base_commit_id);
+	if (err)
+		goto done;
+	SIMPLEQ_INSERT_TAIL(&parent_ids, pid, entry);
+	err = got_object_commit_create(new_commit_id, new_tree_id, &parent_ids,
+	    1, author, time(NULL), committer, time(NULL), logmsg, repo);
+	got_object_qid_free(pid);
 done:
 	unlockerr = lock_worktree(worktree, LOCK_SH);
 	if (unlockerr && err == NULL)