1 /* commit.c:
2  *
3  ****************************************************************
4  * Copyright (C) 2003 Tom Lord
5  *
6  * See the file "COPYING" for further information about
7  * the copyright and warranty status of this work.
8  */
9 
10 
11 #include "hackerlab/bugs/panic.h"
12 #include "hackerlab/os/time.h"
13 #include "hackerlab/char/str.h"
14 #include "hackerlab/fs/file-names.h"
15 #include "hackerlab/vu/safe.h"
16 #include "tla/libdate/date-string.h"
17 #include "tla/libfsutils/string-files.h"
18 #include "tla/libfsutils/copy-file.h"
19 #include "tla/libfsutils/tmp-files.h"
20 #include "tla/libfsutils/rmrf.h"
21 #include "tla/libarch/diffs.h"
22 #include "tla/libarch/patch-logs.h"
23 #include "tla/libarch/invent.h"
24 #include "tla/libarch/my.h"
25 #include "tla/libarch/hooks.h"
26 #include "tla/libarch/namespace.h"
27 #include "tla/libarch/pristines.h"
28 #include "tla/libarch/project-tree.h"
29 #include "tla/libarch/make-changeset-files.h"
30 #include "tla/libarch/make-changeset.h"
31 #include "tla/libarch/changeset-report.h"
32 #include "tla/libarch/local-cache.h"
33 #include "tla/libarch/inv-ids.h"
34 #include "tla/libarch/changelogs.h"
35 #include "tla/libarch/apply-changeset.h"
36 #include "tla/libarch/inode-sig.h"
37 #include "tla/libarch/chatter.h"
38 #include "tla/libarch/commit.h"
39 
40 
41 /* __STDC__ prototypes for static functions */
42 
43 
44 
45 static t_uchar * arch_prepare_commit_changeset (t_uchar ** changelog_loc_ret,
46                                                 int chatter_fd,
47                                                 t_uchar ** cooked_log_ret,
48                                                 t_uchar * tree_root,
49                                                 t_uchar * raw_log,
50                                                 struct arch_archive * arch,
51                                                 t_uchar * revision,
52                                                 t_uchar * prev_level,
53                                                 rel_table file_list,
54                                                 int escape_classes);
55 static rel_table pick_non_control (rel_table table);
56 static rel_table pick_patch_logs (rel_table table);
57 static void arch_commit_mid_commit (t_uchar * tree_root, t_uchar * cooked_log);
58 static void arch_finish_commit (int chatter_fd,
59                                 t_uchar * tree_root,
60                                 t_uchar * archive,
61                                 t_uchar * prev_revision,
62                                 t_uchar * revision,
63                                 t_uchar * changeset,
64                                 t_uchar * changelog_loc,
65                                 int escape_classes,
66                                 int full_meta);
67 static void arch_commit_failed (t_uchar * tree_root, t_uchar * archive, t_uchar * revision, t_uchar * changeset);
68 static void commit_make_changeset_callback (void * vfd, const char * fmt, va_list ap);
69 
70 
71 
72 void
arch_commit(int chatter_fd,struct arch_archive * arch,t_uchar * revision,t_uchar * tree_root,t_uchar * raw_log,rel_table file_list,int escape_classes)73 arch_commit (int chatter_fd,
74              struct arch_archive * arch,
75              t_uchar * revision,
76              t_uchar * tree_root,
77              t_uchar * raw_log,
78              rel_table file_list,
79              int escape_classes)
80 {
81   int full_meta;
82   t_uchar * errstr;
83   t_uchar * version = 0;
84   t_uchar * this_level = 0;
85   t_uchar * prev_revision = 0;
86   t_uchar * prev_level = 0;
87   t_uchar * changelog_loc = 0;
88   t_uchar * changeset_path = 0;
89   t_uchar * cooked_log = 0;
90   t_uchar * my_uid = 0;
91   t_uchar * txn_id = 0;
92   int error;
93 
94   invariant (!!raw_log);
95 
96   full_meta = arch_tree_has_meta_flag (tree_root);
97 
98   version = arch_parse_package_name (arch_ret_package_version, 0, revision);
99   this_level = arch_parse_package_name (arch_ret_patch_level, 0, revision);
100   prev_revision = arch_previous_revision (arch, revision);
101   prev_level = arch_parse_package_name (arch_ret_patch_level, 0, prev_revision);
102 
103   changeset_path = arch_prepare_commit_changeset (&changelog_loc, chatter_fd, &cooked_log, tree_root, raw_log, arch, revision, prev_level, file_list, escape_classes);
104 
105   invariant (!!prev_level);
106 
107   /* Check the error return code for the "precommit" hook and exit if non-zero.
108    */
109   error = arch_run_hook ("precommit", "ARCH_ARCHIVE", arch->name, "ARCH_REVISION", revision, "ARCH_TREE_ROOT", tree_root, (t_uchar*)0) ;
110   if (error)
111     {
112       safe_printfmt (2, "arch_commit: precommit hook function failed with error (%d)\n commit cancelled.\n", error);
113       exit (2);
114     }
115 
116   my_uid = arch_my_id_uid ();
117   txn_id = arch_generate_txn_id ();
118 
119   if (arch_archive_lock_revision (&errstr, arch, version, prev_level, my_uid, txn_id, this_level))
120     {
121       safe_printfmt (2, "arch_commit: unable to acquire revision lock (%s)\n    tree: %s\n    revision: %s/%s\n",
122                      errstr, tree_root, arch->name, revision);
123       exit (2);
124     }
125 
126   if (arch_archive_put_log (&errstr, arch, version, prev_level, my_uid, txn_id, cooked_log))
127     {
128       safe_printfmt (2, "arch_commit: unable to send log message to archive (%s)\n    tree: %s\n    revision: %s/%s\n",
129                      errstr, tree_root, arch->name, version);
130       exit (2);
131     }
132 
133   if (arch_archive_put_changeset (&errstr, arch, version, prev_level, my_uid, txn_id, this_level, changeset_path))
134     {
135       safe_printfmt (2, "arch_commit: unable to send changeset to archive (%s)\n    tree: %s\n    revision: %s/%s\n",
136                      errstr, tree_root, arch->name, revision);
137       exit (2);
138     }
139 
140   if (arch_revision_ready (&errstr, arch, version, prev_level, my_uid, txn_id, this_level))
141     {
142       safe_printfmt (2, "arch_commit: error sending revision to archive (%s)\n    tree: %s\n    revision: %s/%s\n",
143                      errstr, tree_root, arch->name, revision);
144       exit (2);
145     }
146 
147 
148   arch_commit_mid_commit (tree_root, cooked_log);
149 
150   if (arch_archive_finish_revision (&errstr, arch, version, prev_level, my_uid, txn_id, this_level))
151     {
152       arch_commit_failed (tree_root, arch->name, version, changeset_path);
153       safe_printfmt (2, "arch_commit: unable to complete commit transaction (%s)\n    tree: %s\n    revision: %s/%s\n",
154                      errstr, tree_root, arch->name, version);
155       exit (2);
156     }
157 
158   arch_finish_commit (chatter_fd, tree_root, arch->name, prev_revision, revision, changeset_path, changelog_loc, escape_classes, full_meta);
159 
160   if (rel_n_records (file_list) == 0)
161     arch_snap_inode_sig (tree_root, arch->name, revision);
162   else
163   {
164     arch_snap_inode_sig_files(tree_root, arch->name, prev_revision, revision, file_list);
165   }
166 
167   arch_run_hook ("commit", "ARCH_ARCHIVE", arch->name, "ARCH_REVISION", revision, "ARCH_TREE_ROOT", tree_root, (t_uchar*)0);
168 
169   lim_free (0, version);
170   lim_free (0, this_level);
171   lim_free (0, prev_revision);
172   lim_free (0, prev_level);
173   lim_free (0, changeset_path);
174   lim_free (0, cooked_log);
175   lim_free (0, changelog_loc);
176   lim_free (0, my_uid);
177   lim_free (0, txn_id);
178 }
179 
180 
181 
182 
183 static t_uchar *
arch_prepare_commit_changeset(t_uchar ** changelog_loc_ret,int chatter_fd,t_uchar ** cooked_log_ret,t_uchar * tree_root,t_uchar * raw_log,struct arch_archive * arch,t_uchar * revision,t_uchar * prev_level,rel_table file_list,int escape_classes)184 arch_prepare_commit_changeset (t_uchar ** changelog_loc_ret,
185                                int chatter_fd,
186                                t_uchar ** cooked_log_ret,
187                                t_uchar * tree_root,
188                                t_uchar * raw_log,
189                                struct arch_archive * arch,
190                                t_uchar * revision,
191                                t_uchar * prev_level,
192                                rel_table file_list,
193                                int escape_classes)
194 {
195   t_uchar * archive = arch->name;
196   t_uchar * tmp_stem = 0;
197   t_uchar * tmp_path = 0;
198   t_uchar * changeset_basename = 0;
199   t_uchar * changeset_path = 0; /* return value */
200   t_uchar * version = 0;
201   t_uchar * level = 0;
202   t_uchar * prev_revision = 0;
203   t_uchar * prev_rev_path = 0;
204   struct arch_make_changeset_report make_report = {0, }; /* should have a chatter callback here */
205   t_uchar * changelog_id_suffix = 0;
206   t_uchar * changelog_x_id = 0;
207   t_uchar * changelog_i_id = 0;
208   t_uchar * changelog_id = 0;
209   t_uchar * changelog_orig_loc = 0;
210   t_uchar * changelog_mod_loc = 0;
211   struct arch_changeset_report csr = {rel_table_nil, };
212   int changelog_diffs_fd = -1;
213   int changelog_add_fd = -1;
214   t_uchar * new_log_id = 0;
215   t_uchar * new_log_loc = 0;
216   int new_log_fd = -1;
217   t_uchar * new_log_path = 0;
218   t_uchar * cooked_log = 0;
219   t_uchar * new_changelog_path = 0;
220 
221 
222 
223   /****************************************************************
224    * double check that we were handed a valid log message, if any
225    */
226   invariant (arch_valid_log_file (raw_log));
227 
228 
229   /****************************************************************
230    * make a temp dir for the changeset
231    */
232   tmp_stem = str_alloc_cat_many (0, ",,commit.", revision, "--", archive, str_end);
233   tmp_path = tmp_file_name (tree_root, tmp_stem);
234 
235   rmrf_file (tmp_path);
236   safe_mkdir (tmp_path, 0777);
237 
238   changeset_basename = str_alloc_cat (0, revision, ".patches");
239   changeset_path = file_name_in_vicinity (0, tmp_path, changeset_basename);
240 
241 
242   /****************************************************************
243    * Compute the raw changeset
244    *
245    * The changeset computed here does _not_ include an add of the new log
246    * message and does _not_ include updates to automatic changelogs.
247    */
248 
249   version = arch_parse_package_name (arch_ret_package_version, 0, revision);
250   level = arch_parse_package_name (arch_ret_patch_level, 0, revision);
251   prev_revision = str_alloc_cat_many (0, version, "--", prev_level, str_end);
252   prev_rev_path = arch_find_or_make_local_copy (chatter_fd, tree_root, 0, arch, archive, prev_revision);
253 
254   if (chatter_fd >= 0)
255     {
256       make_report.callback = commit_make_changeset_callback;
257       make_report.thunk = (void *)(long)chatter_fd;
258     }
259 
260   if (!rel_n_records (file_list))
261     {
262       assoc_table inode_shortcut = 0;
263 
264       arch_read_inode_sig (0, &inode_shortcut, tree_root, archive, prev_revision);
265 
266       arch_make_changeset (&make_report, prev_rev_path, tree_root, changeset_path, arch_unspecified_id_tagging, arch_inventory_unrecognized, rel_table_nil, inode_shortcut, 0, escape_classes);
267 
268       free_assoc_table (inode_shortcut);
269     }
270   else
271     arch_make_files_changeset (&make_report, changeset_path, file_list, prev_rev_path, tree_root, arch_unspecified_id_tagging, arch_inventory_unrecognized, escape_classes);
272 
273   /****************************************************************
274    * Look for a Changelog for the version we're committing to.
275    */
276 
277   changelog_id_suffix = str_alloc_cat_many (0, "_automatic-ChangeLog--", archive, "/", version, str_end);
278   changelog_x_id = str_alloc_cat (0, "x", changelog_id_suffix);
279   changelog_i_id = str_alloc_cat (0, "i", changelog_id_suffix);
280 
281   {
282     const t_uchar * tmp;
283 
284     tmp = assoc_get_str_taking (make_report.mod_file_loc_of, rel_make_field_str (changelog_x_id));
285     if (tmp)
286       {
287         changelog_mod_loc = str_save (0, tmp);
288         changelog_id = str_save (0, changelog_x_id);
289       }
290     else
291       {
292         const t_uchar * tmp;
293 
294         tmp = assoc_get_str_taking (make_report.mod_file_loc_of, rel_make_field_str (changelog_i_id));
295         if (tmp)
296           {
297             changelog_mod_loc = str_save (0, tmp);
298             changelog_id = str_save (0, changelog_i_id);
299           }
300         else
301           {
302             changelog_mod_loc = 0;
303             changelog_id = 0;
304           }
305       }
306   }
307 
308   if (changelog_mod_loc)
309     {
310       if (changelog_loc_ret)
311         {
312           *changelog_loc_ret = str_save (0, changelog_mod_loc);
313         }
314 
315       {
316         const t_uchar * tmp;
317 
318         tmp = assoc_get_str_taking (make_report.orig_file_loc_of, rel_make_field_str (changelog_id));
319         if (tmp)
320           changelog_orig_loc = str_save (0, tmp);
321         else
322           changelog_orig_loc = 0;
323       }
324     }
325 
326   /* post-condition:
327    *
328    * changelog_id, changelog_mod_loc: 0 if no MOD tree changelog
329    *                                        set if there is a changelog
330    *
331    * changelog_orig_loc: 0 if no MOD or no ORIG changelog, set if both
332    */
333 
334 
335   /****************************************************************
336    * Get a report about this changeset
337    */
338 
339   arch_evaluate_changeset (&csr, changeset_path);
340 
341 
342   /****************************************************************
343    * Update the changeset indexes to reflect the patch log and changelog
344    *
345    * The changelog for this version, if any, is going to change
346    * as a result of the new patch log for this commit.
347    * Usually (though we don't count on it) it didn't change between
348    * pristine and project tree.
349    *
350    * So, we have to touch up the changeset to reflect a diff to that
351    * changelog.  At this stage, only the file and dir indexes are
352    * modified to reflect that (we haven't generated the new log entry
353    * yet, so we can't produce the actual changelog diffs).
354    *
355    * Also, we know we're adding a new patch log, so the indexes should
356    * reflect that, too.
357    *
358    * The reason to touch up the indexes early is that the patch log
359    * is derived, in part, from those indexes.
360    */
361 
362   if (changelog_mod_loc && changelog_orig_loc)
363     {
364       changelog_diffs_fd = arch_changeset_add_diffs (&csr, &make_report, changeset_path, changelog_orig_loc, changelog_mod_loc, changelog_id);
365     }
366   else if (changelog_mod_loc)
367     {
368       changelog_add_fd = arch_changeset_add_file (&new_changelog_path, &csr, &make_report, changeset_path, changelog_mod_loc, changelog_id);
369     }
370 
371   new_log_loc = arch_log_file (".", archive, revision);
372   new_log_id = arch_log_file_id (archive, revision);
373   new_log_fd = arch_changeset_add_file (&new_log_path, &csr, &make_report, changeset_path, new_log_loc, new_log_id);
374 
375   arch_changeset_rewrite_indexes (changeset_path, &csr);
376 
377 
378   /****************************************************************
379    * Generate the Cooked Log Entry
380    */
381   {
382     t_uchar * my_id = 0;
383     time_t now;
384     t_uchar * std_date = 0;
385     t_uchar * human_date = 0;
386     int log_fd;
387 
388     my_id = arch_my_id ();
389     now = time (0);
390     std_date = standard_date (now);
391     human_date = pretty_date (now);
392 
393     log_fd = make_output_to_string_fd ();
394 
395     safe_printfmt (log_fd, "Revision: %s\n", revision);
396     safe_printfmt (log_fd, "Archive: %s\n", archive);
397     safe_printfmt (log_fd, "Creator: %s\n", my_id);
398     safe_printfmt (log_fd, "Date: %s\n", human_date);
399     safe_printfmt (log_fd, "Standard-date: %s\n", std_date);
400 
401     /********************************
402      * automatic headers for various file and patch lists
403      */
404 
405     {
406       rel_table new_files = rel_table_nil;
407       rel_table removed_files = rel_table_nil;
408       rel_table new_directories = rel_table_nil;
409       rel_table removed_directories = rel_table_nil;
410       rel_table modified_files = rel_table_nil;
411       rel_table new_patches = rel_table_nil;
412       rel_table removed_patches = rel_table_nil;
413 
414       new_files = pick_non_control (csr.added_files);
415       rel_append_x (&new_files, csr.added_symlinks);
416       rel_sort_table_by_field (0, new_files, 0);
417 
418       removed_files = pick_non_control (csr.removed_files);
419       rel_append_x (&removed_files, csr.removed_symlinks);
420       rel_sort_table_by_field (0, removed_files, 0);
421 
422       new_directories = pick_non_control (csr.added_dirs);
423       removed_directories = pick_non_control (csr.removed_dirs);
424 
425       modified_files = rel_copy_table (csr.patched_regular_files);
426       rel_append_x (&modified_files, csr.patched_symlinks);
427       rel_append_x (&modified_files, csr.patched_binaries);
428       rel_append_x (&modified_files, csr.file_metadata_changed);
429       rel_append_x (&modified_files, csr.symlink_to_file);
430       rel_append_x (&modified_files, csr.file_to_symlink);
431       rel_sort_table_by_field (0, modified_files, 0);
432       rel_uniq_by_field (&modified_files, 0);
433 
434       new_patches = pick_patch_logs (csr.added_files);
435       removed_patches = pick_patch_logs (csr.removed_files);
436 
437       arch_print_log_list_header (log_fd, "New-files", new_files, 0);
438       arch_print_log_list_header (log_fd, "New-directories", new_directories, 0);
439       arch_print_log_list_header (log_fd, "Removed-files", removed_files, 0);
440       arch_print_log_list_header (log_fd, "Removed-directories", removed_directories, 0);
441       arch_print_log_pairs_header (log_fd, "Renamed-files", csr.renamed_files, 0, 1);
442       arch_print_log_pairs_header (log_fd, "Renamed-directories", csr.renamed_dirs, 0, 1);
443       arch_print_log_list_header (log_fd, "Modified-files", modified_files, 0);
444       arch_print_log_list_header (log_fd, "Modified-directories", csr.dir_metadata_changed, 0);
445       arch_print_log_list_header (log_fd, "New-patches", new_patches, 0);
446       arch_print_log_list_header (log_fd, "Removed-patches", removed_patches, 0);
447 
448       rel_free_table (new_files);
449       rel_free_table (removed_files);
450       rel_free_table (new_directories);
451       rel_free_table (removed_directories);
452       rel_free_table (modified_files);
453       rel_free_table (new_patches);
454       rel_free_table (removed_patches);
455     }
456 
457 
458     /********************************
459      * copy the user headers, and copy or generate the log body
460      */
461     {
462       t_uchar * eoh = raw_log;
463 
464       while (1)
465         {
466           eoh = str_chr_index (eoh, '\n');
467           if (!eoh || (eoh[1] == '\n') || (!eoh[1]))
468             break;
469           else
470             ++eoh;
471         }
472 
473       if (eoh)
474         {
475           eoh = eoh + 1;
476           safe_printfmt (log_fd, "%.*s", (int)(eoh - raw_log), raw_log);
477         }
478 
479       if (eoh && *eoh)
480         {
481           safe_printfmt (log_fd, "%s", eoh);
482         }
483       else
484         {
485           safe_printfmt (log_fd, "\n\n");
486         }
487     }
488 
489     /********************************
490      * oh... did i mention we were writing
491      * the log to a string?
492      */
493     cooked_log = string_fd_close (log_fd);
494 
495     lim_free (0, my_id);
496     lim_free (0, std_date);
497     lim_free (0, human_date);
498   }
499 
500   /****************************************************************
501    * Write the log into the changeset
502    */
503   safe_printfmt (new_log_fd, "%s", cooked_log);
504   safe_close (new_log_fd);
505 
506 
507   /****************************************************************
508    * Give a copy of the log to the caller.
509    */
510   if (cooked_log_ret)
511     *cooked_log_ret = str_save (0, cooked_log);
512 
513 
514   /****************************************************************
515    * Generate the new changelog.
516    */
517 
518   if (changelog_add_fd > 0)
519     {
520       invariant (changelog_add_fd >= 0);
521       invariant (changelog_diffs_fd < 0);
522 
523       arch_generate_changelog (changelog_add_fd, tree_root, 0, 0, level, new_log_path, archive, version);
524       /* new_changelog_path already set. */
525       safe_close (changelog_add_fd);
526     }
527   else if (changelog_diffs_fd > 0)
528     {
529       int fd = -1;
530       t_uchar * changelog_orig_path = 0;
531 
532       new_changelog_path = file_name_in_vicinity (0, changeset_path, ",,changelog");
533       fd = safe_open (new_changelog_path, O_WRONLY | O_CREAT | O_EXCL, 0444);
534       arch_generate_changelog (fd, tree_root, 0, 0, level, new_log_path, archive, version);
535       safe_close (fd);
536 
537       changelog_orig_path = file_name_in_vicinity (0, prev_rev_path, changelog_orig_loc);
538 
539       invariant (changelog_diffs_fd >= 0);
540       invariant (changelog_add_fd < 0);
541 
542       arch_invoke_diff (changelog_diffs_fd, changelog_orig_path, changelog_orig_loc, new_changelog_path, changelog_mod_loc, 0, 0);
543 
544       safe_close (changelog_diffs_fd);
545 
546       rmrf_file (new_changelog_path);
547 
548       lim_free (0, changelog_orig_path);
549     }
550 
551   lim_free (0, tmp_stem);
552   lim_free (0, tmp_path);
553   lim_free (0, changeset_basename);
554   lim_free (0, version);
555   lim_free (0, level);
556   lim_free (0, prev_revision);
557   lim_free (0, prev_rev_path);
558   arch_free_make_changeset_report_data (&make_report);
559   lim_free (0, changelog_id_suffix);
560   lim_free (0, changelog_x_id);
561   lim_free (0, changelog_i_id);
562   lim_free (0, changelog_id);
563   lim_free (0, changelog_orig_loc);
564   lim_free (0, changelog_mod_loc);
565   arch_free_changeset_report_data (&csr);
566   lim_free (0, new_log_id);
567   lim_free (0, new_log_loc);
568   lim_free (0, new_log_path);
569   lim_free (0, cooked_log);
570   lim_free (0, new_changelog_path);
571 
572   /****************************************************************
573    * Give the user the path to the pristine tree for base-0.
574    * It's up tot he caller to stash this in the archive.
575    */
576   return changeset_path;
577 }
578 
579 
580 static rel_table
pick_non_control(rel_table table)581 pick_non_control (rel_table table)
582 {
583   int x;
584   rel_table answer = rel_table_nil;
585 
586   for (x = 0; x < rel_n_records (table); ++x)
587     {
588       const t_uchar * id;
589 
590       id = rel_peek_str (table, x, 1);
591 
592       if (str_cmp_prefix ("A_", id))
593         rel_add_records (&answer, rel_copy_record (rel_peek_record (table, x)), rel_record_null);
594     }
595 
596   return answer;
597 }
598 
599 
600 static rel_table
pick_patch_logs(rel_table table)601 pick_patch_logs (rel_table table)
602 {
603   int x;
604   rel_table answer = rel_table_nil;
605 
606   for (x = 0; x < rel_n_records (table); ++x)
607     {
608       t_uchar * f = 0;
609       t_uchar * t = 0;
610       t_uchar * d = 0;
611       t_uchar * level = 0;
612       t_uchar * archive = 0;
613       t_uchar * version = 0;
614       t_uchar * revision = 0;
615       t_uchar * fqrev = 0;
616 
617       f = str_save (0, rel_peek_str (table, x, 0));
618       t = file_name_tail (0, f);
619       d = file_name_directory_file (0, f);
620 
621       if (arch_valid_patch_level_name (t))
622         {
623           level = str_save (0, t);
624 
625           lim_free (0, f);
626           f = d;
627           t = file_name_tail (0, f);
628           d = file_name_directory_file (0, f);
629 
630           if (!str_cmp ("patch-log", t))
631             {
632               lim_free (0, f);
633               f = d;
634               t = file_name_tail (0, f);
635               d = file_name_directory_file (0, f);
636 
637               if (arch_valid_archive_name (t))
638                 {
639                   archive = str_save (0, t);
640 
641                   lim_free (0, f);
642                   f = d;
643                   t = file_name_tail (0, f);
644                   d = file_name_directory_file (0, f);
645 
646                   if (arch_valid_package_name (t, arch_no_archive, arch_req_version, 0))
647                     {
648                       version = str_save (0, t);
649 
650                       lim_free (0, f);
651                       f = d;
652                       t = file_name_tail (0, f);
653                       d = file_name_directory_file (0, f);
654 
655                       if (arch_valid_package_name (t, arch_no_archive, arch_req_package, 0))
656                         {
657                           lim_free (0, f);
658                           f = d;
659                           t = file_name_tail (0, f);
660                           d = file_name_directory_file (0, f);
661 
662                           if (arch_valid_package_name (t, arch_no_archive, arch_req_category, 0))
663                             {
664                               if (!str_cmp ("./{arch}", d))
665                                 {
666                                   revision = str_alloc_cat_many (0, version, "--", level, str_end);
667                                   fqrev = arch_fully_qualify (archive, revision);
668                                   rel_add_records (&answer,
669                                                    rel_make_record_3_taking (rel_make_field_str (fqrev),
670                                                                              rel_get_field (table, x, 1),
671                                                                              rel_get_field (table, x, 2)),
672                                                    rel_record_null);
673                                 }
674                             }
675                         }
676 
677                     }
678                 }
679             }
680           lim_free (0, f);
681           lim_free (0, t);
682           lim_free (0, d);
683           lim_free (0, level);
684           lim_free (0, archive);
685           lim_free (0, version);
686           lim_free (0, revision);
687           lim_free (0, fqrev);
688         }
689     }
690 
691   arch_sort_table_by_name_field (0, answer, 0);
692 
693   return answer;
694 }
695 
696 
697 static void
arch_commit_mid_commit(t_uchar * tree_root,t_uchar * cooked_log)698 arch_commit_mid_commit (t_uchar * tree_root, t_uchar * cooked_log)
699 {
700   arch_start_tree_commit (tree_root, cooked_log);
701 }
702 
703 
704 static void
arch_finish_commit(int chatter_fd,t_uchar * tree_root,t_uchar * archive,t_uchar * prev_revision,t_uchar * revision,t_uchar * changeset,t_uchar * changelog_loc,int escape_classes,int full_meta)705 arch_finish_commit (int chatter_fd,
706                     t_uchar * tree_root,
707                     t_uchar * archive,
708                     t_uchar * prev_revision,
709                     t_uchar * revision,
710                     t_uchar * changeset,
711                     t_uchar * changelog_loc,
712                     int escape_classes,
713                     int full_meta)
714 {
715   t_uchar * dir = 0;
716   t_uchar * dir_tail = 0;
717   t_uchar * recycled_pristine_src = 0;
718   t_uchar * recycled_pristine_tmp = 0;
719 
720   dir = file_name_directory_file (0, changeset);
721   dir_tail = file_name_tail (0, dir);
722   invariant (!str_cmp_prefix (",,", dir_tail));
723 
724   arch_finish_tree_commit (tree_root, archive, revision, changelog_loc, full_meta);
725 
726   recycled_pristine_src = arch_find_pristine (0, tree_root, archive, prev_revision, arch_unlocked_pristine, arch_tree_pristine_search);
727   if (recycled_pristine_src)
728     {
729       t_uchar * inventory_path = 0;
730       struct arch_apply_changeset_report report = {0, };
731 
732       arch_chatter (chatter_fd, "* update pristine tree (%s/%s => %s)\n", archive, prev_revision, revision);
733 
734       recycled_pristine_tmp = tmp_file_name (dir, ",,pristine");
735       safe_rename (recycled_pristine_src, recycled_pristine_tmp);
736 
737       inventory_path = file_name_in_vicinity (0, recycled_pristine_tmp, ",,index");
738       rmrf_file (inventory_path);
739 
740       arch_apply_changeset (&report, changeset, recycled_pristine_tmp, arch_unspecified_id_tagging, arch_inventory_unrecognized, 0, 0, 0, 0, 0, escape_classes);
741       invariant (!arch_conflicts_occured (&report));
742 
743       arch_install_pristine (tree_root, archive, revision, recycled_pristine_tmp);
744 
745       lim_free (0, inventory_path);
746     }
747 
748   rmrf_file (dir);
749 
750   lim_free (0, dir);
751   lim_free (0, dir_tail);
752   lim_free (0, recycled_pristine_src);
753   lim_free (0, recycled_pristine_tmp);
754 }
755 
756 
757 static void
arch_commit_failed(t_uchar * tree_root,t_uchar * archive,t_uchar * revision,t_uchar * changeset)758 arch_commit_failed (t_uchar * tree_root, t_uchar * archive, t_uchar * revision, t_uchar * changeset)
759 {
760   t_uchar * dir = 0;
761   t_uchar * dir_tail = 0;
762 
763   dir = file_name_directory_file (0, changeset);
764   dir_tail = file_name_tail (0, dir);
765   invariant (!str_cmp_prefix (",,", dir_tail));
766 
767   arch_abort_tree_commit (tree_root, archive, revision);
768 
769 
770   rmrf_file (dir);
771 
772   lim_free (0, dir);
773   lim_free (0, dir_tail);
774 }
775 
776 
777 static void
commit_make_changeset_callback(void * vfd,const char * fmt,va_list ap)778 commit_make_changeset_callback (void * vfd, const char * fmt, va_list ap)
779 {
780   int fd;
781 
782   fd = (int)(t_ulong)vfd;
783   safe_printfmt_va_list (fd, fmt, ap);
784   safe_flush (1);
785 }
786 
787 
788 
789 
790 
791 
792 /* tag: Tom Lord Mon May 26 12:05:54 2003 (commit.c)
793  */
794