Merge lp:~apw/britney/britney1-ubuntu--fix-bug-blocks into lp:britney
- britney1-ubuntu--fix-bug-blocks
- Merge into britney2
Status: | Superseded |
---|---|
Proposed branch: | lp:~apw/britney/britney1-ubuntu--fix-bug-blocks |
Merge into: | lp:britney |
Diff against target: |
7386 lines (+7242/-0) 28 files modified
README (+104/-0) britney (+584/-0) fauxpkg/FauxPackages (+69/-0) fauxpkg/README (+50/-0) fauxpkg/fauxpkg.py (+193/-0) fauxpkg/noremove.d/README (+3/-0) scripts/backlog-report (+95/-0) scripts/ood_report.py (+101/-0) scripts/udeb-report (+49/-0) update_out/.gitignore (+6/-0) update_out/Makefile (+33/-0) update_out/README (+32/-0) update_out/assert.c (+11/-0) update_out/britney-py.c (+871/-0) update_out/checklib.c (+185/-0) update_out/dpkg-lib.cpp (+34/-0) update_out/dpkg.c (+2013/-0) update_out/dpkg.h (+207/-0) update_out/freelist.c (+188/-0) update_out/freelist.h (+14/-0) update_out/index.html (+18/-0) update_out/memory.c (+389/-0) update_out/memory.h (+47/-0) update_out/memory2.c (+20/-0) update_out/memory3.c (+209/-0) update_out/templates.h (+277/-0) update_out/thoughts (+13/-0) update_out/update_out.py (+1427/-0) |
To merge this branch: | bzr merge lp:~apw/britney/britney1-ubuntu--fix-bug-blocks |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Package Archive Administrators | Pending | ||
Review via email: mp+380628@code.launchpad.net |
Commit message
When searching against a distribution we only actually will find tasks on
bugs open against development. This leads us to miss bugs which either
have a closed development task or have no development task at all. This
affects bugs in then development series which have no general development
task, and those nominated to older series and have a closed development
task. In particular these forms are seen with kernel tracking bugs.
Enhance the blocking bug search to search in both the distribution and
the associated series.
This has been run in unit-test against development and produces the same
block list there. It has been tested against the current live stable
releases and seems to produce believeable block lists, and significantly
longer ones in those releases.
Description of the change
Unmerged revisions
- 329. By Andy Whitcroft
-
britney: identify bug blocks against the nominated series as well as devel
When searching against a distribution we only actually will find tasks on
bugs open against development. This leads us to miss bugs which either
have a closed development task or have no development task at all. This
affects bugs in then development series which have no general development
task, and those nominated to older series and have a closed development
task. In particular these forms are seen with kernel tracking bugs.Enhance the blocking bug search to search in both the distribution and the
associated series.This has been run in unit-test against development and produces the same
block list there. It has been tested against the current live stable
releases and seems to produce believeable block lists, and significantly
longer ones in those releases.Signed-off-by: Andy Whitcroft <email address hidden>
- 328. By Adam Conrad
-
eoan -> focal
- 327. By Adam Conrad
-
[rbalint, r=adconrad] List bugs tagged as update-
excuse( -<release> ) in ExcuseBugs - 326. By Łukasz Zemczak
-
Once again enable sru-regression e-mails.
- 325. By Iain Lane
-
turn off sru-regression emails
they are sending false positives and Łukasz is going to look into it
- 324. By Iain Lane
-
fauxpkg.py: Check all directories for packages
If a package exists in the release pocket, we should not write a faux package
just because it doesn't exist in proposed. - 323. By Iain Lane
-
fauxpkg.py: Don't look at source names
Faux packages are *binary* package names. When considering if there are
duplicates, we should only look at the binaries in the input Packages file and
not the sources as we have been previously doing. - 322. By Iain Lane
-
fauxpkg.py: Print the full path when skipping FauxPackage entries
there's something wrong here - we're skipping things we shouldn't be; would be
helpful to see what's going wrong - 321. By Iain Lane
-
Put the gnome-shell FauxPackage back
We still need this on eoan. It shouldn't break other releases any more, since
r319. If it does, let's fix that instead. - 320. By Łukasz Zemczak
-
Switch off the dry-run enforcement for sru regression notification.
Preview Diff
1 | === added file 'README' |
2 | --- README 1970-01-01 00:00:00 +0000 |
3 | +++ README 2020-03-12 14:58:23 +0000 |
4 | @@ -0,0 +1,104 @@ |
5 | +Britney is run from /org/release.debian.org/britney. Some notes about |
6 | +how it works, what to do and what not: |
7 | + |
8 | + * the code is in code/b1, which is a git repo. Changes must be |
9 | + approved by Release Managers first, and all changes must be commited |
10 | + (i.e. nothing uncommited is allowed there). |
11 | + |
12 | + Commit emails will be send to britney@release.debian.org, you can |
13 | + subscribe to that if you want them (along with cron mail from |
14 | + britney). |
15 | + |
16 | + * the main script is code/b1/britney. It accepts a list of "actions" |
17 | + to perform. See ~release/etc/crontab.release for the default list, |
18 | + and see the "Actions" and "Re-running" sections below. |
19 | + |
20 | + * input/ contains FauxPackages, edit if if you need, and an urgencies/ |
21 | + subdirectory where dinstall places a summary of the uploads of that |
22 | + day. |
23 | + |
24 | + * Heidi/, ssh/: see the "save" action below. |
25 | + |
26 | + * d-i/: udeb handling is done by the release team too. See d-i/README |
27 | + for details (when Dato writes it; Dato takes care of udebs until then). |
28 | + |
29 | + |
30 | +Actions |
31 | +======= |
32 | + |
33 | +The main actions (read, the ones that are invoked from cron) are: |
34 | + |
35 | + * urgencies: updates var/data/testing/Urgency with the data provided |
36 | + by dinstall. |
37 | + |
38 | + * bugs: fetches bug counts from bugs.debian.org. |
39 | + |
40 | + * pkglists: generates all needed Packages files according to the |
41 | + latest dinstall. |
42 | + |
43 | + * run: the main action, running the update_out.py script. Takes |
44 | + hints, packages files, and tries to migrate stuff. When done, it |
45 | + writes a HeidiResult file used by "save" below *and rewrites the |
46 | + var/data/testing/Packags_* files*. That is important. |
47 | + |
48 | + * save: commits the HeidiResult provided by update_out above. This is |
49 | + done by: |
50 | + |
51 | + - taking HeidiResult, stripping unwanted stuff (faux packages), |
52 | + and put the result into a file under Heidi/set, named after the |
53 | + current timestamp. |
54 | + |
55 | + - changing the "current" symlink under Heidi/set to point to this |
56 | + new file, gzipping the previous current. |
57 | + |
58 | + - signaling ftpmaster scripts to import the new file. This is done |
59 | + with a ssh trigger, whose key is in ssh/. |
60 | + |
61 | + IF YOU NEED TO UNDO ONE IMPORT: gunzip the previous file, point |
62 | + the "current" symlink to it, and: |
63 | + |
64 | + % ssh -2 -i % ~release/britney/ssh/ftp-master_trigger_key dak@ries.debian.org |
65 | + |
66 | + * stats: copies the resulting update.OUTPUT and update.EXCUSES files |
67 | + to www/britney, and checks for uninstallabilities. |
68 | + |
69 | + |
70 | +Re-running |
71 | +========== |
72 | + |
73 | +Re-runs can be incremental or not: |
74 | + |
75 | + * incremental means that you run britney against the results of the |
76 | + previous run. This is done by just issuing `./britney run`. |
77 | + |
78 | + WARNING: even if you don't save the results of an incremental |
79 | + re-run, following re-runs will start with the state the previous one |
80 | + left. This means it's a very very bad idea to use incremental |
81 | + re-runs to test force-hint hints; please always use a private |
82 | + britney instead. |
83 | + |
84 | + * non-incremental means that you start from scratch against the state |
85 | + of the previous install. To do this, you need to do "pkglists" prior |
86 | + to "run". |
87 | + |
88 | + IF THERE WERE ANY SUCCESSFUL HINTS IN THE PREVIOUS RUN, YOU MUST |
89 | + CHECK WITH THEIR OWNERS WHETHER IT'S OK TO RUN FROM SCRATCH. Or, in |
90 | + the worst case, you should check whether they have cleaned up their |
91 | + hints already, since in that case their work will be lost. |
92 | + |
93 | + (For this reason it's not very wise to clean your hints before your |
94 | + stuff is dinstalled.) |
95 | + |
96 | +If you're satisfied with the result of your re-run, run `./britney save`. |
97 | + |
98 | + |
99 | +Private britneys |
100 | +================ |
101 | + |
102 | +It is ok to run private britneys if you nice them, though Ganneff |
103 | +prefers if you don't do it while dinstall is running. |
104 | + |
105 | +Do NOT run your britney against britney/var/data directly, use a |
106 | +copy of your own. |
107 | + |
108 | +TODO(dato): Some HOWTO here. |
109 | |
110 | === added file 'britney' |
111 | --- britney 1970-01-01 00:00:00 +0000 |
112 | +++ britney 2020-03-12 14:58:23 +0000 |
113 | @@ -0,0 +1,584 @@ |
114 | +#!/bin/bash |
115 | + |
116 | +set -e |
117 | +set -u |
118 | + |
119 | +ulimit -d 8000000 -m 8000000 -v 8000000 |
120 | +umask 002 |
121 | + |
122 | + |
123 | +OPTIONS="$@" |
124 | +qoption () { |
125 | + for a in $OPTIONS; do if [ "$a" = "$1" ]; then return 0; fi; done |
126 | + return 1 |
127 | +} |
128 | + |
129 | +option () { |
130 | + for a in $OPTIONS; do if [ "$a" = "$1" ]; then date -uR; return 0; fi; done |
131 | + return 1 |
132 | +} |
133 | + |
134 | +LP_SERVICE="${LP_SERVICE:-production}" |
135 | +DISTRIBUTION="${DISTRIBUTION:-ubuntu}" |
136 | +DEFAULT_SERIES=focal |
137 | +SERIES="${SERIES:-$DEFAULT_SERIES}" |
138 | + |
139 | +# DATE |
140 | +NOW=`date +"%F/%T" -u` |
141 | + |
142 | +# Dirs: |
143 | +BASE=/home/ubuntu-archive/proposed-migration |
144 | +DAK_LOCKDIR=/srv/ftp-master.debian.org/lock |
145 | +FTP_MIRROR=/home/ubuntu-archive/mirror/$DISTRIBUTION |
146 | + |
147 | +D_I=$BASE/d-i |
148 | +VAR=$BASE/var |
149 | +SSH=$BASE/ssh |
150 | +HEIDI=$BASE/Heidi |
151 | +INPUT=$BASE/input |
152 | +CODE=$BASE/code/b1 |
153 | + |
154 | +DATA=$VAR/data |
155 | +LOCKDIR=$VAR/lock |
156 | +HEIDI_SET=$HEIDI/set |
157 | +SCRIPTS=$CODE/scripts |
158 | +FAUXDIR=$CODE/fauxpkg |
159 | +UPDATE_OUT=$CODE/update_out |
160 | +URGENCIES=$INPUT/urgencies |
161 | + |
162 | +LOCK=$LOCKDIR/britney-$DISTRIBUTION-$SERIES.lock |
163 | +DAK_LOCK=$DAK_LOCKDIR/daily.lock |
164 | +DAK_STOP=$DAK_LOCKDIR/archive.stop |
165 | + |
166 | +TESTING=$DATA/$SERIES |
167 | +UNSTABLE=$DATA/$SERIES-proposed |
168 | +TPU=$DATA/testing-proposed-updates |
169 | + |
170 | +FAUXPKG_SCRIPT=$FAUXDIR/fauxpkg.py |
171 | +SSH_KEY=$SSH/ftp-master_trigger_key |
172 | + |
173 | +HTML=/home/ubuntu-archive/public_html/proposed-migration |
174 | +if [ "$DISTRIBUTION" != ubuntu ]; then |
175 | + HTML="$HTML/$DISTRIBUTION" |
176 | +fi |
177 | +BOOTSTRAP_DIR=/home/ubuntu-archive/public_html/bootstrap |
178 | + |
179 | +# Britney 2 |
180 | +DATA_B2=$VAR/data-b2 |
181 | +CODE_B2=$BASE/code/b2 |
182 | +B2_OUTPUT=$DATA_B2/output |
183 | +B2_CONFIG=${B2_CONFIG:-$CODE_B2/britney.conf} |
184 | +B2_CONFIG_NOBREAKALL=${B2_CONFIG_NOBREAKALL:-$CODE_B2/britney_nobreakall.conf} |
185 | +B2_AMQP_PASSWORD="$(cat $BASE/amqp-password.txt)" |
186 | + |
187 | +if [ -f $DAK_STOP ]; then |
188 | + echo "$DAK_STOP exists, not running" |
189 | + exit 1 |
190 | +fi |
191 | + |
192 | +# 10800 seconds = 3 hours |
193 | +# 129600 seconds = 36 hours |
194 | +if ! lockfile -r0 -l129600 $LOCK 2>/dev/null >/dev/null; then |
195 | + echo "Could not get britney lockfile!" |
196 | + ls -l "$LOCK" |
197 | + exit 1 |
198 | +fi |
199 | + |
200 | +trap exit_function 0 |
201 | +exit_function () { |
202 | + rm -f $LOCK |
203 | +} |
204 | + |
205 | +#eval $( dak admin config db-shell ) |
206 | + |
207 | +suite_info () { |
208 | + python -c ' |
209 | +from __future__ import print_function |
210 | + |
211 | +import os |
212 | +import sys |
213 | + |
214 | +from launchpadlib.launchpad import Launchpad as _Launchpad |
215 | + |
216 | +# Work around non-multiple-instance-safety of launchpadlib (bug #459418). |
217 | +class Launchpad(_Launchpad): |
218 | + @classmethod |
219 | + def _get_paths(cls, service_root, launchpadlib_dir=None): |
220 | + service_root, launchpadlib_dir, cache_path, service_root_dir = ( |
221 | + _Launchpad._get_paths( |
222 | + service_root, launchpadlib_dir=launchpadlib_dir)) |
223 | + cache_path += "-proposed-migration" |
224 | + if not os.path.exists(cache_path): |
225 | + os.makedirs(cache_path, 0o700) |
226 | + return service_root, launchpadlib_dir, cache_path, service_root_dir |
227 | + |
228 | +launchpad = Launchpad.login_anonymously("proposed-migration", sys.argv[1]) |
229 | +distro = launchpad.distributions[sys.argv[2]] |
230 | +series_name = sys.argv[3].split("-")[0] |
231 | +series = distro.getSeries(name_or_version=series_name) |
232 | +'"$1" "$LP_SERVICE" "$DISTRIBUTION" "$2" |
233 | +} |
234 | + |
235 | +suite_arches () { |
236 | + suite_info 'print(" ".join(arch.architecture_tag for arch in series.architectures))' "$1" |
237 | +} |
238 | + |
239 | +suite_archindep () { |
240 | + suite_info 'print(series.nominatedarchindep.architecture_tag)' "$1" |
241 | +} |
242 | + |
243 | +if ! qoption allowdaklock; then |
244 | + while [ -f $DAK_LOCK ]; do |
245 | + echo `date` $DAK_LOCK exists. Sleeping in 10 more minutes. |
246 | + sleep 600 |
247 | + done |
248 | +fi |
249 | + |
250 | +urgencies () { |
251 | + echo URGENCIES: |
252 | + cd $BASE |
253 | + for u in $URGENCIES/install-urgencies-*; do |
254 | + [ -e "$u" ] || continue |
255 | + cat "$u" >> $1/$SERIES/Urgency # XXX I'd rather not have this in $DATA --dato |
256 | + rm "$u" |
257 | + done |
258 | +} |
259 | + |
260 | +if option urgencies; then |
261 | + urgencies $DATA_B2 |
262 | +fi |
263 | + |
264 | +bugs () { |
265 | + for suite in $SERIES $SERIES-proposed; do |
266 | + x="$1/${suite}/BugsV" |
267 | + wget --quiet -O "${x}.new" http://bugs.debian.org/release-critical/britney/${suite}-nr |
268 | + if [ -s ${x}.new ]; then mv ${x}.new $x; else rm $x.new; exit 1; fi |
269 | + done |
270 | +} |
271 | +if option bugs; then |
272 | + echo BUGS: |
273 | + bugs $DATA_B2 |
274 | +fi |
275 | + |
276 | +if option bugs_b1; then |
277 | + echo BUGS_B1: |
278 | + bugs $DATA |
279 | +fi |
280 | + |
281 | +if option bugs_b2; then |
282 | + echo BUGS_B2: |
283 | + bugs $DATA_B2 |
284 | +fi |
285 | + |
286 | +excuse_bugs() { |
287 | + tagged_bugs $1 update-excuse ExcuseBugs |
288 | +} |
289 | + |
290 | +blocks () { |
291 | + tagged_bugs $1 block-proposed Blocks |
292 | +} |
293 | + |
294 | +tagged_bugs () { |
295 | + local tag_template tags output_file |
296 | + tag_template=$2 |
297 | + output_file=$3 |
298 | + [ "$DISTRIBUTION" = ubuntu ] || return 0 |
299 | + mkdir -p "$1/$SERIES-proposed" |
300 | + if [ "$SERIES" = "$DEFAULT_SERIES" ]; then |
301 | + tags="$tag_template $tag_template-$SERIES" |
302 | + else |
303 | + tags="$tag_template-$SERIES" |
304 | + fi |
305 | + python -c ' |
306 | +from __future__ import print_function |
307 | + |
308 | +import calendar |
309 | +import os |
310 | +import sys |
311 | +try: |
312 | + from urllib.parse import urlsplit |
313 | +except ImportError: |
314 | + from urlparse import urlsplit |
315 | + |
316 | +from launchpadlib.launchpad import Launchpad as _Launchpad |
317 | + |
318 | +# Work around non-multiple-instance-safety of launchpadlib (bug #459418). |
319 | +class Launchpad(_Launchpad): |
320 | + @classmethod |
321 | + def _get_paths(cls, service_root, launchpadlib_dir=None): |
322 | + service_root, launchpadlib_dir, cache_path, service_root_dir = ( |
323 | + _Launchpad._get_paths( |
324 | + service_root, launchpadlib_dir=launchpadlib_dir)) |
325 | + cache_path += "-proposed-migration" |
326 | + if not os.path.exists(cache_path): |
327 | + os.makedirs(cache_path, 0o700) |
328 | + return service_root, launchpadlib_dir, cache_path, service_root_dir |
329 | + |
330 | +launchpad = Launchpad.login_with("proposed-migration", sys.argv[1]) |
331 | +distro = launchpad.distributions[sys.argv[2]] |
332 | +tags = sys.argv[3].split() |
333 | +series = distro.getSeries(name_or_version=sys.argv[4]) |
334 | +blocks = set() |
335 | +tasks = list(series.searchTasks(omit_targeted=False, tags=tags)) |
336 | +tasks += list(distro.searchTasks(omit_targeted=False, tags=tags)) |
337 | +block_detail = {} |
338 | +for task in tasks: |
339 | + target = task.target |
340 | + bug = task.bug |
341 | + if urlsplit(target.resource_type_link).fragment in ( |
342 | + "distribution_source_package", "source_package"): |
343 | + date = block_detail.get(bug.id) |
344 | + if date is None: |
345 | + for action in reversed( |
346 | + [a for a in bug.activity if a.whatchanged == "tags"]): |
347 | + oldtags = action.oldvalue.split() |
348 | + newtags = action.newvalue.split() |
349 | + gained_block = False |
350 | + for tag in tags: |
351 | + if tag not in oldtags and tag in newtags: |
352 | + gained_block = True |
353 | + break |
354 | + if gained_block: |
355 | + date = action.datechanged |
356 | + break |
357 | + else: |
358 | + date = bug.date_created |
359 | + block_detail[bug.id] = date |
360 | + blocks.add("%s %d %d" % |
361 | + (os.path.basename(target.self_link), bug.id, |
362 | + calendar.timegm(date.timetuple()))) |
363 | +print("\n".join(sorted(blocks))) |
364 | +' "$LP_SERVICE" "$DISTRIBUTION" "$tags" "$SERIES" >"$1/$SERIES-proposed/$output_file.new" |
365 | + mv "$1/$SERIES-proposed/$output_file.new" "$1/$SERIES-proposed/$output_file" |
366 | +} |
367 | +if option blocks; then |
368 | + echo BLOCKS: |
369 | + blocks $DATA_B2 |
370 | +fi |
371 | +if option excuse_bugs; then |
372 | + echo EXCUSE BUGS: |
373 | + excuse_bugs $DATA_B2 |
374 | +fi |
375 | + |
376 | +pkg_lists () { |
377 | + for suite in $SERIES $SERIES-proposed; do |
378 | + mkdir -p $1/$suite |
379 | + suite_dirs=$FTP_MIRROR/dists/$suite |
380 | + if [ "$suite" = "$SERIES" ]; then |
381 | + suite_dirs="$suite_dirs $FTP_MIRROR/dists/$SERIES-updates" |
382 | + fi |
383 | + >$1/$suite/Sources |
384 | + for suite_dir in $suite_dirs; do |
385 | + gzip -t $suite_dir/{main,restricted,universe,multiverse}/source/Sources.gz |
386 | + zcat $suite_dir/{main,restricted,universe,multiverse}/source/Sources.gz >>$1/$suite/Sources |
387 | + done |
388 | + for arch in `suite_arches $suite`; do |
389 | + >$1/$suite/Packages_$arch |
390 | + for suite_dir in $suite_dirs; do |
391 | + gzip -t $suite_dir/{main,restricted,universe,multiverse}/binary-$arch/Packages.gz |
392 | + zcat $suite_dir/{main,restricted,universe,multiverse}/binary-$arch/Packages.gz >>$1/$suite/Packages_$arch |
393 | + gzip -t $suite_dir/{main,restricted,universe,multiverse}/debian-installer/binary-$arch/Packages.gz |
394 | + zcat $suite_dir/{main,restricted,universe,multiverse}/debian-installer/binary-$arch/Packages.gz >>$1/$suite/Packages_$arch |
395 | + done |
396 | + done |
397 | + done |
398 | + $FAUXPKG_SCRIPT generate $1/$SERIES $1/$SERIES-proposed |
399 | +} |
400 | + |
401 | +lite_sync () { |
402 | + cat <<EOF | rsync -a --files-from=- $1 $2 |
403 | +$SERIES/Dates |
404 | +$SERIES/BugsV |
405 | +$SERIES/Urgency |
406 | +$SERIES-proposed/BugsV |
407 | +$SERIES-proposed/Hints |
408 | +EOF |
409 | + |
410 | +} |
411 | + |
412 | +if option pkglists; then |
413 | + echo PKGLISTS: |
414 | + cd $DATA_B2 |
415 | + pkg_lists $DATA_B2 |
416 | +fi |
417 | + |
418 | +if option sync_b2; then |
419 | + rsync -ar $DATA/ $DATA_B2 |
420 | +fi |
421 | + |
422 | +# Give options to run a b2 from scratch after b1 has finished |
423 | +if option pkglists_b2; then |
424 | + echo PKGLISTS_B2: |
425 | + cd $DATA_B2 |
426 | + pkg_lists $DATA_B2 |
427 | +fi |
428 | + |
429 | +if option pkglists_b1; then |
430 | + echo PKGLISTS_B1: |
431 | + cd $DATA |
432 | + pkg_lists $DATA |
433 | +fi |
434 | + |
435 | +if option sync_b2_lite; then |
436 | + lite_sync $DATA $DATA_B2 |
437 | +fi |
438 | + |
439 | +if option sync_b1; then |
440 | + rsync -ar $DATA_B2/ $DATA |
441 | +fi |
442 | + |
443 | +if option sync_b1_lite; then |
444 | + lite_sync $DATA_B2 $DATA |
445 | +fi |
446 | + |
447 | +make_hints_branch () { |
448 | + if [ -d "$1" ]; then |
449 | + bzr pull -q -d "$1" --remember --overwrite "$2" |
450 | + else |
451 | + bzr branch "$2" "$1" |
452 | + fi |
453 | +} |
454 | + |
455 | +if option hints_bzr; then |
456 | + echo HINTS_BZR: |
457 | + if [ "$DISTRIBUTION" = ubuntu ]; then |
458 | + if [ "$SERIES" = "$DEFAULT_SERIES" ]; then |
459 | + branch="lp:~ubuntu-release/britney/hints-ubuntu" |
460 | + else |
461 | + branch="lp:~ubuntu-sru/britney/hints-ubuntu-$SERIES" |
462 | + fi |
463 | + make_hints_branch "$DATA_B2/$SERIES-proposed/Hints" "$branch" |
464 | + if [ "$SERIES" = "$DEFAULT_SERIES" ]; then |
465 | + make_hints_branch \ |
466 | + "$DATA_B2/$SERIES-proposed/Hints/ubuntu-touch" \ |
467 | + "lp:~ubuntu-touch-release/britney/hints-ubuntu-touch" |
468 | + else |
469 | + rm -rf "$DATA_B2/$SERIES-proposed/Hints/ubuntu-touch" |
470 | + fi |
471 | + elif [ "$DISTRIBUTION" = ubuntu-rtm ]; then |
472 | + make_hints_branch \ |
473 | + "$DATA_B2/$SERIES-proposed/Hints" \ |
474 | + lp:~ubuntu-release/britney/hints-ubuntu-rtm |
475 | + fi |
476 | +fi |
477 | + |
478 | +run_b1 () { |
479 | + cd $UPDATE_OUT |
480 | + ./update_out.py $TESTING $UNSTABLE $TPU |
481 | +} |
482 | + |
483 | +b2_diff () { |
484 | + tmp_dir=`mktemp -d` |
485 | + master="b2" |
486 | + [ "$master" = "b1" ] && secondary="b2" || secondary="b1" |
487 | + (cd $tmp_dir |
488 | + |
489 | + sort $TESTING/HeidiResult >HeidiResult_b1 |
490 | + sort $B2_OUTPUT/$SERIES/HeidiResult >HeidiResult_b2 |
491 | + |
492 | + sed -e '/^<p>Generated: /d' $CODE/update_out/update.EXCUSES_py >excuses_b1.html |
493 | + sed -e '/^<p>Generated: /d' $B2_OUTPUT/$SERIES/excuses.html >excuses_b2.html |
494 | + |
495 | + touch -m -r $TESTING/HeidiResult HeidiResult_b1 |
496 | + touch -m -r $B2_OUTPUT/$SERIES/HeidiResult HeidiResult_b2 |
497 | + |
498 | + touch -m -r $CODE/update_out/update.EXCUSES_py excuses_b1.html |
499 | + touch -m -r $B2_OUTPUT/$SERIES/excuses.html excuses_b2.html |
500 | + |
501 | + # NB: If you remove the "head" below, add a "|| true"; otherwise |
502 | + # set -e may not allow the HeidiResult diff to execute. |
503 | + diff -u excuses_${master}.html excuses_${secondary}.html | head -n 1000 |
504 | + diff -u HeidiResult_${master} HeidiResult_${secondary} | head -n 1000) |
505 | + rm -rf $tmp_dir |
506 | +} |
507 | + |
508 | +b2_diff_with_mail () { |
509 | + b2_diff |
510 | + b2_diff | ifne mail -s "britney2 diff `date -u +'%Y-%m-%d %H:%M'`" \ |
511 | + -a "Reply-To: britney2@release.debian.org" britney2@release.debian.org |
512 | +} |
513 | + |
514 | +make_b2_config () { |
515 | + local arches archindep |
516 | + arches=`suite_arches $SERIES` |
517 | + archindep=`suite_archindep $SERIES` |
518 | + sed -e "s/^\\(ARCHITECTURES *= \\).*/\\1$arches/" \ |
519 | + -e "s/^\\(NOBREAKALL_ARCHES *= \\).*/\\1$archindep/" \ |
520 | + -e "/^ADT_AMQP/ s@:password@:${B2_AMQP_PASSWORD//@/\\@}@" \ |
521 | + "$1" >"$2" |
522 | + # precise does not yet have ppc64el |
523 | + if [ "$SERIES" = precise ]; then |
524 | + sed -i '/^ADT_ARCHES/ s/ppc64el//' "$2" |
525 | + fi |
526 | + # only do the email thing for the default series |
527 | + # |
528 | + # and |
529 | + # |
530 | + # only do SRU regression emails for the non default series |
531 | + if [ "$SERIES" != "$DEFAULT_SERIES" ]; then |
532 | + sed -i '/^EMAIL_ENABLE/ s/=.*$/= no/' "$2" |
533 | + sed -i '/^SRUREGRESSIONEMAIL_ENABLE/ s/=.*$/= yes/' "$2" |
534 | + fi |
535 | + case $arches in |
536 | + *s390x*) |
537 | + sed -i -e'/^ADT_ARCHES/ s/$/ s390x/' "$2" |
538 | + ;; |
539 | + esac |
540 | +} |
541 | + |
542 | +make_b2_notest_config () { |
543 | + sed -e '/^NONINST_STATUS/ s/ *$/-notest/' \ |
544 | + -e '/^EXCUSES_.*OUTPUT/ s%=.*$%= /dev/null%' \ |
545 | + -e '/^UPGRADE_OUTPUT/ s/output.txt/output_notest.txt/' \ |
546 | + -e '/^HEIDI_OUTPUT/ s/=.*$/=/' \ |
547 | + -e '/^ADT_ENABLE/ s/yes/no/' \ |
548 | + -e '/^EMAIL_ENABLE/ s/=.*$/= no/' \ |
549 | + "$1" > "$2" |
550 | +} |
551 | + |
552 | +run_b2 () { |
553 | + cd $BASE |
554 | + make_b2_config "$B2_CONFIG" "$B2_CONFIG.$DISTRIBUTION.$SERIES" |
555 | + $CODE_B2/britney.py -c "$B2_CONFIG.$DISTRIBUTION.$SERIES" -v --distribution=$DISTRIBUTION --series=$SERIES |
556 | + |
557 | + if [ "$SERIES" = "$DEFAULT_SERIES" ]; then |
558 | + # for the devel series we also want an output.txt without tests, to make |
559 | + # it easier to untangle library transitions |
560 | + make_b2_notest_config "$B2_CONFIG.$DISTRIBUTION.$SERIES" "$B2_CONFIG.$DISTRIBUTION.$SERIES.notest" |
561 | + $CODE_B2/britney.py -c "$B2_CONFIG.$DISTRIBUTION.$SERIES.notest" --distribution=$DISTRIBUTION --series=$SERIES >/dev/null |
562 | + else |
563 | + rm -f $DATA_B2/output/$SERIES/output_notest.txt |
564 | + fi |
565 | +} |
566 | + |
567 | +if option run; then |
568 | + echo RUN: |
569 | + run_b2 |
570 | +fi |
571 | + |
572 | +if option run_b1; then |
573 | + echo RUN_B1: |
574 | + run_b1 |
575 | + # assume that this will have been run after a "run" which is b2 |
576 | + b2_diff_with_mail |
577 | +fi |
578 | + |
579 | +if option run_b2; then |
580 | + echo RUN_B2: |
581 | + run_b2 |
582 | + b2_diff_with_mail |
583 | +fi |
584 | + |
585 | +if option b2_diff; then |
586 | + b2_diff |
587 | +fi |
588 | + |
589 | +lp_import() { |
590 | + # tell LP about the new delta |
591 | + promote-to-release -l "$LP_SERVICE" -d "$DISTRIBUTION" -s "$SERIES" -v "$1" |
592 | +} |
593 | + |
594 | +save () { |
595 | + cd $BASE |
596 | + echo RESULTS: |
597 | + # process a delta |
598 | + if [ "$1" = "b1" ]; then |
599 | + DELTA="$TESTING/HeidiResultDelta" |
600 | + else |
601 | + DELTA="$B2_OUTPUT/$SERIES/HeidiResultDelta" |
602 | + fi |
603 | + echo Using data from $DELTA |
604 | + lp_import "$DELTA" |
605 | + printf " done\n" |
606 | +} |
607 | + |
608 | +if option save_b1; then |
609 | + save b1 |
610 | +fi |
611 | +if option save || option save_b2; then |
612 | + save b2 |
613 | +fi |
614 | + |
615 | +create_uninst_report () { |
616 | + $CODE_B2/britney.py -c $1 --distribution=$DISTRIBUTION --series=$SERIES --print-uninst >$HTML/$2.new |
617 | + echo -e "\n# Generated: `date -uR`" >>$HTML/$2.new |
618 | + mv $HTML/$2.new $HTML/$2 |
619 | +} |
620 | + |
621 | +create_ood_report () { |
622 | + $SCRIPTS/ood_report.py $1 >$HTML/$2.new |
623 | + echo -e "\n# Generated: `date -uR`" >>$HTML/$2.new |
624 | + mv $HTML/$2.new $HTML/$2 |
625 | +} |
626 | + |
627 | +stats () { |
628 | + echo STATS: |
629 | + mkdir -p "$HTML/$SERIES" |
630 | + if [ "$1" = "b1" ]; then |
631 | + cp $UPDATE_OUT/update.EXCUSES_py $HTML/$SERIES/update_excuses.html |
632 | + cp $UPDATE_OUT/update.OUTPUT_py $HTML/$SERIES/update_output.txt |
633 | + else |
634 | + cp $DATA_B2/output/$SERIES/excuses.html $HTML/$SERIES/update_excuses.html |
635 | + cp $DATA_B2/output/$SERIES/excuses.yaml $HTML/$SERIES/update_excuses.yaml |
636 | + cp $DATA_B2/output/$SERIES/output.txt $HTML/$SERIES/update_output.txt |
637 | + if [ -e $DATA_B2/output/$SERIES/output_notest.txt ]; then |
638 | + cp $DATA_B2/output/$SERIES/output_notest.txt $HTML/$SERIES/update_output_notest.txt |
639 | + else |
640 | + rm -f $HTML/$SERIES/update_output_notest.txt |
641 | + fi |
642 | + cp $DATA_B2/$SERIES-proposed/Blocks $HTML/$SERIES/blocks.txt |
643 | + cp $DATA_B2/$SERIES-proposed/ExcuseBugs $HTML/$SERIES/excuse-bugs.txt || true |
644 | + fi |
645 | + #gzip -9 < $HTML/$SERIES/update_excuses.html > $HTML/$SERIES/update_excuses.html.gz |
646 | + #gzip -9 < $HTML/$SERIES/update_output.txt > $HTML/$SERIES/update_output.txt.gz |
647 | + mkdir -p "$HTML/update_output/$SERIES/${NOW%/*}" |
648 | + mkdir -p "$HTML/update_excuses/$SERIES/${NOW%/*}" |
649 | + gzip -9c $HTML/$SERIES/update_output.txt > $HTML/update_output/$SERIES/$NOW.txt.gz |
650 | + gzip -9c $HTML/$SERIES/update_excuses.html > $HTML/update_excuses/$SERIES/$NOW.html.gz |
651 | + gzip -9c $HTML/$SERIES/update_excuses.yaml > $HTML/update_excuses/$SERIES/$NOW.yaml.gz |
652 | + |
653 | + # TODO: {stable,unstable}_uninst.txt -- needs support in b2, talk to Fabio |
654 | + # TODO: this creates uninstallability reports against b2 results, not b1's |
655 | + make_b2_config "$B2_CONFIG" "$B2_CONFIG.$DISTRIBUTION.$SERIES" |
656 | + make_b2_config "$B2_CONFIG_NOBREAKALL" "$B2_CONFIG_NOBREAKALL.$DISTRIBUTION.$SERIES" |
657 | + create_uninst_report "$B2_CONFIG.$DISTRIBUTION.$SERIES" ${SERIES}_uninst.txt |
658 | + create_uninst_report "$B2_CONFIG_NOBREAKALL.$DISTRIBUTION.$SERIES" ${SERIES}_uninst_full.txt |
659 | + |
660 | + #if grep -q -e '-meta-faux' $HTML/testing_uninst.txt; then |
661 | + # echo >&2 'Warning! Some -meta-faux package is uninstallable!' |
662 | + #fi |
663 | + |
664 | + #create_ood_report $DATA_B2/stable stable_outdate.txt |
665 | + #create_ood_report $DATA_B2/testing testing_outdate.txt |
666 | + |
667 | + $SCRIPTS/backlog-report -o $HTML/$SERIES/update_excuses.csv $HTML/$SERIES/update_excuses.html |
668 | +} |
669 | + |
670 | +if option stats_b1; then |
671 | + stats b1 |
672 | +fi |
673 | +if option stats || option stats_b2; then |
674 | + stats b2 |
675 | +fi |
676 | + |
677 | +if option summary; then |
678 | + cd $BASE |
679 | + echo "Out of dates holding up testing:" |
680 | + TERM=vt100 w3m -dump $HTML/$SERIES/update_excuses.html | sed -n 's/^ *[^ ] *[^ ]*out of date on \([^ ]*\): .*$/\1/p' | sort | uniq -c | sort -n |
681 | + echo "Uninstallables holding up testing:" |
682 | + sed < $HTML/$SERIES/update_excuses.html -n 's/^ *<li>[^ ]* (\([^, ]*\),.*) uninstallable.*$/\1/p' | sort | uniq -c | sort -n |
683 | + #echo "wanna-build stats:" |
684 | + #for a in alpha arm hppa hurd-i386 i386 ia64 m68k mips mipsel powerpc s390 sparc; do |
685 | + # printf " %-12s " "$a:" |
686 | + # /srv/wanna-build/bin/wanna-build-statistics --database=$a/build-db | |
687 | + # grep "if also counting" || echo "-" |
688 | + #done |
689 | +fi |
690 | + |
691 | +if option archivedata; then |
692 | + echo ARCHIVE: |
693 | + cd $VAR |
694 | + tar czf data_bkup/data-$(date +"%Y.%m.%d").tgz data/{stable,testing,unstable,testing-proposed-updates} |
695 | +fi |
696 | + |
697 | +echo -n "Finished at: "; date -uR |
698 | |
699 | === added directory 'fauxpkg' |
700 | === added file 'fauxpkg/FauxPackages' |
701 | --- fauxpkg/FauxPackages 1970-01-01 00:00:00 +0000 |
702 | +++ fauxpkg/FauxPackages 2020-03-12 14:58:23 +0000 |
703 | @@ -0,0 +1,69 @@ |
704 | +Package: wine1.4-i386 |
705 | +Source: wine1.6 |
706 | +Version: ${unstable-version} |
707 | +Architecture: amd64 |
708 | +Provides: wine-i386 |
709 | +Multi-Arch: foreign |
710 | + |
711 | +Package: wine1.6-i386 |
712 | +Source: wine1.6 |
713 | +Version: ${unstable-version} |
714 | +Architecture: amd64 |
715 | +Provides: wine-i386 |
716 | +Multi-Arch: foreign |
717 | + |
718 | +Package: ocaml-mingw-w64-x86-64 |
719 | +Source: mingw-ocaml |
720 | +Version: ${unstable-version} |
721 | +Architecture: i386 |
722 | +Multi-Arch: foreign |
723 | + |
724 | +Package: claws-mail-extra-plugins-dbg |
725 | +Version: 1:1 |
726 | + |
727 | +Package: claws-mail-html2-viewer |
728 | +Version: 1:1 |
729 | + |
730 | +Package: ubuntu-emulator-images |
731 | +Source: android |
732 | +Version: ${unstable-version} |
733 | +Architecture: amd64 armhf |
734 | +Multi-Arch: foreign |
735 | + |
736 | +Package: ubuntu-emulator-runtime |
737 | +Source: android |
738 | +Version: ${unstable-version} |
739 | +Architecture: amd64 armhf |
740 | +Multi-Arch: foreign |
741 | + |
742 | +Package: libnss-mdns-i386 |
743 | +Source: nss-mdns |
744 | +Version: ${unstable-version} |
745 | +Architecture: amd64 |
746 | +Multi-Arch: foreign |
747 | + |
748 | +Package: unity8 |
749 | +Version: ${unstable-version} |
750 | +Architecture: powerpc ppc64el s390x |
751 | + |
752 | +Package: liboxideqt-qmlplugin |
753 | +Source: oxide-qt |
754 | +Version: ${unstable-version} |
755 | +Architecture: powerpc ppc64el s390x |
756 | + |
757 | +Package: fenix |
758 | +Version: ${unstable-version} |
759 | +Architecture: amd64 |
760 | + |
761 | +Package: fenix-plugins-system |
762 | +Version: ${unstable-version} |
763 | +Architecture: amd64 |
764 | + |
765 | +Package: steam |
766 | +Version: ${unstable-version} |
767 | +Architecture: amd64 |
768 | +Multi-Arch: foreign |
769 | + |
770 | +Package: gnome-shell |
771 | +Version: ${unstable-version} |
772 | +Architecture: s390x |
773 | |
774 | === added file 'fauxpkg/README' |
775 | --- fauxpkg/README 1970-01-01 00:00:00 +0000 |
776 | +++ fauxpkg/README 2020-03-12 14:58:23 +0000 |
777 | @@ -0,0 +1,50 @@ |
778 | +Files and scripts in this directory are in charge on creating a list of |
779 | +"faux" packages for britney. These are packages that do not exist in the |
780 | +archive, but which we want britney to think they exist. At the moment |
781 | +they are used for: |
782 | + |
783 | + - allowing packages in contrib to migrate even if their dependencies |
784 | + are not satisfied within the archive. This is done by creating a |
785 | + faux package for each missing dependency. |
786 | + |
787 | + - ensure some packages do not get accidentally removed, because they |
788 | + are needed by parts of testing which don't declare a Depends on |
789 | + them. In particular, to ensure packages needed by the installer and |
790 | + tasksel are not removed. This is done by creating faux packages that |
791 | + do depend on all packages which are not to be removed. |
792 | + |
793 | +To create packages of the first kind, just append suitable entries to |
794 | +the toplevel FauxPackages file. These should have at least a Package and |
795 | +Version fields. You can restrict their existance to certain architectures |
796 | +by providing an Architecture field with a list of architectures. Other |
797 | +fields are propagated verbatim to britney, eg. Provides. |
798 | + |
799 | +As for the second kind, you don't directly create faux packages, but |
800 | +just append the packages which shouldn't be removed to the appropriate |
801 | +file under the "noremove.d" directory. Those files just contain a list |
802 | +of *binary* packages, one per line. A couple of important notes: |
803 | + |
804 | + - if the binary package is not in testing, do not add it: wait until |
805 | + it migrates. |
806 | + |
807 | + - if the binary package is not available on i386 (being arch:all would |
808 | + suffice), you have to qualify it with [arch], mentioning one arch in |
809 | + which it is available. |
810 | + |
811 | + - the names of the files under noremove.d must be valid as package |
812 | + names, e.g. not contain underscores. |
813 | + |
814 | +The noremove.d/tasksel file is special: it gets generated automatically |
815 | +by the fauxpkg.py script, by running the script with the "update-tasksel" |
816 | +command. (Currently is it to be run by hand whenever the tasksel |
817 | +maintainer notices our file is out of date.) |
818 | + |
819 | +One further caveat: if one of these faux meta-packages becomes uninstallable, |
820 | +they stop working (since the removal of their dependencies does not increase |
821 | +the uninstallability count). The britney script has a mechanism in place to |
822 | +warn in case they become uninstallable. When adding packages to the lists, |
823 | +make sure to watch the next britney mail, in case you added conflicting |
824 | +packages. (In that case, you want to add such packages in different files |
825 | +under noremove.d.) |
826 | + |
827 | +Please don't forget to commit your changes to files in this directory! |
828 | |
829 | === added file 'fauxpkg/fauxpkg.py' |
830 | --- fauxpkg/fauxpkg.py 1970-01-01 00:00:00 +0000 |
831 | +++ fauxpkg/fauxpkg.py 2020-03-12 14:58:23 +0000 |
832 | @@ -0,0 +1,193 @@ |
833 | +#! /usr/bin/python |
834 | +## encoding: utf-8 |
835 | +# |
836 | +# Copyright (c) 2008 Adeodato Simó (dato@net.com.org.es) |
837 | +# Licensed under the terms of the MIT license. |
838 | + |
839 | +"""Handle the creation of britney faux packages. |
840 | + |
841 | +This program gets called from the "britney" script in order to append to the |
842 | +Packages_<arch> files a list of faux packages. This is done with the "generate" |
843 | +command, passing a list of britney suite directories: |
844 | + |
845 | + % fauxpkg.py generate /home/release/britney/var/data/{testing,unstable} |
846 | + |
847 | +This automatically appeds to the Packages files the list of faux packages. See |
848 | +the README file in this directory for the input files from which such list is |
849 | +generated. |
850 | +""" |
851 | + |
852 | +import os |
853 | +import re |
854 | +import sys |
855 | +import glob |
856 | +import tempfile |
857 | +import subprocess |
858 | + |
859 | +from collections import defaultdict |
860 | + |
861 | +import apt_pkg |
862 | +apt_pkg.init() |
863 | + |
864 | +## |
865 | + |
866 | +BASEDIR = os.path.dirname(__file__) |
867 | + |
868 | +NOREMOVE_DIR = os.path.join(BASEDIR, 'noremove.d') |
869 | +FAUX_PACKAGES = os.path.join(BASEDIR, 'FauxPackages') |
870 | + |
871 | +DEFAULT_NOREMOVE_ARCH = 'amd64' |
872 | + |
873 | +## |
874 | + |
875 | +def main(): |
876 | + if not sys.argv[1:]: |
877 | + print >>sys.stderr, 'Usage: %s <generate | update-tasksel> [ britney_suite_dir1 ... ]' % ( |
878 | + os.path.basename(sys.argv[0])) |
879 | + sys.exit(1) |
880 | + else: |
881 | + command = sys.argv.pop(1) |
882 | + |
883 | + if command == 'generate': |
884 | + if not sys.argv[1:]: |
885 | + print >>sys.stderr, 'E: need at least one britney suite directory' |
886 | + sys.exit(1) |
887 | + else: |
888 | + do_generate(sys.argv[1:]) |
889 | + elif command == 'update-tasksel': |
890 | + if sys.argv[1:]: |
891 | + print >>sys.stderr, 'E: extra arguments not allowed' |
892 | + sys.exit(1) |
893 | + else: |
894 | + do_update_tasksel() |
895 | + else: |
896 | + print >>sys.stderr, 'E: unknown command %s' % (command,) |
897 | + |
898 | +## |
899 | + |
900 | +def do_generate(directories): |
901 | + arches = set() |
902 | + allfaux = {} |
903 | + |
904 | + for dir_ in directories: |
905 | + arches.update([ re.sub(r'^.*/Packages_', '', x) |
906 | + for x in glob.glob(os.path.join(dir_, 'Packages_*')) ]) |
907 | + |
908 | + unstable_versions = {} |
909 | + all_packages = defaultdict(set) |
910 | + for dir_ in directories: |
911 | + with open(os.path.join(dir_, 'Sources')) as f: |
912 | + parser = apt_pkg.TagFile(f) |
913 | + for section in parser: |
914 | + if 'Package' in section and 'Version' in section: |
915 | + unstable_versions[section['Package']] = section['Version'] |
916 | + for packages_file in glob.glob(os.path.join(dir_, 'Packages_*')): |
917 | + arch = re.sub(r'^.*/Packages_', '', packages_file) |
918 | + with open(packages_file, 'r') as f: |
919 | + with apt_pkg.TagFile(f) as tf: |
920 | + for section in tf: |
921 | + all_packages[arch] |= {section.get('Package')} |
922 | + |
923 | + # First, FauxPackages |
924 | + try: |
925 | + parser = apt_pkg.TagFile(file(FAUX_PACKAGES)) |
926 | + step = parser.step |
927 | + section = parser.section |
928 | + except AttributeError, e: |
929 | + parser = apt_pkg.ParseTagFile(file(FAUX_PACKAGES)) |
930 | + step = parser.Step |
931 | + section = parser.Section |
932 | + while step(): |
933 | + d = dict(section) |
934 | + d['Section'] = 'faux' # crucial; britney filters HeidiResult based on section |
935 | + |
936 | + if not d.has_key('Architecture'): |
937 | + these_arches = arches |
938 | + else: |
939 | + these_arches = set(re.split(r'[, ]+', d['Architecture'])) |
940 | + |
941 | + d['Architecture'] = 'all' # same everywhere |
942 | + |
943 | + if d.get('Version') == '${unstable-version}': |
944 | + source = d.get('Source', d.get('Package')) |
945 | + if source in unstable_versions: |
946 | + d['Version'] = unstable_versions[source] |
947 | + |
948 | + for arch in these_arches: |
949 | + allfaux.setdefault(arch, []).append(d) |
950 | + |
951 | + # Now, noremove.d |
952 | + for f in glob.glob(os.path.join(NOREMOVE_DIR, '*.list')): |
953 | + pkgs = {} |
954 | + basename = re.sub(r'.+/(.+)\.list', r'\1', f) |
955 | + |
956 | + for line in file(f): |
957 | + line = line.strip() |
958 | + if re.match(r'^#', line): |
959 | + continue |
960 | + elif re.match(r'\S+$', line): |
961 | + pkg = line |
962 | + arch = DEFAULT_NOREMOVE_ARCH |
963 | + else: |
964 | + m = re.match(r'(\S+)\s+\[(.+)\]', line) |
965 | + if m: |
966 | + pkg, arch = m.groups() |
967 | + else: |
968 | + print >>sys.stderr, 'W: could not parse line %r' % (line,) |
969 | + |
970 | + arch = re.split(r'[, ]+', arch)[0] # just in case |
971 | + pkgs.setdefault(arch, set()).add(pkg) |
972 | + |
973 | + for arch in pkgs.keys(): |
974 | + d = { 'Package': '%s-meta-faux' % (basename,), 'Version': '1', |
975 | + 'Section': 'faux', 'Architecture': '%s' % (arch,), |
976 | + 'Depends': ', '.join(pkgs[arch]) } |
977 | + allfaux.setdefault(arch, []).append(d) |
978 | + |
979 | + # Write the result |
980 | + for arch in arches: |
981 | + if arch not in allfaux: |
982 | + continue |
983 | + for dir_ in directories: |
984 | + f = os.path.join(dir_, 'Packages_' + arch) |
985 | + if not os.path.exists(f): |
986 | + continue |
987 | + else: |
988 | + f = file(f, 'a') |
989 | + for d in allfaux[arch]: |
990 | + if d['Package'] in all_packages[arch]: |
991 | + print >>sys.stderr, 'W: skipping %s/%s (%s) as it is already known' % (d['Package'], arch, f.name) |
992 | + continue |
993 | + f.write('\n'.join('%s: %s' % (k, v) for k, v in d.iteritems()) + '\n\n') |
994 | + |
995 | +## |
996 | + |
997 | +def do_update_tasksel(): |
998 | + p = subprocess.Popen('dak ls -f control-suite -s unstable -a source tasksel', |
999 | + shell=True, stdout=subprocess.PIPE) |
1000 | + p.wait() |
1001 | + version = p.stdout.readline().split()[1] |
1002 | + |
1003 | + p = subprocess.Popen('dak ls -f control-suite -s unstable -S -a i386,all tasksel', |
1004 | + shell=True, stdout=subprocess.PIPE) |
1005 | + p.wait() |
1006 | + tasks = [] |
1007 | + |
1008 | + for line in p.stdout: |
1009 | + pkg = line.split()[0] |
1010 | + |
1011 | + if pkg.startswith('task-'): |
1012 | + tasks.append(pkg) |
1013 | + |
1014 | + # Write the new file |
1015 | + tmpfd, tmpname = tempfile.mkstemp(dir=NOREMOVE_DIR) |
1016 | + os.write(tmpfd, '# Generated from tasksel-data %s\n' % (version,)) |
1017 | + os.write(tmpfd, '\n'.join(sorted(tasks)) + '\n') |
1018 | + os.close(tmpfd) |
1019 | + os.chmod(tmpname, 0644) |
1020 | + os.rename(tmpname, os.path.join(NOREMOVE_DIR, 'tasksel.list')) |
1021 | + |
1022 | +## |
1023 | + |
1024 | +if __name__ == '__main__': |
1025 | + main() |
1026 | |
1027 | === added directory 'fauxpkg/noremove.d' |
1028 | === added file 'fauxpkg/noremove.d/README' |
1029 | --- fauxpkg/noremove.d/README 1970-01-01 00:00:00 +0000 |
1030 | +++ fauxpkg/noremove.d/README 2020-03-12 14:58:23 +0000 |
1031 | @@ -0,0 +1,3 @@ |
1032 | +Packages listed in these files are protected against accidental removals |
1033 | +from testing. Please mail debian-release@lists.debian.org if you think |
1034 | +some package should be added to any of these lists. |
1035 | |
1036 | === added directory 'scripts' |
1037 | === added file 'scripts/backlog-report' |
1038 | --- scripts/backlog-report 1970-01-01 00:00:00 +0000 |
1039 | +++ scripts/backlog-report 2020-03-12 14:58:23 +0000 |
1040 | @@ -0,0 +1,95 @@ |
1041 | +#! /usr/bin/python |
1042 | +# |
1043 | +# Generate a report of the backlog in -proposed. |
1044 | + |
1045 | +from __future__ import print_function |
1046 | + |
1047 | +__metaclass__ = type |
1048 | + |
1049 | +import calendar |
1050 | +import csv |
1051 | +import gzip |
1052 | +import io |
1053 | +from optparse import OptionParser |
1054 | +import os |
1055 | +import re |
1056 | +import sys |
1057 | +import time |
1058 | + |
1059 | + |
1060 | +generated_re = re.compile(r"^<p>Generated: (.*)</p>$") |
1061 | +age_re = re.compile(r"^<li>([0-9]+) days old$") |
1062 | + |
1063 | + |
1064 | +def import_excuses(csv_writer, path): |
1065 | + generated_time = None |
1066 | + valid_candidates = 0 |
1067 | + not_considered = 0 |
1068 | + ages = [] |
1069 | + backlog = 0 |
1070 | + |
1071 | + if path.endswith(".gz"): |
1072 | + binary = gzip.open(path) |
1073 | + else: |
1074 | + binary = io.open(path, mode="rb") |
1075 | + try: |
1076 | + with io.BufferedReader(binary) as buffered: |
1077 | + with io.TextIOWrapper(buffered) as text: |
1078 | + for line in text: |
1079 | + match = generated_re.match(line) |
1080 | + age_match = age_re.match(line) |
1081 | + if match: |
1082 | + generated_time = time.strptime( |
1083 | + match.group(1), "%Y.%m.%d %H:%M:%S +0000") |
1084 | + elif age_match: |
1085 | + ages.append(int(age_match.group(1))) |
1086 | + backlog += max(int(age_match.group(1)) - 3, 0) |
1087 | + elif line.startswith("<li>Valid candidate"): |
1088 | + valid_candidates += 1 |
1089 | + elif line.startswith("<li>Not considered"): |
1090 | + not_considered += 1 |
1091 | + finally: |
1092 | + binary.close() |
1093 | + |
1094 | + assert generated_time is not None |
1095 | + |
1096 | + csv_writer.writerow({ |
1097 | + "time": calendar.timegm(generated_time) * 1000, |
1098 | + "valid candidates": valid_candidates, |
1099 | + "not considered": not_considered, |
1100 | + "total": valid_candidates + not_considered, |
1101 | + "median age": ages[len(ages)/2], |
1102 | + "backlog": backlog, |
1103 | + }) |
1104 | + |
1105 | + |
1106 | +def main(): |
1107 | + parser = OptionParser(description="Generate a backlog report.") |
1108 | + parser.add_option( |
1109 | + "-o", "--output", help="Write output to this file (default: stdout).") |
1110 | + options, args = parser.parse_args() |
1111 | + |
1112 | + if options.output is not None: |
1113 | + csv_is_new = not os.path.exists(options.output) |
1114 | + if sys.version < "3": |
1115 | + output = open(options.output, "ab") |
1116 | + else: |
1117 | + output = open(options.output, "a", newline="") |
1118 | + else: |
1119 | + csv_is_new = True |
1120 | + output = sys.stdout |
1121 | + |
1122 | + try: |
1123 | + csv_writer = csv.DictWriter( |
1124 | + output, ["time", "valid candidates", "not considered", "total", "median age", "backlog"]) |
1125 | + if csv_is_new: |
1126 | + csv_writer.writeheader() |
1127 | + for arg in args: |
1128 | + import_excuses(csv_writer, arg) |
1129 | + finally: |
1130 | + if options.output is not None: |
1131 | + output.close() |
1132 | + |
1133 | + |
1134 | +if __name__ == "__main__": |
1135 | + main() |
1136 | |
1137 | === added file 'scripts/ood_report.py' |
1138 | --- scripts/ood_report.py 1970-01-01 00:00:00 +0000 |
1139 | +++ scripts/ood_report.py 2020-03-12 14:58:23 +0000 |
1140 | @@ -0,0 +1,101 @@ |
1141 | +#! /usr/bin/python |
1142 | +## encoding: utf-8 |
1143 | +# |
1144 | +# Copyright (c) 2008 Adeodato Simó (dato@net.com.org.es) |
1145 | +# Licensed under the terms of the MIT license. |
1146 | + |
1147 | +"""Create a report of packages that are out-of-date in each architecture. |
1148 | + |
1149 | +It expects a single "directory" argument, that should be a britney directory |
1150 | +for a distribution, i.e. containing Packages_<arch> files and Sources. |
1151 | +""" |
1152 | + |
1153 | +import os |
1154 | +import re |
1155 | +import sys |
1156 | +import glob |
1157 | + |
1158 | +import apt_pkg |
1159 | +apt_pkg.init() |
1160 | + |
1161 | +## |
1162 | + |
1163 | +def main(): |
1164 | + if len(sys.argv) != 2: |
1165 | + print >>sys.stderr, 'Usage: %s <directory>' |
1166 | + sys.exit(1) |
1167 | + else: |
1168 | + directory = sys.argv[1] |
1169 | + |
1170 | + pkgfiles = glob.glob(os.path.join(directory, 'Packages_*')) |
1171 | + versions = get_src_versions(os.path.join(directory, 'Sources')) |
1172 | + |
1173 | + ood = {} # { arch1: { srcpk1: (oldver, [binpkg1, binpkg2, ...]), ... }, ... } |
1174 | + |
1175 | + for pkgfile in pkgfiles: |
1176 | + arch = re.sub(r'^.*/Packages_', '', pkgfile) |
1177 | + try: |
1178 | + parser = apt_pkg.TagFile(file(pkgfile)) |
1179 | + step = parser.step |
1180 | + get_section = parser.section |
1181 | + get_field = parser.section.get |
1182 | + except AttributeError, e: |
1183 | + parser = apt_pkg.ParseTagFile(file(pkgfile)) |
1184 | + step = parser.Step |
1185 | + get_section = parser.Section |
1186 | + get_field = parser.Section.get |
1187 | + d = ood[arch] = {} |
1188 | + |
1189 | + while step(): |
1190 | + pkg = get_section['Package'] |
1191 | + src = get_field('Source') or pkg |
1192 | + |
1193 | + if ' ' in src: |
1194 | + m = re.match(r'(\S+) \((\S+)\)$', src) |
1195 | + src = m.group(1) |
1196 | + ver = m.group(2) |
1197 | + else: |
1198 | + ver = re.sub(r'\+b\d+$', '', get_section['Version']) |
1199 | + |
1200 | + try: |
1201 | + distver = versions[src] |
1202 | + except KeyError: |
1203 | + pass # faux package |
1204 | + else: |
1205 | + if ver != distver: |
1206 | + d.setdefault(src, (ver, []))[1].append(pkg) |
1207 | + |
1208 | + arches = sorted(ood.keys()) |
1209 | + |
1210 | + for arch in arches: |
1211 | + print '* %s' % (arch,) |
1212 | + for src, (oldver, binpkgs) in sorted(ood[arch].iteritems()): |
1213 | + # do not print binpkgs, I think it clutters the view too much |
1214 | + print ' %s (%s)' % (src, oldver) |
1215 | |
1216 | + |
1217 | + print '* summary' |
1218 | + print '\n'.join(map(lambda x: '%4d %s' % (len(ood[x]), x), arches)) |
1219 | + |
1220 | +## |
1221 | + |
1222 | +def get_src_versions(sources_file): |
1223 | + """Return a dict { srcname: version, ... }.""" |
1224 | + mydict = {} |
1225 | + try: |
1226 | + parser = apt_pkg.TagFile(file(sources_file)) |
1227 | + |
1228 | + while parser.step(): |
1229 | + mydict[parser.section['Package']] = parser.section['Version'] |
1230 | + except AttributeError, e: |
1231 | + parser = apt_pkg.ParseTagFile(file(sources_file)) |
1232 | + |
1233 | + while parser.Step(): |
1234 | + mydict[parser.Section['Package']] = parser.Section['Version'] |
1235 | + |
1236 | + return mydict |
1237 | + |
1238 | +## |
1239 | + |
1240 | +if __name__ == '__main__': |
1241 | + main() |
1242 | |
1243 | === added file 'scripts/udeb-report' |
1244 | --- scripts/udeb-report 1970-01-01 00:00:00 +0000 |
1245 | +++ scripts/udeb-report 2020-03-12 14:58:23 +0000 |
1246 | @@ -0,0 +1,49 @@ |
1247 | +#!/bin/sh |
1248 | + |
1249 | +# Generate a report with out-of-date udebs. Queries come from the |
1250 | +# original "d-i" script by Jeroen van Wolffelaar. Modified not to emit |
1251 | +# output for queries that return 0 rows by Adeodato Simó. |
1252 | + |
1253 | +# TODO(dato): rewrite these queries. |
1254 | + |
1255 | +export PAGER="cat" |
1256 | + |
1257 | +eval $(dak admin config db-shell) |
1258 | + |
1259 | +## |
1260 | + |
1261 | +maybe_print () { |
1262 | + if ! echo "$2" | grep -q -E '^\(0 rows\)$'; then |
1263 | + echo "$1" |
1264 | + echo "$2" |
1265 | + echo |
1266 | + fi |
1267 | +} |
1268 | + |
1269 | +maybe_print "udeb's in testing that don't (anymore) correspond to any testing source:" \ |
1270 | +"`psql -c \"select b.package, b.version, (SELECT arch_string from |
1271 | +architecture where b.architecture=architecture.id) as arch, s.source from |
1272 | +bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s |
1273 | +on (b.source=s.id) WHERE ba.suite=4 AND s.id NOT IN (SELECT source from |
1274 | +src_associations WHERE suite=4) AND b.type = 'udeb' ORDER BY s.source, |
1275 | +b.package, b.architecture;\"`" |
1276 | + |
1277 | +maybe_print "udeb's in unstable that should be in testing too:" \ |
1278 | +"`psql -c \"select b.package, b.version, (SELECT arch_string from |
1279 | +architecture where b.architecture=architecture.id) as arch, s.source from |
1280 | +bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s |
1281 | +on (b.source=s.id) WHERE ba.suite=5 AND NOT EXISTS (SELECT 1 FROM |
1282 | +bin_associations ba2 WHERE ba2.suite=4 AND ba2.bin=ba.bin) AND s.id IN (SELECT |
1283 | +source from src_associations WHERE suite=4) AND b.type = 'udeb' AND |
1284 | +b.architecture IN (SELECT architecture from suite_architectures where suite = 4) |
1285 | +ORDER BY s.source, b.package, b.architecture;\"`" |
1286 | + |
1287 | +maybe_print "udeb's in t-p-u that should be in testing too:" \ |
1288 | +"`psql -c \"select b.package, b.version, (SELECT arch_string from |
1289 | +architecture where b.architecture=architecture.id) as arch, s.source from |
1290 | +bin_associations ba LEFT JOIN binaries b on (ba.bin=b.id) LEFT JOIN source s |
1291 | +on (b.source=s.id) WHERE ba.suite=3 AND NOT EXISTS (SELECT 1 FROM |
1292 | +bin_associations ba2 WHERE ba2.suite=4 AND ba2.bin=ba.bin) AND s.id IN (SELECT |
1293 | +source from src_associations WHERE suite=4) AND b.type = 'udeb' AND |
1294 | +b.architecture IN (SELECT architecture from suite_architectures where suite = 4) |
1295 | +ORDER BY s.source, b.package, b.architecture;\"`" |
1296 | |
1297 | === added directory 'update_out' |
1298 | === added file 'update_out/.gitignore' |
1299 | --- update_out/.gitignore 1970-01-01 00:00:00 +0000 |
1300 | +++ update_out/.gitignore 2020-03-12 14:58:23 +0000 |
1301 | @@ -0,0 +1,6 @@ |
1302 | +*.o |
1303 | +*.so |
1304 | +/oldstuff |
1305 | +/Makefile.dep |
1306 | +/update.EXCUSES_py |
1307 | +/update.OUTPUT_py |
1308 | |
1309 | === added file 'update_out/Makefile' |
1310 | --- update_out/Makefile 1970-01-01 00:00:00 +0000 |
1311 | +++ update_out/Makefile 2020-03-12 14:58:23 +0000 |
1312 | @@ -0,0 +1,33 @@ |
1313 | + |
1314 | +CC = gcc |
1315 | +CXX = g++ |
1316 | +CFLAGS = -fPIC -Wall -W -O2 -DNDEBUG -DMDEBUG0 -g -p # -DDIAGNOSE |
1317 | +CXXFLAGS = $(CFLAGS) |
1318 | + |
1319 | +all : britneymodule.so # libajdpkg.a aptvercmp checklib freelist |
1320 | + |
1321 | +clean : |
1322 | + rm -f *.so *.o *~ Makefile.dep gmon.out |
1323 | + rm -f freelist aptvercmp checklib libajdpkg.a |
1324 | + |
1325 | +checklib : checklib.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o |
1326 | + $(CC) $(CFLAGS) -o checklib $^ -lapt-pkg # -lccmalloc -ldl |
1327 | + |
1328 | +aptvercmp : dpkg-lib.cpp |
1329 | + $(CXX) $(CFLAGS) -DTESTBIN -o aptvercmp dpkg-lib.cpp -lapt-pkg |
1330 | + |
1331 | +freelist : freelist.c assert.o |
1332 | + $(CC) $(CFLAGS) -DTESTBIN -o $@ $^ |
1333 | + |
1334 | +#libajdpkg.a : dpkg.o dpkg-lib.o memory3.o freelist.o assert.o |
1335 | +# ar rv $@ $^ |
1336 | +# ranlib $@ |
1337 | + |
1338 | +britneymodule.so : britney-py.o dpkg.o dpkg-lib.o memory3.o freelist.o assert.o |
1339 | + $(CXX) -shared -o britneymodule.so $^ -lapt-pkg |
1340 | + |
1341 | +Makefile.dep : |
1342 | + @gcc -MM *.c *.cpp > Makefile.dep |
1343 | + @echo Makefile.dep : Makefile *.c *.h >> Makefile.dep |
1344 | + |
1345 | +-include Makefile.dep |
1346 | |
1347 | === added file 'update_out/README' |
1348 | --- update_out/README 1970-01-01 00:00:00 +0000 |
1349 | +++ update_out/README 2020-03-12 14:58:23 +0000 |
1350 | @@ -0,0 +1,32 @@ |
1351 | + |
1352 | +BUILDING |
1353 | +======== |
1354 | + |
1355 | +Install libapt-pkg-dev |
1356 | + |
1357 | +testing/ $ make |
1358 | +testing/ $ mkdir old cur out |
1359 | +testing/ $ cd testing |
1360 | +testing/testing/ $ perl Makefile.PL |
1361 | +testing/testing/ $ make |
1362 | + |
1363 | +Add old and new packages files into old and cur, respectively. |
1364 | + |
1365 | +testing/ $ ./checklib i386 alpha |
1366 | + |
1367 | +Will generate some test stuff in out/ |
1368 | + |
1369 | +TODO |
1370 | +==== |
1371 | + |
1372 | +Need some way of actually updating archives. |
1373 | +Need some way of judging differences between Packages files. |
1374 | + (so I can see what hasn't been updated and work out why; |
1375 | + so I can check that Packages.gz matches dpkg-scanpackages output) |
1376 | +Need some way of automatically explaining why packages aren't upgraded. |
1377 | + (shouldn't be hard?) |
1378 | + |
1379 | +BUGS |
1380 | +==== |
1381 | + |
1382 | +out/ directory must exist for checklib, or segfault |
1383 | |
1384 | === added file 'update_out/assert.c' |
1385 | --- update_out/assert.c 1970-01-01 00:00:00 +0000 |
1386 | +++ update_out/assert.c 2020-03-12 14:58:23 +0000 |
1387 | @@ -0,0 +1,11 @@ |
1388 | +#include <stdio.h> |
1389 | +#include <stdlib.h> |
1390 | + |
1391 | +int _myassertbug(int line, char *file, char *err) { |
1392 | + fprintf(stderr, "Assertion failed: %s:%d: %s\n", file, line, err); |
1393 | + fprintf(stderr, "I HATE YOU!!!"); |
1394 | + ((void(*)())0)(); |
1395 | + abort(); |
1396 | + return 0; |
1397 | +} |
1398 | + |
1399 | |
1400 | === added file 'update_out/britney-py.c' |
1401 | --- update_out/britney-py.c 1970-01-01 00:00:00 +0000 |
1402 | +++ update_out/britney-py.c 2020-03-12 14:58:23 +0000 |
1403 | @@ -0,0 +1,871 @@ |
1404 | +#include <python2.7/Python.h> |
1405 | + |
1406 | +#include "dpkg.h" |
1407 | + |
1408 | +#define MAKE_PY_LIST(L,S,E,I,V) \ |
1409 | + do { \ |
1410 | + L = PyList_New(0); \ |
1411 | + if (!L) break; \ |
1412 | + for (S; E; I) { \ |
1413 | + PyObject *EL; \ |
1414 | + EL = Py_BuildValue V; \ |
1415 | + if (!EL) { \ |
1416 | + Py_DECREF(L); \ |
1417 | + L = NULL; \ |
1418 | + break; \ |
1419 | + } \ |
1420 | + PyList_Append(L, EL); \ |
1421 | + Py_DECREF(EL); \ |
1422 | + } \ |
1423 | + if (L) PyList_Sort(L); \ |
1424 | + } while(0) |
1425 | + |
1426 | +/************************************************************************** |
1427 | + * britney.Packages -- dpkg_packages wrapper |
1428 | + *******************************************/ |
1429 | + |
1430 | +typedef enum { DONTFREE, FREE } dpkgpackages_freeme; |
1431 | +typedef struct { |
1432 | + PyObject_HEAD |
1433 | + dpkg_packages *pkgs; |
1434 | + PyObject *ref; /* object packages are "in" */ |
1435 | + dpkgpackages_freeme freeme; /* free pkgs when deallocing? */ |
1436 | +} dpkgpackages; |
1437 | + |
1438 | +staticforward PyTypeObject Packages_Type; |
1439 | + |
1440 | +static PyObject *dpkgpackages_new(dpkg_packages *pkgs, |
1441 | + dpkgpackages_freeme freeme, PyObject *ref) |
1442 | +{ |
1443 | + dpkgpackages *res; |
1444 | + |
1445 | + res = PyObject_NEW(dpkgpackages, &Packages_Type); |
1446 | + if (res == NULL) return NULL; |
1447 | + |
1448 | + res->pkgs = pkgs; |
1449 | + res->ref = ref; Py_INCREF(res->ref); |
1450 | + res->freeme = freeme; |
1451 | + |
1452 | + return (PyObject *) res; |
1453 | +} |
1454 | + |
1455 | +static void dpkgpackages_dealloc(dpkgpackages *self) { |
1456 | + if (self->freeme == FREE) free_packages(self->pkgs); |
1457 | + Py_XDECREF(self->ref); |
1458 | + self->pkgs = NULL; |
1459 | + self->ref = NULL; |
1460 | + PyObject_DEL(self); |
1461 | +} |
1462 | + |
1463 | + |
1464 | +static dpkg_collected_package *dpkgpackages_lookuppkg(dpkgpackages *self, |
1465 | + char *pkgname) |
1466 | +{ |
1467 | + dpkg_collected_package *cpkg = NULL; |
1468 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1469 | + if (!cpkg) { |
1470 | + PyErr_SetString(PyExc_ValueError, "Not a valid package"); |
1471 | + } |
1472 | + return cpkg; |
1473 | +} |
1474 | + |
1475 | +static PyObject *dpkgpackages_ispresent(dpkgpackages *self, PyObject *args) { |
1476 | + dpkg_collected_package *cpkg; |
1477 | + char *pkgname; |
1478 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1479 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1480 | + return cpkg ? Py_BuildValue("i", 1) : Py_BuildValue("i", 0); |
1481 | +} |
1482 | + |
1483 | +static PyObject *dpkgpackages_getversion(dpkgpackages *self, PyObject *args) { |
1484 | + dpkg_collected_package *cpkg; |
1485 | + char *pkgname; |
1486 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1487 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1488 | + if (cpkg) return Py_BuildValue("s", cpkg->pkg->version); |
1489 | + else return Py_BuildValue(""); |
1490 | +} |
1491 | +static PyObject *dpkgpackages_getsource(dpkgpackages *self, PyObject *args) { |
1492 | + dpkg_collected_package *cpkg; |
1493 | + char *pkgname; |
1494 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1495 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1496 | + if (cpkg) return Py_BuildValue("s", cpkg->pkg->source); |
1497 | + else return Py_BuildValue(""); |
1498 | +} |
1499 | +static PyObject *dpkgpackages_getsourcever(dpkgpackages *self, PyObject *args) { |
1500 | + dpkg_collected_package *cpkg; |
1501 | + char *pkgname; |
1502 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1503 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1504 | + if (cpkg) return Py_BuildValue("s", cpkg->pkg->source_ver); |
1505 | + else return Py_BuildValue(""); |
1506 | +} |
1507 | +static PyObject *dpkgpackages_isarchall(dpkgpackages *self, PyObject *args) { |
1508 | + dpkg_collected_package *cpkg; |
1509 | + char *pkgname; |
1510 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1511 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1512 | + if (cpkg) return Py_BuildValue("i", cpkg->pkg->arch_all); |
1513 | + else return Py_BuildValue(""); |
1514 | +} |
1515 | +static PyObject *dpkgpackages_isntarchall(dpkgpackages *self, PyObject *args) { |
1516 | + dpkg_collected_package *cpkg; |
1517 | + char *pkgname; |
1518 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1519 | + cpkg = lookup_packagetbl(self->pkgs->packages, pkgname); |
1520 | + if (cpkg) return Py_BuildValue("i", !cpkg->pkg->arch_all); |
1521 | + else return Py_BuildValue(""); |
1522 | +} |
1523 | +static PyObject *dpkgpackages_getfield(dpkgpackages *self, PyObject *args) { |
1524 | + char *field; |
1525 | + char *pkgname; |
1526 | + int i; |
1527 | + dpkg_collected_package *cpkg; |
1528 | + dpkg_paragraph *para; |
1529 | + if (!PyArg_ParseTuple(args, "ss", &pkgname, &field)) return NULL; |
1530 | + cpkg = dpkgpackages_lookuppkg(self, pkgname); |
1531 | + if (!cpkg) return NULL; |
1532 | + para = cpkg->pkg->details; |
1533 | + for (i = 0; i < para->n_entries; i++) { |
1534 | + if (strcasecmp(para->entry[i].name, field) == 0) { |
1535 | + return Py_BuildValue("s", para->entry[i].value); |
1536 | + } |
1537 | + } |
1538 | + return Py_BuildValue(""); |
1539 | +} |
1540 | +static PyObject *dpkgpackages_isinstallable(dpkgpackages *self, PyObject *args) |
1541 | +{ |
1542 | + char *pkgname; |
1543 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1544 | + if (checkinstallable2(self->pkgs, pkgname)) { |
1545 | + return Py_BuildValue("i", 1); |
1546 | + } else { |
1547 | + return Py_BuildValue(""); |
1548 | + } |
1549 | +} |
1550 | +static PyObject *dpkgpackages_isuninstallable(dpkgpackages *self, |
1551 | + PyObject *args) |
1552 | +{ |
1553 | + char *pkgname; |
1554 | + if (!PyArg_ParseTuple(args, "s", &pkgname)) return NULL; |
1555 | + if (!checkinstallable2(self->pkgs, pkgname)) { |
1556 | + return Py_BuildValue("i", 1); |
1557 | + } else { |
1558 | + return Py_BuildValue(""); |
1559 | + } |
1560 | +} |
1561 | +static PyObject *dpkgpackages_unsatdeps(dpkgpackages *self, PyObject *args) { |
1562 | + /* arguments are: |
1563 | + * testingpkgs[arch].unsatisfiable_deps(unstablepkgs[arch], "netbase", "Depends") |
1564 | + * exciting, huh? |
1565 | + */ |
1566 | + |
1567 | + dpkgpackages *pkgpkgs; |
1568 | + char *pkgname, *fieldname; |
1569 | + dpkg_collected_package *cpkg; |
1570 | + int fieldidx; |
1571 | + int buflen = 100; |
1572 | + char *buf = malloc(buflen); |
1573 | + const char *fields[] = { "Pre-Depends", "Depends", "Recommends", |
1574 | + "Suggests", NULL }; |
1575 | + satisfieddeplist *unsatdeps, *dl; |
1576 | + PyObject *res = Py_BuildValue("[]"); |
1577 | + |
1578 | + if (!PyArg_ParseTuple(args, "O!ss", &Packages_Type, &pkgpkgs, &pkgname, &fieldname)) return NULL; |
1579 | + |
1580 | + cpkg = lookup_packagetbl(pkgpkgs->pkgs->packages, pkgname); |
1581 | + if (!cpkg) { |
1582 | + PyErr_SetString(PyExc_ValueError, "Not a valid package"); |
1583 | + return NULL; |
1584 | + } |
1585 | + |
1586 | + for (fieldidx = 0; fields[fieldidx]; fieldidx++) { |
1587 | + if (strcmp(fields[fieldidx], fieldname) == 0) break; |
1588 | + } |
1589 | + if (!fields[fieldidx]) { |
1590 | + PyErr_SetString(PyExc_ValueError, "Not a valid dependency field"); |
1591 | + return NULL; |
1592 | + } |
1593 | + |
1594 | + unsatdeps = checkunsatisfiabledeps(self->pkgs, |
1595 | + cpkg->pkg->depends[fieldidx]); |
1596 | + for (dl = unsatdeps; dl != NULL; dl = dl->next) { |
1597 | + int len; |
1598 | + packagelist *it; |
1599 | + PyObject *pkglist; |
1600 | + deplist *depl; |
1601 | + dependency *dep; |
1602 | + |
1603 | + len = 0; |
1604 | + buf[0] = '\0'; |
1605 | + for (depl = dl->value->depl; depl; depl = depl->next) { |
1606 | + dep = depl->value; |
1607 | + len += strlen(dep->package) + 4; |
1608 | + /* 4 = strlen(" | ") + 1 */ |
1609 | + if (dep->op != dr_NOOP) { |
1610 | + len += strlen(dep->version) + 6; |
1611 | + /* 6 = strlen(" (>= )") */ |
1612 | + } |
1613 | + if (len >= buflen) { |
1614 | + char *newbuf; |
1615 | + newbuf = realloc(buf, len + 100); |
1616 | + if (newbuf == NULL) { |
1617 | + free_satisfieddeplist(unsatdeps); |
1618 | + free(buf); |
1619 | + Py_DECREF(res); |
1620 | + PyErr_SetFromErrno(PyExc_MemoryError); |
1621 | + return NULL; |
1622 | + } |
1623 | + buf = newbuf; |
1624 | + buflen = len + 100; |
1625 | + } |
1626 | + if (buf[0] != '\0') strcat(buf, " | "); |
1627 | + strcat(buf, dep->package); |
1628 | + if (dep->op != dr_NOOP) { |
1629 | + sprintf(buf + strlen(buf), " (%s %s)", |
1630 | + dependency_relation_sym[dep->op], |
1631 | + dep->version); |
1632 | + } |
1633 | + } |
1634 | + |
1635 | + MAKE_PY_LIST(pkglist, it = dl->value->pkgs, it, it = it->next, |
1636 | + ("s", it->value->package) |
1637 | + ); |
1638 | + |
1639 | + { |
1640 | + PyObject *depel = Py_BuildValue("(sN)", buf, pkglist); |
1641 | + PyList_Append(res, depel); |
1642 | + Py_DECREF(depel); |
1643 | + } |
1644 | + } |
1645 | + |
1646 | + free_satisfieddeplist(unsatdeps); |
1647 | + free(buf); |
1648 | + |
1649 | + return res; |
1650 | +} |
1651 | + |
1652 | +static PyObject *dpkgpackages_getattr(dpkgpackages *self, char *name) { |
1653 | + static struct PyMethodDef dpkgsources_methods[] = { |
1654 | + { "is_present", (binaryfunc) dpkgpackages_ispresent, |
1655 | + METH_VARARGS, NULL }, |
1656 | + { "get_version", (binaryfunc) dpkgpackages_getversion, |
1657 | + METH_VARARGS, NULL }, |
1658 | + { "get_source", (binaryfunc) dpkgpackages_getsource, |
1659 | + METH_VARARGS, NULL }, |
1660 | + { "get_sourcever", (binaryfunc) dpkgpackages_getsourcever, |
1661 | + METH_VARARGS, NULL }, |
1662 | + { "is_arch_all", (binaryfunc) dpkgpackages_isarchall, |
1663 | + METH_VARARGS, NULL }, |
1664 | + { "isnt_arch_all", (binaryfunc) dpkgpackages_isntarchall, |
1665 | + METH_VARARGS, NULL }, |
1666 | + { "get_field", (binaryfunc) dpkgpackages_getfield, |
1667 | + METH_VARARGS, NULL }, |
1668 | + { "is_installable", (binaryfunc) dpkgpackages_isinstallable, |
1669 | + METH_VARARGS, NULL }, |
1670 | + { "is_uninstallable", (binaryfunc)dpkgpackages_isuninstallable, |
1671 | + METH_VARARGS, NULL }, |
1672 | + { "unsatisfiable_deps", (binaryfunc) dpkgpackages_unsatdeps, |
1673 | + METH_VARARGS, NULL }, |
1674 | + { NULL, NULL, 0, NULL } |
1675 | + }; |
1676 | + |
1677 | + if (strcmp(name, "packages") == 0) { |
1678 | + PyObject *packages; |
1679 | + packagetbl_iter it; |
1680 | + MAKE_PY_LIST(packages, |
1681 | + it = first_packagetbl(self->pkgs->packages), |
1682 | + !done_packagetbl(it), it = next_packagetbl(it), |
1683 | + ("s", it.k) |
1684 | + ); |
1685 | + return packages; |
1686 | + } |
1687 | + |
1688 | + return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name); |
1689 | +} |
1690 | + |
1691 | +static PyTypeObject Packages_Type = { |
1692 | + PyObject_HEAD_INIT(&PyType_Type) |
1693 | + |
1694 | + 0, /* ob_size (0) */ |
1695 | + "Packages", /* type name */ |
1696 | + sizeof(dpkgpackages), /* basicsize */ |
1697 | + 0, /* itemsize (0) */ |
1698 | + |
1699 | + (destructor) dpkgpackages_dealloc, |
1700 | + (printfunc) 0, |
1701 | + (getattrfunc) dpkgpackages_getattr, |
1702 | + (setattrfunc) 0, |
1703 | + (cmpfunc) 0, |
1704 | + (reprfunc) 0, |
1705 | + |
1706 | + 0, /* number methods */ |
1707 | + 0, /* sequence methods */ |
1708 | + 0, /* mapping methods */ |
1709 | + |
1710 | + (hashfunc) 0, /* dict[x] ?? */ |
1711 | + (ternaryfunc) 0, /* x() */ |
1712 | + (reprfunc) 0 /* str(x) */ |
1713 | +}; |
1714 | + |
1715 | +/************************************************************************** |
1716 | + * britney.Sources -- dpkg_sources wrapper |
1717 | + *****************************************/ |
1718 | + |
1719 | +typedef struct { |
1720 | + PyObject_HEAD |
1721 | + dpkg_sources *srcs; |
1722 | +} dpkgsources; |
1723 | + |
1724 | +staticforward PyTypeObject Sources_Type; |
1725 | + |
1726 | +static PyObject *dpkgsources_new(PyObject *self, PyObject *args) { |
1727 | + dpkgsources *res = NULL; |
1728 | + char *dir; |
1729 | + PyObject *arches; |
1730 | + char **archesStr = NULL; |
1731 | + int i, count; |
1732 | + |
1733 | + (void)self; /* unused */ |
1734 | + |
1735 | + if (!PyArg_ParseTuple(args, "sO!", &dir, &PyList_Type, &arches)) { |
1736 | + goto end; |
1737 | + } |
1738 | + |
1739 | + count = PyList_Size(arches); |
1740 | + if (count <= 0) { |
1741 | + PyErr_SetString(PyExc_TypeError, "No architectures specified"); |
1742 | + goto end; |
1743 | + } |
1744 | + |
1745 | + archesStr = malloc(sizeof(char *) * count); |
1746 | + if (!archesStr) { |
1747 | + PyErr_SetFromErrno(PyExc_MemoryError); |
1748 | + goto end; |
1749 | + } |
1750 | + |
1751 | + for (i = 0; i < count; i++) { |
1752 | + PyObject *arch = PyList_GetItem(arches, i); |
1753 | + if (!PyString_Check(arch)) { |
1754 | + goto end; |
1755 | + } |
1756 | + archesStr[i] = PyString_AsString(arch); |
1757 | + } |
1758 | + |
1759 | + res = PyObject_NEW(dpkgsources, &Sources_Type); |
1760 | + if (res == NULL) goto end; |
1761 | + |
1762 | + res->srcs = read_directory(dir, count, archesStr); |
1763 | + if (!res->srcs) { |
1764 | + Py_DECREF(res); |
1765 | + res = NULL; |
1766 | + goto end; |
1767 | + } |
1768 | + |
1769 | +end: |
1770 | + if (archesStr) free(archesStr); |
1771 | + return (PyObject *) res; |
1772 | +} |
1773 | + |
1774 | +static void dpkgsources_dealloc(dpkgsources *self) { |
1775 | + free_sources(self->srcs); |
1776 | + self->srcs = NULL; |
1777 | + PyObject_DEL(self); |
1778 | +} |
1779 | + |
1780 | +static PyObject *dpkgsources_packages(dpkgsources *self, PyObject *args) |
1781 | +{ |
1782 | + char *arch; |
1783 | + dpkg_packages *pkgs; |
1784 | + if (!PyArg_ParseTuple(args, "s", &arch)) return NULL; |
1785 | + pkgs = get_architecture(self->srcs, arch); |
1786 | + return dpkgpackages_new(pkgs, FREE, (PyObject *) self); |
1787 | +} |
1788 | + |
1789 | +static PyObject *dpkgsources_isfake(dpkgsources *self, PyObject *args) { |
1790 | + char *srcname; |
1791 | + dpkg_source *src; |
1792 | + |
1793 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
1794 | + src = lookup_sourcetbl(self->srcs->sources, srcname); |
1795 | + if (src) return Py_BuildValue("i", src->fake); |
1796 | + else return Py_BuildValue(""); |
1797 | +} |
1798 | + |
1799 | +static PyObject *dpkgsources_getversion(dpkgsources *self, PyObject *args) { |
1800 | + char *srcname; |
1801 | + dpkg_source *src; |
1802 | + |
1803 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
1804 | + src = lookup_sourcetbl(self->srcs->sources, srcname); |
1805 | + if (src) return Py_BuildValue("s", src->version); |
1806 | + else return Py_BuildValue(""); |
1807 | +} |
1808 | + |
1809 | +static PyObject *dpkgsources_getfield(dpkgsources *self, PyObject *args) { |
1810 | + char *srcname, *field; |
1811 | + dpkg_source *src; |
1812 | + int i; |
1813 | + dpkg_paragraph *para; |
1814 | + |
1815 | + if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL; |
1816 | + src = lookup_sourcetbl(self->srcs->sources, srcname); |
1817 | + if (!src) { |
1818 | + PyErr_SetString(PyExc_ValueError, "Not a valid source package"); |
1819 | + return NULL; |
1820 | + } |
1821 | + para = src->details; |
1822 | + if (para) { |
1823 | + for (i = 0; i < para->n_entries; i++) { |
1824 | + if (strcasecmp(para->entry[i].name, field) == 0) { |
1825 | + return Py_BuildValue("s", para->entry[i].value); |
1826 | + } |
1827 | + } |
1828 | + } |
1829 | + return Py_BuildValue(""); |
1830 | +} |
1831 | + |
1832 | +static PyObject *dpkgsources_ispresent(dpkgsources *self, PyObject *args) { |
1833 | + char *srcname; |
1834 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
1835 | + if (lookup_sourcetbl(self->srcs->sources, srcname)) { |
1836 | + return Py_BuildValue("i", 1); |
1837 | + } else { |
1838 | + return Py_BuildValue("i", 0); |
1839 | + } |
1840 | +} |
1841 | + |
1842 | +static PyObject *dpkgsources_binaries(dpkgsources *self, PyObject *args) { |
1843 | + char *srcname, *arch; |
1844 | + int archnum; |
1845 | + dpkg_source *src; |
1846 | + PyObject *res; |
1847 | + ownedpackagelist *p; |
1848 | + |
1849 | + if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL; |
1850 | + |
1851 | + for (archnum = 0; archnum < self->srcs->n_arches; archnum++) { |
1852 | + if (strcmp(arch, self->srcs->archname[archnum]) == 0) break; |
1853 | + } |
1854 | + if (archnum == self->srcs->n_arches) { |
1855 | + PyErr_SetString(PyExc_ValueError, "Not a valid architecture"); |
1856 | + return NULL; |
1857 | + } |
1858 | + |
1859 | + src = lookup_sourcetbl(self->srcs->sources, srcname); |
1860 | + if (src == NULL) { |
1861 | + PyErr_SetString(PyExc_ValueError, "Not a valid source package"); |
1862 | + return NULL; |
1863 | + } |
1864 | + |
1865 | + MAKE_PY_LIST(res, p = src->packages[archnum], p, p = p->next, |
1866 | + ("s", p->value->package) |
1867 | + ); |
1868 | + return res; |
1869 | +} |
1870 | + |
1871 | +static PyObject *dpkgsources_getattr(dpkgsources *self, char *name) { |
1872 | + static struct PyMethodDef dpkgsources_methods[] = { |
1873 | + { "Packages", (binaryfunc) dpkgsources_packages, |
1874 | + METH_VARARGS, NULL }, |
1875 | + { "is_fake", (binaryfunc) dpkgsources_isfake, |
1876 | + METH_VARARGS, NULL }, |
1877 | + { "get_version", (binaryfunc) dpkgsources_getversion, |
1878 | + METH_VARARGS, NULL }, |
1879 | + { "get_field", (binaryfunc) dpkgsources_getfield, |
1880 | + METH_VARARGS, NULL }, |
1881 | + { "is_present", (binaryfunc) dpkgsources_ispresent, |
1882 | + METH_VARARGS, NULL }, |
1883 | + { "binaries", (binaryfunc) dpkgsources_binaries, |
1884 | + METH_VARARGS, NULL }, |
1885 | + { NULL, NULL, 0, NULL } |
1886 | + }; |
1887 | + |
1888 | + if (strcmp(name, "arches") == 0) { |
1889 | + PyObject *arches; |
1890 | + int i; |
1891 | + MAKE_PY_LIST(arches, i = 0, i < self->srcs->n_arches, i++, |
1892 | + ("s", self->srcs->archname[i]) |
1893 | + ); |
1894 | + return arches; |
1895 | + } else if (strcmp(name, "sources") == 0) { |
1896 | + PyObject *sources; |
1897 | + sourcetbl_iter it; |
1898 | + MAKE_PY_LIST(sources, |
1899 | + it = first_sourcetbl(self->srcs->sources), |
1900 | + !done_sourcetbl(it), it = next_sourcetbl(it), |
1901 | + ("s", it.k) |
1902 | + ); |
1903 | + return sources; |
1904 | + } |
1905 | + |
1906 | + return Py_FindMethod(dpkgsources_methods, (PyObject *)self, name); |
1907 | +} |
1908 | + |
1909 | +static PyTypeObject Sources_Type = { |
1910 | + PyObject_HEAD_INIT(&PyType_Type) |
1911 | + |
1912 | + 0, /* ob_size (0) */ |
1913 | + "Sources", /* type name */ |
1914 | + sizeof(dpkgsources), /* basicsize */ |
1915 | + 0, /* itemsize (0) */ |
1916 | + |
1917 | + (destructor) dpkgsources_dealloc, |
1918 | + (printfunc) 0, |
1919 | + (getattrfunc) dpkgsources_getattr, |
1920 | + (setattrfunc) 0, |
1921 | + (cmpfunc) 0, |
1922 | + (reprfunc) 0, |
1923 | + |
1924 | + 0, /* number methods */ |
1925 | + 0, /* sequence methods */ |
1926 | + 0, /* mapping methods */ |
1927 | + |
1928 | + (hashfunc) 0, /* dict[x] ?? */ |
1929 | + (ternaryfunc) 0, /* x() */ |
1930 | + (reprfunc) 0 /* str(x) */ |
1931 | +}; |
1932 | + |
1933 | +/************************************************************************** |
1934 | + * britney.SourcesNote -- dpkg_sourcesnote wrapper |
1935 | + *************************************************/ |
1936 | + |
1937 | +typedef struct { |
1938 | + PyObject_HEAD |
1939 | + dpkg_sources_note *srcsn; |
1940 | + PyObject *refs; /* list of referenced dpkgsources */ |
1941 | +} dpkgsrcsn; |
1942 | + |
1943 | +staticforward PyTypeObject SourcesNote_Type; |
1944 | + |
1945 | +static PyObject *dpkgsrcsn_new(PyObject *self, PyObject *args) { |
1946 | + dpkgsrcsn *res = NULL; |
1947 | + PyObject *arches; |
1948 | + char **archesStr = NULL; |
1949 | + int i, count; |
1950 | + |
1951 | + (void)self; /* unused */ |
1952 | + |
1953 | + if (!PyArg_ParseTuple(args, "O!", &PyList_Type, &arches)) { |
1954 | + goto end; |
1955 | + } |
1956 | + |
1957 | + count = PyList_Size(arches); |
1958 | + if (count <= 0) { |
1959 | + PyErr_SetString(PyExc_TypeError, "No architectures specified"); |
1960 | + goto end; |
1961 | + } |
1962 | + |
1963 | + archesStr = malloc(sizeof(char *) * count); |
1964 | + if (!archesStr) { |
1965 | + PyErr_SetFromErrno(PyExc_MemoryError); |
1966 | + goto end; |
1967 | + } |
1968 | + |
1969 | + for (i = 0; i < count; i++) { |
1970 | + PyObject *arch = PyList_GetItem(arches, i); |
1971 | + if (!PyString_Check(arch)) { |
1972 | + goto end; |
1973 | + } |
1974 | + archesStr[i] = PyString_AsString(arch); |
1975 | + } |
1976 | + |
1977 | + res = PyObject_NEW(dpkgsrcsn, &SourcesNote_Type); |
1978 | + if (res == NULL) goto end; |
1979 | + |
1980 | + res->refs = PyList_New(0); |
1981 | + res->srcsn = new_sources_note(count, archesStr); |
1982 | + if (!res->refs || !res->srcsn) { |
1983 | + Py_DECREF(res); |
1984 | + res = NULL; |
1985 | + goto end; |
1986 | + } |
1987 | + |
1988 | +end: |
1989 | + if (archesStr) free(archesStr); |
1990 | + return (PyObject *) res; |
1991 | +} |
1992 | + |
1993 | +static void dpkgsrcsn_dealloc(dpkgsrcsn *self) { |
1994 | + if (self->srcsn) free_sources_note(self->srcsn); |
1995 | + self->srcsn = NULL; |
1996 | + Py_XDECREF(self->refs); |
1997 | + self->refs = NULL; |
1998 | + |
1999 | + PyObject_DEL(self); |
2000 | +} |
2001 | + |
2002 | +static PyObject *dpkgsrcsn_removesource(dpkgsrcsn *self, PyObject *args) { |
2003 | + char *name; |
2004 | + if (!PyArg_ParseTuple(args, "s", &name)) return NULL; |
2005 | + remove_source(self->srcsn, name); |
2006 | + return Py_BuildValue(""); |
2007 | +} |
2008 | +static PyObject *dpkgsrcsn_upgradesource(dpkgsrcsn *self, PyObject *args) { |
2009 | + char *name; |
2010 | + dpkgsources *srcs; |
2011 | + dpkg_source *src; |
2012 | + if (!PyArg_ParseTuple(args, "O!s", &Sources_Type, &srcs, &name)) |
2013 | + return NULL; |
2014 | + src = lookup_sourcetbl(srcs->srcs->sources, name); |
2015 | + if (!src) { |
2016 | + PyErr_SetString(PyExc_ValueError, "Source does not exist"); |
2017 | + return NULL; |
2018 | + } |
2019 | + if (!PySequence_In(self->refs, (PyObject *)srcs)) |
2020 | + PyList_Append(self->refs, (PyObject *)srcs); |
2021 | + upgrade_source(self->srcsn, src); |
2022 | + return Py_BuildValue(""); |
2023 | +} |
2024 | +static PyObject *dpkgsrcsn_upgradearch(dpkgsrcsn *self, PyObject *args) { |
2025 | + char *name, *arch; |
2026 | + dpkgsources *srcs; |
2027 | + dpkg_source *src; |
2028 | + if (!PyArg_ParseTuple(args, "O!ss", &Sources_Type, &srcs, &name, &arch)) |
2029 | + return NULL; |
2030 | + src = lookup_sourcetbl(srcs->srcs->sources, name); |
2031 | + if (!src) { |
2032 | + PyErr_SetString(PyExc_ValueError, "Source does not exist"); |
2033 | + return NULL; |
2034 | + } |
2035 | + if (!PySequence_In(self->refs, (PyObject *)srcs)) |
2036 | + PyList_Append(self->refs, (PyObject *)srcs); |
2037 | + upgrade_arch(self->srcsn, src, arch); |
2038 | + return Py_BuildValue(""); |
2039 | +} |
2040 | + |
2041 | +static PyObject *dpkgsrcsn_undochange(dpkgsrcsn *self, PyObject *args) { |
2042 | + if (!PyArg_ParseTuple(args, "")) return NULL; |
2043 | + undo_change(self->srcsn); |
2044 | + return Py_BuildValue(""); |
2045 | +} |
2046 | + |
2047 | +static PyObject *dpkgsrcsn_commitchanges(dpkgsrcsn *self, PyObject *args) { |
2048 | + if (!PyArg_ParseTuple(args, "")) return NULL; |
2049 | + commit_changes(self->srcsn); |
2050 | + return Py_BuildValue(""); |
2051 | +} |
2052 | + |
2053 | +static PyObject *dpkgsrcsn_writenotes(dpkgsrcsn *self, PyObject *args) { |
2054 | + char *dir; |
2055 | + if (!PyArg_ParseTuple(args, "s", &dir)) return NULL; |
2056 | + write_notes(dir, self->srcsn); |
2057 | + return Py_BuildValue(""); |
2058 | +} |
2059 | + |
2060 | +static PyObject *dpkgsrcsn_packages(dpkgsrcsn *self, PyObject *args) { |
2061 | + char *arch; |
2062 | + int archnum; |
2063 | + if (!PyArg_ParseTuple(args, "s", &arch)) return NULL; |
2064 | + for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) { |
2065 | + if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break; |
2066 | + } |
2067 | + if (archnum == self->srcsn->n_arches) { |
2068 | + PyErr_SetString(PyExc_ValueError, "Not a valid architecture"); |
2069 | + return NULL; |
2070 | + } |
2071 | + return dpkgpackages_new(self->srcsn->pkgs[archnum], DONTFREE, |
2072 | + (PyObject *) self); |
2073 | +} |
2074 | + |
2075 | +static PyObject *dpkgsrcsn_getversion(dpkgsrcsn *self, PyObject *args) { |
2076 | + char *srcname; |
2077 | + dpkg_source_note *srcn; |
2078 | + |
2079 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
2080 | + srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname); |
2081 | + if (srcn) return Py_BuildValue("s", srcn->source->version); |
2082 | + else return Py_BuildValue(""); |
2083 | +} |
2084 | +static PyObject *dpkgsrcsn_getfield(dpkgsrcsn *self, PyObject *args) { |
2085 | + char *srcname, *field; |
2086 | + dpkg_source_note *srcn; |
2087 | + int i; |
2088 | + dpkg_paragraph *para; |
2089 | + |
2090 | + if (!PyArg_ParseTuple(args, "ss", &srcname, &field)) return NULL; |
2091 | + srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname); |
2092 | + if (!srcn) { |
2093 | + PyErr_SetString(PyExc_ValueError, "Not a valid source package"); |
2094 | + return NULL; |
2095 | + } |
2096 | + para = srcn->source->details; |
2097 | + if (para) { |
2098 | + for (i = 0; i < para->n_entries; i++) { |
2099 | + if (strcasecmp(para->entry[i].name, field) == 0) { |
2100 | + return Py_BuildValue("s", para->entry[i].value); |
2101 | + } |
2102 | + } |
2103 | + } |
2104 | + return Py_BuildValue(""); |
2105 | +} |
2106 | +static PyObject *dpkgsrcsn_ispresent(dpkgsrcsn *self, PyObject *args) { |
2107 | + char *srcname; |
2108 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
2109 | + if (lookup_sourcenotetbl(self->srcsn->sources, srcname)) { |
2110 | + return Py_BuildValue("i", 1); |
2111 | + } else { |
2112 | + return Py_BuildValue("i", 0); |
2113 | + } |
2114 | +} |
2115 | + |
2116 | +static PyObject *dpkgsrcsn_isfake(dpkgsrcsn *self, PyObject *args) { |
2117 | + char *srcname; |
2118 | + dpkg_source_note *srcn; |
2119 | + |
2120 | + if (!PyArg_ParseTuple(args, "s", &srcname)) return NULL; |
2121 | + srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname); |
2122 | + if (srcn) return Py_BuildValue("i", srcn->source->fake); |
2123 | + else return Py_BuildValue(""); |
2124 | +} |
2125 | + |
2126 | +static PyObject *dpkgsrcsn_binaries(dpkgsrcsn *self, PyObject *args) { |
2127 | + char *srcname, *arch; |
2128 | + int archnum; |
2129 | + dpkg_source_note *srcn; |
2130 | + PyObject *res; |
2131 | + packagelist *p; |
2132 | + |
2133 | + if (!PyArg_ParseTuple(args, "ss", &srcname, &arch)) return NULL; |
2134 | + |
2135 | + for (archnum = 0; archnum < self->srcsn->n_arches; archnum++) { |
2136 | + if (strcmp(arch, self->srcsn->archname[archnum]) == 0) break; |
2137 | + } |
2138 | + if (archnum == self->srcsn->n_arches) { |
2139 | + PyErr_SetString(PyExc_ValueError, "Not a valid architecture"); |
2140 | + return NULL; |
2141 | + } |
2142 | + |
2143 | + srcn = lookup_sourcenotetbl(self->srcsn->sources, srcname); |
2144 | + if (srcn == NULL) { |
2145 | + PyErr_SetString(PyExc_ValueError, "Not a valid source package"); |
2146 | + return NULL; |
2147 | + } |
2148 | + |
2149 | + MAKE_PY_LIST(res, p = srcn->binaries[archnum], p, p = p->next, |
2150 | + ("s", p->value->package) |
2151 | + ); |
2152 | + return res; |
2153 | +} |
2154 | + |
2155 | +static PyObject *dpkgsrcsn_getattr(dpkgsrcsn *self, char *name) { |
2156 | + static struct PyMethodDef dpkgsrcsn_methods[] = { |
2157 | + { "remove_source", (binaryfunc) dpkgsrcsn_removesource, |
2158 | + METH_VARARGS, NULL }, |
2159 | + { "upgrade_source", (binaryfunc) dpkgsrcsn_upgradesource, |
2160 | + METH_VARARGS, NULL }, |
2161 | + { "upgrade_arch", (binaryfunc) dpkgsrcsn_upgradearch, |
2162 | + METH_VARARGS, NULL }, |
2163 | + |
2164 | + { "undo_change", (binaryfunc) dpkgsrcsn_undochange, |
2165 | + METH_VARARGS, NULL }, |
2166 | + { "commit_changes", (binaryfunc) dpkgsrcsn_commitchanges, |
2167 | + METH_VARARGS, NULL }, |
2168 | + |
2169 | + { "write_notes", (binaryfunc) dpkgsrcsn_writenotes, |
2170 | + METH_VARARGS, NULL }, |
2171 | + |
2172 | + { "Packages", (binaryfunc) dpkgsrcsn_packages, |
2173 | + METH_VARARGS, NULL }, |
2174 | + |
2175 | + { "get_version", (binaryfunc) dpkgsrcsn_getversion, |
2176 | + METH_VARARGS, NULL }, |
2177 | + { "get_field", (binaryfunc) dpkgsrcsn_getfield, |
2178 | + METH_VARARGS, NULL }, |
2179 | + { "is_present", (binaryfunc) dpkgsrcsn_ispresent, |
2180 | + METH_VARARGS, NULL }, |
2181 | + { "is_fake", (binaryfunc) dpkgsrcsn_isfake, |
2182 | + METH_VARARGS, NULL }, |
2183 | + { "binaries", (binaryfunc) dpkgsrcsn_binaries, |
2184 | + METH_VARARGS, NULL }, |
2185 | + { NULL, NULL, 0, NULL } |
2186 | + }; |
2187 | + |
2188 | + if (strcmp(name, "arches") == 0) { |
2189 | + PyObject *arches; |
2190 | + int i; |
2191 | + MAKE_PY_LIST(arches, i = 0, i < self->srcsn->n_arches, i++, |
2192 | + ("s", self->srcsn->archname[i]) |
2193 | + ); |
2194 | + return arches; |
2195 | + } else if (strcmp(name, "sources") == 0) { |
2196 | + PyObject *sources; |
2197 | + sourcenotetbl_iter it; |
2198 | + MAKE_PY_LIST(sources, |
2199 | + it = first_sourcenotetbl(self->srcsn->sources), |
2200 | + !done_sourcenotetbl(it), |
2201 | + it = next_sourcenotetbl(it), |
2202 | + ("s", it.k) |
2203 | + ); |
2204 | + return sources; |
2205 | + } else if (strcmp(name, "can_undo") == 0) { |
2206 | + if (can_undo(self->srcsn)) { |
2207 | + return Py_BuildValue("i", 1); |
2208 | + } else { |
2209 | + return Py_BuildValue(""); |
2210 | + } |
2211 | + } |
2212 | + |
2213 | + return Py_FindMethod(dpkgsrcsn_methods, (PyObject *)self, name); |
2214 | +} |
2215 | + |
2216 | +static PyTypeObject SourcesNote_Type = { |
2217 | + PyObject_HEAD_INIT(&PyType_Type) |
2218 | + |
2219 | + 0, /* ob_size (0) */ |
2220 | + "SourcesNote", /* type name */ |
2221 | + sizeof(dpkgsrcsn), /* basicsize */ |
2222 | + 0, /* itemsize (0) */ |
2223 | + |
2224 | + (destructor) dpkgsrcsn_dealloc, |
2225 | + (printfunc) 0, |
2226 | + (getattrfunc) dpkgsrcsn_getattr, |
2227 | + (setattrfunc) 0, |
2228 | + (cmpfunc) 0, |
2229 | + (reprfunc) 0, |
2230 | + |
2231 | + 0, /* number methods */ |
2232 | + 0, /* sequence methods */ |
2233 | + 0, /* mapping methods */ |
2234 | + |
2235 | + (hashfunc) 0, /* dict[x] ?? */ |
2236 | + (ternaryfunc) 0, /* x() */ |
2237 | + (reprfunc) 0 /* str(x) */ |
2238 | +}; |
2239 | + |
2240 | +/************************************************************************** |
2241 | + * britney.versioncmp() -- apt version compare function |
2242 | + ******************************************************/ |
2243 | + |
2244 | +static PyObject *apt_versioncmp(PyObject *self, PyObject *args) { |
2245 | + char *l, *r; |
2246 | + int res; |
2247 | + |
2248 | + (void)self; /* unused */ |
2249 | + |
2250 | + if (!PyArg_ParseTuple(args, "ss", &l, &r)) { |
2251 | + return NULL; |
2252 | + } |
2253 | + |
2254 | + res = versioncmp(l,r); |
2255 | + return Py_BuildValue("i", res); |
2256 | +} |
2257 | + |
2258 | +/************************************************************************** |
2259 | + * module initialisation |
2260 | + ***********************/ |
2261 | + |
2262 | +static PyMethodDef britneymethods[] = { |
2263 | + { "Sources", dpkgsources_new, METH_VARARGS, NULL }, |
2264 | + { "SourcesNote", dpkgsrcsn_new, METH_VARARGS, NULL }, |
2265 | + |
2266 | + { "versioncmp", apt_versioncmp, METH_VARARGS, NULL }, |
2267 | + |
2268 | + { NULL, NULL, 0, NULL } |
2269 | +}; |
2270 | + |
2271 | +void initbritney(void) { |
2272 | + Py_InitModule("britney", britneymethods); |
2273 | +} |
2274 | + |
2275 | |
2276 | === added file 'update_out/checklib.c' |
2277 | --- update_out/checklib.c 1970-01-01 00:00:00 +0000 |
2278 | +++ update_out/checklib.c 2020-03-12 14:58:23 +0000 |
2279 | @@ -0,0 +1,185 @@ |
2280 | +#include <stdlib.h> |
2281 | +#include <unistd.h> |
2282 | + |
2283 | +#include <assert.h> |
2284 | + |
2285 | +#include "dpkg.h" |
2286 | + |
2287 | +#if 0 |
2288 | +static void checknewsrc(sourcetbl *srcstbl, dpkg_source *cur, void *data) { |
2289 | + dpkg_sources *oldsrc = data; |
2290 | + dpkg_source *old; |
2291 | + old = lookup_sourcetbl(oldsrc->sources, cur->package); |
2292 | + if (old == NULL) { |
2293 | + printf("New: %s (%s)\n", cur->package, cur->version ); |
2294 | + } else if (strcmp(old->version, cur->version) != 0) { |
2295 | + printf("Updated: %s (%s, was %s)\n", |
2296 | + cur->package, cur->version, old->version ); |
2297 | + } else { |
2298 | + dpkg_source *src2; |
2299 | + src2 = remove_sourcetbl(srcstbl, cur->package); |
2300 | + assert(cur == src2); |
2301 | + free_source(cur); |
2302 | + } |
2303 | +} |
2304 | + |
2305 | +static void checkoldsrc(sourcetbl *oldsrctbl, dpkg_source *old, void *data) { |
2306 | + dpkg_sources *src = data; |
2307 | + dpkg_source *cur; |
2308 | + (void)oldsrctbl; |
2309 | + cur = lookup_sourcetbl(src->sources, old->package); |
2310 | + if (cur == NULL) { |
2311 | + printf("Removed: %s (was %s)\n", old->package, old->version ); |
2312 | + } |
2313 | +} |
2314 | + |
2315 | +static void checkuptodate(sourcetbl *srctbl, dpkg_source *src, void *data) { |
2316 | + int i; |
2317 | + int remove; |
2318 | + ownedpackagelist **p; |
2319 | + dpkg_sources *srcs = data; |
2320 | + |
2321 | + (void)srctbl; |
2322 | + |
2323 | + remove = 0; |
2324 | + for (i = 0; i < srcs->n_arches; i++) { |
2325 | + p = &src->packages[i]; |
2326 | + while(*p != NULL) { |
2327 | + if (strcmp((*p)->value->source_ver, src->version) != 0) { |
2328 | + if (cmpversions((*p)->value->source_ver, GT, src->version)) { |
2329 | + printf("ALERT: old source: "); |
2330 | + } else { |
2331 | + printf("WARN: out of date: "); |
2332 | + } |
2333 | + printf("%s %s: %s binary: %s %s from %s\n", |
2334 | + src->package, src->version, srcs->archname[i], |
2335 | + (*p)->value->package, (*p)->value->version, |
2336 | + (*p)->value->source_ver); |
2337 | + delete_ownedpackagelist(p); |
2338 | + } else { |
2339 | + p = &(*p)->next; |
2340 | + } |
2341 | + } |
2342 | + if (src->packages[i] == NULL) { |
2343 | + printf("%s missing uptodate binaries for %s\n", |
2344 | + src->package, srcs->archname[i]); |
2345 | + remove = 1; |
2346 | + } |
2347 | + } |
2348 | + if (remove) { |
2349 | + dpkg_source *src2; |
2350 | + src2 = remove_sourcetbl(srcs->sources, src->package); |
2351 | + assert(src == src2); |
2352 | + free_source(src); |
2353 | + } |
2354 | +} |
2355 | +#endif |
2356 | + |
2357 | +static void upgrade(sourcetbl *srctbl, dpkg_source *src, void *data) { |
2358 | + static int i = 0; |
2359 | + dpkg_sources_note *srcsn = data; |
2360 | + (void)srctbl; |
2361 | + i++; i %= 1000; |
2362 | + if (can_undo(srcsn)) { |
2363 | + if (i % 29 == 1 || i % 31 == 1 || i % 7 == 5) |
2364 | + undo_change(srcsn); |
2365 | + if (i % 33 == 0) commit_changes(srcsn); |
2366 | + } |
2367 | + upgrade_source(data, src); |
2368 | +} |
2369 | + |
2370 | +static void checkpkgs(packagetbl *pkgtbl, dpkg_collected_package *cpkg, |
2371 | + void *data) |
2372 | +{ |
2373 | + dpkg_packages *pkgs = data; |
2374 | + assert(pkgs->packages == pkgtbl); |
2375 | + printf("Trying %s (%s, %s)\n", cpkg->pkg->package, cpkg->pkg->version, pkgs->arch); |
2376 | + if (!checkinstallable2(pkgs, cpkg->pkg->package)) { |
2377 | + printf("Package: %s (%s, %s) is uninstallable\n", |
2378 | + cpkg->pkg->package, cpkg->pkg->version, pkgs->arch); |
2379 | + } |
2380 | +} |
2381 | + |
2382 | +void print_memblock_summary(void); |
2383 | + |
2384 | +int main(int argc, char **argv) { |
2385 | + dpkg_sources *src = NULL, *oldsrc = NULL; |
2386 | + dpkg_sources_note *srcsn; |
2387 | + dpkg_source *srcpkg; |
2388 | + dpkg_packages *pkgs[10]; |
2389 | + int n_pkgs; |
2390 | + int i,j; |
2391 | + int reps; |
2392 | + |
2393 | + if (argc < 3) { |
2394 | + printf("Usage: %s <reps> <arch>...\n", argv[0]); |
2395 | + exit(EXIT_FAILURE); |
2396 | + } |
2397 | + |
2398 | + reps = atoi(argv[1]); |
2399 | + if (reps < 1) { |
2400 | + printf("reps must be >= 1\n"); |
2401 | + exit(EXIT_FAILURE); |
2402 | + } |
2403 | + |
2404 | + src = read_directory("cur", argc - 2, argv + 2); |
2405 | + oldsrc = read_directory("old", argc - 2, argv + 2); |
2406 | + srcsn = new_sources_note(argc - 2, argv + 2); |
2407 | + |
2408 | + printf("FINISHED LOADING\n"); fflush(stdout); /* sleep(5); */ |
2409 | + |
2410 | +#if 0 |
2411 | + iterate_sourcetbl(oldsrc->sources, checkoldsrc, src); |
2412 | + |
2413 | + printf("FIRST\n"); |
2414 | + iterate_sourcetbl(src->sources, checkuptodate, src); |
2415 | + printf("SECOND\n"); |
2416 | + iterate_sourcetbl(src->sources, checkuptodate, src); |
2417 | + printf("END\n"); |
2418 | + |
2419 | + iterate_sourcetbl(src->sources, checknewsrc, oldsrc); |
2420 | +#endif |
2421 | + |
2422 | + n_pkgs = 0; |
2423 | + for (i = argc - 1; i > 1; i--) { |
2424 | + pkgs[n_pkgs++] = get_architecture(oldsrc, argv[i]); |
2425 | + } |
2426 | + for (j = 0; j < reps; j++) { |
2427 | + printf("Round %d/%d starting...\n", j + 1, reps); |
2428 | + for (i = 0; i < n_pkgs; i++) { |
2429 | + iterate_packagetbl(pkgs[i]->packages, checkpkgs, pkgs[i]); |
2430 | + } |
2431 | + printf("Round %d ended.\n", j+1); |
2432 | + } |
2433 | + iterate_sourcetbl(src->sources, upgrade, srcsn); |
2434 | + iterate_sourcetbl(oldsrc->sources, upgrade, srcsn); |
2435 | + |
2436 | + for (i = 0; i < n_pkgs; i++) { |
2437 | + free_packages(pkgs[i]); |
2438 | + } |
2439 | + |
2440 | + srcpkg = lookup_sourcetbl(oldsrc->sources, "omirr"); |
2441 | + if (srcpkg != NULL) { |
2442 | + printf("Adding old\n"); |
2443 | + upgrade_source(srcsn, srcpkg); |
2444 | + } |
2445 | + srcpkg = lookup_sourcetbl(src->sources, "omirr"); |
2446 | + if (srcpkg != NULL) { |
2447 | + printf("Adding cur\n"); |
2448 | + upgrade_source(srcsn, srcpkg); |
2449 | + } |
2450 | + |
2451 | + printf("FINISHED PROCESSING\n"); fflush(stdout); /* sleep(5); */ |
2452 | + |
2453 | + write_directory("out", oldsrc); |
2454 | + |
2455 | + printf("FINISHED WRITING\n"); fflush(stdout); /* sleep(5); */ |
2456 | + |
2457 | + free_sources_note(srcsn); |
2458 | + free_sources(src); |
2459 | + free_sources(oldsrc); |
2460 | + |
2461 | + DEBUG_ONLY( print_memblock_summary(); ) |
2462 | + |
2463 | + return 0; |
2464 | +} |
2465 | |
2466 | === added file 'update_out/dpkg-lib.cpp' |
2467 | --- update_out/dpkg-lib.cpp 1970-01-01 00:00:00 +0000 |
2468 | +++ update_out/dpkg-lib.cpp 2020-03-12 14:58:23 +0000 |
2469 | @@ -0,0 +1,34 @@ |
2470 | + |
2471 | +#include <apt-pkg/debversion.h> |
2472 | + |
2473 | +extern "C" { |
2474 | + |
2475 | +#include "dpkg.h" |
2476 | + |
2477 | +int versioncmp(char *left, char *right) { |
2478 | + return debVS.CmpVersion(left, right); |
2479 | +} |
2480 | + |
2481 | +int cmpversions(char *left, int op, char *right) { |
2482 | + int i = debVS.CmpVersion(left, right); |
2483 | + |
2484 | + switch(op) { |
2485 | + case dr_LT: return i < 0; |
2486 | + case dr_LTEQ: return i <= 0; |
2487 | + case dr_EQ: return i == 0; |
2488 | + case dr_GTEQ: return i >= 0; |
2489 | + case dr_GT: return i > 0; |
2490 | + } |
2491 | + return 0; |
2492 | +} |
2493 | + |
2494 | +} |
2495 | + |
2496 | +#ifdef TESTBIN |
2497 | +int main(int argc, char **argv) { |
2498 | + if (argc != 3) { printf("Usage: %s <ver> <ver>\n", argv[0]); exit(1); } |
2499 | + |
2500 | + printf("%d\n", versioncmp(argv[1], argv[2])); |
2501 | + return 0; |
2502 | +} |
2503 | +#endif |
2504 | |
2505 | === added file 'update_out/dpkg.c' |
2506 | --- update_out/dpkg.c 1970-01-01 00:00:00 +0000 |
2507 | +++ update_out/dpkg.c 2020-03-12 14:58:23 +0000 |
2508 | @@ -0,0 +1,2013 @@ |
2509 | +#include <stdio.h> |
2510 | +#include <stdlib.h> |
2511 | +#include <string.h> |
2512 | +#include <ctype.h> |
2513 | +#include <errno.h> |
2514 | + |
2515 | +#include "dpkg.h" |
2516 | +#include "memory.h" |
2517 | + |
2518 | + |
2519 | +// enlarge this is britney has issues to parse packages |
2520 | +#define SIZEOFHASHMAP 16 |
2521 | + |
2522 | +#define insert_packagenamelist(x,y) insert_l_packagenamelist(x,y,__LINE__) |
2523 | + |
2524 | +static void free_dependency(dependency *dep); |
2525 | +static void free_package(dpkg_package *pkg); |
2526 | +static void free_collected_package(dpkg_collected_package *pkg); |
2527 | +static dpkg_paragraph *read_paragraph( FILE *f ); |
2528 | +static dpkg_package *read_package( FILE *f ); |
2529 | +static collpackagelist **get_matching_low(collpackagelist **addto, |
2530 | + dpkg_packages *pkgs, dependency *dep, int line); |
2531 | +static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line); |
2532 | +static deplist *read_dep_and(char *buf); |
2533 | +static deplistlist *read_dep_andor(char *buf); |
2534 | +static ownedpackagenamelist *read_packagenames(char *buf); |
2535 | +static dpkg_sources *read_sources_file(char *filename, int n_arches); |
2536 | +static dpkg_source *new_source(dpkg_sources *owner); |
2537 | +static dpkg_source *read_source(FILE *f, dpkg_sources *owner); |
2538 | +static deplist *read_deplist(char **buf, char sep, char end); |
2539 | +static dependency *read_dependency(char **buf, char *end); |
2540 | +static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package, |
2541 | + char *version, dpkg_collected_package *cpkg); |
2542 | +static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname, |
2543 | + dpkg_collected_package *cpkg); |
2544 | +static char *read_packagename(char **buf, char *end); |
2545 | +static char *read_until_char(char **buf, char *end); |
2546 | +static void add_package(dpkg_packages *pkgs, dpkg_package *pkg); |
2547 | +static void remove_package(dpkg_packages *pkgs, dpkg_collected_package *pkg); |
2548 | +static dpkg_source_note *copy_source_note(dpkg_source_note *srcn); |
2549 | + |
2550 | +#if 0 |
2551 | +static inline void *bm(size_t s, int n) { void *res = block_malloc(s); fprintf(stderr, "ALLOCED: %d %p %lu\n", n, res, s); return res; } |
2552 | +static inline void bf(void *p, size_t s, int n) { block_free(p,s); fprintf(stderr, "FREED: %d %p %lu\n", n, p, s); } |
2553 | + |
2554 | +#define block_malloc(s) bm(s,__LINE__) |
2555 | +#define block_free(p,s) bf(p,s,__LINE__) |
2556 | +#endif |
2557 | + |
2558 | +#define block_malloc(s) block_malloc2(s, __LINE__) |
2559 | + |
2560 | +static char *priorities[] = { |
2561 | + "required", |
2562 | + "important", |
2563 | + "standard", |
2564 | + "optional", |
2565 | + "extra", |
2566 | + NULL |
2567 | +}; |
2568 | + |
2569 | +static char *dependency_title[] = { |
2570 | + "Pre-Depends", "Depends", "Recommends", "Suggests", NULL |
2571 | +}; |
2572 | + |
2573 | +static int dependency_counts[] = { 1, 1, 0, 0 }; |
2574 | + |
2575 | +char *dependency_relation_sym[] = {"*", "<<", "<=", "=", ">=", ">>"}; |
2576 | + |
2577 | +#define SMB_SIZE (1<<22) |
2578 | +struct stringmemblock { |
2579 | + struct stringmemblock *next; |
2580 | + size_t last; |
2581 | + char mem[SMB_SIZE]; |
2582 | +}; |
2583 | +static struct stringmemblock *stringmemory = NULL; |
2584 | +static int stringmemorycount = 0; |
2585 | +static const unsigned long stringmemblocksizekib = (unsigned long) sizeof(struct stringmemblock) / 1024; |
2586 | + |
2587 | +char *my_strdup(char *foo) { |
2588 | + struct stringmemblock *which; |
2589 | + size_t len; |
2590 | + |
2591 | + if (!foo) return NULL; |
2592 | + |
2593 | + len = strlen(foo) + 1; |
2594 | + |
2595 | + if (len > SMB_SIZE) return strdup(foo); |
2596 | + |
2597 | + for (which = stringmemory; which; which = which->next) { |
2598 | + if (SMB_SIZE - which->last > len + 1) { |
2599 | + break; |
2600 | + } |
2601 | + } |
2602 | + if (!which) { |
2603 | + which = malloc(sizeof(struct stringmemblock)); |
2604 | + if (!which) return NULL; |
2605 | + MDEBUG1_ONLY(fprintf(stderr, |
2606 | + "ALLOC: string memblock %d (%lu KiB, %lu KiB total)\n", |
2607 | + stringmemorycount, stringmemblocksizekib, |
2608 | + (stringmemorycount+1) * stringmemblocksizekib)); |
2609 | + memset(which->mem, 0, SMB_SIZE); |
2610 | + which->last = 0; |
2611 | + which->next = stringmemory; |
2612 | + stringmemory = which; |
2613 | + stringmemorycount++; |
2614 | + } |
2615 | + strcpy(&which->mem[which->last], foo); |
2616 | + foo = &which->mem[which->last]; |
2617 | + which->last += len; |
2618 | + return foo; |
2619 | +} |
2620 | + |
2621 | +char *my_rep_strdup(char *foo) { |
2622 | + static char *repeats[1000] = {0}; |
2623 | + int i; |
2624 | + |
2625 | + for (i = 0; i < 1000; i++) { |
2626 | + if (repeats[i] == NULL) { |
2627 | + DEBUG_ONLY(fprintf(stderr, "REPEAT NR %d\n", i+1); ) |
2628 | + return repeats[i] = my_strdup(foo); |
2629 | + } |
2630 | + if (strcmp(repeats[i], foo) == 0) return repeats[i]; |
2631 | + } |
2632 | + |
2633 | + return my_strdup(foo); |
2634 | +} |
2635 | + |
2636 | +/* DIE **/ |
2637 | + |
2638 | +static void die(char *orig_msg) { |
2639 | + char *msg = my_strdup(orig_msg); |
2640 | + if (*msg && msg[strlen(msg)-1] == ':') { |
2641 | + msg[strlen(msg)-1] = '\0'; |
2642 | + perror(msg); |
2643 | + } else { |
2644 | + printf("%s\n", msg); |
2645 | + } |
2646 | + abort(); |
2647 | +} |
2648 | + |
2649 | +/************************************************************************* |
2650 | + * Dpkg Control/Packages/etc Operations |
2651 | + */ |
2652 | + |
2653 | +static dpkg_paragraph *read_paragraph( FILE *f ) { |
2654 | + dpkg_paragraph *result; |
2655 | + static int line_size = 0; |
2656 | + static char *line = NULL; |
2657 | + char *pch; |
2658 | + |
2659 | + dpkg_entry *c_entry = NULL; |
2660 | + char *c_value = NULL; |
2661 | + |
2662 | + if (line == NULL) { |
2663 | + line_size = 10; |
2664 | + line = malloc(line_size); |
2665 | + if (line == NULL) die("read_paragraph alloc 0:"); |
2666 | + } |
2667 | + |
2668 | + result = block_malloc( sizeof(dpkg_paragraph) ); |
2669 | + if (result == NULL) die("read_paragraph alloc 1:"); |
2670 | + |
2671 | + result->n_entries = 0; |
2672 | + result->entry = NULL; |
2673 | + result->n_allocated = 0; |
2674 | + |
2675 | + while(fgets(line, line_size, f)) { |
2676 | + while (!feof(f) && *line && line[strlen(line)-1] != '\n') { |
2677 | + line = realloc(line, line_size * 2); |
2678 | + if (!line) die("read_paragraph realloc:"); |
2679 | + fgets(line + strlen(line), line_size, f); |
2680 | + line_size *= 2; |
2681 | + } |
2682 | + |
2683 | + if (line[0] == '\n') break; |
2684 | + |
2685 | + if (isspace(line[0])) { |
2686 | + if (c_value == NULL) |
2687 | + die("read_paragraph early spaces"); |
2688 | + |
2689 | + if (c_entry == NULL) { |
2690 | + /* no need to bother */ |
2691 | + } else { |
2692 | + /* extend the line */ |
2693 | + c_value = realloc(c_value, strlen(c_value) + strlen(line) + 1); |
2694 | + if (c_value == NULL) |
2695 | + die("read_paragraph realloc c_value:"); |
2696 | + |
2697 | + strcat(c_value, line); |
2698 | + } |
2699 | + } else { |
2700 | + if (c_entry) { |
2701 | + c_entry->value = my_strdup(c_value); |
2702 | + c_value[0] = '\0'; |
2703 | + free(c_value); |
2704 | + c_value = NULL; |
2705 | + } else if (c_value) { |
2706 | + free(c_value); |
2707 | + c_value = NULL; |
2708 | + } |
2709 | + pch = strchr(line, ':'); |
2710 | + if (pch == NULL) { |
2711 | + fprintf(stderr, "the line was: \"%s\"\n", line); |
2712 | + die("read_paragraph: no colon"); |
2713 | + } |
2714 | + |
2715 | + *pch = '\0'; |
2716 | + while(isspace(*++pch)); |
2717 | + |
2718 | + if (strcmp(line, "Description") == 0) { |
2719 | + c_value = strdup(pch); |
2720 | + c_entry = NULL; |
2721 | + } else { |
2722 | + assert(result->n_entries <= result->n_allocated); |
2723 | + if (result->n_entries >= result->n_allocated) { |
2724 | + result->n_allocated += 10; |
2725 | + result->entry = realloc( result->entry, |
2726 | + sizeof(dpkg_entry) |
2727 | + * result->n_allocated); |
2728 | + if (result->entry == NULL) |
2729 | + die("read_paragraph realloc entry:"); |
2730 | + } |
2731 | + |
2732 | + c_entry = &result->entry[result->n_entries++]; |
2733 | + c_entry->name = my_rep_strdup(line); |
2734 | + c_value = strdup(pch); |
2735 | + } |
2736 | + } |
2737 | + } |
2738 | + |
2739 | + if (c_entry) { |
2740 | + c_entry->value = my_strdup(c_value); |
2741 | + c_value[0] = '\0'; |
2742 | + free(c_value); |
2743 | + c_value = NULL; |
2744 | + } |
2745 | + |
2746 | + if (result->n_entries == 0) { |
2747 | + if (result->entry) free(result->entry); |
2748 | + block_free(result, sizeof(dpkg_paragraph)); |
2749 | + return NULL; |
2750 | + } else { |
2751 | + result->entry = realloc(result->entry, |
2752 | + sizeof(result->entry[0]) * result->n_entries); |
2753 | + result->n_allocated = result->n_entries; |
2754 | + } |
2755 | + |
2756 | + return result; |
2757 | +} |
2758 | + |
2759 | +static void write_paragraph(FILE *f, dpkg_paragraph *p) { |
2760 | + int i; |
2761 | + |
2762 | + for (i = 0; i < p->n_entries; i++) { |
2763 | + fprintf(f, "%s: %s", p->entry[i].name, p->entry[i].value); |
2764 | + } |
2765 | + fprintf(f, "\n"); |
2766 | +} |
2767 | + |
2768 | + |
2769 | +static void free_paragraph(dpkg_paragraph *p) { |
2770 | + int i; |
2771 | + |
2772 | + if (p == NULL) return; |
2773 | + |
2774 | + for (i = 0; i < p->n_entries; i++) { |
2775 | + /* block_free(p->entry[i].name); */ |
2776 | + /* block_free(p->entry[i].value); */ |
2777 | + } |
2778 | + free(p->entry); |
2779 | + block_free(p, sizeof(dpkg_paragraph)); |
2780 | +} |
2781 | + |
2782 | +/************************************************************************* |
2783 | + * Basic Package Operations |
2784 | + */ |
2785 | + |
2786 | +static dpkg_package *new_package(void) { |
2787 | + dpkg_package *result; |
2788 | + |
2789 | + result = block_malloc(sizeof(dpkg_package)); |
2790 | + if (result == NULL) die("new_package alloc:"); |
2791 | + |
2792 | + result->package = NULL; |
2793 | + result->version = NULL; |
2794 | + |
2795 | + result->priority = 0; |
2796 | + result->arch_all = 0; |
2797 | + |
2798 | + result->source = NULL; |
2799 | + result->source_ver = NULL; |
2800 | + |
2801 | + result->depends[0] = NULL; |
2802 | + result->depends[1] = NULL; |
2803 | + result->depends[2] = NULL; |
2804 | + result->depends[3] = NULL; |
2805 | + |
2806 | + result->conflicts = NULL; |
2807 | + |
2808 | + result->provides = NULL; |
2809 | + result->details = NULL; |
2810 | + |
2811 | + return result; |
2812 | +} |
2813 | + |
2814 | +static dpkg_collected_package *new_collected_package(dpkg_package *pkg) { |
2815 | + dpkg_collected_package *result; |
2816 | + |
2817 | + result = block_malloc(sizeof(dpkg_collected_package)); |
2818 | + if (result == NULL) die("new_collected_package alloc:"); |
2819 | + |
2820 | + result->pkg = pkg; |
2821 | + |
2822 | + result->installed = 0; |
2823 | + result->conflicted = 0; |
2824 | + |
2825 | + result->installable = UNKNOWN; |
2826 | + result->mayaffect = NULL; |
2827 | + |
2828 | + return result; |
2829 | +} |
2830 | + |
2831 | +static void free_collected_package(dpkg_collected_package *cpkg) { |
2832 | + if (cpkg == NULL) return; |
2833 | + cpkg->pkg = NULL; |
2834 | + free_packagenamelist(cpkg->mayaffect); |
2835 | + cpkg->mayaffect = NULL; |
2836 | + block_free(cpkg, sizeof(dpkg_collected_package)); |
2837 | +} |
2838 | + |
2839 | +static void free_package(dpkg_package *pkg) { |
2840 | + int i; |
2841 | + if (pkg == NULL) return; |
2842 | + |
2843 | + /* block_free(pkg->package); |
2844 | + * block_free(pkg->version); |
2845 | + * block_free(pkg->source); |
2846 | + * block_free(pkg->source_ver); */ |
2847 | + |
2848 | + for (i = 0; i < 4; i++) |
2849 | + free_deplistlist(pkg->depends[i]); |
2850 | + |
2851 | + free_deplist(pkg->conflicts); |
2852 | + free_ownedpackagenamelist(pkg->provides); |
2853 | + |
2854 | + free_paragraph(pkg->details); |
2855 | + |
2856 | + block_free(pkg, sizeof(dpkg_package)); |
2857 | +} |
2858 | + |
2859 | +static dpkg_package *read_package( FILE *f ) { |
2860 | + dpkg_package *result; |
2861 | + dpkg_paragraph *para; |
2862 | + dpkg_entry *e; |
2863 | + int i; |
2864 | + |
2865 | + para = read_paragraph(f); |
2866 | + if (para == NULL) return NULL; |
2867 | + |
2868 | + result = new_package(); |
2869 | + result->details = para; |
2870 | + |
2871 | + for (e = ¶->entry[0]; e < ¶->entry[para->n_entries]; e++) { |
2872 | + if (strcasecmp("Package", e->name) == 0) { |
2873 | + result->package = my_strdup(e->value); |
2874 | + if (result->package == NULL) |
2875 | + die("read_package my_strdup:"); |
2876 | + result->package[strlen(result->package)-1] = '\0'; |
2877 | + } |
2878 | + |
2879 | + if (strcasecmp("Version", e->name) == 0) { |
2880 | + result->version = my_strdup(e->value); |
2881 | + if (result->version == NULL) |
2882 | + die("read_package my_strdup:"); |
2883 | + result->version[strlen(result->version)-1] = '\0'; |
2884 | + } |
2885 | + |
2886 | + if (strcasecmp("Priority", e->name) == 0) { |
2887 | + int i; |
2888 | + for (i = 0; priorities[i] != NULL; i++) { |
2889 | + if (strcasecmp(priorities[i], e->value)) |
2890 | + break; |
2891 | + } |
2892 | + result->priority = i; |
2893 | + if (priorities[i] == NULL) { |
2894 | + die("read_package: unknown priority"); |
2895 | + } |
2896 | + } |
2897 | + |
2898 | + if (strcasecmp("Architecture", e->name) == 0) { |
2899 | + if (strncasecmp(e->value, "all", 3) == 0) { |
2900 | + if (!e->value[3] || isspace(e->value[3])) { |
2901 | + result->arch_all = 1; |
2902 | + } |
2903 | + } |
2904 | + } |
2905 | + |
2906 | + for (i = 0; dependency_title[i] != NULL; i++) { |
2907 | + if (strcasecmp(dependency_title[i], e->name) == 0) { |
2908 | + result->depends[i] = read_dep_andor(e->value); |
2909 | + } |
2910 | + } |
2911 | + |
2912 | + /* |
2913 | + * Support Breaks by treating them as Conflicts. |
2914 | + */ |
2915 | + if (strcasecmp("Conflicts", e->name) == 0 |
2916 | + || strcasecmp("Breaks", e->name) == 0) { |
2917 | + deplist *pkgs = read_dep_and(e->value); |
2918 | + if (result->conflicts == NULL) |
2919 | + result->conflicts = pkgs; |
2920 | + else { |
2921 | + // TODO(dato): create extend_deplist() in templates.h? |
2922 | + deplist *end = result->conflicts; |
2923 | + while (end->next) |
2924 | + end = end->next; |
2925 | + end->next = pkgs; |
2926 | + } |
2927 | + } |
2928 | + |
2929 | + if (strcasecmp("Provides", e->name) == 0) |
2930 | + result->provides = read_packagenames(e->value); |
2931 | + |
2932 | + if (strcasecmp("source", e->name) == 0) { |
2933 | + char *pch = e->value; |
2934 | + |
2935 | + assert(result->source == NULL); |
2936 | + assert(result->source_ver == NULL); |
2937 | + |
2938 | + result->source = my_strdup(read_packagename(&pch, "(")); |
2939 | + if (result->source == NULL) |
2940 | + die("read_package: bad source header"); |
2941 | + |
2942 | + while(isspace(*pch)) pch++; |
2943 | + if (*pch == '(') { |
2944 | + pch++; |
2945 | + result->source_ver = my_strdup(read_until_char(&pch, ")")); |
2946 | + if (result->source_ver == NULL) |
2947 | + die("read_package: bad source version"); |
2948 | + while(isspace(*pch)) pch++; |
2949 | + if (*pch != ')') |
2950 | + die("read_package: unterminated ver"); |
2951 | + } |
2952 | + } |
2953 | + } |
2954 | + |
2955 | + if (result->source == NULL) { |
2956 | + assert(result->source_ver == NULL); |
2957 | + result->source = my_strdup(result->package); |
2958 | + } |
2959 | + if (result->source_ver == NULL) { |
2960 | + result->source_ver = my_strdup(result->version); |
2961 | + } |
2962 | + |
2963 | + return result; |
2964 | +} |
2965 | + |
2966 | +static void freesize(void *p, size_t s) { (void)s; free(p); } |
2967 | + |
2968 | +LIST_IMPL(deplist, dependency*, free_dependency, block_malloc, block_free); |
2969 | +LIST_IMPL(deplistlist, deplist*, free_deplist, block_malloc, block_free); |
2970 | + |
2971 | +LIST_IMPLX(packagenamelist, char*, KEEP(char*)); |
2972 | + |
2973 | +LIST_IMPL(ownedpackagenamelist, char*, KEEP(char*), block_malloc, block_free); |
2974 | + /* ownedpackagenamelist stores the packagename in the string store */ |
2975 | + |
2976 | +static int packagecmp(dpkg_package *l, dpkg_package *r) { |
2977 | + if (l->priority < r->priority) return -1; |
2978 | + if (l->priority > r->priority) return +1; |
2979 | + return strcmp(l->package, r->package); |
2980 | +} |
2981 | + |
2982 | +/* container for owned pkgs */ |
2983 | +LIST_IMPL(ownedpackagelist, dpkg_package *, free_package, |
2984 | + block_malloc, block_free); |
2985 | + |
2986 | +/* container for existing pkgs */ |
2987 | +LIST_IMPL(packagelist, dpkg_package *, KEEP(dpkg_package *), block_malloc, block_free); |
2988 | + |
2989 | +LIST_IMPLX(collpackagelist, dpkg_collected_package *, |
2990 | + KEEP(dpkg_collected_package *)) |
2991 | +#define insert_collpackagelist(x,y) insert_l_collpackagelist(x,y,__LINE__) |
2992 | + |
2993 | +/************************************************************************* |
2994 | + * Operations on distributions (collections of packages) |
2995 | + */ |
2996 | + |
2997 | +dpkg_packages *new_packages(char *arch) { |
2998 | + dpkg_packages *result; |
2999 | + |
3000 | + result = block_malloc(sizeof(dpkg_packages)); |
3001 | + if (result == NULL) die("new_packages alloc:"); |
3002 | + |
3003 | + result->arch = my_strdup(arch); |
3004 | + result->packages = new_packagetbl(); |
3005 | + result->virtualpkgs = new_virtualpkgtbl(); |
3006 | + |
3007 | + return result; |
3008 | +} |
3009 | + |
3010 | +static void add_package(dpkg_packages *pkgs, dpkg_package *pkg) |
3011 | +{ |
3012 | + ownedpackagenamelist *v; |
3013 | + dpkg_collected_package *cpkg; |
3014 | + |
3015 | + if (lookup_packagetbl(pkgs->packages, pkg->package) != NULL) |
3016 | + return; |
3017 | + |
3018 | + cpkg = new_collected_package(pkg); |
3019 | + |
3020 | + add_packagetbl(pkgs->packages, cpkg->pkg->package, cpkg); |
3021 | + |
3022 | + add_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package, |
3023 | + cpkg->pkg->version, cpkg); |
3024 | + for (v = cpkg->pkg->provides; v != NULL; v = v->next) { |
3025 | + add_virtualpackage(pkgs->virtualpkgs, v->value, NULL, cpkg); |
3026 | + } |
3027 | +} |
3028 | + |
3029 | +static void remove_package(dpkg_packages *pkgs, dpkg_collected_package *cpkg) { |
3030 | + ownedpackagenamelist *v; |
3031 | + packagenamelist *aff; |
3032 | + dpkg_collected_package *p; |
3033 | + |
3034 | + for (aff = cpkg->mayaffect; aff != NULL; aff = aff->next) { |
3035 | + p = lookup_packagetbl(pkgs->packages, aff->value); |
3036 | + if (p == NULL) continue; |
3037 | + p->installable = UNKNOWN; |
3038 | + } |
3039 | + |
3040 | + p = remove_packagetbl(pkgs->packages, cpkg->pkg->package); |
3041 | + if (p != cpkg) return; |
3042 | + |
3043 | + remove_virtualpackage(pkgs->virtualpkgs, cpkg->pkg->package, cpkg); |
3044 | + for (v = cpkg->pkg->provides; v != NULL; v = v->next) { |
3045 | + remove_virtualpackage(pkgs->virtualpkgs, v->value, cpkg); |
3046 | + } |
3047 | + |
3048 | + free_collected_package(cpkg); |
3049 | +} |
3050 | + |
3051 | +dpkg_packages *get_architecture(dpkg_sources *srcs, char *arch) { |
3052 | + int i, arch_index; |
3053 | + dpkg_packages *result; |
3054 | + sourcetbl_iter srci; |
3055 | + ownedpackagelist *p; |
3056 | + |
3057 | + arch_index = -1; |
3058 | + for (i = 0; i < srcs->n_arches; i++) { |
3059 | + if (strcmp(srcs->archname[i], arch) == 0) { |
3060 | + arch_index = i; |
3061 | + break; |
3062 | + } |
3063 | + } |
3064 | + if (arch_index == -1) die("get_architecture: unknown arch"); |
3065 | + |
3066 | + result = new_packages(arch); |
3067 | + |
3068 | + for (srci = first_sourcetbl(srcs->sources); |
3069 | + !done_sourcetbl(srci); |
3070 | + srci = next_sourcetbl(srci)) |
3071 | + { |
3072 | + for (p = srci.v->packages[arch_index]; p != NULL; p = p->next) { |
3073 | + add_package(result, p->value); |
3074 | + } |
3075 | + } |
3076 | + |
3077 | + return result; |
3078 | +} |
3079 | + |
3080 | +void free_packages(dpkg_packages *pkgs) { |
3081 | + if (pkgs == NULL) return; |
3082 | + /* block_free(pkgs->arch); */ |
3083 | + free_packagetbl(pkgs->packages); |
3084 | + free_virtualpkgtbl(pkgs->virtualpkgs); |
3085 | + block_free(pkgs, sizeof(dpkg_packages)); |
3086 | +} |
3087 | + |
3088 | + |
3089 | +HASH_IMPL(packagetbl, char *, dpkg_collected_package *, SIZEOFHASHMAP, strhash, strcmp, |
3090 | + KEEP(char*),free_collected_package); |
3091 | +HASH_IMPL(virtualpkgtbl, char *, virtualpkg *, SIZEOFHASHMAP, strhash, strcmp, |
3092 | + KEEP(char*), free_virtualpkg); |
3093 | + |
3094 | +/* dpkg_provision refers to memory allocated elsewhere */ |
3095 | +LIST_IMPL(virtualpkg, dpkg_provision, KEEP(dpkg_provision), block_malloc, block_free); |
3096 | + |
3097 | +static void remove_virtualpackage(virtualpkgtbl *vpkgs, char *pkgname, |
3098 | + dpkg_collected_package *cpkg) |
3099 | +{ |
3100 | + virtualpkg *list; |
3101 | + virtualpkg **where; |
3102 | + list = lookup_virtualpkgtbl(vpkgs, pkgname); |
3103 | + assert(list != NULL); |
3104 | + |
3105 | + where = &list; |
3106 | + while((*where)->value.pkg != cpkg) { |
3107 | + where = &(*where)->next; |
3108 | + assert(*where != NULL); |
3109 | + } |
3110 | + |
3111 | + delete_virtualpkg(where); |
3112 | + |
3113 | + if (list == NULL) { |
3114 | + remove_virtualpkgtbl(vpkgs, pkgname); |
3115 | + } else { |
3116 | + replace_virtualpkgtbl(vpkgs, pkgname, list); |
3117 | + } |
3118 | +} |
3119 | + |
3120 | +static void add_virtualpackage(virtualpkgtbl *vpkgs, char *package, |
3121 | + char *version, dpkg_collected_package *cpkg) |
3122 | +{ |
3123 | + dpkg_provision value; |
3124 | + virtualpkg *list, **addto; |
3125 | + int shouldreplace; |
3126 | + |
3127 | + value.pkg = cpkg; |
3128 | + value.version = version; |
3129 | + |
3130 | + list = lookup_virtualpkgtbl(vpkgs, package); |
3131 | + shouldreplace = (list != NULL); |
3132 | + |
3133 | + addto = &list; |
3134 | + while (*addto != NULL |
3135 | + && packagecmp(cpkg->pkg, (*addto)->value.pkg->pkg) >= 0) |
3136 | + { |
3137 | + addto = &(*addto)->next; |
3138 | + } |
3139 | + insert_virtualpkg(addto, value); |
3140 | + |
3141 | + if (shouldreplace) { |
3142 | + replace_virtualpkgtbl(vpkgs, package, list); |
3143 | + /* old list is included in new list, so we don't need to free */ |
3144 | + } else { |
3145 | + add_virtualpkgtbl(vpkgs, package, list); |
3146 | + } |
3147 | +} |
3148 | + |
3149 | +/************************************************************************* |
3150 | + * Parsing Helper Functions |
3151 | + */ |
3152 | + |
3153 | +static ownedpackagenamelist *read_packagenames(char *buf) { |
3154 | + ownedpackagenamelist *result = NULL; |
3155 | + ownedpackagenamelist **addto = &result; |
3156 | + |
3157 | + DEBUG_ONLY( char *strend = buf + strlen(buf); ) |
3158 | + |
3159 | + char *sub; |
3160 | + |
3161 | + while ((sub = my_strdup(read_packagename(&buf, ",")))) { |
3162 | + insert_ownedpackagenamelist(addto, sub); |
3163 | + addto = &(*addto)->next; |
3164 | + |
3165 | + while(isspace(*buf)) buf++; |
3166 | + if (*buf == ',') { |
3167 | + buf++; |
3168 | + continue; |
3169 | + } |
3170 | + if (*buf == '\0') { |
3171 | + break; |
3172 | + } |
3173 | + |
3174 | + die("read_packagenames no/bad seperator"); |
3175 | + } |
3176 | + |
3177 | + DEBUG_ONLY( assert(buf <= strend); ) |
3178 | + |
3179 | + return result; |
3180 | +} |
3181 | + |
3182 | +static char *read_until_char(char **buf, char *end) { |
3183 | + static char *result = NULL; |
3184 | + char *start; |
3185 | + DEBUG_ONLY( char *strend = *buf + strlen(*buf); ) |
3186 | + int n; |
3187 | + |
3188 | + while(isspace(**buf)) (*buf)++; |
3189 | + |
3190 | + start = *buf; |
3191 | + while (**buf && !isspace(**buf) && strchr(end, **buf) == NULL) { |
3192 | + (*buf)++; |
3193 | + } |
3194 | + |
3195 | + n = *buf - start; |
3196 | + if (n == 0) return NULL; |
3197 | + |
3198 | + result = realloc(result, n + 1); |
3199 | + if (result == NULL) die("read_until_char alloc:"); |
3200 | + |
3201 | + strncpy(result, start, n); |
3202 | + result[n] = '\0'; |
3203 | + |
3204 | + while(isspace(**buf)) (*buf)++; |
3205 | + |
3206 | + DEBUG_ONLY( assert(*buf <= strend); ) |
3207 | + |
3208 | + return result; |
3209 | +} |
3210 | + |
3211 | +static char *read_packagename(char **buf, char *end) { |
3212 | + return read_until_char(buf, end); |
3213 | +} |
3214 | + |
3215 | +static deplist *read_dep_and(char *buf) { |
3216 | + return read_deplist(&buf, ',', '\0'); |
3217 | +} |
3218 | + |
3219 | +static deplist *read_deplist(char **buf, char sep, char end) { |
3220 | + deplist *result = NULL; |
3221 | + deplist **addto = &result; |
3222 | + |
3223 | + char separs[3] = { sep, end, '\0' }; |
3224 | + |
3225 | + DEBUG_ONLY( char *strend = *buf + strlen(*buf); ) |
3226 | + |
3227 | + dependency *sub; |
3228 | + |
3229 | + while ((sub = read_dependency(buf, separs))) { |
3230 | + insert_deplist(addto, sub); |
3231 | + addto = &(*addto)->next; |
3232 | + |
3233 | + while(isspace(**buf)) (*buf)++; |
3234 | + if (**buf == sep) { |
3235 | + (*buf)++; |
3236 | + continue; |
3237 | + } |
3238 | + if (**buf == '\0' || **buf == end) { |
3239 | + break; |
3240 | + } |
3241 | + |
3242 | + die("read_deplist no/bad seperator"); |
3243 | + } |
3244 | + |
3245 | + DEBUG_ONLY( assert(*buf <= strend); ) |
3246 | + |
3247 | + return result; |
3248 | +} |
3249 | + |
3250 | +static deplistlist *read_dep_andor(char *buf) { |
3251 | + deplistlist *result = NULL; |
3252 | + deplistlist **addto = &result; |
3253 | + |
3254 | + deplist *sub; |
3255 | + |
3256 | + DEBUG_ONLY( char *strend = buf + strlen(buf); ) |
3257 | + |
3258 | + while ((sub = read_deplist(&buf, '|', ','))) { |
3259 | + insert_deplistlist(addto, sub); |
3260 | + addto = &(*addto)->next; |
3261 | + |
3262 | + if (*buf == ',') buf++; |
3263 | + } |
3264 | + |
3265 | + DEBUG_ONLY( assert(buf <= strend); ) |
3266 | + |
3267 | + return result; |
3268 | +} |
3269 | + |
3270 | +static dependency *read_dependency(char **buf, char *end) { |
3271 | + dependency *dep; |
3272 | + char *name; |
3273 | + char newend[10]; |
3274 | + DEBUG_ONLY( char *strend = *buf + strlen(*buf); ) |
3275 | + |
3276 | + assert(strlen(end) <= 8); |
3277 | + newend[0] = '('; strcpy(newend + 1, end); |
3278 | + |
3279 | + name = my_strdup(read_until_char(buf, newend)); |
3280 | + if (name == NULL) return NULL; |
3281 | + |
3282 | + dep = block_malloc(sizeof(dependency)); |
3283 | + if (dep == NULL) die("read_dependency alloc 1:"); |
3284 | + |
3285 | + dep->package = name; |
3286 | + |
3287 | + while(isspace(**buf)) (*buf)++; |
3288 | + |
3289 | + if (**buf != '(') { |
3290 | + dep->op = dr_NOOP; |
3291 | + dep->version = NULL; |
3292 | + } else { |
3293 | + (*buf)++; |
3294 | + while(isspace(**buf)) (*buf)++; |
3295 | + /* << , <= , = , >= , >> */ |
3296 | + if (**buf == '<') { |
3297 | + (*buf)++; |
3298 | + if (**buf == '<') { |
3299 | + dep->op = dr_LT; |
3300 | + (*buf)++; |
3301 | + } else if (**buf == '=') { |
3302 | + dep->op = dr_LTEQ; |
3303 | + (*buf)++; |
3304 | + } else { |
3305 | + /* The forms `<' and `>' were used to mean earlier/later or |
3306 | + * equal, rather than strictly earlier/later, so they should |
3307 | + * not appear in new packages (though `dpkg' still supports |
3308 | + * them). |
3309 | + */ |
3310 | + dep->op = dr_LTEQ; |
3311 | + } |
3312 | + } else if (**buf == '>') { |
3313 | + (*buf)++; |
3314 | + if (**buf == '>') { |
3315 | + dep->op = dr_GT; |
3316 | + (*buf)++; |
3317 | + } else if (**buf == '=') { |
3318 | + dep->op = dr_GTEQ; |
3319 | + (*buf)++; |
3320 | + } else { |
3321 | + dep->op = dr_GTEQ; |
3322 | + } |
3323 | + } else if (**buf == '=') { |
3324 | + dep->op = dr_EQ; |
3325 | + (*buf)++; |
3326 | + if (**buf == '>') { |
3327 | + dep->op = dr_GTEQ; |
3328 | + (*buf)++; |
3329 | + } else if (**buf == '<') { |
3330 | + dep->op = dr_LTEQ; |
3331 | + (*buf)++; |
3332 | + } |
3333 | + } else { |
3334 | + /* treat it as an implicit = :( */ |
3335 | + dep->op = dr_EQ; |
3336 | + /* would prefer to: die("read_dependency unknown version op"); */ |
3337 | + } |
3338 | + |
3339 | + while (isspace(**buf)) (*buf)++; |
3340 | + newend[0] = ')'; |
3341 | + dep->version = my_strdup(read_until_char(buf, newend)); |
3342 | + while (isspace(**buf)) (*buf)++; |
3343 | + |
3344 | + if (dep->version == NULL) die("read_dependency: no version"); |
3345 | + if (**buf != ')') die("read_dependency: unterminated version"); |
3346 | + (*buf)++; |
3347 | + } |
3348 | + |
3349 | + DEBUG_ONLY( assert(*buf <= strend); ) |
3350 | + |
3351 | + return dep; |
3352 | +} |
3353 | + |
3354 | +static void free_dependency(dependency *dep) { |
3355 | + if (dep == NULL) return; |
3356 | + /* block_free(dep->package); */ |
3357 | + /* if (dep->version) block_free(dep->version); */ |
3358 | + block_free(dep, sizeof(dependency)); |
3359 | +} |
3360 | + |
3361 | +/************************************************************************* |
3362 | + * Installability Checking |
3363 | + */ |
3364 | + |
3365 | +static collpackagelist **get_matching_low(collpackagelist **addto, |
3366 | + dpkg_packages *pkgs, dependency *dep, int line) |
3367 | +{ |
3368 | + virtualpkg *vpkg; |
3369 | + for (vpkg = lookup_virtualpkgtbl(pkgs->virtualpkgs, dep->package); |
3370 | + vpkg != NULL; |
3371 | + vpkg = vpkg->next) |
3372 | + { |
3373 | + int add; |
3374 | + |
3375 | + add = 0; |
3376 | + if (dep->op == dr_NOOP) { |
3377 | + add = 1; |
3378 | + } else if (vpkg->value.version != NULL) { |
3379 | + if (cmpversions(vpkg->value.version, dep->op, dep->version)) { |
3380 | + add = 1; |
3381 | + } |
3382 | + } |
3383 | + |
3384 | + if (add) { |
3385 | + insert_l_collpackagelist(addto, vpkg->value.pkg, line); |
3386 | + addto = &(*addto)->next; |
3387 | + } |
3388 | + } |
3389 | + |
3390 | + return addto; |
3391 | +} |
3392 | + |
3393 | +static collpackagelist *get_matching(dpkg_packages *pkgs, deplist *depopts, int line) { |
3394 | + collpackagelist *list = NULL; |
3395 | + collpackagelist **addto = &list; |
3396 | + |
3397 | + for(; depopts != NULL; depopts = depopts->next) { |
3398 | + addto = get_matching_low(addto, pkgs, depopts->value, line); |
3399 | + } |
3400 | + |
3401 | + return list; |
3402 | +} |
3403 | + |
3404 | +typedef struct instonelist instonelist; |
3405 | +struct instonelist { |
3406 | + collpackagelist *curX; |
3407 | + collpackagelist *instoneX; |
3408 | + int expandedX; |
3409 | + struct instonelist *nextX, *prevX, *cutoffX; |
3410 | +}; |
3411 | + |
3412 | +#define I1CUR(i1) ((i1)->curX) |
3413 | +#define I1INSTONE(i1) ((i1)->instoneX) |
3414 | +#define I1CUTOFF(i1) ((i1)->cutoffX) |
3415 | +#define I1NEXT(i1) ((i1)->nextX) /* can be modified ! */ |
3416 | +#define I1PREV(i1) ((i1)->prevX) |
3417 | +#define I1EXPANDED(i1) ((i1)->expandedX) |
3418 | + |
3419 | +static instonelist *insert_instonelist(instonelist *where, collpackagelist *instone); |
3420 | +static void trim_instonelist_after(instonelist *first); |
3421 | +static void free_instonelist(instonelist *l); |
3422 | + |
3423 | +static int max_instone_len = 0; |
3424 | +static int cur_instone_len = 0; |
3425 | + |
3426 | +static instonelist *insert_instonelist(instonelist *old, collpackagelist *instone) |
3427 | +{ |
3428 | + instonelist *n = block_malloc(sizeof(instonelist)); |
3429 | + if (n == NULL) |
3430 | + die("insert_instonelist alloc:"); |
3431 | + |
3432 | + n->curX = NULL; |
3433 | + n->instoneX = instone; |
3434 | + n->cutoffX = NULL; |
3435 | + n->nextX = (old ? old->nextX : NULL); |
3436 | + n->prevX = old; |
3437 | + n->expandedX = 0; |
3438 | + |
3439 | + if (old) old->nextX = n; |
3440 | + if (n->nextX) n->nextX->prevX = n; |
3441 | + |
3442 | + cur_instone_len++; |
3443 | + if (cur_instone_len > max_instone_len) max_instone_len = cur_instone_len; |
3444 | + |
3445 | + return n; |
3446 | +} |
3447 | + |
3448 | +static void trim_instonelist_after(instonelist *first) { |
3449 | + if (!first->nextX) return; |
3450 | + first->nextX->prevX = NULL; |
3451 | + free_instonelist(first->nextX); |
3452 | + first->nextX = NULL; |
3453 | +} |
3454 | + |
3455 | +static void free_instonelist(instonelist *l) { |
3456 | + instonelist *p, *k; |
3457 | + if (!l) return; |
3458 | + for (p = l; p->nextX; p = p->nextX); |
3459 | + do { |
3460 | + k = p; |
3461 | + p = k->prevX; |
3462 | + free_collpackagelist(k->instoneX); |
3463 | + block_free(k, sizeof(instonelist)); |
3464 | + cur_instone_len--; |
3465 | + } while (k != l); |
3466 | +} |
3467 | + |
3468 | +static int caninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) { |
3469 | + collpackagelist *conflicts; |
3470 | + collpackagelist *conf; |
3471 | + int okay; |
3472 | + |
3473 | + if (cpkg->installed > 0) return 1; |
3474 | + if (cpkg->conflicted > 0) return 0; |
3475 | + |
3476 | + conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__); |
3477 | + |
3478 | + okay = 1; |
3479 | + for (conf = conflicts; conf != NULL; conf = conf->next) { |
3480 | + if (conf->value->installed > 0) { |
3481 | + okay = 0; |
3482 | + break; |
3483 | + } |
3484 | + } |
3485 | + free_collpackagelist(conflicts); |
3486 | + return okay; |
3487 | +} |
3488 | + |
3489 | +static int cur_install =0; |
3490 | +static int max_install = 0; |
3491 | +static int cur_conflicted = 0; |
3492 | +static int max_conflicted = 0; |
3493 | + |
3494 | +static void install(dpkg_packages *pkgs, dpkg_collected_package *cpkg) { |
3495 | + if (cpkg->installed == 0) { |
3496 | + collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__); |
3497 | + collpackagelist *conf; |
3498 | + for (conf = conflicts; conf != NULL; conf = conf->next) { |
3499 | + if (conf->value == cpkg) continue; |
3500 | + assert(conf->value->installed == 0); |
3501 | + conf->value->conflicted++; |
3502 | + if (conf->value->conflicted == 1) { |
3503 | + cur_conflicted++; |
3504 | + if (max_conflicted < cur_conflicted) |
3505 | + max_conflicted = cur_conflicted; |
3506 | + } |
3507 | + } |
3508 | + free_collpackagelist(conflicts); |
3509 | + cur_install++; |
3510 | + if (max_install < cur_install) max_install = cur_install; |
3511 | + } |
3512 | + assert(cpkg->conflicted == 0); |
3513 | + cpkg->installed++; |
3514 | +} |
3515 | + |
3516 | +static void uninstall(dpkg_packages *pkgs, dpkg_collected_package *cpkg) { |
3517 | + assert(cpkg->installed > 0); |
3518 | + assert(cpkg->conflicted == 0); |
3519 | + cpkg->installed--; |
3520 | + if (cpkg->installed == 0) { |
3521 | + collpackagelist *conflicts = get_matching(pkgs, cpkg->pkg->conflicts, __LINE__); |
3522 | + collpackagelist *conf; |
3523 | + for (conf = conflicts; conf != NULL; conf = conf->next) { |
3524 | + if (conf->value == cpkg) continue; |
3525 | + assert(conf->value->installed == 0); |
3526 | + assert(conf->value->conflicted > 0); |
3527 | + conf->value->conflicted--; |
3528 | + if (conf->value->conflicted == 0) cur_conflicted--; |
3529 | + } |
3530 | + free_collpackagelist(conflicts); |
3531 | + cur_install--; |
3532 | + } |
3533 | +} |
3534 | + |
3535 | +satisfieddep *new_satisfieddep(void) { |
3536 | + satisfieddep *sd = block_malloc(sizeof(satisfieddep)); |
3537 | + if (!sd) die("new_satisfieddep alloc:"); |
3538 | + return sd; |
3539 | +} |
3540 | + |
3541 | +void free_satisfieddep(satisfieddep *sd) { |
3542 | + if (!sd) return; |
3543 | + free_packagelist(sd->pkgs); |
3544 | + block_free(sd, sizeof(satisfieddep)); |
3545 | +} |
3546 | + |
3547 | +LIST_IMPL(satisfieddeplist, satisfieddep *, free_satisfieddep, block_malloc, block_free); |
3548 | + |
3549 | +packagelist *collpkglist2pkglist(collpackagelist *l) { |
3550 | + packagelist *r = NULL; |
3551 | + packagelist **addto = &r; |
3552 | + |
3553 | + for (; l != NULL; l = l->next) { |
3554 | + insert_packagelist(addto, l->value->pkg); |
3555 | + addto = &(*addto)->next; |
3556 | + } |
3557 | + |
3558 | + return r; |
3559 | +} |
3560 | + |
3561 | +satisfieddeplist *checkunsatisfiabledeps(dpkg_packages *pkgs, |
3562 | + deplistlist *deps) { |
3563 | + satisfieddeplist *unsatisfiable = NULL; |
3564 | + satisfieddeplist **addto = &unsatisfiable; |
3565 | + satisfieddep *sd; |
3566 | + collpackagelist *deppkgs; |
3567 | + |
3568 | + for (; deps != NULL; deps = deps->next) { |
3569 | + /* deplist *dep; */ |
3570 | + /* for (dep = deps->value; dep != NULL; dep = dep->next) { */ |
3571 | + sd = new_satisfieddep(); |
3572 | + /* sd->dep = dep->value; */ |
3573 | + sd->depl = deps->value; |
3574 | + |
3575 | + deppkgs = NULL; |
3576 | + /* get_matching_low(&deppkgs, pkgs, dep->value); */ |
3577 | + deppkgs = get_matching(pkgs, deps->value, __LINE__); |
3578 | + sd->pkgs = collpkglist2pkglist(deppkgs); |
3579 | + free_collpackagelist(deppkgs); |
3580 | + |
3581 | + insert_satisfieddeplist(addto, sd); |
3582 | + addto = &(*addto)->next; |
3583 | + /* } */ |
3584 | + } |
3585 | + |
3586 | + return unsatisfiable; |
3587 | +} |
3588 | + |
3589 | +int checkinstallable2(dpkg_packages *pkgs, char *pkgname) { |
3590 | + dpkg_collected_package *cpkg = lookup_packagetbl(pkgs->packages, pkgname); |
3591 | + collpackagelist *cpl = NULL; |
3592 | + |
3593 | + if (cpkg == NULL) return 0; |
3594 | + |
3595 | + insert_collpackagelist(&cpl, cpkg); |
3596 | + /* cpl gets freed in checkinstallable :-/ */ |
3597 | + return checkinstallable(pkgs, cpl); |
3598 | +} |
3599 | + |
3600 | +static void debug_checkinstallable(FILE *out, instonelist *list, |
3601 | + instonelist *last, instonelist *pointer) |
3602 | +{ |
3603 | + instonelist *l; |
3604 | + fprintf(out, "Status:"); |
3605 | + |
3606 | + /* codes: | = multiple options here |
3607 | + * @ = no options can satisfy this dep |
3608 | + * + = dependencies that can be expanded have been |
3609 | + * * = nothing selected yet |
3610 | + * > = where pointer points |
3611 | + * ^ = the cut point for where we are |
3612 | + */ |
3613 | + |
3614 | + for (l = list; ; l = I1NEXT(l)) { |
3615 | + fprintf(out, " "); |
3616 | + if (l == pointer) fprintf(out, ">"); |
3617 | + if (l == I1CUTOFF(pointer)) fprintf(out, "^"); |
3618 | + if (I1INSTONE(l) == NULL) { |
3619 | + fprintf(out, "@"); |
3620 | + } else { |
3621 | + if (I1INSTONE(l)->next != NULL) { |
3622 | + fprintf(out, "|"); |
3623 | + } |
3624 | + if (I1EXPANDED(l)) { |
3625 | + fprintf(out, "+"); |
3626 | + } |
3627 | + if (I1CUR(l) == NULL) { |
3628 | + fprintf(out, "*%s", I1INSTONE(l)->value->pkg->package); |
3629 | + } else { |
3630 | + fprintf(out, "%s", I1CUR(l)->value->pkg->package); |
3631 | + } |
3632 | + } |
3633 | + if (l == last) break; |
3634 | + } |
3635 | + fprintf(out, " ###\n"); |
3636 | + fflush(out); |
3637 | +} |
3638 | + |
3639 | +int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof) { |
3640 | + /* We use pkg->installed, pkg->conflicted to note how many |
3641 | + * times we've used this pkg to satisfy a dependency or installed |
3642 | + * a package that conflicts with it. |
3643 | + * Thus: pkg->installed == 0, or pkg->conflicted == 0 |
3644 | + * |
3645 | + * We assume these are okay initially, aren't being played with |
3646 | + * concurrently elsewhere, and make sure they're still okay when |
3647 | + * we return. |
3648 | + */ |
3649 | + |
3650 | + instonelist *list; |
3651 | + instonelist *last; |
3652 | + |
3653 | + instonelist *pointer; |
3654 | + |
3655 | + unsigned long counter = 500000000; |
3656 | + |
3657 | + int last_max_inst = max_install; |
3658 | + int last_max_instone = max_instone_len; |
3659 | + int last_max_conflict = max_conflicted; |
3660 | + |
3661 | + { |
3662 | + collpackagelist *cpkg; |
3663 | + for (cpkg = instoneof; cpkg; cpkg = cpkg->next) { |
3664 | + if (cpkg->value->installable == YES) { |
3665 | + free_collpackagelist(instoneof); |
3666 | + return 1; |
3667 | + } |
3668 | + } |
3669 | + } |
3670 | + |
3671 | + list = insert_instonelist(NULL, instoneof); |
3672 | + |
3673 | + last = list; |
3674 | + pointer = list; |
3675 | + |
3676 | + while(--counter > 0 && pointer) { |
3677 | + deplistlist *dep; |
3678 | + dpkg_collected_package *instpkg; /* convenient alias */ |
3679 | + int i; |
3680 | + |
3681 | +#ifndef NDEBUG |
3682 | + { |
3683 | + instonelist *p; |
3684 | + for (p = list; p != pointer; p = I1NEXT(p)) { |
3685 | + assert(p != NULL); |
3686 | + assert(I1CUR(p) != NULL); |
3687 | + assert(I1CUR(p)->value != NULL); |
3688 | + assert(I1CUR(p)->value->installed > 0); |
3689 | + assert(I1CUR(p)->value->conflicted == 0); |
3690 | + } |
3691 | + if (I1NEXT(pointer) == NULL) { |
3692 | + assert(pointer == last); |
3693 | + } else { |
3694 | + for (p = I1NEXT(pointer); p; p = I1NEXT(p)) { |
3695 | + if (I1NEXT(p) == NULL) { |
3696 | + assert(p == last); |
3697 | + } |
3698 | + assert(I1CUR(p) == NULL); |
3699 | + } |
3700 | + } |
3701 | + } |
3702 | +#endif |
3703 | + |
3704 | +#ifdef DIAGNOSE |
3705 | + debug_checkinstallable(stdout, list, last, pointer); |
3706 | +#endif |
3707 | + |
3708 | + if (I1CUR(pointer) == NULL) { |
3709 | + I1CUR(pointer) = I1INSTONE(pointer); |
3710 | + /* try to choose an already installed package if there is one */ |
3711 | + while (I1CUR(pointer) != NULL) { |
3712 | + if (I1CUR(pointer)->value->installed != 0) { |
3713 | + break; |
3714 | + } |
3715 | + I1CUR(pointer) = I1CUR(pointer)->next; |
3716 | + } |
3717 | + if (I1CUR(pointer) == NULL) { |
3718 | + I1CUR(pointer) = I1INSTONE(pointer); |
3719 | + } |
3720 | + assert(I1CUR(pointer) || !I1INSTONE(pointer)); |
3721 | + |
3722 | + I1CUTOFF(pointer) = last; |
3723 | + } else { |
3724 | + uninstall(pkgs, I1CUR(pointer)->value); |
3725 | + trim_instonelist_after(I1CUTOFF(pointer)); |
3726 | + last = I1CUTOFF(pointer); |
3727 | + |
3728 | + if (I1CUR(pointer)->value->installed > 0) { |
3729 | + /* this dependency isn't the issue -- even doing |
3730 | + * nothing to satisfy it (ie, using an already |
3731 | + * installed package) doesn't do any good. So give up. |
3732 | + */ |
3733 | + I1CUR(pointer) = NULL; |
3734 | + } else { |
3735 | + I1CUR(pointer) = I1CUR(pointer)->next; |
3736 | + } |
3737 | + } |
3738 | + |
3739 | + while(I1CUR(pointer) && !caninstall(pkgs, I1CUR(pointer)->value)) { |
3740 | + I1CUR(pointer) = I1CUR(pointer)->next; |
3741 | + } |
3742 | + |
3743 | + if (I1CUR(pointer) == NULL) { |
3744 | + if (I1PREV(pointer) == NULL) break; |
3745 | + pointer = I1PREV(pointer); |
3746 | + continue; |
3747 | + } |
3748 | + |
3749 | + instpkg = I1CUR(pointer)->value; |
3750 | + |
3751 | + install(pkgs, instpkg); |
3752 | + |
3753 | + assert(instpkg->installed > 0); |
3754 | + if (instpkg->installed == 1) { |
3755 | + /* if it's been installed exactly once, then this must've been |
3756 | + * the first time it was touched, so we need to look at the |
3757 | + * dependencies. If it's the second or later, then we don't care |
3758 | + * about them. |
3759 | + */ |
3760 | + |
3761 | + /* if any of the deps can't be satisfied, don't move on */ |
3762 | + int bother = 1; |
3763 | + |
3764 | + int expanded = I1EXPANDED(pointer); |
3765 | + |
3766 | + for (i = 0; i < 4; i++) { |
3767 | + if (!dependency_counts[i]) continue; |
3768 | + for (dep = instpkg->pkg->depends[i]; |
3769 | + dep != NULL; dep = dep->next) |
3770 | + { |
3771 | + collpackagelist *thisdep = get_matching(pkgs, dep->value, __LINE__); |
3772 | + |
3773 | + if (thisdep == NULL) { |
3774 | + bother = 0; |
3775 | + |
3776 | + } else if (thisdep != NULL && thisdep->next == NULL) { |
3777 | + collpackagelist *x; |
3778 | + |
3779 | + /* if there's only one way of fulfilling this dep, |
3780 | + * do it "ASAP" |
3781 | + */ |
3782 | + |
3783 | + /* optimisation: if thisdep == foo, but the parent |
3784 | + * was foo|bar, then we already know "foo" is not going |
3785 | + * to work in this combination, and we can skip it. |
3786 | + * |
3787 | + * This deals with cases like X deps: Y|bar, bar deps: Y |
3788 | + * where bar is a virtual package; cf xlibs |
3789 | + */ |
3790 | + for (x = I1INSTONE(pointer); x != I1CUR(pointer); x = x->next) { |
3791 | + if (x->value == thisdep->value) { |
3792 | + bother = 0; |
3793 | + break; |
3794 | + } |
3795 | + } |
3796 | + |
3797 | + if (I1INSTONE(pointer)->next == NULL) { |
3798 | + /* the parent of this entry essentially depends |
3799 | + * on this too, so we'll get it out of the way |
3800 | + * ASAP, to reduce the degree of exponentiation |
3801 | + * in bad cases. |
3802 | + * |
3803 | + * _However_ we only want to do this _once_ for |
3804 | + * any particular node. |
3805 | + */ |
3806 | + if (expanded) { |
3807 | + /* thisdep isn't used! */ |
3808 | + free_collpackagelist(thisdep); |
3809 | + } else { |
3810 | + insert_instonelist(pointer, thisdep); |
3811 | + I1EXPANDED(pointer) = 1; |
3812 | + } |
3813 | + } else { |
3814 | + insert_instonelist(I1CUTOFF(pointer), thisdep); |
3815 | + } |
3816 | + if (I1NEXT(last)) last = I1NEXT(last); |
3817 | + assert(!I1NEXT(last)); |
3818 | + |
3819 | + } else { |
3820 | + /* otherwise it's a multi possibility dep, so do it |
3821 | + * at the end |
3822 | + */ |
3823 | + |
3824 | + last = insert_instonelist(last, thisdep); |
3825 | + } |
3826 | + } |
3827 | + } |
3828 | + if (!bother) { |
3829 | + /* stay where we are, and try the next possibility */ |
3830 | + continue; |
3831 | + } |
3832 | + } |
3833 | + |
3834 | + pointer = I1NEXT(pointer); |
3835 | + } |
3836 | + |
3837 | + if (max_install>last_max_inst || max_instone_len>last_max_instone || max_conflicted >last_max_conflict) { |
3838 | + printf("MAX: i:%d / c:%d / i1:%d %s\n", max_install,max_conflicted,max_instone_len,instoneof->value->pkg->package); |
3839 | + } |
3840 | + |
3841 | + if (counter == 0) { |
3842 | + fprintf(stderr, "AIEEE: counter overflow:"); |
3843 | + assert(pointer != NULL); |
3844 | + if (I1CUR(pointer) == NULL || I1CUR(pointer)->value == NULL) { |
3845 | + /* we're not guaranteed that pointer will make sense here */ |
3846 | + pointer = I1PREV(pointer); |
3847 | + } |
3848 | + for (; pointer != NULL; pointer = I1PREV(pointer)) { |
3849 | + if (I1CUR(pointer) == NULL) { |
3850 | + /* should only happen at pointer, so not here */ |
3851 | + fprintf(stderr, " >> eep, no packages at pointer <<"); |
3852 | + continue; |
3853 | + } |
3854 | + if (I1CUR(pointer)->value == NULL) { |
3855 | + /* should never happen */ |
3856 | + fprintf(stderr, " >> eep, no package selected <<"); |
3857 | + continue; |
3858 | + } |
3859 | + fprintf(stderr, " %s%s", |
3860 | + (I1INSTONE(pointer)->next == NULL ? "" : "|"), |
3861 | + I1CUR(pointer)->value->pkg->package); |
3862 | + uninstall(pkgs, I1CUR(pointer)->value); |
3863 | + } |
3864 | + fprintf(stderr, ".\n"); |
3865 | + free_instonelist(list); |
3866 | + return 0; |
3867 | + } |
3868 | + |
3869 | + if (pointer == NULL) { |
3870 | + dpkg_collected_package *cpkg = I1CUR(list)->value; |
3871 | + assert(cpkg->installable != YES); |
3872 | + cpkg->installable = YES; |
3873 | + for (pointer = last; pointer != NULL; pointer = I1PREV(pointer)) { |
3874 | + if (I1CUR(pointer)->value->installed == 1) { |
3875 | + packagenamelist **p = &I1CUR(pointer)->value->mayaffect; |
3876 | +#if 0 |
3877 | + while ( *p && (*p)->value < cpkg->pkg->package ) { |
3878 | + p = &(*p)->next; |
3879 | + } |
3880 | + if (*p == NULL || (*p)->value > cpkg->pkg->package) |
3881 | +#endif |
3882 | + { |
3883 | + insert_packagenamelist(p, cpkg->pkg->package); |
3884 | + } |
3885 | + } |
3886 | + uninstall(pkgs, I1CUR(pointer)->value); |
3887 | + } |
3888 | + free_instonelist(list); |
3889 | + return 1; |
3890 | + } else { |
3891 | + assert(I1CUR(list) == NULL); |
3892 | + free_instonelist(list); |
3893 | + return 0; |
3894 | + } |
3895 | +} |
3896 | + |
3897 | +/******************/ |
3898 | + |
3899 | +HASH_IMPL(sourcetbl, char *, dpkg_source *, SIZEOFHASHMAP, strhash, strcmp, |
3900 | + KEEP(char*), free_source); |
3901 | + |
3902 | +static dpkg_sources *read_sources_file(char *filename, int n_arches) { |
3903 | + FILE *f; |
3904 | + dpkg_sources *result; |
3905 | + dpkg_source *src; |
3906 | + int i; |
3907 | + |
3908 | + f = fopen(filename, "r"); |
3909 | + if (f == NULL && errno != ENOENT) { |
3910 | + die("read_sources_file: couldn't open file:"); |
3911 | + } |
3912 | + |
3913 | + result = block_malloc(sizeof(dpkg_sources)); |
3914 | + if (result == NULL) die("read_sources_file alloc 1:"); |
3915 | + |
3916 | + result->n_arches = n_arches; |
3917 | + result->archname = block_malloc(sizeof(char*) * n_arches); |
3918 | + if (result->archname == NULL) die("read_sources_file alloc 2:"); |
3919 | + for (i = 0; i < n_arches; i++) result->archname[i] = NULL; |
3920 | + result->unclaimedpackages = block_malloc(sizeof(ownedpackagelist*) |
3921 | + * n_arches); |
3922 | + if (result->unclaimedpackages == NULL) die("read_sources_file alloc 3:"); |
3923 | + for (i = 0; i < n_arches; i++) result->unclaimedpackages[i] = NULL; |
3924 | + |
3925 | + result->sources = new_sourcetbl(); |
3926 | + |
3927 | + if (f != NULL) { |
3928 | + while ((src = read_source(f, result))) { |
3929 | + dpkg_source *old = lookup_sourcetbl(result->sources, src->package); |
3930 | + if (old == NULL) { |
3931 | + add_sourcetbl(result->sources, src->package, src); |
3932 | + } else { |
3933 | + if (versioncmp(old->version, src->version) || 1) { |
3934 | + int i; |
3935 | + old = replace_sourcetbl(result->sources, src->package, src); |
3936 | + for (i = 0; i < old->owner->n_arches; i++) { |
3937 | + assert(old->packages[i] == NULL); |
3938 | + } |
3939 | + free_source(old); |
3940 | + } else { |
3941 | + int i; |
3942 | + for (i = 0; i < src->owner->n_arches; i++) { |
3943 | + assert(src->packages[i] == NULL); |
3944 | + } |
3945 | + free_source(src); |
3946 | + } |
3947 | + } |
3948 | + } |
3949 | + fclose(f); |
3950 | + } |
3951 | + |
3952 | + return result; |
3953 | +} |
3954 | + |
3955 | +void free_sources(dpkg_sources *s) { |
3956 | + int i; |
3957 | + if (s == NULL) return; |
3958 | + free_sourcetbl(s->sources); |
3959 | + for (i = 0; i < s->n_arches; i++) { |
3960 | + /* block_free(s->archname[i]); */ |
3961 | + free_ownedpackagelist(s->unclaimedpackages[i]); |
3962 | + } |
3963 | + block_free(s->archname, s->n_arches * sizeof(char*)); |
3964 | + block_free(s->unclaimedpackages, s->n_arches * sizeof(ownedpackagelist*)); |
3965 | + block_free(s, sizeof(dpkg_sources)); |
3966 | +} |
3967 | + |
3968 | +static dpkg_source *new_source(dpkg_sources *owner) { |
3969 | + dpkg_source *result; |
3970 | + int i; |
3971 | + |
3972 | + result = block_malloc(sizeof(dpkg_source)); |
3973 | + if (result == NULL) die("new_source alloc 1:"); |
3974 | + |
3975 | + result->package = NULL; |
3976 | + result->version = NULL; |
3977 | + result->details = NULL; |
3978 | + result->fake = 0; |
3979 | + |
3980 | + result->owner = owner; |
3981 | + result->packages = block_malloc(sizeof(packagelist*) * owner->n_arches); |
3982 | + if (result->packages == NULL) die("new_source alloc 2:"); |
3983 | + for (i = 0; i < owner->n_arches; i++) { |
3984 | + result->packages[i] = NULL; |
3985 | + } |
3986 | + |
3987 | + return result; |
3988 | +} |
3989 | + |
3990 | +static dpkg_source *read_source(FILE *f, dpkg_sources *owner) { |
3991 | + dpkg_source *result; |
3992 | + dpkg_paragraph *para; |
3993 | + dpkg_entry *e; |
3994 | + |
3995 | + para = read_paragraph(f); |
3996 | + if (para == NULL) return NULL; |
3997 | + |
3998 | + result = new_source(owner); |
3999 | + result->details = para; |
4000 | + |
4001 | + for (e = ¶->entry[0]; e < ¶->entry[para->n_entries]; e++) { |
4002 | + if (strcmp("Package", e->name) == 0) { |
4003 | + result->package = my_strdup(e->value); |
4004 | + if (result->package == NULL) |
4005 | + die("read_source strdup:"); |
4006 | + result->package[strlen(result->package)-1] = '\0'; |
4007 | + } |
4008 | + |
4009 | + if (strcmp("Version", e->name) == 0) { |
4010 | + result->version = my_strdup(e->value); |
4011 | + if (result->version == NULL) |
4012 | + die("read_source strdup:"); |
4013 | + result->version[strlen(result->version)-1] = '\0'; |
4014 | + } |
4015 | + } |
4016 | + |
4017 | + return result; |
4018 | +} |
4019 | + |
4020 | +void free_source(dpkg_source *s) { |
4021 | + int i; |
4022 | + if (s == NULL) return; |
4023 | + assert(s->owner != NULL); /* shouldn't have allocated it */ |
4024 | + /* block_free(s->package); */ |
4025 | + /* block_free(s->version); */ |
4026 | + free_paragraph(s->details); |
4027 | + for (i = 0; i < s->owner->n_arches; i++) { |
4028 | + free_ownedpackagelist(s->packages[i]); |
4029 | + } |
4030 | + block_free(s->packages, s->owner->n_arches * sizeof(ownedpackagelist*)); |
4031 | + block_free(s, sizeof(dpkg_source)); |
4032 | +} |
4033 | + |
4034 | +/******************************/ |
4035 | + |
4036 | +dpkg_sources *read_directory(char *dir, int n_arches, char *archname[]) { |
4037 | + char buf[1000]; |
4038 | + dpkg_sources *srcs; |
4039 | + int i; |
4040 | + |
4041 | + snprintf(buf, 1000, "%s/Sources", dir); |
4042 | + srcs = read_sources_file(buf, n_arches); |
4043 | + |
4044 | + for (i = 0; i < n_arches; i++) { |
4045 | + FILE *f; |
4046 | + dpkg_package *pkg; |
4047 | + |
4048 | + srcs->archname[i] = my_strdup(archname[i]); |
4049 | + |
4050 | + snprintf(buf, 1000, "%s/Packages_%s", dir, archname[i]); |
4051 | + f = fopen(buf, "r"); |
4052 | + if (f == NULL && errno != ENOENT) die("load_dirctory fopen:"); |
4053 | + if (f != NULL) { |
4054 | + while ((pkg = read_package(f))) { |
4055 | + dpkg_source *src = lookup_sourcetbl(srcs->sources, pkg->source); |
4056 | + if (src == NULL) { |
4057 | + src = new_source(srcs); |
4058 | + src->fake = 1; |
4059 | + src->package = my_strdup(pkg->source); |
4060 | + src->version = my_strdup(pkg->source_ver); |
4061 | + add_sourcetbl(srcs->sources, src->package, src); |
4062 | + } |
4063 | + insert_ownedpackagelist(&src->packages[i], pkg); |
4064 | + } |
4065 | + fclose(f); |
4066 | + } |
4067 | + } |
4068 | + |
4069 | + return srcs; |
4070 | +} |
4071 | + |
4072 | +void write_directory(char *dir, dpkg_sources *srcs) { |
4073 | + FILE *src; |
4074 | + FILE *archfile[100]; |
4075 | + char buf[1000]; |
4076 | + int i; |
4077 | + sourcetbl_iter srciter; |
4078 | + |
4079 | + snprintf(buf, 1000, "%s/Sources", dir); |
4080 | + src = fopen(buf, "w"); |
4081 | + if (!src) die("write_directory: Couldn't open Sources file for output"); |
4082 | + |
4083 | + for (i = 0; i < srcs->n_arches; i++) { |
4084 | + snprintf(buf, 1000, "%s/Packages_%s", dir, srcs->archname[i]); |
4085 | + archfile[i] = fopen(buf, "w"); |
4086 | + } |
4087 | + |
4088 | + for (srciter = first_sourcetbl(srcs->sources); |
4089 | + !done_sourcetbl(srciter); |
4090 | + srciter = next_sourcetbl(srciter)) |
4091 | + { |
4092 | + ownedpackagelist *p; |
4093 | + int i; |
4094 | + |
4095 | + if (!srciter.v->fake) |
4096 | + write_paragraph(src, srciter.v->details); |
4097 | + |
4098 | + for (i = 0; i < srcs->n_arches; i++) { |
4099 | + for (p = srciter.v->packages[i]; p != NULL; p = p->next) { |
4100 | + write_paragraph(archfile[i], p->value->details); |
4101 | + } |
4102 | + } |
4103 | + } |
4104 | + |
4105 | + fclose(src); |
4106 | + for (i = 0; i < srcs->n_arches; i++) { |
4107 | + fclose(archfile[i]); |
4108 | + } |
4109 | +} |
4110 | + |
4111 | +/*********************/ |
4112 | + |
4113 | +HASH_IMPL(sourcenotetbl, char *, dpkg_source_note *, SIZEOFHASHMAP, strhash, strcmp, |
4114 | + KEEP(char*), free_source_note); |
4115 | + |
4116 | +dpkg_source_note *new_source_note(dpkg_source *src, int n_arches) { |
4117 | + dpkg_source_note *result = block_malloc(sizeof(dpkg_source_note)); |
4118 | + int i; |
4119 | + |
4120 | + if (result == NULL) die("new_source_note alloc 1:"); |
4121 | + result->source = src; |
4122 | + result->n_arches = n_arches; |
4123 | + result->binaries = block_malloc(n_arches * sizeof(packagelist*)); |
4124 | + if (result->binaries == NULL) die("new_source_note alloc 2:"); |
4125 | + for (i = 0; i < n_arches; i++) { |
4126 | + result->binaries[i] = NULL; |
4127 | + } |
4128 | + return result; |
4129 | +} |
4130 | + |
4131 | +void free_source_note(dpkg_source_note *srcn) { |
4132 | + int i; |
4133 | + |
4134 | + if (srcn == NULL) return; |
4135 | + |
4136 | + if (srcn->binaries != NULL) { |
4137 | + for (i = 0; i < srcn->n_arches; i++) { |
4138 | + free_packagelist(srcn->binaries[i]); |
4139 | + } |
4140 | + block_free(srcn->binaries, sizeof(packagelist*) * srcn->n_arches); |
4141 | + } |
4142 | + block_free(srcn, sizeof(dpkg_source_note)); |
4143 | +} |
4144 | + |
4145 | +#ifdef DEBUG |
4146 | +static int is_sources_note(dpkg_sources_note *srcsn) { |
4147 | + int i; |
4148 | + |
4149 | + assert(srcsn != NULL); |
4150 | + assert(srcsn->magic == 0xa1eebabe); |
4151 | + assert(srcsn->pkgs != NULL); |
4152 | + for (i = 0; i < srcsn->n_arches; i++) { |
4153 | + assert(srcsn->pkgs[i] != NULL && srcsn->archname[i] != NULL); |
4154 | + assert(strcmp(srcsn->archname[i], srcsn->pkgs[i]->arch) == 0); |
4155 | + } |
4156 | + |
4157 | + return 1; |
4158 | +} |
4159 | +#endif |
4160 | + |
4161 | +dpkg_sources_note *new_sources_note(int n_arches, char **archname) { |
4162 | + dpkg_sources_note *result = block_malloc(sizeof(dpkg_sources_note)); |
4163 | + int i; |
4164 | + |
4165 | + if (result == NULL) die("new_sources_note alloc 1:"); |
4166 | + result->magic = 0xA1EEBABE; |
4167 | + result->sources = new_sourcenotetbl(); |
4168 | + result->pkgs = block_malloc(n_arches * sizeof(dpkg_packages*)); |
4169 | + if (result->pkgs == NULL) die("new_sources_note alloc 2:"); |
4170 | + result->archname = block_malloc(n_arches * sizeof(char*)); |
4171 | + if (result->archname == NULL) die("new_sources_note alloc 3:"); |
4172 | + |
4173 | + result->n_arches = n_arches; |
4174 | + for (i = 0; i < n_arches; i++) { |
4175 | + result->archname[i] = my_strdup(archname[i]); |
4176 | + result->pkgs[i] = new_packages(result->archname[i]); |
4177 | + } |
4178 | + result->undo = NULL; |
4179 | + return result; |
4180 | +} |
4181 | + |
4182 | +void free_sources_note(dpkg_sources_note *srcsn) { |
4183 | + int i; |
4184 | + if (srcsn == NULL) return; |
4185 | + assert(is_sources_note(srcsn)); |
4186 | + srcsn->magic = 0xBABEA1EE; |
4187 | + free_sourcenotetbl(srcsn->sources); |
4188 | + for (i = 0; i < srcsn->n_arches; i++) { |
4189 | + free_packages(srcsn->pkgs[i]); |
4190 | + /* block_free(srcsn->archname[i]); */ |
4191 | + } |
4192 | + block_free(srcsn->pkgs, sizeof(dpkg_packages*) * srcsn->n_arches); |
4193 | + block_free(srcsn->archname, sizeof(char*) * srcsn->n_arches); |
4194 | + free_source_note_listlist(srcsn->undo); |
4195 | + block_free(srcsn, sizeof(dpkg_sources_note)); |
4196 | +} |
4197 | + |
4198 | +static void new_op(dpkg_sources_note *srcsn) { |
4199 | + assert(is_sources_note(srcsn)); |
4200 | + insert_source_note_listlist(&srcsn->undo, NULL); |
4201 | +} |
4202 | +static void save_source_note(dpkg_sources_note *srcsn, dpkg_source_note *srcn) { |
4203 | + source_note_list **where; |
4204 | + assert(is_sources_note(srcsn)); |
4205 | + assert(srcsn->undo != NULL); |
4206 | + |
4207 | + for (where = &srcsn->undo->value; |
4208 | + *where != NULL; |
4209 | + where = &(*where)->next) |
4210 | + { |
4211 | + if ((*where)->value->source == srcn->source) |
4212 | + return; /* already saved */ |
4213 | + } |
4214 | + |
4215 | + insert_source_note_list(where, copy_source_note(srcn)); |
4216 | +} |
4217 | +static void save_empty_source_note(dpkg_sources_note *srcsn, dpkg_source *src) { |
4218 | + dpkg_source_note *srcn; |
4219 | + source_note_list **where; |
4220 | + |
4221 | + for (where = &srcsn->undo->value; |
4222 | + *where != NULL; |
4223 | + where = &(*where)->next) |
4224 | + { |
4225 | + if ((*where)->value->source == src) |
4226 | + return; /* already saved */ |
4227 | + } |
4228 | + |
4229 | + srcn = block_malloc(sizeof(dpkg_source_note)); |
4230 | + if (srcn == NULL) die("save_empty_source_note alloc:"); |
4231 | + assert(is_sources_note(srcsn)); |
4232 | + |
4233 | + srcn->source = src; |
4234 | + srcn->n_arches = 0; |
4235 | + srcn->binaries = NULL; |
4236 | + |
4237 | + insert_source_note_list(where, srcn); |
4238 | +} |
4239 | + |
4240 | +typedef enum { DO_ARCHALL = 0, SKIP_ARCHALL = 1 } do_this; |
4241 | +static void remove_binaries_by_arch(dpkg_sources_note *srcsn, |
4242 | + dpkg_source_note *srcn, int archnum, |
4243 | + do_this arch_all) |
4244 | +{ |
4245 | + packagelist *p; |
4246 | + packagelist *leftovers = NULL, **addto = &leftovers; |
4247 | + assert(is_sources_note(srcsn)); |
4248 | + |
4249 | + assert(arch_all == SKIP_ARCHALL || NULL == lookup_sourcenotetbl(srcsn->sources,srcn->source->package)); |
4250 | + /* if we're removing the entire binary, we should already have |
4251 | + * removed the source. if we're removing just the binaries on this |
4252 | + * arch (not arch:all) then we may be keeping the source |
4253 | + * |
4254 | + * really a logical XOR, I think. we don't rely on this assertion |
4255 | + * here |
4256 | + */ |
4257 | + |
4258 | + for (p = srcn->binaries[archnum]; p != NULL; p = p->next) { |
4259 | + dpkg_collected_package *cpkg; |
4260 | + if (arch_all == SKIP_ARCHALL && p->value->arch_all) { |
4261 | + insert_packagelist(addto, p->value); |
4262 | + addto = &(*addto)->next; |
4263 | + continue; |
4264 | + } |
4265 | + cpkg = lookup_packagetbl(srcsn->pkgs[archnum]->packages, |
4266 | + p->value->package); |
4267 | + remove_package(srcsn->pkgs[archnum], cpkg); |
4268 | + } |
4269 | + free_packagelist(srcn->binaries[archnum]); |
4270 | + srcn->binaries[archnum] = leftovers; |
4271 | +} |
4272 | + |
4273 | +typedef enum { NOTUNDOABLE = 0, UNDOABLE = 1 } undoable; |
4274 | +static void add_binaries_by_arch(dpkg_sources_note *srcsn, |
4275 | + dpkg_source_note *srcn, dpkg_source *src, |
4276 | + int archnum, undoable undoop, do_this arch_all) |
4277 | +{ |
4278 | + ownedpackagelist *p; |
4279 | + const char *archname = srcsn->archname[archnum]; |
4280 | + int origarchnum = -1; |
4281 | + int i; |
4282 | + |
4283 | + assert(is_sources_note(srcsn)); |
4284 | + assert(srcn == lookup_sourcenotetbl(srcsn->sources,srcn->source->package)); |
4285 | + for (i = 0; i < src->owner->n_arches; i++) { |
4286 | + if (strcmp(archname, src->owner->archname[i]) == 0) { |
4287 | + origarchnum = i; |
4288 | + break; |
4289 | + } |
4290 | + } |
4291 | + if (origarchnum == -1) return; /* nothing to add, no biggie */ |
4292 | + |
4293 | + for (p = src->packages[origarchnum]; p != NULL; p = p->next) { |
4294 | + dpkg_collected_package *cpkg; |
4295 | + |
4296 | + if (arch_all == SKIP_ARCHALL && p->value->arch_all) continue; |
4297 | + |
4298 | + if ((cpkg = lookup_packagetbl(srcsn->pkgs[archnum]->packages, |
4299 | + p->value->package))) |
4300 | + { |
4301 | + dpkg_source_note *srcnB; |
4302 | + packagelist **p; |
4303 | + |
4304 | + if (!undoop) { |
4305 | + printf("conflict w/o undo: binary %s, owned by %s, replaced by %s\n", cpkg->pkg->package, cpkg->pkg->source, src->package); |
4306 | + fflush(stdout); |
4307 | + } |
4308 | + srcnB = lookup_sourcenotetbl(srcsn->sources, cpkg->pkg->source); |
4309 | + assert(srcnB != NULL); |
4310 | + |
4311 | + for (p = &srcnB->binaries[archnum]; *p != NULL; p = &(*p)->next) { |
4312 | + if ((*p)->value == cpkg->pkg) break; |
4313 | + } |
4314 | + assert(*p != NULL); /* binary should be from source */ |
4315 | + |
4316 | + assert(undoop); |
4317 | + save_source_note(srcsn, srcnB); |
4318 | + remove_package(srcsn->pkgs[archnum], cpkg); |
4319 | + remove_packagelist(p); |
4320 | + } |
4321 | + |
4322 | + add_package(srcsn->pkgs[archnum], p->value); |
4323 | + insert_packagelist(&srcn->binaries[archnum], p->value); |
4324 | + } |
4325 | +} |
4326 | + |
4327 | +void upgrade_source(dpkg_sources_note *srcsn, dpkg_source *src) { |
4328 | + dpkg_source_note *srcn; |
4329 | + int i; |
4330 | + |
4331 | + new_op(srcsn); |
4332 | + |
4333 | + assert(is_sources_note(srcsn)); |
4334 | + /* first, find the old source, if it exists */ |
4335 | + srcn = remove_sourcenotetbl(srcsn->sources, src->package); |
4336 | + if (srcn != NULL) { |
4337 | + save_source_note(srcsn, srcn); |
4338 | + for (i = 0; i < srcn->n_arches; i++) { |
4339 | + remove_binaries_by_arch(srcsn, srcn, i, DO_ARCHALL); |
4340 | + } |
4341 | + free_source_note(srcn); |
4342 | + } else { |
4343 | + save_empty_source_note(srcsn, src); |
4344 | + } |
4345 | + |
4346 | + /* then add the new one */ |
4347 | + srcn = new_source_note(src, srcsn->n_arches); |
4348 | + add_sourcenotetbl(srcsn->sources, src->package, srcn); |
4349 | + for (i = 0; i < srcsn->n_arches; i++) { |
4350 | + add_binaries_by_arch(srcsn, srcn, src, i, UNDOABLE, DO_ARCHALL); |
4351 | + } |
4352 | + assert(is_sources_note(srcsn)); |
4353 | +} |
4354 | + |
4355 | +void upgrade_arch(dpkg_sources_note *srcsn, dpkg_source *src, char *arch) { |
4356 | + dpkg_source_note *srcn; |
4357 | + int archnum = -1; |
4358 | + int i; |
4359 | + |
4360 | + assert(is_sources_note(srcsn)); |
4361 | + /* first, find the old source */ |
4362 | + srcn = lookup_sourcenotetbl(srcsn->sources, src->package); |
4363 | + |
4364 | + assert(srcn != NULL); |
4365 | + new_op(srcsn); |
4366 | + save_source_note(srcsn, srcn); |
4367 | + |
4368 | + /* then lookup the archnum */ |
4369 | + for (i = 0; i < srcsn->n_arches; i++) { |
4370 | + if (strcmp(arch, srcsn->archname[i]) == 0) { |
4371 | + archnum = i; |
4372 | + break; |
4373 | + } |
4374 | + } |
4375 | + if (archnum == -1) die("upgrade_arch: unknown arch"); |
4376 | + |
4377 | + /* then remove the old stuff and add the new */ |
4378 | + remove_binaries_by_arch(srcsn, srcn, archnum, SKIP_ARCHALL); |
4379 | + add_binaries_by_arch(srcsn, srcn, src, archnum, UNDOABLE, SKIP_ARCHALL); |
4380 | + assert(is_sources_note(srcsn)); |
4381 | +} |
4382 | + |
4383 | +void remove_source(dpkg_sources_note *srcsn, char *name) { |
4384 | + dpkg_source_note *srcn; |
4385 | + int i; |
4386 | + |
4387 | + assert(is_sources_note(srcsn)); |
4388 | + srcn = remove_sourcenotetbl(srcsn->sources, name); |
4389 | + assert(srcn != NULL); |
4390 | + |
4391 | + new_op(srcsn); |
4392 | + save_source_note(srcsn, srcn); |
4393 | + for (i = 0; i < srcn->n_arches; i++) { |
4394 | + remove_binaries_by_arch(srcsn, srcn, i, DO_ARCHALL); |
4395 | + } |
4396 | + free_source_note(srcn); |
4397 | + assert(is_sources_note(srcsn)); |
4398 | +} |
4399 | + |
4400 | +int can_undo(dpkg_sources_note *srcsn) { |
4401 | + assert(is_sources_note(srcsn)); |
4402 | + return srcsn->undo != NULL; |
4403 | +} |
4404 | + |
4405 | +void undo_change(dpkg_sources_note *srcsn) { |
4406 | + dpkg_source_note *srcnO, *srcnC; /* old, current */ |
4407 | + source_note_list *srcnl; |
4408 | + int i; |
4409 | + |
4410 | + assert(is_sources_note(srcsn)); |
4411 | + assert(can_undo(srcsn)); |
4412 | + |
4413 | + srcnl = remove_source_note_listlist(&srcsn->undo); |
4414 | + |
4415 | + while(srcnl) { |
4416 | + srcnO = remove_source_note_list(&srcnl); |
4417 | + assert(srcnO != NULL); /* can_undo() implies this is true... */ |
4418 | + |
4419 | + srcnC = remove_sourcenotetbl(srcsn->sources, srcnO->source->package); |
4420 | + if (srcnC != NULL) { |
4421 | + for (i = 0; i < srcnC->n_arches; i++) { |
4422 | + remove_binaries_by_arch(srcsn, srcnC, i, DO_ARCHALL); |
4423 | + } |
4424 | + free_source_note(srcnC); |
4425 | + assert(!lookup_sourcenotetbl(srcsn->sources, |
4426 | + srcnO->source->package)); |
4427 | + } |
4428 | + |
4429 | + if (srcnO->binaries == NULL) { |
4430 | + /* no original source */ |
4431 | + assert(srcnC != NULL); /* some sort of no-op? freaky. */ |
4432 | + free_source_note(srcnO); |
4433 | + } else { |
4434 | + packagelist *p; |
4435 | + /* original source */ |
4436 | + add_sourcenotetbl(srcsn->sources, srcnO->source->package, srcnO); |
4437 | + for (i = 0; i < srcsn->n_arches; i++) { |
4438 | + for (p = srcnO->binaries[i]; p != NULL; p = p->next) { |
4439 | + add_package(srcsn->pkgs[i], p->value); |
4440 | + } |
4441 | + } |
4442 | + } |
4443 | + } |
4444 | +} |
4445 | + |
4446 | +LIST_IMPL(source_note_list, dpkg_source_note *, free_source_note, |
4447 | + block_malloc, block_free); |
4448 | +LIST_IMPL(source_note_listlist, source_note_list *, free_source_note_list, |
4449 | + block_malloc, block_free); |
4450 | + |
4451 | +void commit_changes(dpkg_sources_note *srcsn) { |
4452 | + assert(is_sources_note(srcsn)); |
4453 | + free_source_note_listlist(srcsn->undo); |
4454 | + srcsn->undo = NULL; |
4455 | +} |
4456 | + |
4457 | +dpkg_source_note *copy_source_note(dpkg_source_note *srcn) { |
4458 | + dpkg_source_note *srcn2; |
4459 | + packagelist *src, **dest; |
4460 | + int i; |
4461 | + |
4462 | + assert(srcn->binaries != NULL); |
4463 | + |
4464 | + srcn2 = block_malloc(sizeof(dpkg_source_note)); |
4465 | + if (srcn2 == NULL) die("copy_source_note alloc:"); |
4466 | + |
4467 | + srcn2->source = srcn->source; |
4468 | + srcn2->n_arches = srcn->n_arches; |
4469 | + srcn2->binaries = block_malloc(sizeof(packagenamelist*) * srcn2->n_arches); |
4470 | + if (srcn2->binaries == NULL) die("copy_source_note alloc:"); |
4471 | + |
4472 | + for (i = 0; i < srcn2->n_arches; i++) { |
4473 | + dest = &(srcn2->binaries[i]); |
4474 | + *dest = NULL; |
4475 | + for (src = srcn->binaries[i]; src; src = src->next) { |
4476 | + insert_packagelist(dest, src->value); |
4477 | + dest = &((*dest)->next); |
4478 | + } |
4479 | + } |
4480 | + |
4481 | + return srcn2; |
4482 | +} |
4483 | + |
4484 | +void write_notes(char *dir, dpkg_sources_note *srcsn) { |
4485 | + FILE *src; |
4486 | + FILE *archfile[100]; |
4487 | + char buf[1000]; |
4488 | + int i; |
4489 | + sourcenotetbl_iter srciter; |
4490 | + |
4491 | + assert(is_sources_note(srcsn)); |
4492 | + snprintf(buf, 1000, "%s/Sources", dir); |
4493 | + src = fopen(buf, "w"); |
4494 | + for (i = 0; i < srcsn->n_arches; i++) { |
4495 | + snprintf(buf, 1000, "%s/Packages_%s", dir, srcsn->archname[i]); |
4496 | + archfile[i] = fopen(buf, "w"); |
4497 | + } |
4498 | + |
4499 | + for (srciter = first_sourcenotetbl(srcsn->sources); |
4500 | + !done_sourcenotetbl(srciter); |
4501 | + srciter = next_sourcenotetbl(srciter)) |
4502 | + { |
4503 | + packagelist *p; |
4504 | + int i; |
4505 | + |
4506 | + if (!srciter.v->source->fake) |
4507 | + write_paragraph(src, srciter.v->source->details); |
4508 | + |
4509 | + for (i = 0; i < srcsn->n_arches; i++) { |
4510 | + for (p = srciter.v->binaries[i]; p != NULL; p = p->next) { |
4511 | + write_paragraph(archfile[i], p->value->details); |
4512 | + } |
4513 | + } |
4514 | + } |
4515 | + |
4516 | + fclose(src); |
4517 | + for (i = 0; i < srcsn->n_arches; i++) { |
4518 | + fclose(archfile[i]); |
4519 | + } |
4520 | +} |
4521 | + |
4522 | |
4523 | === added file 'update_out/dpkg.h' |
4524 | --- update_out/dpkg.h 1970-01-01 00:00:00 +0000 |
4525 | +++ update_out/dpkg.h 2020-03-12 14:58:23 +0000 |
4526 | @@ -0,0 +1,207 @@ |
4527 | +#ifndef DPKG_H |
4528 | +#define DPKG_H |
4529 | + |
4530 | +#include "templates.h" |
4531 | +#include "memory.h" |
4532 | + |
4533 | +#include <stdio.h> |
4534 | + |
4535 | +/************************************************************************** |
4536 | + * Coping with an rfc822-esque field |
4537 | + */ |
4538 | + |
4539 | +typedef struct dpkg_entry dpkg_entry; |
4540 | +struct dpkg_entry { |
4541 | + char *name; |
4542 | + char *value; |
4543 | +}; |
4544 | + |
4545 | +typedef struct dpkg_paragraph dpkg_paragraph; |
4546 | +struct dpkg_paragraph { |
4547 | + int n_entries; |
4548 | + int n_allocated; |
4549 | + dpkg_entry *entry; |
4550 | +}; |
4551 | + |
4552 | +/************************************************************************** |
4553 | + * Coping with a package (or many pkgs) as an abstract entity |
4554 | + */ |
4555 | + |
4556 | +typedef enum {dr_NOOP,dr_LT,dr_LTEQ,dr_EQ,dr_GTEQ,dr_GT} dependency_relation; |
4557 | +extern char *dependency_relation_sym[]; |
4558 | + |
4559 | +typedef struct dependency dependency; |
4560 | +struct dependency { |
4561 | + char *package; |
4562 | + dependency_relation op; |
4563 | + char *version; |
4564 | +}; |
4565 | + |
4566 | +LIST(deplist, dependency*); |
4567 | +LIST(deplistlist, deplist*); |
4568 | + |
4569 | +LIST(packagenamelist, char*); |
4570 | +LIST(ownedpackagenamelist, char*); |
4571 | + |
4572 | +typedef struct dpkg_package dpkg_package; |
4573 | + |
4574 | +struct dpkg_package { |
4575 | + char *package; |
4576 | + char *version; |
4577 | + |
4578 | + char *source; |
4579 | + char *source_ver; |
4580 | + |
4581 | + int priority; |
4582 | + |
4583 | + int arch_all; |
4584 | + |
4585 | + deplistlist *depends[4]; |
4586 | + deplist *conflicts; |
4587 | + ownedpackagenamelist *provides; |
4588 | + |
4589 | + dpkg_paragraph *details; |
4590 | +}; |
4591 | + |
4592 | +LIST(packagelist, dpkg_package *); |
4593 | +LIST(ownedpackagelist, dpkg_package *); |
4594 | + |
4595 | +typedef struct satisfieddep satisfieddep; |
4596 | + |
4597 | +struct satisfieddep { |
4598 | + /* dependency *dep; */ |
4599 | + deplist *depl; |
4600 | + packagelist *pkgs; |
4601 | +}; |
4602 | + |
4603 | +LIST(satisfieddeplist, satisfieddep *); |
4604 | + |
4605 | +/************************************************************************** |
4606 | + * Coping with a source package (and collections thereof) as an abstract |
4607 | + * entity, owning a bunch of binary packages |
4608 | + */ |
4609 | + |
4610 | +typedef struct dpkg_source dpkg_source; |
4611 | +struct dpkg_source { |
4612 | + char *package; |
4613 | + char *version; |
4614 | + |
4615 | + int fake; |
4616 | + |
4617 | + struct dpkg_sources *owner; |
4618 | + ownedpackagelist **packages; /* one for each architecture */ |
4619 | + |
4620 | + dpkg_paragraph *details; |
4621 | +}; |
4622 | + |
4623 | +HASH(sourcetbl,char *,dpkg_source *); |
4624 | + |
4625 | +typedef struct dpkg_sources dpkg_sources; |
4626 | +struct dpkg_sources { |
4627 | + int n_arches; |
4628 | + char **archname; |
4629 | + sourcetbl *sources; |
4630 | + ownedpackagelist **unclaimedpackages; /* one for each arch */ |
4631 | +}; |
4632 | + |
4633 | +/************************************************************************** |
4634 | + */ |
4635 | + |
4636 | +typedef struct dpkg_collected_package dpkg_collected_package; |
4637 | +struct dpkg_collected_package { |
4638 | + dpkg_package *pkg; |
4639 | + |
4640 | + int installed, conflicted; |
4641 | + |
4642 | + enum { UNKNOWN, YES } installable; |
4643 | + packagenamelist *mayaffect; |
4644 | + |
4645 | + /* on update, the installability_checked of each /mayaffect/ed package |
4646 | + * is cleared, and the mayaffect list is cleared. |
4647 | + * |
4648 | + * note that installable = NO couldn't be maintained over adding a package |
4649 | + * to testing. installable = YES can be, thanks to the mayaffect list |
4650 | + * (once a package is removed, everything it mayaffect must be set back |
4651 | + * to unknown, but everything else is okay) |
4652 | + */ |
4653 | +}; |
4654 | + |
4655 | +LIST(collpackagelist, dpkg_collected_package *); |
4656 | + |
4657 | +/************************************************************************** |
4658 | + */ |
4659 | + |
4660 | +typedef struct dpkg_provision dpkg_provision; |
4661 | +struct dpkg_provision { |
4662 | + char *version; |
4663 | + dpkg_collected_package *pkg; |
4664 | +}; |
4665 | + |
4666 | +LIST(virtualpkg, dpkg_provision); |
4667 | + |
4668 | +HASH(virtualpkgtbl,char *,virtualpkg *); |
4669 | +HASH(packagetbl,char *,dpkg_collected_package *); |
4670 | + |
4671 | +typedef struct dpkg_packages dpkg_packages; |
4672 | +struct dpkg_packages { |
4673 | + char *arch; |
4674 | + packagetbl *packages; |
4675 | + virtualpkgtbl *virtualpkgs; |
4676 | +}; |
4677 | + |
4678 | +typedef struct dpkg_source_note dpkg_source_note; |
4679 | +struct dpkg_source_note { |
4680 | + dpkg_source *source; /* unowned */ |
4681 | + int n_arches; |
4682 | + packagelist **binaries; /* one for each arch */ |
4683 | +}; |
4684 | +HASH(sourcenotetbl, char *, dpkg_source_note *); |
4685 | + |
4686 | +LIST(source_note_list, dpkg_source_note *); |
4687 | + /* contains a copy of the previous source_note */ |
4688 | +LIST(source_note_listlist, source_note_list *); |
4689 | + /* contains a copy of all the source_notes modified by the last op */ |
4690 | + |
4691 | +typedef struct dpkg_sources_note dpkg_sources_note; |
4692 | +struct dpkg_sources_note { |
4693 | + unsigned long magic; |
4694 | + sourcenotetbl *sources; |
4695 | + int n_arches; |
4696 | + dpkg_packages **pkgs; |
4697 | + char **archname; |
4698 | + |
4699 | + source_note_listlist *undo; |
4700 | +}; |
4701 | + |
4702 | +void free_packages(dpkg_packages *pkgs); |
4703 | +void free_sources(dpkg_sources *s); |
4704 | + |
4705 | +dpkg_packages *get_architecture(dpkg_sources *srcs, char *arch); |
4706 | + |
4707 | +/* parsing things */ |
4708 | +int checkinstallable(dpkg_packages *pkgs, collpackagelist *instoneof); |
4709 | +int checkinstallable2(dpkg_packages *pkgs, char *pkgname); |
4710 | +satisfieddeplist *checkunsatisfiabledeps(dpkg_packages *pkgs, |
4711 | + deplistlist *deps); |
4712 | + |
4713 | +dpkg_sources *read_directory(char *dir, int n_arches, char *archname[]); |
4714 | +void write_directory(char *dir, dpkg_sources *srcs); |
4715 | + |
4716 | +void free_source(dpkg_source *s); |
4717 | + |
4718 | +/* adding and deleting and stuff */ |
4719 | +dpkg_sources_note *new_sources_note(int n_arches, char **archname); |
4720 | +void remove_source(dpkg_sources_note *srcsn, char *name); |
4721 | +void upgrade_source(dpkg_sources_note *srcsn, dpkg_source *src); |
4722 | +void upgrade_arch(dpkg_sources_note *srcsn, dpkg_source *src, char *arch); |
4723 | +void write_notes(char *dir, dpkg_sources_note *srcsn); |
4724 | +void free_sources_note(dpkg_sources_note *srcsn); |
4725 | +void free_source_note(dpkg_source_note *srcn); |
4726 | +void undo_change(dpkg_sources_note *srcsn); |
4727 | +int can_undo(dpkg_sources_note *srcsn); |
4728 | +void commit_changes(dpkg_sources_note *srcsn); |
4729 | + |
4730 | +int versioncmp(char *left, char *right); |
4731 | +int cmpversions(char *left, int op, char *right); |
4732 | + |
4733 | +#endif |
4734 | |
4735 | === added file 'update_out/freelist.c' |
4736 | --- update_out/freelist.c 1970-01-01 00:00:00 +0000 |
4737 | +++ update_out/freelist.c 2020-03-12 14:58:23 +0000 |
4738 | @@ -0,0 +1,188 @@ |
4739 | +#include <stdio.h> |
4740 | +#include <stdlib.h> |
4741 | +#include "templates.h" |
4742 | + |
4743 | +typedef unsigned long ul; |
4744 | + |
4745 | +#define SIZE (sizeof(ul) * 8) |
4746 | +#define ROUND_DOWN(x) ((x) & ~(SIZE-1)) |
4747 | +#define ROUND_UP(x) ROUND_DOWN((x) + (SIZE-1)) |
4748 | +#define NEXT_UP(x) ROUND_DOWN((x) + SIZE) |
4749 | +#define NEXT_DOWN(x) ROUND_DOWN((x) - 1) |
4750 | + |
4751 | +#define SETBIT(s,p) \ |
4752 | + assert( (bits[(s)/SIZE] & (p)) == (setp ? 0 : (p)) ); \ |
4753 | + if (setp) bits[(s)/SIZE] |= (p); \ |
4754 | + else bits[(s)/SIZE] &= ~(p) |
4755 | + |
4756 | +#define GETBIT(s) (bits[ROUND_DOWN(s)/SIZE] & (1ul << (NEXT_UP(s) - s - 1))) |
4757 | + |
4758 | +size_t count_free_bits_back(ul *bits, size_t s) { |
4759 | + size_t cnt = 0; |
4760 | + ul w = ROUND_DOWN(s) / SIZE; |
4761 | + size_t add = s % SIZE; |
4762 | + ul off = (~0ul) << (SIZE - add); |
4763 | + ul H, d; |
4764 | + |
4765 | + while ((bits[w] & off) == 0) { |
4766 | + cnt += add; |
4767 | + add = SIZE; |
4768 | + off = ~0ul; |
4769 | + if (w == 0) |
4770 | + return cnt; |
4771 | + w--; |
4772 | + } |
4773 | + |
4774 | + H = add; |
4775 | + add = 0; |
4776 | + while ((d = (H - add) / 2) > 0) { |
4777 | + ul offM = (off >> d) & off; |
4778 | + if (bits[w] & offM) { |
4779 | + off = offM; |
4780 | + H = H - d; |
4781 | + } else { |
4782 | + add = H - d; |
4783 | + } |
4784 | + } |
4785 | + cnt += add; |
4786 | + return cnt; |
4787 | +} |
4788 | + |
4789 | +size_t count_free_bits_after(ul *bits, size_t s, size_t end) { |
4790 | + size_t cnt = 0; |
4791 | + ul w = ROUND_DOWN(s) / SIZE; |
4792 | + size_t add = SIZE - s % SIZE; |
4793 | + ul off = (~0ul) >> (SIZE - add); |
4794 | + ul H, d; |
4795 | + |
4796 | + end /= SIZE; |
4797 | + |
4798 | + while ((bits[w] & off) == 0) { |
4799 | + cnt += add; |
4800 | + add = SIZE; |
4801 | + off = ~0ul; |
4802 | + w++; |
4803 | + if (w == end) |
4804 | + return cnt; |
4805 | + } |
4806 | + |
4807 | + H = add; |
4808 | + add = 0; |
4809 | + while ((d = (H - add) / 2) > 0) { |
4810 | + ul offM = off << d; |
4811 | + if (bits[w] & offM) { |
4812 | + off = offM; |
4813 | + H = H - d; |
4814 | + } else { |
4815 | + add = H - d; |
4816 | + } |
4817 | + } |
4818 | + cnt += add; |
4819 | + return cnt; |
4820 | +} |
4821 | + |
4822 | +void find_long_freebits(ul *bits, size_t s, ul *start, size_t *size) { |
4823 | + ul clen = 0; |
4824 | + ul bstart = 0, blen = 0; |
4825 | + ul i, k; |
4826 | + |
4827 | + for (i = 0; i < s; i++) { |
4828 | + if (bits[i] == 0) { |
4829 | + clen++; |
4830 | + } else { |
4831 | + if (clen > blen) { |
4832 | + bstart = i - clen; |
4833 | + blen = clen; |
4834 | + } |
4835 | + clen = 0; |
4836 | + } |
4837 | + } |
4838 | + |
4839 | + if (blen == 0) return; |
4840 | + |
4841 | + bstart *= SIZE; blen *= SIZE; |
4842 | + k = count_free_bits_back(bits, bstart); |
4843 | + bstart -= k; blen += k; |
4844 | + |
4845 | + blen += count_free_bits_after(bits, bstart + blen, s*SIZE); |
4846 | + |
4847 | + *start = bstart; *size = blen; |
4848 | +} |
4849 | + |
4850 | +void mark_bits(ul *bits, ul s, size_t size, int setp) { |
4851 | + ul e = s+size; |
4852 | + |
4853 | + ul rds = ROUND_DOWN(s); |
4854 | + ul nus = rds + SIZE; |
4855 | + ul rue = ROUND_UP(e); |
4856 | + |
4857 | + ul patl = (~0UL) >> (s % SIZE); |
4858 | + ul patr = (~0UL) << (rue - e); |
4859 | + |
4860 | + assert(size > 0); |
4861 | + |
4862 | + /* bits[s1..e1] get touched, but bits[s1], bits[e1] only partially |
4863 | + * |
4864 | + * if s1 == e1, then bits[s1] get touched from [s%SIZE, e%SIZE) |
4865 | + * else |
4866 | + * bits[s1] gets touched from [s%SIZE, SIZE) |
4867 | + * bits[s2..e1) get reset completely |
4868 | + * bits[e1] gets touched from [0, e%SIZE) |
4869 | + */ |
4870 | + |
4871 | + if (nus >= e) { |
4872 | + /* ROUND_DOWN(s) <= s < e <= NEXT_UP(s) */ |
4873 | + SETBIT(rds, patl & patr); |
4874 | + } else { |
4875 | + /* ROUND_DOWN(s) <= s < NEXT_UP(s) <= NEXT_DOWN(e) < e */ |
4876 | + ul rde = ROUND_DOWN(e); |
4877 | + |
4878 | + SETBIT(rds, patl); |
4879 | + SETBIT(rde, patr); |
4880 | + while (nus < rde) { |
4881 | + SETBIT(nus, ~0UL); |
4882 | + nus += SIZE; |
4883 | + } |
4884 | + } |
4885 | +} |
4886 | + |
4887 | +void print_bits(ul *bits, ul s) { |
4888 | + ul i; |
4889 | + putchar(' '); |
4890 | + for (i = 0; i < s * SIZE; i++) { |
4891 | + putchar( GETBIT(i) ? '1' : '0' ); |
4892 | + } |
4893 | +} |
4894 | + |
4895 | +#ifdef TESTBIN |
4896 | + |
4897 | +#define X 2 |
4898 | +int main(void) { |
4899 | + ul memory[X]; |
4900 | + ul l, r; |
4901 | + ul k = 5; |
4902 | + |
4903 | + memset(memory, 0, sizeof(memory)); |
4904 | + for (l = 0; l < X*SIZE; l += k) { |
4905 | + for (r = 1; l+(r*r) < X*SIZE; r++) { |
4906 | + |
4907 | + printf("%lu %lu (%lu %lu", l, r*r, |
4908 | + (unsigned long) count_free_bits_back(memory, X*SIZE), (unsigned long) X*SIZE); |
4909 | + mark_bits(memory, l, r*r, 1); |
4910 | + printf("; %lu %lu %lu; %lu %lu %lu;): ", |
4911 | + (unsigned long) count_free_bits_back(memory, X*SIZE) + l + r*r, |
4912 | + (unsigned long) count_free_bits_after(memory, l + r*r, X*SIZE) + l + r*r, |
4913 | + (unsigned long) X*SIZE, |
4914 | + (unsigned long) count_free_bits_back(memory, l), |
4915 | + (unsigned long) count_free_bits_after(memory, 0, X*SIZE), |
4916 | + l); |
4917 | + print_bits(memory, X); |
4918 | + printf("\n"); |
4919 | + |
4920 | + mark_bits(memory, l, r*r, 0); |
4921 | + } |
4922 | + } |
4923 | + |
4924 | + return 0; |
4925 | +} |
4926 | +#endif |
4927 | |
4928 | === added file 'update_out/freelist.h' |
4929 | --- update_out/freelist.h 1970-01-01 00:00:00 +0000 |
4930 | +++ update_out/freelist.h 2020-03-12 14:58:23 +0000 |
4931 | @@ -0,0 +1,14 @@ |
4932 | + |
4933 | +#ifndef FREELIST_H |
4934 | +#define FREELIST_H |
4935 | + |
4936 | +#include <stdlib.h> |
4937 | + |
4938 | +typedef unsigned long flb_t; |
4939 | + |
4940 | +void mark_bits(flb_t *bits, flb_t s, size_t size, int setp); |
4941 | +size_t count_free_bits_back(flb_t *bits, size_t s); |
4942 | +size_t count_free_bits_after(flb_t *bits, size_t s, size_t end); |
4943 | +void find_long_freebits(flb_t *bits, flb_t s, flb_t *start, size_t *size); |
4944 | + |
4945 | +#endif |
4946 | |
4947 | === added file 'update_out/index.html' |
4948 | --- update_out/index.html 1970-01-01 00:00:00 +0000 |
4949 | +++ update_out/index.html 2020-03-12 14:58:23 +0000 |
4950 | @@ -0,0 +1,18 @@ |
4951 | +<a href="README">README</a><br> |
4952 | +<a href="Makefile">Makefile</a><br> |
4953 | +<a href="assert.c">assert.c</a><br> |
4954 | +<a href="britney-py.c">britney-py.c</a><br> |
4955 | +<a href="checklib.c">checklib.c</a><br> |
4956 | +<a href="dpkg.c">dpkg.c</a><br> |
4957 | +<a href="freelist.c">freelist.c</a><br> |
4958 | +<a href="memory.c">memory.c</a><br> |
4959 | +<a href="memory2.c">memory2.c</a><br> |
4960 | +<a href="memory3.c">memory3.c</a><br> |
4961 | +<a href="dpkg-lib.cpp">dpkg-lib.cpp</a><br> |
4962 | +<a href="dpkg.h">dpkg.h</a><br> |
4963 | +<a href="freelist.h">freelist.h</a><br> |
4964 | +<a href="memory.h">memory.h</a><br> |
4965 | +<a href="templates.h">templates.h</a><br> |
4966 | +<a href="check_out.py">check_out.py</a><br> |
4967 | +<a href="check_uptodate.py">check_uptodate.py</a><br> |
4968 | +<a href="update_out.py">update_out.py</a><br> |
4969 | |
4970 | === added file 'update_out/memory.c' |
4971 | --- update_out/memory.c 1970-01-01 00:00:00 +0000 |
4972 | +++ update_out/memory.c 2020-03-12 14:58:23 +0000 |
4973 | @@ -0,0 +1,389 @@ |
4974 | +#include <stdio.h> |
4975 | +#include <stdlib.h> |
4976 | + |
4977 | +#include "memory.h" |
4978 | +#include "templates.h" |
4979 | +#include "freelist.h" |
4980 | + |
4981 | +/**** THEORY |
4982 | + * |
4983 | + |
4984 | +So, we have blocks with a freelist |
4985 | + |
4986 | + XXX............XXXXXXX..XXXXX.....XXXXXX...... |
4987 | + |
4988 | +Within a block, we work with segments. A segment is... |
4989 | + |
4990 | + ^..........| |
4991 | + |
4992 | +Every now and then we make sure we've got a decent sized segment. |
4993 | + |
4994 | +We have multiple blocks. They're kept ordered by the size of their |
4995 | +current segment. |
4996 | + |
4997 | + **********************************************/ |
4998 | + |
4999 | +#define ALIGN 4 |
5000 | + |