/* commit.c:
*
* vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
****************************************************************
* Copyright (C) 2003 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/bugs/exception.h"
#include "hackerlab/bugs/panic.h"
#include "hackerlab/os/time.h"
#include "hackerlab/char/str.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "libdate/date-string.h"
#include "libfsutils/string-files.h"
#include "libfsutils/copy-file.h"
#include "libfsutils/tmp-files.h"
#include "libfsutils/rmrf.h"
#include "libarch/ancestry.h"
#include "libarch/archive-cache.h"
#include "libarch/diffs.h"
#include "libarch/patch-logs.h"
#include "libarch/invent.h"
#include "libarch/my.h"
#include "libarch/hooks.h"
#include "libarch/namespace.h"
#include "libarch/pristines.h"
#include "libarch/project-tree.h"
#include "libarch/make-changeset-files.h"
#include "libarch/make-changeset.h"
#include "libarch/changeset-report.h"
#include "libarch/local-cache.h"
#include "libarch/project-tree.h"
#include "libarch/inv-ids.h"
#include "libarch/changelogs.h"
#include "libarch/apply-changeset.h"
#include "libarch/inode-sig.h"
#include "libarch/chatter.h"
#include "libarch/arch-cache.h"
#include "libarch/commit.h"
/* __STDC__ prototypes for static functions */
static t_uchar * arch_prepare_commit_changeset (t_uchar ** changelog_loc_ret,
int chatter_fd,
t_uchar ** cooked_log_ret,
arch_project_tree_t * tree,
t_uchar * raw_log,
struct arch_archive * arch,
t_uchar * revision,
t_uchar * prev_level,
rel_table file_list,
int escape_classes);
static rel_table pick_patch_logs (rel_table table);
static void arch_recycle_pristine (int chatter_fd, arch_project_tree_t * tree, t_uchar * archive, t_uchar * prev_revision, t_uchar * revision, t_uchar * changeset, t_uchar * changelog_loc, int escape_classes);
static void arch_commit_failed (arch_project_tree_t * tree, t_uchar * archive, t_uchar * revision, t_uchar * changeset);
static void commit_make_changeset_callback (void * vfd, char * fmt, va_list ap);
int
arch_commit (int chatter_fd,
struct arch_archive * arch,
t_uchar * revision,
arch_project_tree_t * tree,
t_uchar * raw_log,
rel_table file_list,
int just_commit,
int escape_classes)
{
t_uchar * errstr;
t_uchar * version = 0;
t_uchar * this_level = 0;
arch_patch_id * prev_revision;
t_uchar * changelog_loc = 0;
t_uchar * changeset_path = 0;
t_uchar * cooked_log = 0;
t_uchar * my_uid = 0;
t_uchar * txn_id = 0;
int error;
int result = 0;
int do_cacherev = 0;
arch_patch_id * patch_id = arch_patch_id_new_archive (arch->official_name, revision);
invariant (!!raw_log);
version = arch_parse_package_name (arch_ret_package_version, 0, revision);
this_level = arch_parse_package_name (arch_ret_patch_level, 0, revision);
prev_revision = arch_previous_revision (arch, patch_id);
changeset_path = arch_prepare_commit_changeset (&changelog_loc, chatter_fd, &cooked_log, tree, raw_log, arch, revision, arch_patch_id_patchlevel (prev_revision), file_list, escape_classes);
invariant (!!arch_patch_id_patchlevel (prev_revision));
/* Check the error return code for the "precommit" hook and exit if non-zero.
*/
error = arch_run_hook ("precommit", "ARCH_ARCHIVE", arch->official_name, "ARCH_REVISION", revision, "ARCH_TREE_ROOT", tree->root, 0) ;
if (error)
{
safe_printfmt (2, "arch_commit: precommit hook function failed with error (%d)\n commit cancelled.\n", error);
exit (2);
}
my_uid = arch_my_id_uid ();
txn_id = arch_generate_txn_id ();
if (arch_archive_lock_revision (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id, this_level))
{
safe_printfmt (2, "arch_commit: unable to acquire revision lock (%s)\n tree: %s\n revision: %s/%s\n url: %s\n",
errstr, tree->root, arch->official_name, revision, arch->location);
exit (2);
}
if (arch_archive_put_log (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id, cooked_log))
{
safe_printfmt (2, "arch_commit: unable to send log message to archive (%s)\n tree: %s\n revision: %s/%s\n url: %s\n",
errstr, tree->root, arch->official_name, version, arch->location);
exit (2);
}
if (arch_archive_put_changeset (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id, this_level, changeset_path))
{
safe_printfmt (2, "arch_commit: unable to send changeset to archive (%s)\n tree: %s\n revision: %s/%s\n url: %s\n",
errstr, tree->root, arch->official_name, revision, arch->location);
exit (2);
}
if (arch_revision_ready (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id, this_level))
{
safe_printfmt (2, "arch_commit: error sending revision to archive (%s)\n tree: %s\n revision: %s/%s\n url: %s\n",
errstr, tree->root, arch->official_name, revision, arch->location);
/* FIXME: detail unlock failures to the user gracefully */
invariant (!arch_archive_break_revision_lock (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id));
result = -1;
goto error_exit;
}
arch_start_tree_commit (tree, cooked_log);
if (arch_archive_finish_revision (&errstr, arch, version, arch_patch_id_patchlevel (prev_revision), my_uid, txn_id, this_level))
{
arch_commit_failed (tree, arch->official_name, version, changeset_path);
safe_printfmt (2, "arch_commit: unable to complete commit transaction (%s)\n tree: %s\n revision: %s/%s\n url: %s\n",
errstr, tree->root, arch->official_name, version, arch->location);
exit (2);
}
if (!just_commit)
{
struct exception * e;
/* FIXME upload limited history and update a current dir in the archive */
ancestry_upload_patch (arch, patch_id, -1);
Try
{
/* pull in the tree ancestry */
/* bah again with the needing policy stuff */
rel_table ancestry = patch_ancestry (talloc_context, tree, patch_id, -1);
do_cacherev = rel_n_records (ancestry) % MAGIC_CACHEREV_INTERVAL == 2;
rel_free_table (ancestry);
}
Catch (e)
{
/* invariants */
if (e->code < 0)
Throw (e);
talloc_free (e);
}
}
arch_maybe_cache_commit (arch, revision, arch->official_name, arch_patch_id_revision (prev_revision), changeset_path);
arch_finish_tree_commit (tree, arch->official_name, revision, changelog_loc);
arch_recycle_pristine (chatter_fd, tree, arch->official_name, arch_patch_id_revision (prev_revision), revision, changeset_path, changelog_loc, escape_classes);
arch_run_hook ("commit", "ARCH_ARCHIVE", arch->official_name, "ARCH_REVISION", revision, "ARCH_TREE_ROOT", tree->root, 0);
if (rel_n_records (file_list) == 0)
arch_snap_inode_sig_not_reference (tree, arch->official_name, revision);
else
{
arch_snap_inode_sig_not_reference_files(tree, arch->official_name, arch_patch_id_revision (prev_revision), revision, file_list);
}
if (do_cacherev)
arch_archive_cache (2, arch, arch->official_name, revision, tree);
error_exit:
lim_free (0, version);
lim_free (0, this_level);
talloc_free (prev_revision);
lim_free (0, changeset_path);
lim_free (0, cooked_log);
lim_free (0, changelog_loc);
lim_free (0, my_uid);
lim_free (0, txn_id);
talloc_free (patch_id);
return result;
}
static t_uchar *
arch_prepare_commit_changeset (t_uchar ** changelog_loc_ret,
int chatter_fd,
t_uchar ** cooked_log_ret,
arch_project_tree_t * tree,
t_uchar * raw_log,
struct arch_archive * arch,
t_uchar * revision,
t_uchar * prev_level,
rel_table file_list,
int escape_classes)
{
t_uchar * archive = arch->official_name;
t_uchar * tmp_stem = 0;
t_uchar * tmp_path = 0;
t_uchar * changeset_basename = 0;
t_uchar * changeset_path = 0; /* return value */
t_uchar * version = 0;
t_uchar * level = 0;
t_uchar * prev_revision = 0;
t_uchar * prev_rev_path = 0;
arch_project_tree_t * prev_rev_tree;
struct arch_make_changeset_report make_report = {0, }; /* should have a chatter callback here */
t_uchar * changelog_id_suffix = 0;
t_uchar * changelog_x_id = 0;
t_uchar * changelog_i_id = 0;
t_uchar * changelog_id = 0;
t_uchar * changelog_orig_loc = 0;
t_uchar * changelog_mod_loc = 0;
struct arch_changeset_report csr = {0, };
int changelog_diffs_fd = -1;
int changelog_add_fd = -1;
t_uchar * new_log_id = 0;
t_uchar * new_log_loc = 0;
int new_log_fd = -1;
t_uchar * new_log_path = 0;
t_uchar * cooked_log = 0;
t_uchar * new_changelog_path = 0;
/****************************************************************
* double check that we were handed a valid log message, if any
*/
invariant (arch_valid_log_file (raw_log));
/****************************************************************
* make a temp dir for the changeset
*/
tmp_stem = str_alloc_cat_many (0, ",,commit.", revision, "--", archive, str_end);
tmp_path = talloc_tmp_file_name (talloc_context, tree->root, tmp_stem);
rmrf_file (tmp_path);
safe_mkdir (tmp_path, 0777);
changeset_basename = str_alloc_cat (0, revision, ".patches");
changeset_path = file_name_in_vicinity (0, tmp_path, changeset_basename);
/****************************************************************
* Compute the raw changeset
*
* The changeset computed here does _not_ include an add of the new log
* message and does _not_ include updates to automatic changelogs.
*/
version = arch_parse_package_name (arch_ret_package_version, 0, revision);
level = arch_parse_package_name (arch_ret_patch_level, 0, revision);
prev_revision = str_alloc_cat_many (0, version, "--", prev_level, str_end);
prev_rev_path = arch_find_or_make_local_copy (chatter_fd, tree, 0, arch, archive, prev_revision);
prev_rev_tree = arch_project_tree_new (talloc_context, prev_rev_path);
if (chatter_fd >= 0)
{
make_report.callback = commit_make_changeset_callback;
make_report.thunk = (void *)(long)chatter_fd;
}
if (!file_list)
{
assoc_table inode_shortcut = 0;
arch_read_inode_sig_ids (0, &inode_shortcut, tree->root, archive, prev_revision);
arch_make_changeset (&make_report, prev_rev_tree, tree, changeset_path, arch_unspecified_id_tagging, arch_inventory_unrecognized, 0, inode_shortcut, 0, escape_classes);
free_assoc_table (inode_shortcut);
}
else
arch_make_files_changeset (&make_report, changeset_path, file_list, prev_rev_tree, tree, arch_unspecified_id_tagging, arch_inventory_unrecognized, escape_classes);
/****************************************************************
* Look for a Changelog for the version we're committing to.
*/
changelog_id_suffix = str_alloc_cat_many (0, "_automatic-ChangeLog--", archive, "/", version, str_end);
changelog_x_id = str_alloc_cat (0, "x", changelog_id_suffix);
changelog_i_id = str_alloc_cat (0, "i", changelog_id_suffix);
changelog_mod_loc = assoc_ref (make_report.mod_file_loc_of, changelog_x_id);
if (changelog_mod_loc)
{
changelog_mod_loc = str_save (0, changelog_mod_loc);
changelog_id = str_save (0, changelog_x_id);
}
else
{
changelog_mod_loc = assoc_ref (make_report.mod_file_loc_of, changelog_i_id);
if (changelog_mod_loc)
{
changelog_mod_loc = str_save (0, changelog_mod_loc);
changelog_id = str_save (0, changelog_i_id);
}
}
if (changelog_mod_loc)
{
if (changelog_loc_ret)
{
*changelog_loc_ret = str_save (0, changelog_mod_loc);
}
changelog_orig_loc = assoc_ref (make_report.orig_file_loc_of, changelog_id);
if (changelog_orig_loc)
changelog_orig_loc = str_save (0, changelog_orig_loc);
}
/* post-condition:
*
* changelog_id, changelog_mod_loc: 0 if no MOD tree changelog
* set if there is a changelog
*
* changelog_orig_loc: 0 if no MOD or no ORIG changelog, set if both
*/
/****************************************************************
* Get a report about this changeset
*/
arch_evaluate_changeset (&csr, changeset_path);
/****************************************************************
* Update the changeset indexes to reflect the patch log and changelog
*
* The changelog for this version, if any, is going to change
* as a result of the new patch log for this commit.
* Usually (though we don't count on it) it didn't change between
* pristine and project tree.
*
* So, we have to touch up the changeset to reflect a diff to that
* changelog. At this stage, only the file and dir indexes are
* modified to reflect that (we haven't generated the new log entry
* yet, so we can't produce the actual changelog diffs).
*
* Also, we know we're adding a new patch log, so the indexes should
* reflect that, too.
*
* The reason to touch up the indexes early is that the patch log
* is derived, in part, from those indexes.
*/
if (changelog_mod_loc && changelog_orig_loc)
{
changelog_diffs_fd = arch_changeset_add_diffs (&csr, &make_report, changeset_path, changelog_orig_loc, changelog_mod_loc, changelog_id);
}
else if (changelog_mod_loc)
{
changelog_add_fd = arch_changeset_add_file (&new_changelog_path, &csr, &make_report, changeset_path, changelog_mod_loc, changelog_id);
}
new_log_loc = arch_log_file (".", archive, revision);
new_log_id = arch_log_file_id (archive, revision);
new_log_fd = arch_changeset_add_file (&new_log_path, &csr, &make_report, changeset_path, new_log_loc, new_log_id);
arch_changeset_rewrite_indexes (changeset_path, &csr);
/****************************************************************
* Generate the Cooked Log Entry
*/
{
t_uchar * my_id = 0;
time_t now;
t_uchar * std_date = 0;
t_uchar * human_date = 0;
int log_fd;
my_id = arch_my_id ();
now = time (0);
std_date = standard_date (now);
human_date = pretty_date (now);
log_fd = make_output_to_string_fd ();
safe_printfmt (log_fd, "Revision: %s\n", revision);
safe_printfmt (log_fd, "Archive: %s\n", archive);
safe_printfmt (log_fd, "Creator: %s\n", my_id);
safe_printfmt (log_fd, "Date: %s\n", human_date);
safe_printfmt (log_fd, "Standard-date: %s\n", std_date);
/********************************
* automatic headers for various file and patch lists
*/
{
rel_table new_files = 0;
rel_table removed_files = 0;
rel_table new_directories = 0;
rel_table removed_directories = 0;
rel_table modified_files = 0;
rel_table new_patches = 0;
rel_table removed_patches = 0;
new_files = pick_non_control (csr.added_files);
rel_append_x (&new_files, csr.added_symlinks);
rel_sort_table_by_field (0, new_files, 0);
removed_files = pick_non_control (csr.removed_files);
rel_append_x (&removed_files, csr.removed_symlinks);
rel_sort_table_by_field (0, removed_files, 0);
new_directories = pick_non_control (csr.added_dirs);
removed_directories = pick_non_control (csr.removed_dirs);
modified_files = rel_copy_table (csr.patched_regular_files);
rel_append_x (&modified_files, csr.patched_symlinks);
rel_append_x (&modified_files, csr.patched_binaries);
rel_append_x (&modified_files, csr.file_metadata_changed);
rel_append_x (&modified_files, csr.symlink_to_file);
rel_append_x (&modified_files, csr.file_to_symlink);
rel_sort_table_by_field (0, modified_files, 0);
rel_uniq_by_field (&modified_files, 0);
new_patches = pick_patch_logs (csr.added_files);
removed_patches = pick_patch_logs (csr.removed_files);
arch_print_log_list_header (log_fd, "New-files", new_files, 0);
arch_print_log_list_header (log_fd, "New-directories", new_directories, 0);
arch_print_log_list_header (log_fd, "Removed-files", removed_files, 0);
arch_print_log_list_header (log_fd, "Removed-directories", removed_directories, 0);
arch_print_log_pairs_header (log_fd, "Renamed-files", csr.renamed_files, 0, 1);
arch_print_log_pairs_header (log_fd, "Renamed-directories", csr.renamed_dirs, 0, 1);
arch_print_log_list_header (log_fd, "Modified-files", modified_files, 0);
arch_print_log_list_header (log_fd, "Modified-directories", csr.dir_metadata_changed, 0);
arch_print_log_list_header (log_fd, "New-patches", new_patches, 0);
arch_print_log_list_header (log_fd, "Removed-patches", removed_patches, 0);
rel_free_table (new_files);
rel_free_table (removed_files);
rel_free_table (new_directories);
rel_free_table (removed_directories);
rel_free_table (modified_files);
rel_free_table (new_patches);
rel_free_table (removed_patches);
}
/********************************
* copy the user headers, and copy or generate the log body
*/
{
t_uchar * eoh = raw_log;
while (1)
{
eoh = str_chr_index (eoh, '\n');
if (!eoh || (eoh[1] == '\n') || (!eoh[1]))
break;
else
++eoh;
}
if (eoh)
{
eoh = eoh + 1;
safe_printfmt (log_fd, "%.*s", (int)(eoh - raw_log), raw_log);
}
if (eoh && *eoh)
{
safe_printfmt (log_fd, "%s", eoh);
}
else
{
safe_printfmt (log_fd, "\n\n");
}
}
/********************************
* oh... did i mention we were writing
* the log to a string?
*/
cooked_log = string_fd_close (log_fd);
lim_free (0, my_id);
lim_free (0, std_date);
lim_free (0, human_date);
}
/****************************************************************
* Write the log into the changeset
*/
safe_printfmt (new_log_fd, "%s", cooked_log);
safe_close (new_log_fd);
/****************************************************************
* Give a copy of the log to the caller.
*/
if (cooked_log_ret)
*cooked_log_ret = str_save (0, cooked_log);
/****************************************************************
* Generate the new changelog.
*/
if (changelog_add_fd > 0)
{
invariant (changelog_add_fd >= 0);
invariant (changelog_diffs_fd < 0);
arch_generate_changelog (changelog_add_fd, tree, 0, 0, level, new_log_path, archive, version);
/* new_changelog_path already set. */
safe_close (changelog_add_fd);
}
else if (changelog_diffs_fd > 0)
{
int fd = -1;
t_uchar * changelog_orig_path = 0;
new_changelog_path = file_name_in_vicinity (0, changeset_path, ",,changelog");
fd = safe_open (new_changelog_path, O_WRONLY | O_CREAT | O_EXCL, 0444);
arch_generate_changelog (fd, tree, 0, 0, level, new_log_path, archive, version);
safe_close (fd);
changelog_orig_path = file_name_in_vicinity (0, prev_rev_tree->root, changelog_orig_loc);
invariant (changelog_diffs_fd >= 0);
invariant (changelog_add_fd < 0);
arch_invoke_diff (changelog_diffs_fd, changelog_orig_path, changelog_orig_loc, new_changelog_path, changelog_mod_loc, 0, 0);
safe_close (changelog_diffs_fd);
rmrf_file (new_changelog_path);
lim_free (0, changelog_orig_path);
}
lim_free (0, tmp_stem);
talloc_free (tmp_path);
lim_free (0, changeset_basename);
lim_free (0, version);
lim_free (0, level);
lim_free (0, prev_revision);
lim_free (0, prev_rev_path);
arch_project_tree_delete (prev_rev_tree);
arch_free_make_changeset_report_data (&make_report);
lim_free (0, changelog_id_suffix);
lim_free (0, changelog_x_id);
lim_free (0, changelog_i_id);
lim_free (0, changelog_id);
lim_free (0, changelog_orig_loc);
lim_free (0, changelog_mod_loc);
arch_free_changeset_report_data (&csr);
lim_free (0, new_log_id);
lim_free (0, new_log_loc);
lim_free (0, new_log_path);
lim_free (0, cooked_log);
lim_free (0, new_changelog_path);
/****************************************************************
* Give the user the path to the pristine tree for base-0.
* It's up tot he caller to stash this in the archive.
*/
return changeset_path;
}
static rel_table
pick_patch_logs (rel_table table)
{
int x;
rel_table answer = 0;
for (x = 0; x < rel_n_records (table); ++x)
{
t_uchar * f = 0;
t_uchar * t = 0;
t_uchar * d = 0;
t_uchar * level = 0;
t_uchar * archive = 0;
t_uchar * version = 0;
t_uchar * revision = 0;
t_uchar * fqrev = 0;
f = str_save (0, table[x][0]);
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (arch_valid_patch_level_name (t))
{
level = str_save (0, t);
lim_free (0, f);
f = d;
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (!str_cmp ("patch-log", t))
{
lim_free (0, f);
f = d;
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (arch_valid_archive_name (t))
{
archive = str_save (0, t);
lim_free (0, f);
f = d;
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (arch_valid_package_name (t, arch_no_archive, arch_req_version, 0))
{
version = str_save (0, t);
lim_free (0, f);
f = d;
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (arch_valid_package_name (t, arch_no_archive, arch_req_package, 0))
{
lim_free (0, f);
f = d;
t = file_name_tail (0, f);
d = file_name_directory_file (0, f);
if (arch_valid_package_name (t, arch_no_archive, arch_req_category, 0))
{
if (!str_cmp ("./{arch}", d))
{
revision = str_alloc_cat_many (0, version, "--", level, str_end);
fqrev = arch_fully_qualify (archive, revision);
rel_add_records (&answer, rel_make_record (fqrev, table[x][1], table[x][2], 0), 0);
}
}
}
}
}
}
lim_free (0, f);
lim_free (0, t);
lim_free (0, d);
lim_free (0, level);
lim_free (0, archive);
lim_free (0, version);
lim_free (0, revision);
lim_free (0, fqrev);
}
}
arch_sort_table_by_name_field (0, answer, 0);
return answer;
}
static void
arch_recycle_pristine (int chatter_fd, arch_project_tree_t * tree, t_uchar * archive, t_uchar * prev_revision, t_uchar * revision, t_uchar * changeset, t_uchar * changelog_loc, int escape_classes)
{
t_uchar * dir = 0;
t_uchar * dir_tail = 0;
arch_project_tree_t * recycled_pristine_src = 0;
dir = file_name_directory_file (0, changeset);
dir_tail = file_name_tail (0, dir);
invariant (!str_cmp_prefix (",,", dir_tail));
{
arch_patch_id * prev = arch_patch_id_new_archive (archive, prev_revision);
recycled_pristine_src = arch_find_pristine (tree, prev, arch_tree_pristine_search);
talloc_free (prev);
}
if (recycled_pristine_src)
{
t_uchar * inventory_path = 0;
struct arch_apply_changeset_report * report;
arch_project_tree_t * recycled_tree;
t_uchar * recycled_pristine_tmp = 0;
arch_chatter (chatter_fd, "* update pristine tree (%s/%s => %s)\n", archive, prev_revision, revision);
recycled_pristine_tmp = talloc_tmp_file_name (talloc_context, dir, ",,pristine");
safe_rename (recycled_pristine_src->root, recycled_pristine_tmp);
inventory_path = file_name_in_vicinity (0, recycled_pristine_tmp, ",,index");
rmrf_file (inventory_path);
recycled_tree = arch_project_tree_new (talloc_context, recycled_pristine_tmp);
report = arch_apply_changeset (changeset, talloc_context, recycled_tree, arch_unspecified_id_tagging, arch_inventory_unrecognized, 0, 0, escape_classes, NULL, NULL);
invariant (!arch_conflicts_occurred (report));
talloc_free (report);
arch_install_pristine (tree, archive, revision, recycled_pristine_tmp);
arch_project_tree_delete (recycled_tree);
lim_free (0, inventory_path);
talloc_free (recycled_pristine_tmp);
}
rmrf_file (dir);
lim_free (0, dir);
lim_free (0, dir_tail);
arch_project_tree_delete (recycled_pristine_src);
}
static void
arch_commit_failed (arch_project_tree_t * tree, t_uchar * archive, t_uchar * revision, t_uchar * changeset)
{
t_uchar * dir = 0;
t_uchar * dir_tail = 0;
dir = file_name_directory_file (0, changeset);
dir_tail = file_name_tail (0, dir);
invariant (!str_cmp_prefix (",,", dir_tail));
arch_abort_tree_commit (tree, archive, revision);
rmrf_file (dir);
lim_free (0, dir);
lim_free (0, dir_tail);
}
static void
commit_make_changeset_callback (void * vfd, char * fmt, va_list ap)
{
int fd;
fd = (int)(t_ulong)vfd;
safe_printfmt_va_list (fd, fmt, ap);
safe_flush (1);
}
/* tag: Tom Lord Mon May 26 12:05:54 2003 (commit.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1