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