Commit Diff


commit - df3352425b599a7ca9e473a9024c6b5333778dc5
commit + 0cb83759ff5e9ca28c397bb04edb8e0629eba4bd
blob - f4f431a41a6b1d33399a3974a26880899d231b80
blob + 9963b821c1f57a0322e8913d88df883c8de53679
--- include/got_worktree.h
+++ include/got_worktree.h
@@ -371,3 +371,9 @@ const struct got_error *got_worktree_histedit_abort(st
 /* Get the path to this work tree's histedit script file. */
 const struct got_error *got_worktree_get_histedit_script_path(char **,
     struct got_worktree *);
+
+/* Stage the specified paths for commit. */
+const struct got_error *got_worktree_stage_paths(struct got_worktree *,
+    struct got_pathlist_head *, struct got_repository *,
+    got_worktree_status_cb, void *,
+    got_worktree_cancel_cb , void *);
blob - 61af730e3e3e103061ccd973a5695d28529aff30
blob + dbf735c60f305ce21773733986a5a067e065d008
--- lib/fileindex.c
+++ lib/fileindex.c
@@ -161,9 +161,17 @@ got_fileindex_entry_path_len(const struct got_fileinde
 }
 
 uint32_t
-got_fileindex_entry_stage(const struct got_fileindex_entry *ie)
+got_fileindex_entry_stage_get(const struct got_fileindex_entry *ie)
 {
 	return ((ie->flags & GOT_FILEIDX_F_STAGE) >> GOT_FILEIDX_F_STAGE_SHIFT);
+}
+
+void
+got_fileindex_entry_stage_set(struct got_fileindex_entry *ie, uint32_t stage)
+{
+	ie->flags &= ~GOT_FILEIDX_F_STAGE;
+	ie->flags |= ((stage << GOT_FILEIDX_F_STAGE_SHIFT) &
+	    GOT_FILEIDX_F_STAGE);
 }
 
 int
@@ -379,7 +387,7 @@ write_fileindex_entry(SHA1_CTX *ctx, struct got_filein
 	if (err)
 		return err;
 
-	stage = got_fileindex_entry_stage(ie);
+	stage = got_fileindex_entry_stage_get(ie);
 	if (stage == GOT_FILEIDX_STAGE_MODIFY ||
 	    stage == GOT_FILEIDX_STAGE_ADD) {
 		SHA1Update(ctx, ie->staged_blob_sha1, SHA1_DIGEST_LENGTH);
@@ -579,7 +587,7 @@ read_fileindex_entry(struct got_fileindex_entry **iep,
 		goto done;
 
 	if (version >= 2) {
-		uint32_t stage = got_fileindex_entry_stage(ie);
+		uint32_t stage = got_fileindex_entry_stage_get(ie);
 		if (stage == GOT_FILEIDX_STAGE_MODIFY ||
 		    stage == GOT_FILEIDX_STAGE_ADD) {
 			n = fread(ie->staged_blob_sha1, 1, SHA1_DIGEST_LENGTH,
blob - 33b7f142cf74b87064731e83d2bfd65101294ff3
blob + 83e6be7d83308583c41892a51e5aa6a7f5bac56c
--- lib/got_lib_fileindex.h
+++ lib/got_lib_fileindex.h
@@ -156,5 +156,7 @@ const struct got_error *got_fileindex_diff_dir(struct 
 int got_fileindex_entry_has_blob(struct got_fileindex_entry *);
 int got_fileindex_entry_has_commit(struct got_fileindex_entry *);
 int got_fileindex_entry_has_file_on_disk(struct got_fileindex_entry *);
+uint32_t got_fileindex_entry_stage_get(const struct got_fileindex_entry *);
+void got_fileindex_entry_stage_set(struct got_fileindex_entry *ie, uint32_t);
 
 void got_fileindex_entry_mark_deleted_from_disk(struct got_fileindex_entry *);
blob - a64b0f8a733115f6aa705ad8e394e407b54590f8
blob + e2d15ef7a6c7d7222b3bcc4ffe515453b008c1f9
--- lib/worktree.c
+++ lib/worktree.c
@@ -4854,5 +4854,107 @@ got_worktree_histedit_skip_commit(struct got_worktree 
 	err = delete_ref(commit_ref_name, repo);
 done:
 	free(commit_ref_name);
+	return err;
+}
+
+static const struct got_error *
+stage_path(const char *path, size_t path_len, struct got_worktree *worktree,
+    struct got_fileindex *fileindex, struct got_repository *repo,
+    got_worktree_status_cb status_cb, void *status_arg)
+{
+	const struct got_error *err = NULL;
+	char *ondisk_path;
+	struct got_fileindex_entry *ie;
+	unsigned char status;
+	struct stat sb;
+	struct got_object_id *blob_id = NULL;
+	uint32_t stage;
+
+	if (asprintf(&ondisk_path, "%s/%s", worktree->root_path, path) == -1)
+		return got_error_from_errno("asprintf");
+
+	ie = got_fileindex_entry_get(fileindex, path, path_len);
+	if (ie == NULL) {
+		err = got_error_path(path, GOT_ERR_FILE_STATUS);
+		goto done;
+	}
+
+	err = get_file_status(&status, &sb, ie, ondisk_path, repo);
+	if (err)
+		goto done;
+
+	switch (status) {
+	case GOT_STATUS_ADD:
+	case GOT_STATUS_MODIFY:
+		err = got_object_blob_create(&blob_id, ondisk_path,
+		    repo);
+		if (err)
+			goto done;
+		memcpy(ie->staged_blob_sha1, blob_id->sha1,
+		    SHA1_DIGEST_LENGTH);
+		if (status == GOT_STATUS_ADD)
+			stage = GOT_FILEIDX_STAGE_ADD;
+		else
+			stage = GOT_FILEIDX_STAGE_MODIFY;
+		break;
+	case GOT_STATUS_DELETE:
+		stage = GOT_FILEIDX_STAGE_DELETE;
+		break;
+	default:
+		err = got_error_path(path, GOT_ERR_FILE_STATUS);
+		goto done;
+	}
+
+	got_fileindex_entry_stage_set(ie, stage);
+
+	/* XXX TODO pass 'staged' status separately */
+	err = (*status_cb)(status_arg, status, path, blob_id, NULL);
+done:
+	free(blob_id);
+	free(ondisk_path);
 	return err;
 }
+
+const struct got_error *
+got_worktree_stage_paths(struct got_worktree *worktree,
+    struct got_pathlist_head *paths, struct got_repository *repo,
+    got_worktree_status_cb status_cb, void *status_arg,
+    got_worktree_cancel_cb cancel_cb, void *cancel_arg)
+{
+	const struct got_error *err = NULL, *sync_err, *unlockerr;
+	struct got_pathlist_entry *pe;
+	struct got_fileindex *fileindex = NULL;
+	char *fileindex_path = NULL;
+
+	err = lock_worktree(worktree, LOCK_EX);
+	if (err)
+		return err;
+
+	err = open_fileindex(&fileindex, &fileindex_path, worktree);
+	if (err)
+		goto done;
+
+	TAILQ_FOREACH(pe, paths, entry) {
+		if (cancel_cb) {
+			err = (*cancel_cb)(cancel_arg);
+			if (err)
+				break;
+		}
+		err = stage_path(pe->path, pe->path_len, worktree, fileindex,
+		    repo, status_cb, status_arg);
+		if (err)
+			break;
+	}
+
+	sync_err = sync_fileindex(fileindex, fileindex_path);
+	if (sync_err && err == NULL)
+		err = sync_err;
+done:
+	free(fileindex_path);
+	if (fileindex)
+		got_fileindex_free(fileindex);
+	unlockerr = lock_worktree(worktree, LOCK_SH);
+	if (unlockerr && err == NULL)
+		err = unlockerr;
+	return err;
+}