commit de18fc635cbce498d8f11d0b994a9de1821760bb from: Stefan Sperling date: Thu May 09 19:36:10 2019 UTC write commit objects 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 ", 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)