/* conflict-handling.c * * vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2 **************************************************************** * Copyright (C) 2005 Canonical Ltd. * Original Author: James Blackwell * See the file "COPYING" for further information about * the copyright and warranty status of this work. */ #include "hackerlab/bugs/panic.h" #include "hackerlab/char/pika-escaping-utils.h" #include "hackerlab/char/str.h" #include "hackerlab/fs/file-names.h" #include "hackerlab/os/errno.h" #include "hackerlab/os/errno-to-string.h" #include "hackerlab/vu/safe.h" #include "libarch/arch.h" #include "libarch/conflict-handling.h" #include "libarch/pfs.h" #include "libarch/project-tree.h" #include "libarch/proj-tree-lint.h" #include "libawk/relational.h" #include "libfsutils/rmrf.h" #include "po/gettext.h" #define conflicts_exist_string "+rejects-list" #define old_conflicts_exist_string "=rejects-exist" static int arch_tree_save_conflicts (arch_project_tree_t * tree, rel_table file_list); static int load_conflict_file (t_uchar * program_name, arch_project_tree_t * tree, rel_table * conflicts); static int arch_tree_add_conflicts (arch_project_tree_t * tree, rel_table new_files); static int load_conflict_file (t_uchar * program_name, arch_project_tree_t * tree, rel_table * return_conflicts) { int in_fd; int errn; t_uchar * conflict_file; t_uchar * arch_tree; rel_table conflicts; arch_tree = arch_tree_ctl_dir(tree->root); /* We better have an empty tree */ if (! arch_tree) return 1; conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); in_fd = vu_open (&errn, conflict_file, O_RDONLY , 0); if (in_fd == -1) { return errn; } conflicts = rel_read_pika_unescape_iso8859_1_table (in_fd, 2, program_name, conflicts_exist_string); safe_close (in_fd); rel_append_x(return_conflicts, conflicts); rel_free_table(conflicts); return 0; } enum arch_conflict_problems arch_tree_unconflict_files (t_uchar * program_name, arch_project_tree_t * tree, rel_table files) { int errn; enum arch_conflict_problems retval; t_uchar * conflict_file; t_uchar * arch_tree; rel_table new_conflicts = NULL; rel_table conflicts = NULL; invariant (tree->root != NULL); invariant (rel_n_records (files)); /* We need to gather some information. Where the arch tree is, * the name of the conflict file. We also need to load the conflict file */ arch_tree = arch_tree_ctl_dir(tree->root); if (! arch_tree) return CONFLICTS_TREE_PROBLEM; conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); errn = load_conflict_file (program_name, tree, & conflicts); if (errn) /* FIXME LEAKS */ return CONFLICTS_FS_PROBLEM; rel_sort_table_by_field (0, conflicts, 0); rel_sort_table_by_field (0, files,0); new_conflicts = rel_join (1, rel_join_output (1,0, 1,1, -1), 0, 0, conflicts, files); /* One possibility: The user fixed everything */ if ( rel_n_records(new_conflicts) == 0) { retval = CONFLICTS_NO_LONGER_CONFLICTED; rmrf_file(conflict_file); } /* Another possibility: They fixed NOTHING */ else if (rel_n_records(new_conflicts) == rel_n_records(conflicts)) { retval = CONFLICTS_NOTHING_CHANGED; } /* Most likely, they fixed something */ else { int num_conflicts; retval = CONFLICTS_REMOVED; num_conflicts = arch_tree_save_conflicts (tree, new_conflicts); if (num_conflicts < 0) safe_printfmt(2, _("Unable to save new conflicts file")); safe_printfmt(2, _("%d conflicts remain in this tree\n"), num_conflicts); } lim_free(0, conflict_file); lim_free(0, arch_tree); rel_free_table(conflicts); rel_free_table(new_conflicts); return retval; } int arch_tree_show_conflicts (t_uchar * program_name, arch_project_tree_t * tree, rel_table * output) { rel_table conflicts = 0; int errn; int loop; errn = load_conflict_file (program_name, tree, &conflicts); if (errn) return errn; for ( loop = 0; loop < rel_n_records(conflicts); loop++) { t_uchar * after_dotslash; after_dotslash = conflicts[loop][0]+2; rel_add_records(output, rel_make_record(after_dotslash, 0), 0); } return 0; } int arch_tree_add_conflicts (arch_project_tree_t * tree, rel_table new_conflicts) { int result; t_uchar * arch_tree; t_uchar * conflict_file; rel_table old_conflicts = 0; rel_table final_conflicts = 0; rel_table merge_conflicts = 0; arch_tree = arch_tree_ctl_dir (tree->root); if (! arch_tree) { return -1; } conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); result = load_conflict_file ("arch_tree_add_conflicts", tree, &old_conflicts); if ( rel_n_records (old_conflicts) == 0) { /* We only have new conflict files */ final_conflicts = new_conflicts; } else { /* we have existing conflicts. Now we have to merge two tables into one, * avoiding duplicates */ int x; int y; /* First, lets hit the existing ones. Though duplicates shouldn't * exist, it doesn't hurt to be extra careful making sure */ for (x = 0; x < rel_n_records(old_conflicts); x++) { int found = 0; for (y = 0; y < rel_n_records(merge_conflicts); y++) /*Compare against merge confclits to see if its there yet */ { if (0 == str_cmp(old_conflicts[x][0], merge_conflicts[y][0])) found = 1; } if (! found) rel_add_records (&merge_conflicts, rel_copy_record (old_conflicts[y]) ,0 ); } /* Now, we'll compare the new conflicts against the merge conflicts. * If we don't have it in there, then add it */ for (x = 0; x < rel_n_records(new_conflicts); x++) { int found = 0; for (y = 0; y < rel_n_records(merge_conflicts); y++) { /*Compare against merge confclits to see if its there yet */ if (0 == str_cmp (new_conflicts[x][0], merge_conflicts[y][0])) found = 1; } if ( ! found) rel_add_records (&merge_conflicts, rel_copy_record (new_conflicts[y]),0); } final_conflicts = merge_conflicts; } if (rel_n_records (final_conflicts)) result = arch_tree_save_conflicts (tree, final_conflicts); else result = 0; lim_free (0, conflict_file); lim_free (0, arch_tree); rel_free_table (old_conflicts); rel_free_table (merge_conflicts); return result; } int arch_tree_save_conflicts (arch_project_tree_t * tree, rel_table file_list) { t_uchar * arch_tree = 0; arch_tree = arch_tree_ctl_dir(tree->root); if (! arch_tree) return -1; else { int out_fd; int errn; t_uchar * conflict_file = 0; conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); out_fd = vu_open (&errn, conflict_file, O_WRONLY|O_TRUNC|O_CREAT , 0666); rel_print_pika_escape_iso8859_1_table (out_fd, arch_escape_classes, file_list); safe_close (out_fd); lim_free (0, conflict_file); } lim_free (0, arch_tree); return rel_n_records (file_list); } void arch_tree_note_conflicts (arch_project_tree_t * tree, struct arch_apply_changeset_report * r) { int num_conflicts; rel_table all_conflicts = 0; rel_append_x ( &all_conflicts, r->conflict_files); rel_append_x ( &all_conflicts, r->conflict_dirs); rel_append_x ( &all_conflicts, r->metadata_conflict_files); rel_append_x ( &all_conflicts, r->metadata_conflict_dirs); num_conflicts = arch_tree_add_conflicts (tree, all_conflicts); if (num_conflicts) { safe_printfmt(2, "****************************************************\n"); safe_printfmt(2, "%d conflicted items in this tree. Please\n", num_conflicts); safe_printfmt(2, "resolve each conflict with baz \"resolved 'filename'\"\n"); safe_printfmt(2, "****************************************************\n"); } } void arch_tree_ensure_no_conflicts (arch_project_tree_t * tree) { if ( arch_tree_conflicts_exist(tree)) { safe_printfmt(2, "Sorry. This command may not be used when the tree is in a \n" " conflicted state. Please resolve conflicts first, and then \n" " run baz resolved\n"); exit(2); } } int arch_tree_conflicts_exist (arch_project_tree_t * tree) { t_uchar * arch_tree = 0; int answer = 0; arch_tree = arch_tree_ctl_dir(tree->root); if (! arch_tree) /* Whoah! No arch tree?!?! */ answer= -1; else { t_uchar * conflict_file = 0; conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); answer = safe_access (conflict_file, F_OK) ? 0 : 1; lim_free (0, conflict_file); } lim_free (0, arch_tree); return answer; } int arch_tree_clear_conflicts (arch_project_tree_t * tree) { t_uchar * arch_tree = 0; int answer = 0; arch_tree = arch_tree_ctl_dir(tree->root); if (! arch_tree) /* Whoah! No arch tree?!?! */ answer= -1; else { t_uchar * conflict_file = 0; conflict_file = file_name_in_vicinity (0, arch_tree, conflicts_exist_string); rmrf_file (conflict_file); lim_free (0, conflict_file); conflict_file = file_name_in_vicinity (0, arch_tree, old_conflicts_exist_string); rmrf_file (conflict_file); lim_free (0, conflict_file); } lim_free (0, arch_tree); return answer; } /* tag: James Blackwell Mon Jan 31 00:22:09 EST 2005 (conflict-handling.c) */