Mercurial > treepkg > treepkg
comparison treepkg/packager.py @ 4:fee641fec94e
Separate the kolab specific parts.
author | Bernhard Herzog <bh@intevation.de> |
---|---|
date | Fri, 09 Mar 2007 12:26:01 +0100 |
parents | e6a9f4037f68 |
children | 96f4f58c62b5 |
comparison
equal
deleted
inserted
replaced
3:7e9db903ba16 | 4:fee641fec94e |
---|---|
25 return property(get) | 25 return property(get) |
26 | 26 |
27 | 27 |
28 class SourcePackager(object): | 28 class SourcePackager(object): |
29 | 29 |
30 # Derived classes must supply the package basename | |
31 pkg_basename = None | |
32 | |
30 def __init__(self, plant, status, work_dir, src_dir, revision): | 33 def __init__(self, plant, status, work_dir, src_dir, revision): |
31 self.plant = plant | 34 self.plant = plant |
32 self.status = status | 35 self.status = status |
33 self.work_dir = work_dir | 36 self.work_dir = work_dir |
34 self.src_dir = src_dir | 37 self.src_dir = src_dir |
35 self.revision = revision | 38 self.revision = revision |
36 self.enterprise_version = (time.strftime("%Y%m%d", time.localtime()) \ | 39 assert(self.pkg_basename) |
37 + "." + str(self.revision)) | |
38 | |
39 def kdepim_version(self, directory): | |
40 """Determine the kdepim version. | |
41 | |
42 The version is taken from the kdepim.lsm file in the plants | |
43 checkout dir. | |
44 """ | |
45 return util.extract_lsm_version(os.path.join(directory, "kdepim.lsm")) | |
46 | 40 |
47 def determine_package_version(self, directory): | 41 def determine_package_version(self, directory): |
48 enterprise_version = self.enterprise_version | 42 """Returns the version number of the new package as a string |
49 kdepimversion = self.kdepim_version(directory) | 43 |
50 version_template = "%(kdepimversion)s.enterprise.0.%(enterprise_version)s" | 44 The directory parameter is the name of the directory containing |
51 return version_template % locals() | 45 the newly exported sources. The sources were exported with the |
46 export_sources method. | |
47 | |
48 The default implementation simply returns the revision converted | |
49 to a string. | |
50 """ | |
51 return str(self.revision) | |
52 | 52 |
53 def export_sources(self): | 53 def export_sources(self): |
54 """Export the sources from the subversion working directory | |
55 | |
56 This method first exports the sources to a temporary directory | |
57 and then renames the directory. The new name is of the form | |
58 | |
59 <pkg_basename>-<version> | |
60 | |
61 Where pkg_basename is the value of self.pkg_basename and version | |
62 is the return value of the determine_package_version() method. | |
63 """ | |
54 temp_dir = os.path.join(self.work_dir, "temp") | 64 temp_dir = os.path.join(self.work_dir, "temp") |
55 self.plant.export_sources(temp_dir) | 65 self.plant.export_sources(temp_dir) |
56 | 66 |
57 pkgbaseversion = self.determine_package_version(temp_dir) | 67 pkgbaseversion = self.determine_package_version(temp_dir) |
58 pkgbasedir = os.path.join(self.work_dir, "kdepim-" + pkgbaseversion) | 68 pkgbasedir = os.path.join(self.work_dir, |
69 self.pkg_basename + "-" + pkgbaseversion) | |
59 | 70 |
60 os.rename(temp_dir, pkgbasedir) | 71 os.rename(temp_dir, pkgbasedir) |
61 return pkgbaseversion, pkgbasedir | 72 return pkgbaseversion, pkgbasedir |
62 | 73 |
63 | 74 |
64 def update_version_numbers(self, pkgbasedir): | 75 def update_version_numbers(self, pkgbasedir): |
65 versionstring = "(enterprise %s)" % self.enterprise_version | 76 """Updates the version numbers in the code in pkgbasedir. |
66 for versionfile in ["kmail/kmversion.h", "kontact/src/main.cpp", | 77 |
67 "korganizer/version.h"]: | 78 The default implementation does nothing. Derived classes should |
68 filename = os.path.join(pkgbasedir, versionfile) | 79 override this method if necessary. |
69 patched = re.sub("\(enterprise ([^)]*)\)", versionstring, | 80 """ |
70 open(filename).read()) | |
71 f = open(filename, "w") | |
72 f.write(patched) | |
73 f.close() | |
74 | 81 |
75 def create_tarball(self, tarballname, workdir, basedir): | 82 def create_tarball(self, tarballname, workdir, basedir): |
83 """Creates a new tarball. | |
84 | |
85 Parameters: | |
86 | |
87 tarballname -- the filename of the new tarball | |
88 workdir -- The directory into which to change before running tar. | |
89 (actually this is done with GNUI tar's -C option) | |
90 basedir -- The basedirectory of the files that are packaged | |
91 into the tarfile. This should be a relative | |
92 filename directly in workdir. | |
93 """ | |
76 logging.info("Creating tarball %r", tarballname) | 94 logging.info("Creating tarball %r", tarballname) |
77 run.call(["tar", "czf", tarballname, "-C", workdir, basedir]) | 95 run.call(["tar", "czf", tarballname, "-C", workdir, basedir]) |
78 | 96 |
79 def copy_debian_directory(self, pkgbasedir, pkgbaseversion, changemsg): | 97 def copy_debian_directory(self, pkgbasedir, pkgbaseversion, changemsg): |
98 """Copies the debian directory and updates the copy's changelog | |
99 | |
100 Parameter: | |
101 pkgbasedir -- The directory holding the unpacked source package | |
102 pkgbaseversion -- The version to update the changelog to | |
103 changemsg -- The message for the changelog | |
104 | |
105 When determining the actual version for the new package, this | |
106 function looks at the previous version in the changelog. If it | |
107 has a prefix separated from the version number by a colon this | |
108 prefix is prepended to the pkgbaseversion parameter. Debian | |
109 uses such prefixes for the kde packages. | |
110 """ | |
80 debian_dir = os.path.join(pkgbasedir, "debian") | 111 debian_dir = os.path.join(pkgbasedir, "debian") |
81 changelog = os.path.join(debian_dir, "changelog") | 112 changelog = os.path.join(debian_dir, "changelog") |
82 | 113 |
83 self.plant.copy_debian_directory(debian_dir) | 114 self.plant.copy_debian_directory(debian_dir) |
84 | 115 |
93 changemsg], | 124 changemsg], |
94 env=self.plant.debian_environment()) | 125 env=self.plant.debian_environment()) |
95 | 126 |
96 | 127 |
97 def create_source_package(self, pkgbasedir, origtargz): | 128 def create_source_package(self, pkgbasedir, origtargz): |
129 """Creates a new source package from pkgbasedir and origtargz""" | |
98 logging.info("Creating new source package") | 130 logging.info("Creating new source package") |
99 run.call(["dpkg-source", "-b", os.path.basename(pkgbasedir), | 131 run.call(["dpkg-source", "-b", os.path.basename(pkgbasedir), |
100 os.path.basename(origtargz)], | 132 os.path.basename(origtargz)], |
101 cwd=os.path.dirname(pkgbasedir), | 133 cwd=os.path.dirname(pkgbasedir), |
102 suppress_output=True, | 134 suppress_output=True, |
103 env=self.plant.debian_environment()) | 135 env=self.plant.debian_environment()) |
104 | 136 |
137 def move_source_package(self, pkgbasename): | |
138 """Moves the new source package from the work_dir to the src_dir""" | |
139 logging.info("Moving source package to %r", self.src_dir) | |
140 util.ensure_directory(self.src_dir) | |
141 for filename in [filename for filename in os.listdir(self.work_dir) | |
142 if filename.startswith(pkgbasename)]: | |
143 os.rename(os.path.join(self.work_dir, filename), | |
144 os.path.join(self.src_dir, filename)) | |
145 | |
105 def package(self): | 146 def package(self): |
147 """Creates a source package from a subversion checkout. | |
148 | |
149 After setting up the working directory, this method calls the | |
150 do_package method to do the actual packaging. Afterwards the | |
151 work directory is removed. | |
152 """ | |
106 util.ensure_directory(self.work_dir) | 153 util.ensure_directory(self.work_dir) |
107 try: | 154 try: |
108 self.status.set("creating_source_package") | 155 self.status.set("creating_source_package") |
109 pkgbaseversion, pkgbasedir = self.export_sources() | 156 self.do_package() |
110 self.update_version_numbers(pkgbasedir) | |
111 | |
112 pkgbasename = "kdepim_" + pkgbaseversion | |
113 origtargz = os.path.join(self.work_dir, | |
114 pkgbasename + ".orig.tar.gz") | |
115 self.create_tarball(origtargz, self.work_dir, | |
116 os.path.basename(pkgbasedir)) | |
117 | |
118 changemsg = ("Update to SVN enterprise branch rev. %d" | |
119 % (self.revision,)) | |
120 self.copy_debian_directory(pkgbasedir, pkgbaseversion, | |
121 changemsg) | |
122 | |
123 self.create_source_package(pkgbasedir, origtargz) | |
124 | |
125 logging.info("Moving source package to %r", self.src_dir) | |
126 util.ensure_directory(self.src_dir) | |
127 for filename in [filename for filename in os.listdir(self.work_dir) | |
128 if filename.startswith(pkgbasename)]: | |
129 os.rename(os.path.join(self.work_dir, filename), | |
130 os.path.join(self.src_dir, filename)) | |
131 self.status.set("source_package_created") | 157 self.status.set("source_package_created") |
132 finally: | 158 finally: |
133 logging.info("Removing workdir %r", self.work_dir) | 159 logging.info("Removing workdir %r", self.work_dir) |
134 shutil.rmtree(self.work_dir) | 160 shutil.rmtree(self.work_dir) |
161 | |
162 def do_package(self): | |
163 """Does the work of creating a source package | |
164 This method must be overriden by derived classes. | |
165 | |
166 The method should do the work in self.work_dir. When the | |
167 package is done, the source package files should be in | |
168 self.src_dir. | |
169 """ | |
170 raise NotImplementedError | |
135 | 171 |
136 | 172 |
137 class BinaryPackager(object): | 173 class BinaryPackager(object): |
138 | 174 |
139 def __init__(self, plant, status, binary_dir, dsc_file, logfile): | 175 def __init__(self, plant, status, binary_dir, dsc_file, logfile): |
153 self.status.set("binary_package_created") | 189 self.status.set("binary_package_created") |
154 | 190 |
155 | 191 |
156 class RevisionPackager(object): | 192 class RevisionPackager(object): |
157 | 193 |
194 source_packager_cls = SourcePackager | |
195 binary_packager_cls = BinaryPackager | |
196 | |
158 def __init__(self, plant, revision): | 197 def __init__(self, plant, revision): |
159 self.plant = plant | 198 self.plant = plant |
160 self.revision = revision | 199 self.revision = revision |
161 self.base_dir = self.plant.pkg_dir_for_revision(self.revision, 1) | 200 self.base_dir = self.plant.pkg_dir_for_revision(self.revision, 1) |
162 self.status = util.StatusFile(os.path.join(self.base_dir, "status")) | 201 self.status = util.StatusFile(os.path.join(self.base_dir, "status")) |
171 return os.path.join(self.src_dir, filename) | 210 return os.path.join(self.src_dir, filename) |
172 return None | 211 return None |
173 | 212 |
174 def package(self): | 213 def package(self): |
175 try: | 214 try: |
176 src_packager = SourcePackager(self.plant, self.status, | 215 src_packager = self.source_packager_cls(self.plant, self.status, |
177 self.work_dir, self.src_dir, | 216 self.work_dir, self.src_dir, |
178 self.revision) | 217 self.revision) |
179 src_packager.package() | 218 src_packager.package() |
180 | 219 |
181 dsc_file = self.find_dsc_file() | 220 dsc_file = self.find_dsc_file() |
182 if dsc_file is None: | 221 if dsc_file is None: |
183 raise RuntimeError("Cannot find dsc File in %r" % self.src_dir) | 222 raise RuntimeError("Cannot find dsc File in %r" % self.src_dir) |
184 | 223 |
185 bin_packager = BinaryPackager(self.plant, self.status, | 224 bin_packager = self.binary_packager_cls(self.plant, self.status, |
186 self.binary_dir, dsc_file, | 225 self.binary_dir, dsc_file, |
187 os.path.join(self.base_dir, | 226 os.path.join(self.base_dir, |
188 "build.log")) | 227 "build.log")) |
189 bin_packager.package() | 228 bin_packager.package() |
190 except: | 229 except: |
191 self.status.set("failed", traceback.format_exc()) | 230 self.status.set("failed", traceback.format_exc()) |
192 raise | 231 raise |
193 | 232 |
196 shutil.rmtree(self.base_dir) | 235 shutil.rmtree(self.base_dir) |
197 | 236 |
198 | 237 |
199 class AssemblyLine(object): | 238 class AssemblyLine(object): |
200 | 239 |
240 revision_packager_cls = RevisionPackager | |
241 | |
242 svn_external_subdirs = [] | |
243 | |
244 extra_config_desc = [] | |
245 | |
201 def __init__(self, name, base_dir, svn_url, root_cmd, deb_email, | 246 def __init__(self, name, base_dir, svn_url, root_cmd, deb_email, |
202 deb_fullname): | 247 deb_fullname, packager_class="treepkg.packager"): |
203 self.name = name | 248 self.name = name |
204 self.base_dir = base_dir | 249 self.base_dir = base_dir |
205 self.svn_url = svn_url | 250 self.svn_url = svn_url |
206 self.root_cmd = root_cmd | 251 self.root_cmd = root_cmd |
207 self.deb_email = deb_email | 252 self.deb_email = deb_email |
217 def pkg_dir_for_revision(self, revision, increment): | 262 def pkg_dir_for_revision(self, revision, increment): |
218 return os.path.join(self.pkg_dir, | 263 return os.path.join(self.pkg_dir, |
219 self.pkg_dir_template % locals()) | 264 self.pkg_dir_template % locals()) |
220 | 265 |
221 def last_changed_revision(self): | 266 def last_changed_revision(self): |
222 rev1 = subversion.last_changed_revision(self.checkout_dir) | 267 revisions = [] |
223 rev2 = subversion.last_changed_revision(os.path.join(self.checkout_dir, | 268 for directory in [self.checkout_dir] + self.svn_external_subdirs: |
224 "admin")) | 269 directory = os.path.join(self.checkout_dir, directory) |
225 return max(rev1, rev2) | 270 revisions.append(subversion.last_changed_revision(directory)) |
271 return max(revisions) | |
226 | 272 |
227 def last_packaged_revision(self): | 273 def last_packaged_revision(self): |
228 """Returns the revision number of the highest packaged revision. | 274 """Returns the revision number of the highest packaged revision. |
229 | 275 |
230 If the revision cannot be determined because no already packaged | 276 If the revision cannot be determined because no already packaged |
263 logging.info("Exporting sources for tarball to %r", to_dir) | 309 logging.info("Exporting sources for tarball to %r", to_dir) |
264 subversion.export(self.checkout_dir, to_dir) | 310 subversion.export(self.checkout_dir, to_dir) |
265 # some versions of svn (notably version 1.4.2 shipped with etch) | 311 # some versions of svn (notably version 1.4.2 shipped with etch) |
266 # do export externals such as the admin subdirectory. We may | 312 # do export externals such as the admin subdirectory. We may |
267 # have to do that in an extra step. | 313 # have to do that in an extra step. |
268 admindir = os.path.join(to_dir, "admin") | 314 for subdir in self.svn_external_subdirs: |
269 if not os.path.isdir(admindir): | 315 absdir = os.path.join(to_dir, subdir) |
270 subversion.export(os.path.join(self.checkout_dir, "admin"), | 316 if not os.path.isdir(absdir): |
271 admindir) | 317 subversion.export(os.path.join(self.checkout_dir, subdir), |
318 absdir) | |
272 | 319 |
273 def copy_debian_directory(self, to_dir): | 320 def copy_debian_directory(self, to_dir): |
274 logging.info("Copying debian directory to %r", to_dir) | 321 logging.info("Copying debian directory to %r", to_dir) |
275 shutil.copytree(self.debian_dir, to_dir) | 322 shutil.copytree(self.debian_dir, to_dir) |
276 | 323 |
288 logging.info("New revision is %d", current_revision) | 335 logging.info("New revision is %d", current_revision) |
289 previous_revision = self.last_packaged_revision() | 336 previous_revision = self.last_packaged_revision() |
290 logging.info("Previously packaged revision was %d", previous_revision) | 337 logging.info("Previously packaged revision was %d", previous_revision) |
291 if current_revision > previous_revision: | 338 if current_revision > previous_revision: |
292 logging.info("New revision is not packaged yet") | 339 logging.info("New revision is not packaged yet") |
293 return RevisionPackager(self, current_revision) | 340 return self.revision_packager_cls(self, current_revision) |
294 else: | 341 else: |
295 logging.info("New revision already packaged.") | 342 logging.info("New revision already packaged.") |
296 | 343 |
344 | |
345 def create_packager(packager_class, **kw): | |
346 module = util.import_dotted_name(packager_class) | |
347 return module.AssemblyLine(**kw) | |
297 | 348 |
298 | 349 |
299 class Packager(object): | 350 class Packager(object): |
300 | 351 |
301 def __init__(self, assembly_lines, check_interval): | 352 def __init__(self, assembly_lines, check_interval): |