1 /* configs.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/errno.h"
13 #include "hackerlab/os/errno-to-string.h"
14 #include "hackerlab/char/char-class.h"
15 #include "hackerlab/char/str.h"
16 #include "hackerlab/char/pika-escaping-utils.h"
17 #include "hackerlab/fs/file-names.h"
18 #include "hackerlab/fs/cwd.h"
19 #include "hackerlab/vu/safe.h"
20 #include "hackerlab/arrays/ar.h"
21 #include "tla/libfsutils/ensure-dir.h"
22 #include "tla/libfsutils/safety.h"
23 #include "tla/libfsutils/tmp-files.h"
24 #include "tla/libfsutils/read-line.h"
25 #include "tla/libarch/arch.h"
26 #include "tla/libarch/namespace.h"
27 #include "tla/libarch/project-tree.h"
28 #include "tla/libarch/patch-logs.h"
29 #include "tla/libarch/cmd.h"
30 #include "tla/libarch/cmd-get.h"
31 #include "tla/libarch/configs.h"
32
33
34 /* __STDC__ prototypes for static functions */
35
36
37
38 t_uchar *
arch_config_path(t_uchar * tree_root,t_uchar * config_name)39 arch_config_path (t_uchar * tree_root, t_uchar * config_name)
40 {
41 t_uchar * rel = 0;
42 t_uchar * answer = 0;
43
44 invariant (arch_valid_config_name (config_name));
45
46
47 rel = file_name_in_vicinity (0, "configs", config_name);
48 if (safe_access(rel, F_OK))
49 {
50 rel = file_name_in_vicinity (0, "", config_name);
51 }
52 answer = file_name_in_vicinity (0, tree_root, rel);
53
54 lim_free (0, rel);
55 return answer;
56 }
57
58
59 rel_table
arch_read_config(t_uchar * tree_root,t_uchar * config_name)60 arch_read_config (t_uchar * tree_root, t_uchar * config_name)
61 {
62 t_uchar * config_path = 0;
63 int in_fd;
64 rel_table answer = rel_table_nil;
65
66 invariant (arch_valid_config_name (config_name));
67
68 config_path = arch_config_path (tree_root, config_name);
69
70 in_fd = safe_open (config_path, O_RDONLY, 0);
71
72 while (1)
73 {
74 t_uchar * line = 0;
75 t_uchar * pos;
76
77 line = read_line_from_fd (in_fd);
78
79 if (!line)
80 break;
81
82 for (pos = line; char_is_space (*pos); ++pos)
83 ;
84
85 if (*pos && (*pos != '#'))
86 {
87 t_uchar * end;
88 t_uchar * loc = 0;
89 t_uchar * rev = 0;
90
91 for (pos = line; char_is_space (*pos); ++pos)
92 ;
93
94 for (end = pos; *end && !char_is_space (*end); ++end)
95 ;
96
97 if (end == pos)
98 {
99 safe_printfmt (2, "arch_read_config: illegal config file (%s)\n", config_name);
100 exit (2);
101 }
102
103 loc = pika_save_unescape_iso8859_1_n (0, 0, pos, end - pos );
104
105 for (pos = end; char_is_space (*pos); ++pos)
106 ;
107
108 for (end = pos; *end && !char_is_space (*end); ++end)
109 ;
110
111 if (end == pos)
112 {
113 safe_printfmt (2, "arch_read_config: illegal config file (%s)\n", config_name);
114 exit (2);
115 }
116
117 rev = pika_save_unescape_iso8859_1_n (0, 0, pos, end - pos );
118
119 if (!is_non_upwards_relative_path (loc) || !arch_valid_package_name (rev, arch_maybe_archive, arch_req_package, 1))
120 {
121 safe_printfmt (2, "arch_read_config: illegal config file (%s)\n", config_name);
122 exit (2);
123 }
124
125 rel_add_records (&answer, rel_make_record_2_taking (rel_make_field_str (loc), rel_make_field_str (rev)), rel_record_null);
126
127 lim_free (0, loc);
128 lim_free (0, rev);
129 }
130
131 lim_free (0, line);
132 }
133
134 lim_free (0, config_path);
135
136 return answer;
137 }
138
139
140 rel_table
arch_config_from_tree(t_uchar * tree_root,rel_table config_in)141 arch_config_from_tree (t_uchar * tree_root, rel_table config_in)
142 {
143 int here_fd;
144 int x;
145 rel_table answer = rel_table_nil;
146
147 here_fd = safe_open (".", O_RDONLY, 0);
148
149 for (x = 0; x < rel_n_records (config_in); ++x)
150 {
151 t_uchar * subtree_path_spec = 0;
152 t_uchar * subtree_path = 0;
153 t_uchar * archive = 0;
154 t_uchar * version = 0;
155 t_uchar * subtree_root = 0;
156 t_uchar * level = 0;
157 t_uchar * revision = 0;
158 t_uchar * fqr = 0;
159
160 subtree_path_spec = file_name_in_vicinity (0, tree_root, rel_peek_str (config_in, x, 0));
161 safe_chdir (subtree_path_spec);
162 subtree_path = safe_current_working_directory ();
163 safe_fchdir (here_fd);
164
165 subtree_root = arch_tree_root (0, subtree_path, 0);
166 invariant (subtree_root && !str_cmp (subtree_root, subtree_path));
167
168 archive = arch_parse_package_name (arch_ret_archive, 0, rel_peek_str (config_in, x, 1));
169 if (arch_valid_package_name (rel_peek_str (config_in, x, 1), arch_maybe_archive, arch_req_version, 1))
170 version = arch_parse_package_name (arch_ret_package_version, 0, rel_peek_str (config_in, x, 1));
171 else
172 {
173 t_uchar * package = 0;
174
175 package = arch_parse_package_name (arch_ret_package, 0, rel_peek_str (config_in, x, 1));
176 version = arch_latest_logged_version (subtree_root, archive, package);
177
178 lim_free (0, package);
179 }
180
181 level = arch_highest_patch_level (subtree_root, archive, version);
182
183 if (level)
184 {
185 revision = str_alloc_cat_many (0, version, "--", level, str_end);
186 fqr = arch_fully_qualify (archive, revision);
187 }
188 else
189 fqr = arch_fully_qualify (archive, version);
190
191 rel_add_records (&answer, rel_make_record_2_taking (rel_get_field (config_in, x, 0), rel_make_field_str (fqr)), rel_record_null);
192
193 lim_free (0, subtree_path_spec);
194 lim_free (0, subtree_path);
195 lim_free (0, archive);
196 lim_free (0, version);
197 lim_free (0, subtree_root);
198 lim_free (0, level);
199 lim_free (0, revision);
200 lim_free (0, fqr);
201 }
202
203
204 safe_close (here_fd);
205
206 return answer;
207 }
208
209
210 int
arch_begin_new_config(t_uchar * tree_root,t_uchar * name,int force)211 arch_begin_new_config (t_uchar * tree_root, t_uchar * name, int force)
212 {
213 int ign;
214 t_uchar * config_file = 0;
215 t_uchar * config_dir = 0;
216 t_uchar * name_tail = 0;
217 t_uchar * tmp_tail = 0;
218 t_uchar * config_tmp = 0;
219 int answer;
220
221 invariant (arch_valid_config_name (name));
222
223 config_file = arch_config_path (tree_root, name);
224 config_dir = file_name_directory_file (0, config_file);
225 name_tail = file_name_tail (0, name);
226 tmp_tail = str_alloc_cat (0, ",,", name_tail);
227 config_tmp = file_name_in_vicinity (0, config_dir, tmp_tail);
228
229 if (!force && !safe_access (config_file, F_OK))
230 {
231 safe_printfmt (2, "arch_begin_new_config: config already exists (%s)\n", name);
232 exit (2);
233 }
234
235 ensure_directory_exists (config_dir);
236
237 vu_unlink (&ign, config_tmp);
238 answer = safe_open (config_tmp, O_WRONLY | O_CREAT | O_EXCL, 0666);
239
240 lim_free (0, config_file);
241 lim_free (0, config_dir);
242 lim_free (0, name_tail);
243 lim_free (0, tmp_tail);
244 lim_free (0, config_tmp);
245
246 return answer;
247 }
248
249
250 void
arch_finish_new_config(int fd,t_uchar * tree_root,t_uchar * name,int force)251 arch_finish_new_config (int fd, t_uchar * tree_root, t_uchar * name, int force)
252 {
253 t_uchar * config_file = 0;
254 t_uchar * config_dir = 0;
255 t_uchar * name_tail = 0;
256 t_uchar * tmp_tail = 0;
257 t_uchar * config_tmp = 0;
258
259 invariant (arch_valid_config_name (name));
260
261 config_file = arch_config_path (tree_root, name);
262 config_dir = file_name_directory_file (0, config_file);
263 name_tail = file_name_tail (0, name);
264 tmp_tail = str_alloc_cat (0, ",,", name_tail);
265 config_tmp = file_name_in_vicinity (0, config_dir, tmp_tail);
266
267 safe_close (fd);
268
269 if (!force && !safe_access (config_file, F_OK))
270 {
271 safe_printfmt (2, "arch_begin_new_config: config already exists (%s)\n", name);
272 exit (2);
273 }
274
275 safe_rename (config_tmp, config_file);
276
277 lim_free (0, config_file);
278 lim_free (0, config_dir);
279 lim_free (0, name_tail);
280 lim_free (0, tmp_tail);
281 lim_free (0, config_tmp);
282 }
283
284
285 void
arch_build_config(t_uchar * tree_root,t_uchar * config_name,struct arch_build_config_params * params,t_uchar * default_archive)286 arch_build_config (t_uchar * tree_root,
287 t_uchar * config_name,
288 struct arch_build_config_params * params,
289 t_uchar * default_archive)
290 {
291 rel_table config = rel_table_nil;
292 int x;
293
294 config = arch_read_config (tree_root, config_name);
295
296 /* Ensure a shallowist to deepest sort
297 */
298 rel_sort_table_by_field (0, config, 0);
299
300 /* move conflicting dirs and files
301 */
302
303 for (x = 0; x < rel_n_records (config); ++x)
304 {
305 int errn;
306 t_uchar * path = 0;
307 t_uchar * path_dir = 0;
308 t_uchar * path_tail = 0;
309 t_uchar * saved_tail = 0;
310 t_uchar * saved_path = 0;
311
312 path = file_name_in_vicinity (0, tree_root, rel_peek_str (config, x, 0));
313 path_dir = file_name_directory_file (0, path);
314 path_tail = file_name_tail (0, path);
315 saved_tail = str_alloc_cat (0, "++saved.", path_tail);
316 saved_path = tmp_file_name (path_dir, saved_tail);
317
318 if (vu_rename (&errn, path, saved_path) && (errn != ENOENT))
319 {
320 safe_printfmt (2, "build-config: unable to set aside conflicting directory %s\n", path);
321 exit (2);
322 }
323
324 lim_free (0, path);
325 lim_free (0, path_dir);
326 lim_free (0, path_tail);
327 lim_free (0, saved_tail);
328 lim_free (0, saved_path);
329 }
330
331 /* build desired trees.
332 */
333
334 for (x = 0; x < rel_n_records (config); ++x)
335 {
336 t_uchar * path_to_subtree = 0;
337 t_uchar * path_to_subtree_dir = 0;
338 const t_uchar * revspec;
339 int status;
340
341 path_to_subtree = file_name_in_vicinity (0, tree_root, rel_peek_str (config, x, 0));
342 path_to_subtree_dir = file_name_directory_file (0, path_to_subtree);
343
344 ensure_directory_exists (path_to_subtree_dir);
345
346 revspec = rel_peek_str (config, x, 1);
347
348 {
349 char ** argv = 0;
350 char * revspec_copy = 0;
351 char * path_to_subtree_copy = 0;
352
353 /* call `get' -- build an argv for it
354 */
355
356 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "get";
357 if (default_archive)
358 {
359 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "-A";
360 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = default_archive;
361 }
362 if (params->no_pristines)
363 {
364 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--no-pristine";
365 }
366 if (params->hardlinks)
367 {
368 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--link";
369 }
370 if (params->library)
371 {
372 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--library";
373 }
374 if (params->sparse)
375 {
376 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = "--sparse";
377 }
378 revspec_copy = str_save (0, revspec);
379 path_to_subtree_copy = str_save (0, path_to_subtree);
380 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = revspec_copy;
381 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = path_to_subtree_copy;
382 *(char **)ar_push ((void **)&argv, 0, sizeof (char *)) = 0;
383
384 status = arch_cmd_get ("get", (ar_size ((void *)argv, 0, sizeof (char *)) - 1), argv);
385
386 ar_free ((void **)&argv, 0);
387 lim_free (0, revspec_copy);
388 lim_free (0, path_to_subtree_copy);
389 }
390
391 if (status)
392 {
393 safe_printfmt (2, "unable to build %s at %s\n", revspec, path_to_subtree);
394 exit (status);
395 }
396
397 lim_free (0, path_to_subtree);
398 lim_free (0, path_to_subtree_dir);
399 }
400
401 if (params->release_id)
402 {
403 int errn;
404 t_uchar * tree_version = 0;
405 t_uchar * tree_revision = 0;
406 t_uchar * release_id_file = 0;
407 rel_table snapped_config = rel_table_nil;
408 int out_fd;
409
410 tree_version = arch_tree_version (tree_root);
411 if (tree_version)
412 {
413 t_uchar * archive = 0;
414 t_uchar * version = 0;
415 t_uchar * level = 0;
416
417 archive = arch_parse_package_name (arch_ret_archive, 0, tree_version);
418 version = arch_parse_package_name (arch_ret_non_archive, 0, tree_version);
419
420 level = arch_highest_patch_level (tree_root, archive, version);
421
422 tree_revision = str_alloc_cat_many (0, tree_version, "--", level, str_end);
423
424 lim_free (0, archive);
425 lim_free (0, version);
426 lim_free (0, level);
427 }
428
429 snapped_config = arch_config_from_tree (tree_root, config);
430
431 release_id_file = file_name_in_vicinity (0, tree_root, "=RELEASE-ID");
432
433 invariant (!vu_unlink (&errn, release_id_file) || (errn == ENOENT));
434 out_fd = safe_open (release_id_file, O_WRONLY | O_CREAT | O_EXCL, 0666);
435
436 safe_printfmt (out_fd, "# automatically generated release id (by tla build-config)\n");
437 safe_printfmt (out_fd, "#\n");
438 safe_printfmt (out_fd, "\n");
439 safe_printfmt (out_fd, "%s(%s)\n", (tree_revision ? tree_revision : (t_uchar *)"<no tree version set>"), config_name);
440 safe_printfmt (out_fd, "\n");
441
442 rel_print_pika_escape_iso8859_1_table (out_fd, arch_escape_classes, snapped_config);
443
444 safe_close (out_fd);
445
446 lim_free (0, tree_version);
447 lim_free (0, tree_revision);
448 lim_free (0, release_id_file);
449 rel_free_table (snapped_config);
450 }
451
452
453 rel_free_table (config);
454 }
455
456
457
458 /* tag: Tom Lord Fri May 30 00:05:24 2003 (configs.c)
459 */
460