baseline

yet another open-source distributed versioning control system
Log | Files | Refs

commit e0636a2651927691ff939d8cddfc79457cf36b12
parent 75cc5e577f9bff2769b98e2c85645cbbae229c8f
Author: Mohamed Aslan <maslan@sce.carleton.ca>
Date:   Fri, 19 Sep 2014 04:02:21 -0600

add basic support for external diff
* some more work is needed on labels before considering this done.
* missing support for ``git'' and/or ``cvs'' patch formats.

Diffstat:
MMakefile | 3++-
Mbaseline.c | 7+++++--
Acmd-diff.c | 288+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcmd.h | 1+
4 files changed, 296 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,8 @@ PROG= baseline BINDIR= /usr/bin SRCS= baseline.c config.c common.c session.c objects.c helper.c -SRCS+= cmd-add.c cmd-branch.c cmd-cat.c cmd-checkout.c cmd-commit.c cmd-help.c cmd-init.c cmd-ls.c cmd-log.c cmd-version.c +SRCS+= cmd-add.c cmd-branch.c cmd-cat.c cmd-checkout.c cmd-commit.c +SRCS+= cmd-diff.c cmd-help.c cmd-init.c cmd-ls.c cmd-log.c cmd-version.c SRCS+= objdb-fs.c SRCS+= dircache-simple.c diff --git a/baseline.c b/baseline.c @@ -48,12 +48,15 @@ main(int argc, char **argv) else if (!strcmp(argv[1], "commit")) { cmd_commit(argc - 1, argv + 1); } - else if (!strcmp(argv[1], "init")) { - cmd_init(argc - 1, argv + 1); + else if (!strcmp(argv[1], "diff")) { + cmd_diff(argc - 1, argv + 1); } else if (!strcmp(argv[1], "help")) { cmd_help(argc - 1, argv + 1); } + else if (!strcmp(argv[1], "init")) { + cmd_init(argc - 1, argv + 1); + } else if (!strcmp(argv[1], "ls")) { cmd_ls(argc - 1, argv + 1); } diff --git a/cmd-diff.c b/cmd-diff.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2014 Mohamed Aslan <maslan@sce.carleton.ca> + * + * 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 <stdio.h> /* printf(3) */ +#include <stdlib.h> /* EXIT_SUCCESS */ +#include <string.h> /* strdup(3) */ +#include <fcntl.h> /* open(2) */ +#include <err.h> +#include <unistd.h> /* read(2), write(2) */ +#include <sys/stat.h> /* S_ISDIR */ +#include <sys/wait.h> /* waitpid(2) */ + +#include "cmd.h" +#include "session.h" + +#include "objects.h" + +#include "common.h" + + +static char * +make_tmpdir() +{ + char *name = NULL; + char *old, *new; + + name = strdup("/tmp/baseline.XXXXXX"); + if (mkdtemp(name) == NULL) { + errx(EXIT_FAILURE, "error, failed to create a temporary directory."); + } + asprintf(&old, "%s/old", name); + asprintf(&new, "%s/new", name); + if ((mkdir(old, S_IRWXU) < 0) || (mkdir(new, S_IRWXU) < 0)) + errx(EXIT_FAILURE, "error, failed to write to temporary directory."); + free(old); + free(new); + return name; +} + +static char * +make_fifo(const char *path, const char *name) +{ + char *fifo_name = NULL; + + asprintf(&fifo_name, "%s/%s", path, name); + if (mkfifo(fifo_name, S_IRUSR | S_IWUSR) == -1) { + errx(EXIT_FAILURE, "error, failed to create FIFO \'%s\'.", fifo_name); + } + return fifo_name; +} + +static int +open_fifo(const char *fifo) +{ + int fd; + + if ((fd = open(fifo, O_WRONLY)) == -1) { + errx(EXIT_FAILURE, "error, failed to open FIFO \'%s\'.", fifo); + } + return fd; +} + +static void +copy_to_fifo(struct file *f, int fifo) +{ + char buf[2048]; + ssize_t n; + + while ((n = read(f->fd, buf, sizeof(buf))) > 0) { + write(fifo, buf, n); + } + if (n == -1) { + errx(EXIT_FAILURE, "error, failed to read file."); + } +} + +static void +exec_ext_diff(const char *old, const char *old_label, const char *new, const char *new_label) +{ + char buf[2048]; + char *cmd = NULL; + size_t n; + FILE *fp; + + if (old == NULL && new == NULL) + return; + + if (old == NULL) + asprintf(&cmd, "diff -u %s %s -L %s -L %s", "/dev/null", new, "/dev/null", new_label == NULL ? new : new_label); + else if(new == NULL) + asprintf(&cmd, "diff -u %s %s -L %s -L %s", old, "/dev/null", old_label == NULL ? old : old_label, "/dev/null"); + else + asprintf(&cmd, "diff -u %s %s -L %s -L %s", old, new, old_label == NULL ? old : old_label, new_label == NULL ? new : new_label); + + if ((fp = popen(cmd, "r")) == NULL) + errx(EXIT_FAILURE, "error, failed to run external diff."); + /* + while ((n = fread(buf, sizeof(char), sizeof(buf), pf)) > 0) + fwrite(buf, sizeof(char), n, stdout); + */ + while ((n = read(fileno(fp), buf, sizeof(buf))) > 0) + write(1, buf, n); + if (n == -1) + errx(EXIT_FAILURE, "error, reading output from external diff."); + pclose(fp); + free(cmd); +} + +static void +ext_diff_proc(struct session *s, struct dirent *ent, char *fifo) +{ + int fifo_fd; + struct file *f; + + fifo_fd = open_fifo(fifo); + + f = baseline_file_new(); + s->db_ops->select_file(s->db_ctx, ent->id, f); + + copy_to_fifo(f, fifo_fd); + close(fifo_fd); + unlink(fifo); + + baseline_file_free(f); +} + +static void +ext_diff(struct session *s, const char *tmpdir, struct dirent *ent1, struct dirent *ent2) +{ + char *dir; + char *label1, *label2; + char *fifo1 = NULL, *fifo2 = NULL; + pid_t pid1, pid2; + + + if (ent1 == NULL && ent2 == NULL) + return; + + if (ent1 != NULL) { + asprintf(&dir, "%s/old", tmpdir); + fifo1 = make_fifo(dir, ent1->name); + free(dir); + } + if(ent2 != NULL) { + asprintf(&dir, "%s/new", tmpdir); + fifo2 = make_fifo(dir, ent2->name); + free(dir); + } + /* FIXME */ + label1 = fifo1; + label2 = fifo2; + + pid1 = fork(); + if (pid1 < 0) { + errx(EXIT_FAILURE, "error, failed to create a new process."); + } + else if (pid1 == 0) { + exec_ext_diff(fifo1, label1, fifo2, label2); + exit(0); + } + else { + if (ent1 != NULL && ent2 != NULL) { + pid2 = fork(); + + if (pid2 < 0) { + errx(EXIT_FAILURE, "error, failed to create a new process."); + } + else if (pid2 == 0) { + ext_diff_proc(s, ent1, fifo1); + exit(0); + } + else { + ext_diff_proc(s, ent2, fifo2); + } + } + else { + if (ent1 != NULL) + ext_diff_proc(s, ent1, fifo1); + else + ext_diff_proc(s, ent2, fifo2); + } + waitpid(pid1, NULL, 0); + } + free(fifo1); + free(fifo2); +} + +int +cmd_diff(int argc, char **argv) +{ + char *old, *new; + char *tmpdir = NULL; + struct session s; + struct commit *comm_old, *comm_new; + struct dir *dir_old, *dir_new; + struct dirent *ent_old, *ent_new; + + if (argc != 3) { + errx(EXIT_FAILURE, "wrong number of arguments (%d)\n", argc); + } + old = strdup(argv[1]); + new = strdup(argv[2]); + + baseline_session_begin(&s, 0); + + tmpdir = make_tmpdir(); + + /* + s.db_ops->branch_get_head(s.db_ctx, s.branch, &head); + if (head == NULL) + goto ret; + */ + + comm_old = baseline_commit_new(); + s.db_ops->select_commit(s.db_ctx, old, comm_old); + + dir_old = baseline_dir_new(); + s.db_ops->select_dir(s.db_ctx, comm_old->dir, dir_old); + + comm_new = baseline_commit_new(); + s.db_ops->select_commit(s.db_ctx, new, comm_new); + + dir_new = baseline_dir_new(); + s.db_ops->select_dir(s.db_ctx, comm_new->dir, dir_new); + + ent_old = dir_old->children; + ent_new = dir_new->children; + while (1) { + if (ent_old == NULL && ent_new == NULL) + break; + else if (ent_old == NULL) { + /* printf("+++ %s\n", ent_new->name); */ + ext_diff(&s, tmpdir, NULL, ent_new); + ent_new = ent_new->next; + } + else if (ent_new == NULL) { + /* printf("--- %s\n", ent_old->name); */ + ext_diff(&s, tmpdir, ent_old, NULL); + ent_old = ent_old->next; + } + else if (!strcmp(ent_old->name, ent_new->name)) { + if (strcmp(ent_old->id, ent_new->id)) { + /* printf("*** %s\n", ent_old->name); */ + ext_diff(&s, tmpdir, ent_old, ent_new); + } + ent_old = ent_old->next; + ent_new = ent_new->next; + } + else if (strcmp(ent_old->name, ent_new->name) < 0) { + /* printf("--- %s\n", ent_old->name); */ + ext_diff(&s, tmpdir, ent_old, NULL); + ent_old = ent_old->next; + } + else if (strcmp(ent_old->name, ent_new->name) > 0) { + /* printf("+++ %s\n", ent_new->name); */ + ext_diff(&s, tmpdir, NULL, ent_new); + ent_new = ent_new->next; + } + /* + if (S_ISDIR(ent->mode)) + printf("%s/\n", ent->name); + else + printf("%s\n", ent->name); + */ + } + + baseline_dir_free(dir_old); + baseline_dir_free(dir_new); + + remove(tmpdir); + free(tmpdir); + baseline_session_end(&s); + return EXIT_SUCCESS; +} + diff --git a/cmd.h b/cmd.h @@ -22,6 +22,7 @@ int cmd_branch(int, char **); int cmd_cat(int, char **); int cmd_checkout(int, char **); int cmd_commit(int, char **); +int cmd_diff(int, char **); int cmd_help(int, char **); int cmd_init(int, char **); int cmd_log(int, char **);