diff --git a/src/ht-builtin-commit.c b/src/ht-builtin-commit.c index 1273f65b..b26cbdbf 100644 --- a/src/ht-builtin-commit.c +++ b/src/ht-builtin-commit.c @@ -27,6 +27,10 @@ #include static char *repo_path; +static gboolean separator_null; +static int from_fd = -1; +static gboolean from_stdin; +static char *from_file; static char *subject; static char *body; static char **additions; @@ -36,6 +40,10 @@ static GOptionEntry options[] = { { "repo", 0, 0, G_OPTION_ARG_FILENAME, &repo_path, "Repository path", "repo" }, { "subject", 's', 0, G_OPTION_ARG_STRING, &subject, "One line subject", "subject" }, { "body", 'b', 0, G_OPTION_ARG_STRING, &body, "Full description", "body" }, + { "from-fd", 0, 0, G_OPTION_ARG_INT, &from_fd, "Read new tree files from fd", "file descriptor" }, + { "from-stdin", 0, 0, G_OPTION_ARG_NONE, &from_stdin, "Read new tree files from stdin", "file descriptor" }, + { "from-file", 0, 0, G_OPTION_ARG_FILENAME, &from_file, "Read new tree files from another file", "path" }, + { "separator-null", 0, 0, G_OPTION_ARG_NONE, &separator_null, "", "Use '\\0' as filename separator, as with find -print0" }, { "add", 'a', 0, G_OPTION_ARG_FILENAME_ARRAY, &additions, "Relative file path to add", "filename" }, { "remove", 'r', 0, G_OPTION_ARG_FILENAME_ARRAY, &removals, "Relative file path to remove", "filename" }, { NULL } @@ -47,6 +55,8 @@ hacktree_builtin_commit (int argc, char **argv, const char *prefix, GError **err GOptionContext *context; gboolean ret = FALSE; HacktreeRepo *repo = NULL; + gboolean using_filename_cmdline; + gboolean using_filedescriptors; GPtrArray *additions_array = NULL; GPtrArray *removals_array = NULL; GChecksum *commit_checksum = NULL; @@ -67,12 +77,21 @@ hacktree_builtin_commit (int argc, char **argv, const char *prefix, GError **err if (!hacktree_repo_check (repo, error)) goto out; - if (!(removals || additions)) + using_filename_cmdline = (removals || additions); + using_filedescriptors = (from_file || from_fd >= 0 || from_stdin); + + if (!(using_filename_cmdline || using_filedescriptors)) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, "No additions or removals specified"); goto out; } + if (using_filename_cmdline && using_filedescriptors) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "File descriptors may not be combined with --add or --remove"); + goto out; + } if (!subject) { @@ -81,23 +100,54 @@ hacktree_builtin_commit (int argc, char **argv, const char *prefix, GError **err goto out; } - additions_array = g_ptr_array_new (); - removals_array = g_ptr_array_new (); + if (using_filename_cmdline) + { + g_assert (removals || additions); + additions_array = g_ptr_array_new (); + removals_array = g_ptr_array_new (); - if (additions) - for (iter = additions; *iter; iter++) - g_ptr_array_add (additions_array, *iter); - if (removals) - for (iter = removals; *iter; iter++) - g_ptr_array_add (removals_array, *iter); + if (additions) + for (iter = additions; *iter; iter++) + g_ptr_array_add (additions_array, *iter); + if (removals) + for (iter = removals; *iter; iter++) + g_ptr_array_add (removals_array, *iter); + + if (!hacktree_repo_commit (repo, subject, body, NULL, + prefix, additions_array, + removals_array, + &commit_checksum, + error)) + goto out; + } + else if (using_filedescriptors) + { + char separator = separator_null ? '\0' : '\n'; + gboolean temp_fd = -1; - if (!hacktree_repo_commit (repo, subject, body, NULL, - prefix, additions_array, - removals_array, - &commit_checksum, - error)) - goto out; - + if (from_stdin) + from_fd = 0; + else if (from_file) + { + temp_fd = ht_util_open_file_read (from_file, error); + if (temp_fd < 0) + { + g_prefix_error (error, "Failed to open '%s': ", from_file); + goto out; + } + from_fd = temp_fd; + } + if (!hacktree_repo_commit_from_filelist_fd (repo, subject, body, NULL, + prefix, from_fd, separator, + &commit_checksum, error)) + { + if (temp_fd >= 0) + close (temp_fd); + goto out; + } + if (temp_fd >= 0) + close (temp_fd); + } ret = TRUE; g_print ("%s\n", g_checksum_get_string (commit_checksum)); diff --git a/src/libhacktree/hacktree-repo.h b/src/libhacktree/hacktree-repo.h index d9d0eeeb..2f6d7035 100644 --- a/src/libhacktree/hacktree-repo.h +++ b/src/libhacktree/hacktree-repo.h @@ -77,6 +77,16 @@ gboolean hacktree_repo_commit (HacktreeRepo *self, GChecksum **out_commit, GError **error); +gboolean hacktree_repo_commit_from_filelist_fd (HacktreeRepo *self, + const char *subject, + const char *body, + GVariant *metadata, + const char *base, + int fd, + char separator, + GChecksum **out_commit, + GError **error); + gboolean hacktree_repo_checkout (HacktreeRepo *self, const char *ref, const char *destination, diff --git a/tests/libtest.sh b/tests/libtest.sh index e88ac10c..41c7ffbe 100644 --- a/tests/libtest.sh +++ b/tests/libtest.sh @@ -42,6 +42,12 @@ assert_not_has_file () { fi } +assert_file_has_content () { + if ! grep -q "$2" "$1"; then + echo "File '$1' doesn't match regexp '$2'"; exit 1 + fi +} + setup_test_repository1 () { mkdir files cd files diff --git a/tests/t0007-commit-stdin.sh b/tests/t0007-commit-stdin.sh new file mode 100755 index 00000000..b2cb9351 --- /dev/null +++ b/tests/t0007-commit-stdin.sh @@ -0,0 +1,48 @@ +#!/bin/bash +# +# Copyright (C) 2011 Colin Walters +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# Author: Colin Walters + +set -e + +. libtest.sh + +echo "1..2" + +setup_test_repository2 +hacktree checkout $ht_repo HEAD $test_tmpdir/checkout2-head +cd $test_tmpdir/checkout2-head +mkdir -p a/nested/tree +echo one > a/nested/tree/1 +echo two2 > a/nested/2 +echo 3 > a/nested/3 +touch a/4 +echo fivebaby > a/5 +touch a/6 +echo whee > 7 +mkdir -p another/nested/tree +echo anotherone > another/nested/tree/1 +echo whee2 > another/whee +# FIXME - remove grep for . +find | grep -v '^\.$' | hacktree commit $ht_repo --from-stdin -s "From find" +echo "ok commit stdin" +hacktree checkout $ht_repo HEAD $test_tmpdir/checkout3-head +cd $test_tmpdir/checkout3-head +assert_has_file a/nested/2 +assert_file_has_content a/nested/2 'two2' +echo "ok stdin contents"