dphase - Stabilization
[dragonfly.git] / usr.bin / dsynth / repo.c
CommitLineData
8e25f19b
MD
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
1645cafe
MD
39typedef struct pinfo {
40 struct pinfo *next;
41 char *spath;
42 int foundit;
43} pinfo_t;
44
45static int pinfocmp(const void *s1, const void *s2);
46static void scanit(const char *path, const char *subpath,
47 int *countp, pinfo_t ***list_tailp);
48pinfo_t *pinfofind(pinfo_t **ary, int count, char *spath);
f7f25838 49static void scandeletenew(const char *path);
1645cafe 50
8e25f19b 51void
1645cafe 52DoRebuildRepo(int ask)
8e25f19b 53{
1645cafe
MD
54 char *buf;
55
56 if (ask) {
57 if (askyn("Rebuild the repository? ") == 0)
58 return;
59 }
f7f25838
MD
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 */
1645cafe
MD
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 }
8e25f19b
MD
76}
77
78void
79DoUpgradePkgs(pkg_t *pkgs __unused, int ask __unused)
80{
81 dfatal("Not Implemented");
82}
83
84void
1645cafe 85PurgeDistfiles(pkg_t *pkgs)
8e25f19b 86{
1645cafe
MD
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);
8e25f19b
MD
168}
169
170void
171RemovePackages(pkg_t *pkgs __unused)
172{
173 dfatal("Not Implemented");
174}
1645cafe
MD
175
176static int
177pinfocmp(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
185pinfo_t *
186pinfofind(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
211void
212scanit(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 }
1645cafe
MD
245 } else if (S_ISREG(st.st_mode)) {
246 item = calloc(1, sizeof(*item));
247 if (subpath) {
248 asprintf(&item->spath, "%s/%s",
249 subpath, den->d_name);
250 } else {
251 item->spath = strdup(den->d_name);
252 }
253 **list_tailp = item;
254 *list_tailp = &item->next;
255 ++*countp;
256 ddprintf(0, "scan %s\n", item->spath);
1645cafe 257 }
6a3a20b1 258 free(npath);
1645cafe
MD
259 }
260 closedir(dir);
261 }
262}
f7f25838
MD
263
264/*
265 * This removes any .new files left over in the repo. These can wind
266 * being left around when dsynth is killed.
267 */
268static void
269scandeletenew(const char *path)
270{
271 struct dirent *den;
272 const char *ptr;
273 DIR *dir;
274 char *buf;
275
276 if ((dir = opendir(path)) == NULL)
277 dfatal_errno("Cannot scan directory %s", path);
278 while ((den = readdir(dir)) != NULL) {
279 if ((ptr = strrchr(den->d_name, '.')) != NULL &&
280 strcmp(ptr, ".new") == 0) {
281 asprintf(&buf, "%s/%s", path, den->d_name);
282 if (remove(buf) < 0)
283 dfatal_errno("remove: Garbage %s\n", buf);
284 printf("Deleted Garbage %s\n", buf);
285 free(buf);
286 }
287 }
288 closedir(dir);
289}