1 /* import.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/rmrf.h"
18 #include "tla/libfsutils/string-files.h"
19 #include "tla/libfsutils/copy-file.h"
20 #include "tla/libfsutils/tmp-files.h"
21 #include "tla/libfsutils/rmrf.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/changelogs.h"
30 #include "tla/libarch/local-cache.h"
31 #include "tla/libarch/import.h"
32
33
34 /* __STDC__ prototypes for static functions */
35
36
37
38 static t_uchar * arch_prepare_import_pristine (t_uchar ** changelog_loc_ret,
39 t_uchar ** cooked_log_ret,
40 t_uchar * tree_root,
41 t_uchar * raw_log,
42 t_uchar * archive,
43 t_uchar * version,
44 int full_meta);
45 static void arch_import_mid_commit (t_uchar * tree_root, t_uchar * cooked_log);
46 static void arch_finish_import (t_uchar * tree_root,
47 t_uchar * archive,
48 t_uchar * version,
49 t_uchar * pristine,
50 t_uchar * changelog_loc,
51 int full_meta);
52 static void arch_import_failed (t_uchar * tree_root, t_uchar * archive, t_uchar * version, t_uchar * pristine);
53 static rel_table all_patches (t_uchar * tree_root);
54
55
56
57 void
arch_import(struct arch_archive * arch,t_uchar * version,t_uchar * tree_root,t_uchar * raw_log)58 arch_import (struct arch_archive * arch,
59 t_uchar * version,
60 t_uchar * tree_root,
61 t_uchar * raw_log)
62 {
63 t_uchar * changelog_loc = 0;
64 t_uchar * errstr;
65 t_uchar * pristine_path = 0;
66 t_uchar * cooked_log = 0;
67 t_uchar * my_uid = 0;
68 t_uchar * txn_id = 0;
69 t_uchar * revision;
70 const int full_meta = arch_tree_has_meta_flag (tree_root);
71
72 revision = str_alloc_cat (0, version, "--base-0");
73
74 pristine_path = arch_prepare_import_pristine (&changelog_loc, &cooked_log, tree_root, raw_log, arch->name, version, full_meta);
75
76 my_uid = arch_my_id_uid ();
77 txn_id = arch_generate_txn_id ();
78 if (arch_revision_exists (arch, revision))
79 {
80 safe_printfmt (2, "arch_import: the revision already exists\n revision: %s/%s\n", arch->official_name, revision);
81 exit (2);
82 }
83
84 if (arch_archive_lock_revision (&errstr, arch, version, 0, my_uid, txn_id, "base-0"))
85 {
86 safe_printfmt (2, "arch_import: unable to acquire revision lock (%s)\n tree: %s\n revision: %s/%s--base-0\n",
87 errstr, tree_root, arch->name, version);
88 exit (2);
89 }
90
91 if (arch_archive_put_log (&errstr, arch, version, 0, my_uid, txn_id, cooked_log))
92 {
93 safe_printfmt (2, "arch_import: unable to send log message to archive (%s)\n tree: %s\n revision: %s/%s\n",
94 errstr, tree_root, arch->name, version);
95 exit (2);
96 }
97
98 if (arch_archive_put_import (&errstr, arch, version, 0, my_uid, txn_id, "base-0", pristine_path))
99 {
100 safe_printfmt (2, "arch_import: unable to send import tree to archive (%s)\n tree: %s\n revision: %s/%s\n",
101 errstr, tree_root, arch->name, version);
102 exit (2);
103 }
104
105 if (arch_revision_ready (&errstr, arch, version, 0, my_uid, txn_id, "base-0"))
106 {
107 safe_printfmt (2, "arch_import: error sending tree to archive (%s)\n tree: %s\n revision: %s/%s\n",
108 errstr, tree_root, arch->name, version);
109 exit (2);
110 }
111
112 arch_import_mid_commit (tree_root, cooked_log);
113
114 if (arch_archive_finish_revision (&errstr, arch, version, 0, my_uid, txn_id, "base-0"))
115 {
116 arch_import_failed (tree_root, arch->name, version, pristine_path);
117 safe_printfmt (2, "arch_import: unable to complete import transaction (%s)\n tree: %s\n revision: %s/%s\n",
118 errstr, tree_root, arch->name, version);
119 exit (2);
120 }
121
122 arch_finish_import (tree_root, arch->name, version, pristine_path, changelog_loc, full_meta);
123
124 arch_run_hook ("import", "ARCH_ARCHIVE", arch->name, "ARCH_REVISION", revision, "ARCH_TREE_ROOT", tree_root, (t_uchar*)0);
125
126 lim_free (0, revision);
127 lim_free (0, changelog_loc);
128 lim_free (0, pristine_path);
129 lim_free (0, cooked_log);
130 lim_free (0, my_uid);
131 lim_free (0, txn_id);
132 }
133
134
135
136
137 static t_uchar *
arch_prepare_import_pristine(t_uchar ** changelog_loc_ret,t_uchar ** cooked_log_ret,t_uchar * tree_root,t_uchar * raw_log,t_uchar * archive,t_uchar * version,int full_meta)138 arch_prepare_import_pristine (t_uchar ** changelog_loc_ret,
139 t_uchar ** cooked_log_ret,
140 t_uchar * tree_root,
141 t_uchar * raw_log,
142 t_uchar * archive,
143 t_uchar * version,
144 int full_meta)
145 {
146 t_uchar * tmp_stem = 0;
147 t_uchar * tmp_path = 0;
148 t_uchar * revision = 0;
149 t_uchar * pristine_path = 0;
150 rel_table inventory = rel_table_nil;
151 rel_table new_files_list = rel_table_nil;
152 t_uchar * log_message = 0;
153 t_uchar * pristine_log_path = 0;
154 int pristine_log_fd;
155
156 /****************************************************************
157 * double check that we were handed a valid log message, if any
158 */
159 if (raw_log)
160 invariant (arch_valid_log_file (raw_log));
161
162
163 /****************************************************************
164 * make a temp dir for the pristine copy of the import
165 */
166 tmp_stem = str_alloc_cat_many (0, ",,import.", version, "--base-0--", archive, str_end);
167 tmp_path = tmp_file_name (tree_root, tmp_stem);
168
169 rmrf_file (tmp_path);
170 safe_mkdir (tmp_path, 0777);
171
172 revision = str_alloc_cat (0, version, "--base-0");
173 pristine_path = file_name_in_vicinity (0, tmp_path, revision);
174
175 inventory = arch_source_inventory (tree_root, 1, 0, 0);
176
177 safe_mkdir (pristine_path, 0777);
178
179 copy_file_list (pristine_path, tree_root, inventory, full_meta);
180
181
182 /****************************************************************
183 * As long as the cache is hot with directories and inodes, compute
184 * a list of files for the New-files: header in the log message.
185 */
186 new_files_list = arch_source_files_inventory (tree_root, 0, 0);
187
188
189 /****************************************************************
190 * Create a log message for the newly committed base-0.
191 *
192 * Although the message is empty at this point, it's important for
193 * it to appear in directory listings of the patch-log, so that it
194 * shows up in the New-patches: header.
195 */
196 pristine_log_path = arch_log_file (pristine_path, archive, revision);
197 pristine_log_fd = safe_open (pristine_log_path, O_WRONLY | O_CREAT | O_EXCL, 0666);
198
199
200 /****************************************************************
201 * Generate the actual log message, adding automatically generated
202 * headers either to the supplied raw-log or to a default raw-log.
203 */
204 {
205 t_uchar * my_id = 0;
206 time_t now;
207 t_uchar * std_date = 0;
208 t_uchar * human_date = 0;
209 int log_fd;
210 rel_table patches = rel_table_nil;
211 t_uchar * eoh;
212
213 my_id = arch_my_id ();
214 now = time(0);
215 std_date = standard_date (now);
216 human_date = pretty_date (now);
217
218 log_fd = make_output_to_string_fd ();
219
220 safe_printfmt (log_fd, "Revision: %s--base-0\n", version);
221 safe_printfmt (log_fd, "Archive: %s\n", archive);
222 safe_printfmt (log_fd, "Creator: %s\n", my_id);
223 safe_printfmt (log_fd, "Date: %s\n", human_date);
224 safe_printfmt (log_fd, "Standard-date: %s\n", std_date);
225
226 /********************************
227 * Copy headers from the raw log
228 */
229 if (raw_log)
230 {
231 eoh = raw_log;
232 while (1)
233 {
234 eoh = str_chr_index (eoh, '\n');
235 if (!eoh || (eoh[1] == '\n') || (!eoh[1]))
236 break;
237 ++eoh;
238 }
239
240 if (eoh)
241 {
242 eoh = eoh + 1;
243 safe_printfmt (log_fd, "%.*s", (int)(eoh - raw_log), raw_log);
244 }
245 }
246 else
247 {
248 safe_printfmt (log_fd, "Summary: initial import\n");
249 }
250
251 /********************************
252 * automatic headers for New-files: and New-patches:
253 */
254 arch_print_log_list_header (log_fd, "New-files", new_files_list, 0);
255 patches = all_patches (pristine_path);
256 arch_print_log_list_header (log_fd, "New-patches", patches, 0);
257
258 /********************************
259 * copy or generate the log body
260 */
261 if (!raw_log)
262 safe_printfmt (log_fd, "\n\n(automatically generated log message)\n");
263 else
264 {
265 if (*eoh)
266 {
267 safe_printfmt (log_fd, "%s", eoh);
268 }
269 else
270 {
271 safe_printfmt (log_fd, "\n\n");
272 }
273 }
274
275 /********************************
276 * oh... did i mention we were writing
277 * the log to a string?
278 */
279 log_message = string_fd_close (log_fd);
280
281 lim_free (0, my_id);
282 lim_free (0, std_date);
283 lim_free (0, human_date);
284 rel_free_table (patches);
285 }
286
287 /****************************************************************
288 * Write the log into the patch-log of the pristine tree.
289 */
290 safe_printfmt (pristine_log_fd, "%s", log_message);
291 safe_close (pristine_log_fd);
292
293 /****************************************************************
294 * If the import tree has a ChangeLog for this version,
295 * update it in the pristine tree.
296 */
297 {
298 int x;
299 t_uchar * changelog_id_suffix = 0;
300 t_uchar * changelog_x_id = 0;
301 t_uchar * changelog_i_id = 0;
302
303 changelog_id_suffix = str_alloc_cat_many (0, "_automatic-ChangeLog--", archive, "/", version, str_end);
304 changelog_x_id = str_alloc_cat (0, "x", changelog_id_suffix);
305 changelog_i_id = str_alloc_cat (0, "i", changelog_id_suffix);
306
307 for (x = 0; x < rel_n_records (inventory); ++x)
308 {
309 if (!str_cmp (changelog_x_id, rel_peek_str (inventory, x, 1)) || !str_cmp (changelog_i_id, rel_peek_str (inventory, x, 1)))
310 {
311 struct stat clstatb;
312 t_uchar * changelog_path = 0;
313 mode_t clmode;
314 int out_fd = -1;
315
316 if (changelog_loc_ret)
317 *changelog_loc_ret = str_save (0, rel_peek_str (inventory, x, 0));
318
319 changelog_path = file_name_in_vicinity (0, pristine_path, rel_peek_str (inventory, x, 0));
320
321 safe_stat (changelog_path, &clstatb);
322 if (full_meta)
323 {
324 clmode = clstatb.st_mode & 07777;
325 }
326 else
327 {
328 clmode = clstatb.st_mode & 0777;
329 }
330 out_fd = safe_open (changelog_path, O_WRONLY | O_CREAT | O_TRUNC, clmode);
331 safe_fchmod (out_fd, clmode);
332 if (full_meta)
333 safe_fchown (out_fd, clstatb.st_uid, clstatb.st_gid);
334 arch_generate_changelog (out_fd, pristine_path, 0, 0, 0, 0, archive, version);
335 safe_close (out_fd);
336
337 lim_free (0, changelog_path);
338
339 break;
340 }
341 }
342
343 lim_free (0, changelog_id_suffix);
344 lim_free (0, changelog_x_id);
345 lim_free (0, changelog_i_id);
346 }
347
348
349 /****************************************************************
350 * Give a copy of the log to the caller.
351 */
352 if (cooked_log_ret)
353 *cooked_log_ret = str_save (0, log_message);
354
355
356 lim_free (0, tmp_stem);
357 lim_free (0, tmp_path);
358 lim_free (0, revision);
359 rel_free_table (inventory);
360 rel_free_table (new_files_list);
361 lim_free (0, log_message);
362 lim_free (0, pristine_log_path);
363
364 /****************************************************************
365 * Give the user the path to the pristine tree for base-0.
366 * It's up tot he caller to stash this in the archive.
367 */
368 return pristine_path;
369 }
370
371
372 static void
arch_import_mid_commit(t_uchar * tree_root,t_uchar * cooked_log)373 arch_import_mid_commit (t_uchar * tree_root, t_uchar * cooked_log)
374 {
375 arch_start_tree_commit (tree_root, cooked_log);
376 }
377
378
379 static void
arch_finish_import(t_uchar * tree_root,t_uchar * archive,t_uchar * version,t_uchar * pristine,t_uchar * changelog_loc,int full_meta)380 arch_finish_import (t_uchar * tree_root,
381 t_uchar * archive,
382 t_uchar * version,
383 t_uchar * pristine,
384 t_uchar * changelog_loc,
385 int full_meta)
386 {
387 t_uchar * revision = 0;
388 t_uchar * pristine_dir = 0;
389 t_uchar * pristine_dir_tail = 0;
390
391 revision = str_alloc_cat (0, version, "--base-0");
392
393
394 /****************************************************************
395 * txnally install the log file in the patch log
396 */
397 arch_finish_tree_commit (tree_root, archive, revision, changelog_loc, full_meta);
398
399 /****************************************************************
400 * Install the pristine tree unless we have a greedy library
401 * that is eager to slurp it up.
402 *
403 * If we don't snarf the library here, it'll be deleted
404 * during "clean up", below.
405 */
406
407 if (!arch_greedy_library_wants_revision (archive, revision))
408 arch_install_pristine (tree_root, archive, revision, pristine);
409
410 /****************************************************************
411 * clean up
412 */
413 pristine_dir = file_name_directory_file (0, pristine);
414 invariant (!!pristine_dir);
415 pristine_dir_tail = file_name_tail (0, pristine_dir);
416 invariant (!str_cmp_prefix (",,import.", pristine_dir_tail));
417 rmrf_file (pristine_dir);
418
419 lim_free (0, revision);
420 lim_free (0, pristine_dir);
421 lim_free (0, pristine_dir_tail);
422 }
423
424 static void
arch_import_failed(t_uchar * tree_root,t_uchar * archive,t_uchar * version,t_uchar * pristine)425 arch_import_failed (t_uchar * tree_root, t_uchar * archive, t_uchar * version, t_uchar * pristine)
426 {
427 t_uchar * revision = 0;
428 t_uchar * pristine_dir = 0;
429 t_uchar * pristine_dir_tail = 0;
430
431 revision = str_alloc_cat (0, version, "--base-0");
432
433 /****************************************************************
434 * get out of mid-commit state in the project tree
435 */
436 arch_abort_tree_commit (tree_root, archive, revision);
437
438 /****************************************************************
439 * clean up
440 */
441 pristine_dir = file_name_directory_file (0, pristine);
442 invariant (!!pristine_dir);
443 pristine_dir_tail = file_name_tail (0, pristine_dir);
444 invariant (str_cmp_prefix (",,import.", pristine_dir_tail));
445 rmrf_file (pristine_dir);
446
447 lim_free (0, revision);
448 lim_free (0, pristine_dir);
449 lim_free (0, pristine_dir_tail);
450 }
451
452
453
454
455
456 static rel_table
all_patches(t_uchar * tree_root)457 all_patches (t_uchar * tree_root)
458 {
459 rel_table log_versions = rel_table_nil;
460 rel_table answer = rel_table_nil;
461 int x;
462
463 log_versions = arch_log_versions (tree_root, 0, 0, 0, 0);
464
465 for (x = 0; x < rel_n_records (log_versions); ++x)
466 {
467 t_uchar * archive = 0;
468 t_uchar * version = 0;
469 rel_table patch_list = rel_table_nil;
470
471 archive = arch_parse_package_name (arch_ret_archive, 0, rel_peek_str (log_versions, x, 0));
472 version = arch_parse_package_name (arch_ret_non_archive, 0, rel_peek_str (log_versions, x, 0));
473
474 patch_list = arch_logs (tree_root, archive, version, 1);
475 rel_append_x (&answer, patch_list);
476
477 lim_free (0, archive);
478 lim_free (0, version);
479 rel_free_table (patch_list);
480 }
481
482 rel_free_table (log_versions);
483 return answer;
484 }
485
486
487
488
489
490 /* tag: Tom Lord Sat May 24 22:40:45 2003 (import.c)
491 */
492