comparison contrib/bin/copy-latest-pkgs.py @ 542:dc17b62d3cdd

contrib: Added copy-latest-pkgs.py to copy/hardlink latest packages from the mill to the next higher attention level.
author Sascha Teichmann <teichmann@intevation.de>
date Tue, 11 Jan 2011 17:20:02 +0000
parents
children 247a10201cdd
comparison
equal deleted inserted replaced
541:8b49548aa8d4 542:dc17b62d3cdd
1 #!/usr/bin/env python
2 # -*- coding: UTF-8 -*-
3 #
4 # Copyright (C) 2011 by Intevation GmbH
5 # Authors:
6 # Sascha L. Teichmann <sascha.teichmann@intevation.de>
7 #
8 # This program is free software under the GPL (>=v2)
9 # Read the file COPYING coming with the software for details.
10
11 import os
12 import re
13 import sys
14 import subprocess
15 import logging
16 import traceback
17
18 from optparse import OptionParser
19 from shutil import copyfile
20
21 log = logging.getLogger(__name__)
22 log.setLevel(logging.WARNING)
23 log.addHandler(logging.StreamHandler(sys.stderr))
24
25 SAEGEWERKER = "saegewerker"
26
27 FIELD = re.compile("([a-zA-Z]+):\s*(.+)")
28
29
30 class DebCmp(object):
31 """Helper class to make deb files comparable
32 by there versions.
33 """
34
35 def __init__(self, version, path):
36 self.version = version
37 self.path = path
38
39 def __cmp__(self, other):
40 if self.version == other.version:
41 return 0
42 if (subprocess.call([
43 "dpkg", "--compare-versions",
44 self.version, "gt", other.version]) == 0):
45 return +1
46 if (subprocess.call([
47 "dpkg", "--compare-versions",
48 self.version, "lt", other.version]) == 0):
49 return -1
50 return 0
51
52 def __str__(self):
53 return "version: %s / path: %s" % (
54 self.version,
55 self.path)
56
57 def deb_info(deb, fields=["Package", "Version"]):
58 """Extract some meta info from a deb file."""
59 po = subprocess.Popen(
60 ["dpkg-deb", "-f", deb] + fields,
61 stdout=subprocess.PIPE)
62 out = po.communicate()[0]
63 return dict([m.groups()
64 for m in map(FIELD.match, out.splitlines()) if m])
65
66
67 def copy_pkgs(src, dst, options):
68
69 archs = {}
70
71 for arch in os.listdir(src):
72 if arch == 'source': continue
73 arch_dir = os.path.join(src, arch)
74 if not os.path.isdir(arch_dir): continue
75 log.debug("found arch: '%s'" % arch)
76
77 tracks = {}
78
79 for track in os.listdir(arch_dir):
80 track_dir = os.path.join(arch_dir, track)
81 if not os.path.isdir(track_dir): continue
82
83 packages = {}
84
85 log.debug("track dir: '%s'" % track_dir)
86 for f in os.listdir(track_dir):
87 if not f.endswith(".deb"): continue
88 deb_path = os.path.join(track_dir, f)
89 if not os.path.isfile(deb_path): continue
90
91 info = deb_info(deb_path)
92 deb_cmp = DebCmp(info['Version'], deb_path)
93
94 packages.setdefault(info['Package'], []).append(deb_cmp)
95
96 tracks[track] =[max(debs) for debs in packages.itervalues()]
97
98 archs[arch] = tracks
99
100 copy = options.no_hardlinks and copyfile or os.link
101 action = options.no_hardlinks and "copy" or "link"
102
103 for arch, tracks in archs.iteritems():
104 log.debug("writing arch '%s'" % arch)
105 for track, debs in tracks.iteritems():
106 log.debug(" writing track '%s'" % track)
107 dst_dir = os.path.join(dst, arch, track)
108 if not os.path.exists(dst_dir):
109 try:
110 os.makedirs(dst_dir)
111 except:
112 log.warn(traceback.format_exc())
113 continue
114
115 for deb in debs:
116 src_path = deb.path
117 dst_path = os.path.join(dst_dir, os.path.basename(src_path))
118 log.info(" %s '%s' -> '%s'" % (action, src_path, dst_path))
119 if os.path.isfile(dst_path):
120 try: os.remove(dst_path)
121 except: log.warn(traceback.format_exc()); continue
122 try: copy(src_path, dst_path)
123 except: log.warn(traceback.format_exc())
124
125
126 def main():
127 usage = "usage: %prog [options] src-dir dst-dir"
128 parser = OptionParser(usage=usage)
129 parser.add_option(
130 "-v", "--verbose", action="store_true",
131 dest="verbose",
132 help="verbose output")
133 parser.add_option(
134 "-d", "--dry-run", action="store_true",
135 dest="dry_run", default=False,
136 help="don't copy the deb files")
137 parser.add_option(
138 "-n", "--no-saegewerker", action="store_true",
139 dest="no_saegewerker", default=False,
140 help="Don't force run as '%s'" % SAEGEWERKER)
141 parser.add_option(
142 "-l", "--no-hardlinks", action="store_false",
143 dest="no_hardlinks", default=False,
144 help="copy files instead of hard linking")
145
146 options, args = parser.parse_args()
147
148 if len(args) < 2:
149 log.error("need at least two arguments")
150 sys.exit(1)
151
152 src, dst = args[0], args[1]
153
154 for d in (src, dst):
155 if not os.path.isdir(d):
156 log.error("'%s' is not a directory." % d)
157 sys.exit(1)
158
159 if options.verbose: log.setLevel(logging.INFO)
160
161 if not options.no_saegewerker and os.environ['USER'] != SAEGEWERKER:
162 log.error("Need to run as '%s'" % SAEGEWERKER)
163 sys.exit(1)
164
165 copy_pkgs(src, dst, options)
166
167 if __name__ == '__main__':
168 main()
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)