dsynth - Fleshout functions
[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
50 void
51 DoRebuildRepo(int ask)
52 {
53         char *buf;
54
55         if (ask) {
56                 if (askyn("Rebuild the repository? ") == 0)
57                         return;
58         }
59         asprintf(&buf, "pkg repo -o %s %s", PackagesPath, RepositoryPath);
60         printf("Rebuilding repository\n");
61         if (system(buf)) {
62                 printf("Rebuild failed\n");
63         } else {
64                 printf("Rebuild succeeded\n");
65         }
66 }
67
68 void
69 DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused)
70 {
71         dfatal("Not Implemented");
72 }
73
74 void
75 PurgeDistfiles(pkg_t *pkgs)
76 {
77         pinfo_t *list;
78         pinfo_t *item;
79         pinfo_t **list_tail;
80         pinfo_t **ary;
81         char *dstr;
82         char *buf;
83         int count;
84         int delcount;
85         int i;
86
87         printf("Scanning distfiles... ");
88         fflush(stdout);
89         count = 0;
90         list = NULL;
91         list_tail = &list;
92         scanit(DistFilesPath, NULL, &count, &list_tail);
93         printf("Checking %d distfiles\n", count);
94         fflush(stdout);
95
96         ary = calloc(count, sizeof(pinfo_t *));
97         for (i = 0; i < count; ++i) {
98                 ary[i] = list;
99                 list = list->next;
100         }
101         ddassert(list == NULL);
102         qsort(ary, count, sizeof(pinfo_t *), pinfocmp);
103
104         for (; pkgs; pkgs = pkgs->bnext) {
105                 if (pkgs->distfiles == NULL || pkgs->distfiles[0] == 0)
106                         continue;
107                 ddprintf(0, "distfiles %s\n", pkgs->distfiles);
108                 dstr = strtok(pkgs->distfiles, " \t");
109                 while (dstr) {
110                         for (;;) {
111                                 if (pkgs->distsubdir && pkgs->distsubdir[0]) {
112                                         asprintf(&buf, "%s/%s",
113                                                  pkgs->distsubdir, dstr);
114                                         item = pinfofind(ary, count, buf);
115                                         ddprintf(0, "TEST %s %p\n", buf, item);
116                                         free(buf);
117                                         buf = NULL;
118                                 } else {
119                                         item = pinfofind(ary, count, dstr);
120                                         ddprintf(0, "TEST %s %p\n", dstr, item);
121                                 }
122                                 if (item) {
123                                         item->foundit = 1;
124                                         break;
125                                 }
126                                 if (strrchr(dstr, ':') == NULL)
127                                         break;
128                                 *strrchr(dstr, ':') = 0;
129                         }
130                         dstr = strtok(NULL, " \t");
131                 }
132         }
133
134         delcount = 0;
135         for (i = 0; i < count; ++i) {
136                 item = ary[i];
137                 if (item->foundit == 0) {
138                         ++delcount;
139                 }
140         }
141         if (askyn("Delete %d of %d items? ", delcount, count)) {
142                 printf("Deleting %d/%d obsolete source distfiles\n",
143                        delcount, count);
144                 for (i = 0; i < count; ++i) {
145                         item = ary[i];
146                         if (item->foundit == 0) {
147                                 asprintf(&buf, "%s/%s",
148                                          DistFilesPath, item->spath);
149                                 if (remove(buf) < 0)
150                                         printf("Cannot delete %s\n", buf);
151                                 free(buf);
152                         }
153                 }
154         }
155
156
157         free(ary);
158 }
159
160 void
161 RemovePackages(pkg_t *pkgs __unused)
162 {
163         dfatal("Not Implemented");
164 }
165
166 static int
167 pinfocmp(const void *s1, const void *s2)
168 {
169         const pinfo_t *item1 = *(const pinfo_t *const*)s1;
170         const pinfo_t *item2 = *(const pinfo_t *const*)s2;
171
172         return (strcmp(item1->spath, item2->spath));
173 }
174
175 pinfo_t *
176 pinfofind(pinfo_t **ary, int count, char *spath)
177 {
178         pinfo_t *item;
179         int res;
180         int b;
181         int e;
182         int m;
183
184         b = 0;
185         e = count;
186         while (b != e) {
187                 m = b + (e - b) / 2;
188                 item = ary[m];
189                 res = strcmp(spath, item->spath);
190                 if (res == 0)
191                         return item;
192                 if (res < 0) {
193                         e = m;
194                 } else {
195                         b = m + 1;
196                 }
197         }
198         return NULL;
199 }
200
201 void
202 scanit(const char *path, const char *subpath,
203        int *countp, pinfo_t ***list_tailp)
204 {
205         struct dirent *den;
206         pinfo_t *item;
207         char *npath;
208         char *spath;
209         DIR *dir;
210         struct stat st;
211
212         if ((dir = opendir(path)) != NULL) {
213                 while ((den = readdir(dir)) != NULL) {
214                         if (den->d_namlen == 1 && den->d_name[0] == '.')
215                                 continue;
216                         if (den->d_namlen == 2 && den->d_name[0] == '.' &&
217                             den->d_name[1] == '.')
218                                 continue;
219                         asprintf(&npath, "%s/%s", path, den->d_name);
220                         if (lstat(npath, &st) < 0) {
221                                 free(npath);
222                                 continue;
223                         }
224                         if (S_ISDIR(st.st_mode)) {
225                                 if (subpath) {
226                                         asprintf(&spath, "%s/%s",
227                                                  subpath, den->d_name);
228                                         scanit(npath, spath,
229                                                countp, list_tailp);
230                                         free(spath);
231                                 } else {
232                                         scanit(npath, den->d_name,
233                                                countp, list_tailp);
234                                 }
235                                 free(npath);
236                         } else if (S_ISREG(st.st_mode)) {
237                                 item = calloc(1, sizeof(*item));
238                                 if (subpath) {
239                                         asprintf(&item->spath, "%s/%s",
240                                                  subpath, den->d_name);
241                                 } else {
242                                         item->spath = strdup(den->d_name);
243                                 }
244                                 **list_tailp = item;
245                                 *list_tailp = &item->next;
246                                 ++*countp;
247                                 ddprintf(0, "scan   %s\n", item->spath);
248                         } else {
249                                 free(npath);
250                         }
251                 }
252                 closedir(dir);
253         }
254 }