commit - 53ccebc212c162c70f666f060b461d9dccdca647
commit + 7d4057662589d6190d63231f5ea868a05f2780d2
blob - a7df9bcfd7dd5240b4bf896836d2bc6db0cb92ac
blob + 45158e76977b2c703c3ea2388bd8cc163bd7ce31
--- README
+++ README
written in any case to verify a fix and prevent the problem from resurfacing.
It is also possible to write test cases in C. Various examples of this
-exist in the regress/ directory. Most such tests are unit tests written
-before Got's command line interface was available; it is unlikely that a
-problem found during regular usage will require a test to be written in C.
+exist in the regress/ directory. Most such tests are unit tests; it is
+unlikely that a problem found during regular usage will require a test
+to be written in C.
Some areas of code, such as the tog UI, are not covered by automated tests.
Please always try to find a way to trigger your problem via the command line
blob - ead26b8028b6eabf832d64f2b8d487d55f790b32
blob + 7553c630ced30b2ae8f77cad74ae23f3f298c388
--- got-dist.txt
+++ got-dist.txt
/libexec/got-read-tag/Makefile
/libexec/got-read-tag/got-read-tag.c
/regress
-/regress/repository
-/regress/repository/Makefile
-/regress/repository/repository_test.c
/regress/idset
/regress/idset/Makefile
/regress/idset/idset_test.c
/regress/delta
/regress/delta/Makefile
/regress/delta/delta_test.c
-/regress/worktree
-/regress/worktree/Makefile
-/regress/worktree/worktree_test.c
/regress/Makefile
/regress/Makefile.inc
/regress/cmdline
blob - b5554554510d2ea5d8e632dd20c19931b5da7aa1
blob + 060d69c317d74037521f5d1b4a7653dc63a4fb41
--- regress/Makefile
+++ regress/Makefile
-SUBDIR = cmdline delta idset path repository worktree
+SUBDIR = cmdline delta idset path
.include <bsd.subdir.mk>
blob - 6341b049647beede14d907a8e07ff6b709036d9d (mode 644)
blob + /dev/null
--- regress/repository/Makefile
+++ /dev/null
-.PATH:${.CURDIR}/../../lib
-
-PROG = repository_test
-SRCS = path.c repository.c error.c reference.c object.c object_cache.c \
- object_idset.c object_parse.c opentemp.c sha1.c diff.c diffreg.c \
- pack.c privsep.c delta.c fileindex.c worktree.c inflate.c \
- buf.c worklist.c rcsutil.c diff3.c lockfile.c deflate.c \
- object_create.c repository_test.c
-
-CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
-LDADD = -lutil -lz
-
-NOMAN = yes
-
-.include <bsd.regress.mk>
blob - c195445da886beac77bfd5c142d4a744bc55f866 (mode 644)
blob + /dev/null
--- regress/repository/repository_test.c
+++ /dev/null
-/*
- * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/stat.h>
-#include <sys/queue.h>
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <util.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <err.h>
-#include <unistd.h>
-
-#include "got_error.h"
-#include "got_object.h"
-#include "got_reference.h"
-#include "got_repository.h"
-#include "got_diff.h"
-#include "got_opentemp.h"
-#include "got_privsep.h"
-#include "got_path.h"
-
-
-#ifndef nitems
-#define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
-#endif
-
-#define GOT_REPO_PATH "../../../"
-
-static int verbose;
-
-void
-test_printf(char *fmt, ...)
-{
- va_list ap;
-
- if (!verbose)
- return;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- va_end(ap);
-}
-
-static const struct got_error *
-print_commit_object(struct got_object_id *, struct got_repository *);
-
-static const struct got_error *
-print_parent_commits(struct got_commit_object *commit,
- struct got_repository *repo)
-{
- const struct got_object_id_queue *parent_ids;
- struct got_object_qid *qid;
- const struct got_error *err = NULL;
-
- parent_ids = got_object_commit_get_parent_ids(commit);
- SIMPLEQ_FOREACH(qid, parent_ids, entry) {
- err = print_commit_object(qid->id, repo);
- if (err)
- break;
- }
-
- return err;
-}
-
-static const struct got_error *
-print_tree_object(struct got_object_id *id, char *parent,
- struct got_repository *repo)
-{
- struct got_tree_object *tree;
- const struct got_tree_entries *entries;
- struct got_tree_entry *te;
- const struct got_error *err;
-
- err = got_object_open_as_tree(&tree, repo, id);
- if (err != NULL)
- return err;
-
- entries = got_object_tree_get_entries(tree);
- SIMPLEQ_FOREACH(te, &entries->head, entry) {
- char *next_parent;
- char *hex;
-
- err = got_object_id_str(&hex, te->id);
- if (err)
- break;
-
- if (!S_ISDIR(te->mode)) {
- test_printf("%s %s/%s\n", hex, parent, te->name);
- free(hex);
- continue;
- }
- test_printf("%s %s/%s\n", hex, parent, te->name);
- free(hex);
-
- if (asprintf(&next_parent, "%s/%s", parent, te->name) == -1) {
- err = got_error_from_errno("asprintf");
- break;
- }
-
- err = print_tree_object(te->id, next_parent, repo);
- free(next_parent);
- if (err)
- break;
- }
-
- got_object_tree_close(tree);
- return err;
-}
-
-static const struct got_error *
-print_commit_object(struct got_object_id *id, struct got_repository *repo)
-{
- struct got_commit_object *commit;
- const struct got_object_id_queue *parent_ids;
- struct got_object_qid *qid;
- char *buf;
- const struct got_error *err;
- int obj_type;
-
- err = got_object_open_as_commit(&commit, repo, id);
- if (err)
- return err;
-
- err = got_object_id_str(&buf, id);
- if (err) {
- got_object_commit_close(commit);
- return err;
- }
- test_printf("tree: %s\n", buf);
- free(buf);
- test_printf("parent%s: ",
- (got_object_commit_get_nparents(commit) == 1) ? "" : "s");
- parent_ids = got_object_commit_get_parent_ids(commit);
- SIMPLEQ_FOREACH(qid, parent_ids, entry) {
- err = got_object_id_str(&buf, qid->id);
- if (err) {
- got_object_commit_close(commit);
- return err;
- }
- test_printf("%s\n", buf);
- free(buf);
- }
- test_printf("author: %s\n", got_object_commit_get_author(commit));
- test_printf("committer: %s\n", got_object_commit_get_committer(commit));
- test_printf("log: %s\n", got_object_commit_get_logmsg(commit));
-
- err = got_object_get_type(&obj_type, repo,
- got_object_commit_get_tree_id(commit));
- if (err != NULL) {
- got_object_commit_close(commit);
- return err;
- }
- if (obj_type == GOT_OBJ_TYPE_TREE)
- test_printf("\n");
-
- err = print_parent_commits(commit, repo);
- got_object_commit_close(commit);
-
- return err;
-}
-
-static int
-repo_read_log(const char *repo_path)
-{
- const struct got_error *err;
- struct got_repository *repo;
- struct got_reference *head_ref;
- struct got_object_id *id;
- char *buf;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- return 0;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
- if (err != NULL || head_ref == NULL)
- return 0;
- err = got_ref_resolve(&id, repo, head_ref);
- if (err != NULL || head_ref == NULL)
- return 0;
- err = got_object_id_str(&buf, id);
- if (err != NULL)
- return 0;
- test_printf("HEAD is at %s\n", buf);
- free(buf);
- err = print_commit_object(id, repo);
- if (err)
- return 0;
- free(id);
- got_ref_close(head_ref);
- got_repo_close(repo);
- return 1;
-}
-
-static int
-repo_read_tree(const char *repo_path)
-{
- const char *tree_sha1 = "6cc96e0e093fb30630ba7f199d0a008b24c6a690";
- const struct got_error *err;
- struct got_repository *repo;
- struct got_object_id *id;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- return 0;
- err = got_object_resolve_id_str(&id, repo, tree_sha1);
- if (err != NULL)
- return 0;
-
- print_tree_object(id, "", repo);
- test_printf("\n");
-
- got_repo_close(repo);
- return (err == NULL);
-}
-
-static int
-repo_read_blob(const char *repo_path)
-{
- const char *blob_sha1 = "141f5fdc96126c1f4195558560a3c915e3d9b4c3";
- const struct got_error *err;
- struct got_repository *repo;
- struct got_object_id *id;
- struct got_blob_object *blob;
- int i;
- size_t len;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- return 0;
- err = got_object_resolve_id_str(&id, repo, blob_sha1);
- if (err != NULL)
- return 0;
- err = got_object_open_as_blob(&blob, repo, id, 64);
- if (err != NULL)
- return 0;
-
- test_printf("\n");
- do {
- const uint8_t *buf = got_object_blob_get_read_buf(blob);
- err = got_object_blob_read_block(&len, blob);
- if (err)
- break;
- for (i = 0; i < len; i++)
- test_printf("%c", buf[i]);
- } while (len != 0);
- test_printf("\n");
-
- got_object_blob_close(blob);
- got_repo_close(repo);
- return (err == NULL);
-}
-
-static int
-repo_diff_blob(const char *repo_path)
-{
- const char *blob1_sha1 = "141f5fdc96126c1f4195558560a3c915e3d9b4c3";
- const char *blob2_sha1 = "de7eb21b21c7823a753261aadf7cba35c9580fbf";
- const struct got_error *err;
- struct got_repository *repo;
- struct got_object_id *id1, *id2;
- struct got_blob_object *blob1;
- struct got_blob_object *blob2;
- FILE *outfile;
- int i;
- char *line;
- size_t len;
- const char delim[3] = {'\0', '\0', '\0'};
- const char *expected_output[] = {
- "blob - 141f5fdc96126c1f4195558560a3c915e3d9b4c3",
- "blob + de7eb21b21c7823a753261aadf7cba35c9580fbf",
- "--- 141f5fdc96126c1f4195558560a3c915e3d9b4c3",
- "+++ de7eb21b21c7823a753261aadf7cba35c9580fbf",
- "@@ -1,10 +1,10 @@",
- " .PATH:${.CURDIR}/../../lib",
- " ",
- " PROG = repository_test",
- "-SRCS = path.c repository.c error.c refs.c repository_test.c",
- "+SRCS = path.c repository.c error.c refs.c object.c sha1.c repository_test.c",
- " ",
- " CPPFLAGS = -I${.CURDIR}/../../include",
- "-LDADD = -lutil",
- "+LDADD = -lutil -lz",
- " ",
- " NOMAN = yes"
- };
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- return 0;
-
- err = got_object_resolve_id_str(&id1, repo, blob1_sha1);
- if (err != NULL)
- return 0;
-
- err = got_object_resolve_id_str(&id2, repo, blob2_sha1);
- if (err != NULL)
- return 0;
-
- err = got_object_open_as_blob(&blob1, repo, id1, 512);
- if (err != NULL)
- return 0;
-
- err = got_object_open_as_blob(&blob2, repo, id2, 512);
- if (err != NULL)
- return 0;
-
- test_printf("\n");
- outfile = got_opentemp();
- if (outfile == NULL)
- return 0;
- got_diff_blob(blob1, blob2, NULL, NULL, 3, outfile);
- rewind(outfile);
- i = 0;
- while ((line = fparseln(outfile, &len, NULL, delim, 0)) != NULL) {
- test_printf(line);
- test_printf("\n");
- if (i < nitems(expected_output) &&
- strcmp(line, expected_output[i]) != 0) {
- test_printf("diff output mismatch; expected: '%s'\n",
- expected_output[i]);
- return 0;
- }
- i++;
- }
- if (fclose(outfile) != 0 && err == NULL)
- err = got_error_from_errno("fclose");
- test_printf("\n");
- if (i != nitems(expected_output) + 1) {
- test_printf("number of lines expected: %d; actual: %d\n",
- nitems(expected_output), i - 1);
- return 0;
- }
-
- got_object_blob_close(blob1);
- got_object_blob_close(blob2);
- got_repo_close(repo);
- return (err == NULL);
-}
-
-static int
-repo_diff_tree(const char *repo_path)
-{
- const char *tree1_sha1 = "1efc41caf761a0a1f119d0c5121eedcb2e7a88c3";
- const char *tree2_sha1 = "4aa8f2933839ff8a8fb3f905a4c232d22c6ff5f3";
- const struct got_error *err;
- struct got_repository *repo;
- struct got_object_id *id1;
- struct got_object_id *id2;
- struct got_tree_object *tree1;
- struct got_tree_object *tree2;
- FILE *outfile;
- struct got_diff_blob_output_unidiff_arg arg;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- return 0;
-
- err = got_object_resolve_id_str(&id1, repo, tree1_sha1);
- if (err != NULL)
- return 0;
- err = got_object_resolve_id_str(&id2, repo, tree2_sha1);
- if (err != NULL)
- return 0;
-
- err = got_object_open_as_tree(&tree1, repo, id1);
- if (err != NULL)
- return 0;
-
- err = got_object_open_as_tree(&tree2, repo, id2);
- if (err != NULL)
- return 0;
-
- if (!verbose) {
- outfile = fopen("/dev/null", "w+");
- if (outfile == NULL)
- return 0;
- } else
- outfile = stdout;
- test_printf("\n");
- arg.diff_context = 3;
- arg.outfile = outfile;
- got_diff_tree(tree1, tree2, "", "", repo,
- got_diff_blob_output_unidiff, &arg, 1);
- test_printf("\n");
-
- got_object_tree_close(tree1);
- got_object_tree_close(tree2);
- got_repo_close(repo);
- return (err == NULL);
-}
-
-#define RUN_TEST(expr, name) \
- { test_ok = (expr); \
- printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
- failure = (failure || !test_ok); }
-
-
-void
-usage(void)
-{
- fprintf(stderr, "usage: repository_test [-v] [REPO_PATH]\n");
-}
-
-static const struct got_error *
-apply_unveil(const char *repo_path)
-{
- const struct got_error *error;
-
- if (repo_path) {
- if (unveil(repo_path, "r") != 0)
- return got_error_from_errno2("unveil", repo_path);
- }
-
- if (unveil("/tmp", "rwc") != 0)
- return got_error_from_errno2("unveil", "/tmp");
-
- if (unveil("/dev/null", "rwc") != 0)
- return got_error_from_errno2("unveil", "/dev/null");
-
- error = got_privsep_unveil_exec_helpers();
- if (error != NULL)
- return error;
-
- if (unveil(NULL, NULL) != 0)
- return got_error_from_errno("unveil");
-
- return NULL;
-}
-
-int
-main(int argc, char *argv[])
-{
- int test_ok = 0, failure = 0;
- char *repo_path;
- int ch;
- const struct got_error *error;
-
-#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath proc exec sendfd unveil", NULL)
- == -1)
- err(1, "pledge");
-#endif
-
- while ((ch = getopt(argc, argv, "v")) != -1) {
- switch (ch) {
- case 'v':
- verbose = 1;
- break;
- default:
- usage();
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
-
- switch (argc) {
- case 0:
- repo_path = realpath(GOT_REPO_PATH, NULL);
- break;
- case 1:
- repo_path = realpath(argv[0], NULL);
- break;
- default:
- usage();
- return 1;
- }
- if (repo_path == NULL) {
- fprintf(stderr, "realpath: %s\n", strerror(errno));
- return 1;
- }
-
- error = apply_unveil(repo_path);
- if (error) {
- fprintf(stderr, "unveil: %s\n", error->msg);
- free(repo_path);
- return 1;
- }
-
- RUN_TEST(repo_read_tree(repo_path), "read_tree");
- RUN_TEST(repo_read_log(repo_path), "read_log");
- RUN_TEST(repo_read_blob(repo_path), "read_blob");
- RUN_TEST(repo_diff_blob(repo_path), "diff_blob");
- RUN_TEST(repo_diff_tree(repo_path), "diff_tree");
-
- free(repo_path);
- return failure ? 1 : 0;
-}
blob - c29a98dabd56d5ccc65fa9042aa0141e6ef953dc (mode 644)
blob + /dev/null
--- regress/worktree/Makefile
+++ /dev/null
-.PATH:${.CURDIR}/../../lib
-
-PROG = worktree_test
-SRCS = worktree.c repository.c object.c object_cache.c object_idset.c \
- object_parse.c opentemp.c path.c error.c reference.c sha1.c pack.c \
- privsep.c delta.c inflate.c fileindex.c \
- buf.c worklist.c rcsutil.c diff.c diffreg.c diff3.c lockfile.c \
- deflate.c object_create.c worktree_test.c
-
-CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib
-LDADD = -lutil -lz
-
-NOMAN = yes
-
-.include <bsd.regress.mk>
blob - 3df09c5d054b2011eb32474bd2a2f373638965ed (mode 644)
blob + /dev/null
--- regress/worktree/worktree_test.c
+++ /dev/null
-/*
- * Copyright (c) 2018, 2019 Stefan Sperling <stsp@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/limits.h>
-#include <sys/stat.h>
-
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <util.h>
-#include <err.h>
-#include <unistd.h>
-#include <uuid.h>
-
-#include "got_error.h"
-#include "got_object.h"
-#include "got_reference.h"
-#include "got_repository.h"
-#include "got_path.h"
-#include "got_worktree.h"
-#include "got_opentemp.h"
-#include "got_privsep.h"
-
-#include "got_lib_worktree.h"
-
-#define GOT_REPO_PATH "../../../"
-
-static int verbose;
-
-void
-test_printf(char *fmt, ...)
-{
- va_list ap;
-
- if (!verbose)
- return;
-
- va_start(ap, fmt);
- vprintf(fmt, ap);
- va_end(ap);
-}
-
-static int
-remove_got_dir(const char *worktree_path)
-{
- char *path;
-
- if (asprintf(&path, "%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR) == -1)
- return 0;
- rmdir(path);
- free(path);
- return 1;
-}
-
-static int
-remove_meta_file(const char *worktree_path, const char *name)
-{
- char *path;
-
- if (asprintf(&path, "%s/%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR,
- name) == -1)
- return 0;
- unlink(path);
- free(path);
- return 1;
-}
-
-static const struct got_error *
-remove_worktree_base_ref(struct got_worktree *worktree,
- struct got_repository *repo)
-{
- const struct got_error *err = NULL;
- struct got_reference *base_ref = NULL;
- char *refname = NULL;
-
- err = got_worktree_get_base_ref_name(&refname, worktree);
- if (err)
- return err;
-
- err = got_ref_open(&base_ref, repo, refname, 0);
- if (err)
- goto done;
-
- err = got_ref_delete(base_ref, repo);
-done:
- if (base_ref)
- got_ref_close(base_ref);
- free(refname);
- return err;
-
-}
-
-static int
-remove_worktree(const char *worktree_path)
-{
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_HEAD_REF))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_BASE_COMMIT))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_FILE_INDEX))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_REPOSITORY))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_PATH_PREFIX))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_LOCK))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_FORMAT))
- return 0;
- if (!remove_meta_file(worktree_path, GOT_WORKTREE_UUID))
- return 0;
- if (!remove_got_dir(worktree_path))
- return 0;
- if (rmdir(worktree_path) == -1)
- return 0;
- return 1;
-}
-
-static int
-read_meta_file(char **content, const char *path)
-{
- FILE *f;
- size_t len;
- const char delim[3] = {'\0', '\0', '\0'};
- int ret = 0;
-
- f = fopen(path, "r");
- if (f == NULL)
- return errno;
-
- *content = fparseln(f, &len, NULL, delim, 0);
- if (*content == NULL)
- ret = errno;
- if (fclose(f) != 0 && ret == 0)
- ret = errno;
- return ret;
-}
-
-static int
-check_meta_file_exists(const char *worktree_path, const char *name)
-{
- struct stat sb;
- char *path;
- int ret = 0;
-
- if (asprintf(&path, "%s/%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR,
- name) == -1)
- return 0;
- if (stat(path, &sb) == 0)
- ret = 1;
- if (verbose) {
- char *content;
- if (read_meta_file(&content, path) == 0) {
- test_printf("%s:\t%s\n", name, content);
- free(content);
- }
- }
- free(path);
- return ret;
-}
-
-static int
-worktree_init(const char *repo_path)
-{
- const struct got_error *err;
- struct got_repository *repo = NULL;
- struct got_reference *head_ref = NULL;
- char worktree_path[PATH_MAX];
- int ok = 0;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- goto done;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
- if (err != NULL || head_ref == NULL)
- goto done;
-
- strlcpy(worktree_path, "worktree-XXXXXX", sizeof(worktree_path));
- if (mkdtemp(worktree_path) == NULL)
- goto done;
-
- err = got_worktree_init(worktree_path, head_ref, "/", repo);
- if (err != NULL)
- goto done;
-
- /* Ensure required files were created. */
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_HEAD_REF))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_BASE_COMMIT))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_LOCK))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_FILE_INDEX))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_REPOSITORY))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_PATH_PREFIX))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_FORMAT))
- goto done;
- if (!check_meta_file_exists(worktree_path, GOT_WORKTREE_UUID))
- goto done;
-
- if (!remove_worktree(worktree_path))
- goto done;
- ok = 1;
-done:
- if (head_ref)
- got_ref_close(head_ref);
- if (repo)
- got_repo_close(repo);
- return ok;
-}
-
-static int
-obstruct_meta_file(char **path, const char *worktree_path, const char *name)
-{
- FILE *f;
- char *s = "This file should not be here\n";
- int ret = 1;
-
- if (asprintf(path, "%s/%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR,
- name) == -1)
- return 0;
- f = fopen(*path, "w+");
- if (f == NULL) {
- free(*path);
- return 0;
- }
- if (fwrite(s, 1, strlen(s), f) != strlen(s)) {
- free(*path);
- ret = 0;
- }
- if (fclose(f) != 0)
- ret = 0;
- return ret;
-}
-
-static int
-obstruct_meta_file_and_init(int *ok, struct got_repository *repo,
- const char *worktree_path, char *name)
-{
- const struct got_error *err;
- char *path;
- int ret = 0;
- struct got_reference *head_ref = NULL;
-
- if (!obstruct_meta_file(&path, worktree_path, GOT_WORKTREE_FILE_INDEX))
- return 0;
-
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
- if (err != NULL || head_ref == NULL)
- return 0;
-
- err = got_worktree_init(worktree_path, head_ref, "/", repo);
- if (err != NULL && err->code == GOT_ERR_ERRNO && errno == EEXIST) {
- (*ok)++;
- ret = 1;
- }
- unlink(path);
- free(path);
- got_ref_close(head_ref);
- return ret;
-}
-
-static int
-worktree_init_exists(const char *repo_path)
-{
- const struct got_error *err;
- struct got_repository *repo = NULL;
- char worktree_path[PATH_MAX];
- char *gotpath = NULL;
- int ok = 0;
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- goto done;
- strlcpy(worktree_path, "worktree-XXXXXX", sizeof(worktree_path));
- if (mkdtemp(worktree_path) == NULL)
- goto done;
- if (mkdir(worktree_path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST)
- goto done;
-
- if (asprintf(&gotpath, "%s/%s", worktree_path, GOT_WORKTREE_GOT_DIR)
- == -1)
- goto done;
- if (mkdir(gotpath, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST)
- goto done;
-
- /* Create files which got_worktree_init() will try to create as well. */
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_HEAD_REF))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_BASE_COMMIT))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_LOCK))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_FILE_INDEX))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_REPOSITORY))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_PATH_PREFIX))
- goto done;
- if (!obstruct_meta_file_and_init(&ok, repo, worktree_path,
- GOT_WORKTREE_FORMAT))
- goto done;
-
-done:
- if (repo)
- got_repo_close(repo);
- free(gotpath);
- if (ok == 7)
- remove_worktree(worktree_path);
- return (ok == 7);
-}
-
-static const struct got_error *
-progress_cb(void *arg, unsigned char status, const char *path)
-{
- return NULL;
-}
-
-static int
-worktree_checkout(const char *repo_path)
-{
- const struct got_error *err;
- struct got_repository *repo = NULL;
- struct got_reference *head_ref = NULL;
- struct got_worktree *worktree = NULL;
- char *makefile_path = NULL, *cfile_path = NULL;
- char worktree_path[PATH_MAX];
- int ok = 0;
- struct stat sb;
- struct got_pathlist_head paths;
-
- TAILQ_INIT(&paths);
-
- err = got_repo_open(&repo, repo_path);
- if (err != NULL || repo == NULL)
- goto done;
- err = got_ref_open(&head_ref, repo, GOT_REF_HEAD, 0);
- if (err != NULL || head_ref == NULL)
- goto done;
-
- strlcpy(worktree_path, "worktree-XXXXXX", sizeof(worktree_path));
- if (mkdtemp(worktree_path) == NULL)
- goto done;
-
- err = got_worktree_init(worktree_path, head_ref, "/regress/worktree",
- repo);
- if (err != NULL)
- goto done;
-
- err = got_worktree_open(&worktree, worktree_path);
- if (err != NULL)
- goto done;
-
- err = got_pathlist_append(&paths, "", NULL);
- if (err)
- goto done;
- err = got_worktree_checkout_files(worktree, &paths, repo, progress_cb,
- NULL, NULL, NULL);
- if (err != NULL)
- goto done;
-
- test_printf("checked out %s\n", worktree_path);
-
- /* The work tree should contain a Makefile and worktree_test.c. */
- if (asprintf(&makefile_path, "%s/Makefile", worktree_path) == -1)
- goto done;
- if (stat(makefile_path, &sb) != 0)
- goto done;
- else
- unlink(makefile_path);
- if (asprintf(&cfile_path, "%s/worktree_test.c", worktree_path) == -1)
- goto done;
- if (stat(cfile_path, &sb) != 0)
- goto done;
- else
- unlink(cfile_path);
-
- err = remove_worktree_base_ref(worktree, repo);
- if (err)
- goto done;
- if (!remove_worktree(worktree_path))
- goto done;
-
- ok = 1;
-done:
- if (worktree)
- got_worktree_close(worktree);
- if (head_ref)
- got_ref_close(head_ref);
- if (repo)
- got_repo_close(repo);
- got_pathlist_free(&paths);
- free(makefile_path);
- free(cfile_path);
- return ok;
-}
-
-#define RUN_TEST(expr, name) \
- { test_ok = (expr); \
- printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
- failure = (failure || !test_ok); }
-
-
-void
-usage(void)
-{
- fprintf(stderr, "usage: worktree_test [-v] [REPO_PATH]\n");
-}
-
-int
-main(int argc, char *argv[])
-{
- int test_ok = 0, failure = 0;
- const char *repo_path;
- char *cwd = NULL;
- int ch;
-
-#ifndef PROFILE
- if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd "
- "unveil", NULL) == -1)
- err(1, "pledge");
-#endif
-
- while ((ch = getopt(argc, argv, "v")) != -1) {
- switch (ch) {
- case 'v':
- verbose = 1;
- break;
- default:
- usage();
- return 1;
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc == 0)
- repo_path = GOT_REPO_PATH;
- else if (argc == 1)
- repo_path = argv[0];
- else {
- usage();
- return 1;
- }
-
- cwd = getcwd(NULL, 0);
- if (cwd == NULL)
- err(1, "getcwd");
- if (unveil(cwd, "rwc") != 0)
- err(1, "unvail");
- free(cwd);
-
- if (unveil("/tmp", "rwc") != 0)
- err(1, "unveil");
-
- if (unveil(repo_path, "rwc") != 0)
- err(1, "unveil");
-
- if (got_privsep_unveil_exec_helpers() != NULL)
- return 1;
-
- if (unveil(NULL, NULL) != 0)
- err(1, "unveil");
-
- RUN_TEST(worktree_init(repo_path), "init");
- RUN_TEST(worktree_init_exists(repo_path), "init exists");
- RUN_TEST(worktree_checkout(repo_path), "checkout");
-
- return failure ? 1 : 0;
-}