/* make-changeset-files.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/mem/mem.h"
#include "hackerlab/char/str.h"
#include "hackerlab/char/pika-escaping-utils.h"
#include "hackerlab/fs/file-names.h"
#include "hackerlab/vu/safe.h"
#include "libarch/diffs.h"
#include "libawk/relassoc.h"
#include "libarch/invent.h"
#include "libarch/make-changeset-files.h"
/* __STDC__ prototypes for static functions */
static int find_id_in_inventory (rel_table invent, t_uchar * id);
static void double_check_file_identity (t_uchar * from_here_path, t_uchar * tree_root, t_uchar * loc);
#if !defined(__GNUC__)
# undef __attribute__
# define __attribute__(X)
#endif
static void __attribute__((format (printf, 2, 3)))
invoke_report_callback (struct arch_make_changeset_report * report, char * fmt, ...)
{
va_list ap;
if (report->callback)
{
va_start (ap, fmt);
report->callback (report->thunk, fmt, ap);
va_end (ap);
}
}
/**
* \brief make a changeset with limits
*
* fixing up the method and unttaged source here
* requires fixing up inventory.
* \param file_list a list of paths in the orig tree
*/
void
arch_make_files_changeset (struct arch_make_changeset_report * report,
t_uchar * dest,
rel_table file_list,
arch_project_tree_t * orig, arch_project_tree_t * mod,
enum arch_id_tagging_method method,
enum arch_inventory_category untagged_source_category,
int escape_classes)
{
int x;
struct arch_changeset_report csr = {0,};
int overide_untagged_source = 0;
int overide_method = 0;
int prior_untagged_source = 0;
enum arch_id_tagging_method prior_method = arch_unspecified_id_tagging;
if (method == arch_unspecified_id_tagging)
{
/* sets untagged source in mod */
method = arch_tree_id_tagging_method (mod, &untagged_source_category, 0);
}
else
{
overide_untagged_source = 1;
overide_method = 1;
}
/* sets untagged source in orig */
arch_tree_id_tagging_method (orig, &untagged_source_category, 0);
mem_set0 ((t_uchar *)&report->orig_index, sizeof (report->orig_index));
mem_set0 ((t_uchar *)&report->mod_index, sizeof (report->mod_index));
arch_changeset_inventory (&report->orig_index, orig, method,
untagged_source_category, escape_classes);
report->mod_index.dirs = rel_copy_table (report->orig_index.dirs);
report->mod_index.files = rel_copy_table (report->orig_index.files);
/****************************************************************
* build associative tables too and from ids and locs
*/
report->orig_dir_id_of = rel_to_assoc (report->orig_index.dirs, 0, 1);
report->orig_dir_loc_of = rel_to_assoc (report->orig_index.dirs, 1, 0);
report->orig_file_id_of = rel_to_assoc (report->orig_index.files, 0, 1);
report->orig_file_loc_of = rel_to_assoc (report->orig_index.files, 1, 0);
report->mod_dir_id_of = rel_to_assoc (report->mod_index.dirs, 0, 1);
report->mod_dir_loc_of = rel_to_assoc (report->mod_index.dirs, 1, 0);
report->mod_file_id_of = rel_to_assoc (report->mod_index.files, 0, 1);
report->mod_file_loc_of = rel_to_assoc (report->mod_index.files, 1, 0);
assoc_set (&report->orig_dir_id_of, ".", "?_.");
assoc_set (&report->mod_dir_id_of, ".", "?_.");
assoc_set (&report->orig_dir_loc_of, "?_.", ".");
assoc_set (&report->mod_dir_loc_of, "?_.", ".");
arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_dir_id, report->orig_dir_id_of, report->orig_index.dirs);
arch_make_changeset_compute_container_map (&report->orig_container_dir_id_of_file_id, report->orig_dir_id_of, report->orig_index.files);
arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_dir_id, report->mod_dir_id_of, report->mod_index.dirs);
arch_make_changeset_compute_container_map (&report->mod_container_dir_id_of_file_id, report->mod_dir_id_of, report->mod_index.files);
arch_make_empty_changeset (report, &csr, dest);
for (x = 0; x < rel_n_records (file_list); ++x)
{
t_uchar * id = 0;
int orig_index;
int mod_index;
t_uchar * orig_path = 0;
t_uchar * mod_path = 0;
int diff_fd;
if (overide_untagged_source)
{
prior_untagged_source = orig->untagged_is_source;
orig->untagged_is_source = untagged_source_category == arch_inventory_source;
}
if (overide_method)
{
prior_method = orig->tag_method;
orig->tag_method = method;
}
id = arch_inventory_id (orig, file_list[x][0], 0);
if (overide_untagged_source)
orig->untagged_is_source = prior_untagged_source;
if (overide_method)
orig->tag_method = prior_method;
orig_index = find_id_in_inventory (report->orig_index.files, id);
mod_index = find_id_in_inventory (report->mod_index.files, id);
if (orig_index < 0)
{
safe_printfmt (2, "make-changeset-files: file missing from ORIG tree (%s)\n", file_list[x][0]);
exit (1);
}
if (mod_index < 0)
{
safe_printfmt (2, "make-changeset-files: file missing from MOD tree (%s)\n", file_list[x][0]);
exit (1);
}
double_check_file_identity (file_list[x][0], mod->root, report->mod_index.files[mod_index][0]);
orig_path = file_name_in_vicinity (0, orig->root, report->orig_index.files[orig_index][0]);
mod_path = file_name_in_vicinity (0, mod->root, report->mod_index.files[mod_index][0]);
if (arch_binary_files_differ (orig_path, mod_path, 0, 0))
{
int diff_stat;
t_uchar * escaped_tmp;
escaped_tmp = pika_save_escape_iso8859_1 (0, 0, escape_classes, file_list[x][0]);
invoke_report_callback (report, "M %s\n", escaped_tmp);
diff_fd = arch_changeset_add_diffs (&csr, report, dest, report->orig_index.files[orig_index][0], report->mod_index.files[mod_index][0], id);
diff_stat = arch_invoke_diff (diff_fd, orig_path, report->orig_index.files[orig_index][0], mod_path, report->orig_index.files[orig_index][0], 0, 0);
safe_close (diff_fd);
lim_free (0, escaped_tmp);
if (diff_stat == 1)
{
t_uchar diff_pseudo_magic[sizeof ("binary files ")];
t_uchar * patches_path = 0;
t_uchar * patch_path = 0;
int diff_in_fd;
long amt;
patches_path = file_name_in_vicinity (0, dest, "patches");
patch_path = file_name_in_vicinity (0, patches_path, report->mod_index.files[mod_index][0]);
patch_path = str_realloc_cat (0, patch_path, ".patch");
diff_in_fd = safe_open (patch_path, O_RDONLY, 0);
/* diff might have just said "binary files differ" or something
* similar.
*/
amt = safe_read (diff_in_fd, diff_pseudo_magic, sizeof (diff_pseudo_magic) - 1);
if (amt > 0)
{
diff_pseudo_magic[amt] = 0;
if (!str_casecmp (diff_pseudo_magic, "binary files "))
diff_stat = 2;
}
safe_close (diff_in_fd);
lim_free (0, patch_path);
lim_free (0, patches_path);
}
if (diff_stat == 2)
{
safe_printfmt (2, "binary files not yet supported with --files or --file-list\n");
exit (2);
}
}
lim_free (0, id);
lim_free (0, orig_path);
lim_free (0, mod_path);
}
arch_changeset_rewrite_indexes (dest, &csr);
arch_free_changeset_report_data (&csr);
}
static int
find_id_in_inventory (rel_table invent, t_uchar * id)
{
int x;
for (x = 0; x < rel_n_records (invent); ++x)
{
if (!str_cmp (id, invent[x][1]))
return x;
}
return -1;
}
static void
double_check_file_identity (t_uchar * from_here_path, t_uchar * tree_root, t_uchar * loc)
{
struct stat users_stat;
t_uchar * computed_path = 0;
struct stat computed_stat;
safe_stat (from_here_path, &users_stat);
computed_path = file_name_in_vicinity (0, tree_root, loc);
safe_stat (computed_path, &computed_stat);
lim_free (0, computed_path);
if ((users_stat.st_dev != computed_stat.st_dev) || (users_stat.st_ino != computed_stat.st_ino))
{
safe_printfmt (2, "make-changeset --files: the file specified as %s\n is not the same as the one in the project tree (%s)\n", from_here_path, computed_path);
exit (1);
}
}
/* tag: Tom Lord Tue Jun 17 21:39:34 2003 (make-changeset-files.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1