/* 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) */