/* conflict-handling.c
*
* vim:smartindent ts=8:sts=2:sta:et:ai:shiftwidth=2
****************************************************************
* Copyright (C) 2005 Canonical Ltd.
* Original Author: James Blackwell <jblack@gnuarch.org>
* 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)
*/
syntax highlighted by Code2HTML, v. 0.9.1