0f28f8a1db8b05c1fd9518e4d935904956ff8654
[dragonfly.git] / usr.bin / dsynth / repo.c
1 /*
2  * Copyright (c) 2019 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * This code uses concepts and configuration based on 'synth', by
8  * John R. Marino <draco@marino.st>, which was written in ada.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in
18  *    the documentation and/or other materials provided with the
19  *    distribution.
20  * 3. Neither the name of The DragonFly Project nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific, prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
34  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 #include "dsynth.h"
38
39 typedef struct pinfo {
40         struct pinfo *next;
41         char *spath;
42         int foundit;
43 } pinfo_t;
44
45 static int pinfocmp(const void *s1, const void *s2);
46 static void scanit(const char *path, const char *subpath,
47                         int *countp, pinfo_t ***list_tailp);
48 pinfo_t *pinfofind(pinfo_t **ary, int count, char *spath);
49 static void scandeletenew(const char *path);
50
51 void
52 DoRebuildRepo(int ask)
53 {
54         char *buf;
55
56         if (ask) {
57                 if (askyn("Rebuild the repository? ") == 0)
58                         return;
59         }
60
61         /*
62          * Scan the repository for temporary .new files and delete them.
63          */
64         scandeletenew(RepositoryPath);
65
66         /*
67          * Issue the repo command to rebuild the repo
68          */
69         asprintf(&buf, "pkg repo -o %s %s", PackagesPath, RepositoryPath);
70         printf("Rebuilding repository\n");
71         if (system(buf)) {
72                 printf("Rebuild failed\n");
73         } else {
74                 printf("Rebuild succeeded\n");
75         }
76 }
77
78 void
79 DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused)
80 {
81         dfatal("Not Implemented");
82 }
83
84 void
85 PurgeDistfiles(pkg_t *pkgs)
86 {
87         pinfo_t *list;
88         pinfo_t *item;
89         pinfo_t **list_tail;
90         pinfo_t **ary;
91         char *dstr;
92         char *buf;
93         int count;
94         int delcount;
95         int i;
96
97         printf("Scanning distfiles... ");
98         fflush(stdout);
99         count = 0;
100         list = NULL;
101         list_tail = &list;
102         scanit(DistFilesPath, NULL, &count, &list_tail);
103         printf("Checking %d distfiles\n", count);
104         fflush(stdout);
105
106         ary = calloc(count, sizeof(pinfo_t *));
107         for (i = 0; i < count; ++i) {
108                 ary[i] = list;
109                 list = list->next;
110         }
111         ddassert(list == NULL);
112         qsort(ary, count, sizeof(pinfo_t *), pinfocmp);
113
114         for (; pkgs; pkgs = pkgs->bnext) {
115                 if (pkgs->distfiles == NULL || pkgs->distfiles[0] == 0)
116                         continue;
117                 ddprintf(0, "distfiles %s\n", pkgs->distfiles);
118                 dstr = strtok(pkgs->distfiles, " \t");
119                 while (dstr) {
120                         for (;;) {
121                                 if (pkgs->distsubdir && pkgs->distsubdir[0]) {
122                                         asprintf(&buf, "%s/%s",
123                                                  pkgs->distsubdir, dstr);
124                                         item = pinfofind(ary, count, buf);
125                                         ddprintf(0, "TEST %s %p\n", buf, item);
126                                         free(buf);
127                                         buf = NULL;
128                                 } else {
129                                         item = pinfofind(ary, count, dstr);
130                                         ddprintf(0, "TEST %s %p\n", dstr, item);
131                                 }
132                                 if (item) {
133                                         item->foundit = 1;
134                                         break;
135                                 }
136                                 if (strrchr(dstr, ':') == NULL)
137                                         break;
138                                 *strrchr(dstr, ':') = 0;
139                         }
140                         dstr = strtok(NULL, " \t");
141                 }
142         }
143
144         delcount = 0;
145         for (i = 0; i < count; ++i) {
146                 item = ary[i];
147                 if (item->foundit == 0) {
148                         ++delcount;
149                 }
150         }
151         if (askyn("Delete %d of %d items? ", delcount, count)) {
152                 printf("Deleting %d/%d obsolete source distfiles\n",
153                        delcount, count);
154                 for (i = 0; i < count; ++i) {
155                         item = ary[i];
156                         if (item->foundit == 0) {
157                                 asprintf(&buf, "%s/%s",
158                                          DistFilesPath, item->spath);
159                                 if (remove(buf) < 0)
160                                         printf("Cannot delete %s\n", buf);
161                                 free(buf);
162                         }
163                 }
164         }
165
166
167         free(ary);
168 }
169
170 void
171 RemovePackages(pkg_t *pkgs __unused)
172 {
173         dfatal("Not Implemented");
174 }
175
176 static int
177 pinfocmp(const void *s1, const void *s2)
178 {
179         const pinfo_t *item1 = *(const pinfo_t *const*)s1;
180         const pinfo_t *item2 = *(const pinfo_t *const*)s2;
181
182         return (strcmp(item1->spath, item2->spath));
183 }
184
185 pinfo_t *
186 pinfofind(pinfo_t **ary, int count, char *spath)
187 {
188         pinfo_t *item;
189         int res;
190         int b;
191         int e;
192         int m;
193
194         b = 0;
195         e = count;
196         while (b != e) {
197                 m = b + (e - b) / 2;
198                 item = ary[m];
199                 res = strcmp(spath, item->spath);
200                 if (res == 0)
201                         return item;
202                 if (res < 0) {
203                         e = m;
204                 } else {
205                         b = m + 1;
206                 }
207         }
208         return NULL;
209 }
210
211 void
212 scanit(const char *path, const char *subpath,
213        int *countp, pinfo_t ***list_tailp)
214 {
215         struct dirent *den;
216         pinfo_t *item;
217         char *npath;
218         char *spath;
219         DIR *dir;
220         struct stat st;
221
222         if ((dir = opendir(path)) != NULL) {
223                 while ((den = readdir(dir)) != NULL) {
224                         if (den->d_namlen == 1 && den->d_name[0] == '.')
225                                 continue;
226                         if (den->d_namlen == 2 && den->d_name[0] == '.' &&
227                             den->d_name[1] == '.')
228                                 continue;
229                         asprintf(&npath, "%s/%s", path, den->d_name);
230                         if (lstat(npath, &st) < 0) {
231                                 free(npath);
232                                 continue;
233                         }
234                         if (S_ISDIR(st.st_mode)) {
235                                 if (subpath) {
236                                         asprintf(&spath, "%s/%s",
237                                                  subpath, den->d_name);
238                                         scanit(npath, spath,
239                                                countp, list_tailp);
240                                         free(spath);
241                                 } else {
242                                         scanit(npath, den->d_name,
243                                                countp, list_tailp);
244                                 }
245                                 free(npath);
246                         } else if (S_ISREG(st.st_mode)) {
247                                 item = calloc(1, sizeof(*item));
248                                 if (subpath) {
249                                         asprintf(&item->spath, "%s/%s",
250                                                  subpath, den->d_name);
251                                 } else {
252                                         item->spath = strdup(den->d_name);
253                                 }
254                                 **list_tailp = item;
255                                 *list_tailp = &item->next;
256                                 ++*countp;
257                                 ddprintf(0, "scan   %s\n", item->spath);
258                         } else {
259                                 free(npath);
260                         }
261                 }
262                 closedir(dir);
263         }
264 }
265
266 /*
267  * This removes any .new files left over in the repo.  These can wind
268  * being left around when dsynth is killed.
269  */
270 static void
271 scandeletenew(const char *path)
272 {
273         struct dirent *den;
274         const char *ptr;
275         DIR *dir;
276         char *buf;
277
278         if ((dir = opendir(path)) == NULL)
279                 dfatal_errno("Cannot scan directory %s", path);
280         while ((den = readdir(dir)) != NULL) {
281                 if ((ptr = strrchr(den->d_name, '.')) != NULL &&
282                     strcmp(ptr, ".new") == 0) {
283                         asprintf(&buf, "%s/%s", path, den->d_name);
284                         if (remove(buf) < 0)
285                                 dfatal_errno("remove: Garbage %s\n", buf);
286                         printf("Deleted Garbage %s\n", buf);
287                         free(buf);
288                 }
289         }
290         closedir(dir);
291 }