| 1 | #!/usr/bin/python |
|---|
| 2 | |
|---|
| 3 | import sys, os |
|---|
| 4 | from pkgcore.config import load_config |
|---|
| 5 | |
|---|
| 6 | # we use a WorldFile since it *currently* forces unversioned atoms. |
|---|
| 7 | from pkgcore.pkgsets.filelist import WorldFile |
|---|
| 8 | from pkgcore.util.packages import groupby_pkg |
|---|
| 9 | from pkgcore.util.file import iter_read_bash |
|---|
| 10 | from pkgcore.util.osutils import listdir_files |
|---|
| 11 | from pkgcore.ebuild.atom import atom |
|---|
| 12 | |
|---|
| 13 | def main(target_repo, seen, moves): |
|---|
| 14 | # could build the atom from categories/packages, but prefer this; |
|---|
| 15 | # simpler. |
|---|
| 16 | new_seen = set(atom("%s/%s" % x) for x in target_repo.versions) |
|---|
| 17 | |
|---|
| 18 | new_pkgs = new_seen.difference(seen) |
|---|
| 19 | # this is simpler if pkgsets are... actually sets. ;) |
|---|
| 20 | # can't rely on it however since <0.2 lacks it. |
|---|
| 21 | seen_set = set(seen) |
|---|
| 22 | removed = seen_set.difference(new_seen) |
|---|
| 23 | |
|---|
| 24 | finished_moves = removed.intersection(moves) |
|---|
| 25 | removed.difference_update(moves) |
|---|
| 26 | in_transit = seen_set.intersection(moves) |
|---|
| 27 | in_transit.difference_update(finished_moves) |
|---|
| 28 | |
|---|
| 29 | d = {} |
|---|
| 30 | for x in in_transit: |
|---|
| 31 | if moves[x] in new_seen: |
|---|
| 32 | d[x] = moves[x] |
|---|
| 33 | in_transit = d |
|---|
| 34 | |
|---|
| 35 | for l, prefix in ((new_pkgs, "added pkgs"), (removed, "removed pkgs")): |
|---|
| 36 | if l: |
|---|
| 37 | sys.stdout.write("%s:\n %s\n\n" % |
|---|
| 38 | (prefix, "\n ".join(str(x) for x in sorted(l)))) |
|---|
| 39 | |
|---|
| 40 | if finished_moves: |
|---|
| 41 | sys.stdout.write("moved pkgs:\n %s\n\n" % |
|---|
| 42 | "\n ".join("%s -> %s" % (k, moves[k]) |
|---|
| 43 | for k in sorted(finished_moves))) |
|---|
| 44 | if in_transit: |
|---|
| 45 | sys.stdout.write("pkg moves in transit:\n %s\n\n" % |
|---|
| 46 | "\n ".join("%s -> %s" % (k, in_transit[k]) |
|---|
| 47 | for k in sorted(in_transit))) |
|---|
| 48 | |
|---|
| 49 | # just flush the seen fully, simplest. |
|---|
| 50 | for x in seen_set: |
|---|
| 51 | seen.remove(x) |
|---|
| 52 | for x in new_seen: |
|---|
| 53 | seen.add(x) |
|---|
| 54 | return True |
|---|
| 55 | |
|---|
| 56 | |
|---|
| 57 | def apply_updates(moves, atom_set): |
|---|
| 58 | d = {} |
|---|
| 59 | for src, trg in moves.iteritems(): |
|---|
| 60 | if src in atom_set: |
|---|
| 61 | d[src] = trg |
|---|
| 62 | atom_set.remove(src) |
|---|
| 63 | atom_set.add(trg) |
|---|
| 64 | return d |
|---|
| 65 | |
|---|
| 66 | def parse_moves(location): |
|---|
| 67 | pjoin = os.path.join |
|---|
| 68 | |
|---|
| 69 | # schwartzian comparison, convert it into YYYY-QQ |
|---|
| 70 | def get_key(fname): |
|---|
| 71 | return tuple(reversed(fname.split('-'))) |
|---|
| 72 | |
|---|
| 73 | moves = {} |
|---|
| 74 | for update_file in sorted(listdir_files(location), key=get_key): |
|---|
| 75 | for line in iter_read_bash(pjoin(location, update_file)): |
|---|
| 76 | line = line.split() |
|---|
| 77 | if line[0] != 'move': |
|---|
| 78 | continue |
|---|
| 79 | moves[atom(line[1])] = atom(line[2]) |
|---|
| 80 | return moves |
|---|
| 81 | |
|---|
| 82 | |
|---|
| 83 | if __name__ == '__main__': |
|---|
| 84 | args = sys.argv[1:] |
|---|
| 85 | if len(args) not in (2,3) or "--help" in args or "-h" in args: |
|---|
| 86 | sys.stderr.write("need two args; repository to scan, and " |
|---|
| 87 | "file to store the state info in.\nOptional third arg is " |
|---|
| 88 | "a profiles update directory to scan for moves.\n") |
|---|
| 89 | sys.exit(-1) |
|---|
| 90 | |
|---|
| 91 | conf = load_config() |
|---|
| 92 | try: |
|---|
| 93 | repo = conf.repo[args[0]] |
|---|
| 94 | except KeyError: |
|---|
| 95 | sys.stderr.write("repository %r wasn't found- known repos\n%r\n" % |
|---|
| 96 | (args[0], conf.repo.keys())) |
|---|
| 97 | sys.exit(-2) |
|---|
| 98 | |
|---|
| 99 | if not os.path.exists(args[1]): |
|---|
| 100 | open(args[1], "w") |
|---|
| 101 | filelist = WorldFile(args[1]) |
|---|
| 102 | moves = {} |
|---|
| 103 | if len(args) == 3: |
|---|
| 104 | moves = parse_moves(args[2]) |
|---|
| 105 | if main(repo, filelist, moves): |
|---|
| 106 | filelist.flush() |
|---|
| 107 | sys.exit(0) |
|---|
| 108 | sys.exit(1) |
|---|