/* changelogs.c:
*
****************************************************************
* Copyright (C) 2003 Tom Lord
*
* See the file "COPYING" for further information about
* the copyright and warranty status of this work.
*/
#include "hackerlab/bugs/panic.h"
#include "hackerlab/char/char-class.h"
#include "hackerlab/char/str.h"
#include "hackerlab/vu/safe.h"
#include "hackerlab/rx-posix/regex.h"
#include "libarch/patch-logs.h"
#include "libarch/inv-ids.h"
#include "libarch/namespace.h"
#include "libarch/changelogs.h"
/* __STDC__ prototypes for static functions */
static void generate_changelog_entry (int out_fd, t_uchar * archive, t_uchar * version, t_uchar * patch_lvl, t_uchar * file, int no_files);
static void changelog_file_list (int out_fd, assoc_table headers, t_uchar * header, t_uchar * exclude);
static void changelog_file_pair_list (int out_fd, assoc_table headers, t_uchar * header);
static t_uchar arch_changelog_id_prefix[] = "automatic-ChangeLog--";
#define arch_changelog_id_prefix_len \
((size_t)((sizeof(arch_changelog_id_prefix) - 1)/sizeof(t_uchar)))
/*
* Return 0, if the id doesn't match an automatic changelog tag
* or return the package name if it match
*/
static t_uchar *
arch_id_changelog_package_name (t_uchar * id)
{
t_uchar *package_name;
size_t len;
if (*id != 'i' && *id != 'x')
return 0;
id ++;
if (*id != '_')
return 0;
id ++;
len = str_length(id);
if (len < arch_changelog_id_prefix_len)
return 0;
if (str_cmp_n (arch_changelog_id_prefix, arch_changelog_id_prefix_len,
id, arch_changelog_id_prefix_len) != 0)
return 0;
id += arch_changelog_id_prefix_len;
package_name = str_save_n (0, id,
len - arch_changelog_id_prefix_len);
if (!arch_valid_package_name (package_name,
arch_req_archive, arch_req_version, 1))
{
lim_free(0, package_name);
return 0;
}
return package_name;
}
int
arch_id_indicates_changelog (t_uchar * id)
{
t_uchar *package_name;
package_name = arch_id_changelog_package_name(id);
if (!package_name)
return 0;
lim_free(0, package_name);
return 1;
}
void
arch_parse_changelog_id (t_uchar ** archive, t_uchar ** version, t_uchar * id)
{
t_uchar *package_name;
package_name = arch_id_changelog_package_name(id);
*archive = arch_parse_package_name (arch_ret_archive, 0, package_name);
*version = arch_parse_package_name (arch_ret_package_version, 0, package_name);
lim_free(0, package_name);
}
void
arch_generate_changelog (int out_fd,
arch_project_tree_t * tree,
int no_files,
int untagged,
t_uchar * new_entry_patch_lvl,
t_uchar * new_entry_file,
t_uchar * archive,
t_uchar * version)
{
rel_table log_ls;
int lim;
int x;
if (!arch_valid_package_name (version, arch_no_archive, arch_req_version, 0))
{
safe_printfmt (2, "changelog: invalid version name (%s)\n", version);
exit (1);
}
log_ls = arch_logs (tree->root, archive, version, 0);
arch_sort_table_by_patch_level_field (1, log_ls, 0);
{
t_uchar * tag_name;
if (untagged)
tag_name = "non-id";
else if (arch_implicit_id_tagging == arch_tree_id_tagging_method (tree, 0, 0))
tag_name = "tag";
else
tag_name = "arch-tag";
safe_printfmt (out_fd, "# do not edit -- automatically generated by arch changelog\n# %s: %s%s/%s\n#\n\n", tag_name, arch_changelog_id_prefix, archive, version);
}
if (new_entry_patch_lvl)
{
generate_changelog_entry (out_fd, archive, version, new_entry_patch_lvl, new_entry_file, no_files);
}
lim = rel_n_records (log_ls);
for (x = 0; x < lim; ++x)
{
generate_changelog_entry (out_fd, archive, version, log_ls[x][0], log_ls[x][1], no_files);
}
rel_free_table (log_ls);
}
static void
generate_changelog_entry (int out_fd, t_uchar * archive, t_uchar * version, t_uchar * patch_lvl, t_uchar * file, int no_files)
{
int in_fd;
t_uchar * log = 0;
size_t len;
assoc_table headers = 0;
t_uchar * body = 0;
in_fd = safe_open (file, O_RDONLY, 0);
safe_file_to_string (&log, &len, in_fd);
safe_close (in_fd);
log = lim_realloc (0, log, len + 1);
log[len] = 0;
headers = 0;
body = 0;
arch_parse_log (0, &headers, &body, log);
lim_free (0, log);
/* print the first line (date, creator, patch level)
*/
{
t_uchar * raw_date;
t_uchar * cooked_date;
t_uchar * creator;
raw_date = assoc_ref (headers, "standard-date");
if (raw_date)
{
t_uchar * from;
t_uchar * to;
from = raw_date;
while (*from && char_is_space (*from))
++from;
to = from;
while (*to && !char_is_space (*to))
++to;
while (*to && char_is_space (*to))
++to;
while (*to && !char_is_space (*to))
++to;
cooked_date = str_save_n (0, from, to - from);
cooked_date = str_realloc_cat (0, cooked_date, " GMT");
}
else
{
cooked_date = str_save (0, "\?\?\?\?-\?\?-\?\? GMT");
}
creator = assoc_ref (headers, "creator");
if (!creator)
creator = "????";
safe_printfmt (out_fd, "%s\t%s\t%s\n", cooked_date, creator, patch_lvl);
lim_free (0, cooked_date);
}
safe_printfmt (out_fd, "\n");
/* Print the summary: */
{
t_uchar * summary;
summary = assoc_ref (headers, "summary");
if (!summary)
summary = "";
safe_printfmt (out_fd, " Summary:\n %s\n", summary);
}
/* Print the revision name: */
{
t_uchar * revision;
revision = assoc_ref (headers, "revision");
if (!revision)
revision = "";
safe_printfmt (out_fd, " Revision:\n %s\n", revision);
}
safe_printfmt (out_fd, "\n");
/* Print the revision body: */
{
t_uchar * eol;
t_uchar * pos;
pos = body;
while (*pos)
{
eol = str_chr_index (pos, '\n');
if (eol)
{
safe_printfmt (out_fd, " %.*s\n", (int)(eol - pos), pos);
pos = eol + 1;
}
else
{
safe_printfmt (out_fd, " %s\n", pos);
break;
}
}
}
safe_printfmt (out_fd, "\n");
/* file lists */
if (!no_files)
{
t_uchar * revision = 0;
t_uchar * fqrev = 0;
t_uchar * excluded_patch_file = 0;
revision = str_alloc_cat_many (0, version, "--", patch_lvl, str_end);
fqrev = arch_fully_qualify (archive, revision);
excluded_patch_file = arch_log_file (".", archive, revision);
changelog_file_list (out_fd, headers, "new-files", excluded_patch_file + 2);
changelog_file_list (out_fd, headers, "removed-files", 0);
changelog_file_list (out_fd, headers, "modified-files", 0);
changelog_file_pair_list (out_fd, headers, "renamed-files");
changelog_file_list (out_fd, headers, "new-directories", 0);
changelog_file_list (out_fd, headers, "removed-directories", 0);
changelog_file_list (out_fd, headers, "modified-directories", 0);
changelog_file_pair_list (out_fd, headers, "renamed-directories");
changelog_file_list (out_fd, headers, "new-patches", fqrev);
lim_free (0, revision);
lim_free (0, fqrev);
lim_free (0, excluded_patch_file);
}
safe_printfmt (out_fd, "\n");
lim_free (0, body);
free_assoc_table (headers);
}
static void
changelog_file_list (int out_fd, assoc_table headers, t_uchar * header, t_uchar * exclude)
{
t_uchar * value;
int width;
int items_on_line;
int printed_header;
value = assoc_ref (headers, header);
if (!value)
return;
printed_header = 0;
width = 0;
items_on_line = 0;
while (1)
{
t_uchar * end;
while (char_is_space (*value))
++value;
if (!*value)
break;
end = value;
while (*end && !char_is_space (*end))
++end;
if (!exclude || str_cmp_n (exclude, str_length (exclude), value, end - value))
{
if (!printed_header)
{
header = str_save (0, header);
{
t_uchar * h;
for (h = header; *h; ++h)
if (*h == '-')
*h = ' ';
safe_printfmt (out_fd, " %s:\n ", header);
}
lim_free (0, header);
header = 0;
printed_header = 1;
}
if ((items_on_line == 0) || ((width + (1 + end - value)) < 64))
{
width += (end - value) + 1;
++items_on_line;
safe_printfmt (out_fd, " %.*s", (int)(end - value), value);
}
else
{
safe_printfmt (out_fd, "\n %.*s", (int)(end - value), value);
width = (end - value) + 1;
items_on_line = 1;
}
}
value = end;
}
if (printed_header)
safe_printfmt (out_fd, "\n\n");
}
static void
changelog_file_pair_list (int out_fd, assoc_table headers, t_uchar * header)
{
t_uchar * value;
int printed_header = 0;
value = assoc_ref (headers, header);
if (!value)
return;
while (1)
{
t_uchar * end_1;
t_uchar * start_2;
t_uchar * end_2;
while (char_is_space (*value))
++value;
if (!*value)
break;
end_1 = value;
while (*end_1 && !char_is_space (*end_1))
++end_1;
if (!*end_1)
panic ("corrupt log file");
start_2 = end_1;
while (char_is_space (*start_2))
++start_2;
if (!*start_2)
panic ("corrupt log file");
end_2 = start_2;
while (*end_2 && !char_is_space (*end_2))
++end_2;
if (!printed_header)
{
header = str_save (0, header);
{
t_uchar * h;
for (h = header; *h; ++h)
if (*h == '-')
*h = ' ';
safe_printfmt (out_fd, " %s:\n", header);
}
lim_free (0, header);
header = 0;
printed_header = 1;
}
safe_printfmt (out_fd, " %.*s\n ==> %.*s\n", (int)(end_1 - value), value, (int)(end_2 - start_2), start_2);
value = end_2;
}
if (printed_header)
safe_printfmt (out_fd, "\n");
}
/* tag: Tom Lord Wed May 14 12:14:01 2003 (changelogs.c)
*/
syntax highlighted by Code2HTML, v. 0.9.1