]>
Commit | Line | Data |
---|---|---|
4710c53d | 1 | """distutils.command.bdist_rpm\r |
2 | \r | |
3 | Implements the Distutils 'bdist_rpm' command (create RPM source and binary\r | |
4 | distributions)."""\r | |
5 | \r | |
6 | __revision__ = "$Id$"\r | |
7 | \r | |
8 | import sys\r | |
9 | import os\r | |
10 | import string\r | |
11 | \r | |
12 | from distutils.core import Command\r | |
13 | from distutils.debug import DEBUG\r | |
14 | from distutils.file_util import write_file\r | |
15 | from distutils.errors import (DistutilsOptionError, DistutilsPlatformError,\r | |
16 | DistutilsFileError, DistutilsExecError)\r | |
17 | from distutils import log\r | |
18 | \r | |
19 | class bdist_rpm (Command):\r | |
20 | \r | |
21 | description = "create an RPM distribution"\r | |
22 | \r | |
23 | user_options = [\r | |
24 | ('bdist-base=', None,\r | |
25 | "base directory for creating built distributions"),\r | |
26 | ('rpm-base=', None,\r | |
27 | "base directory for creating RPMs (defaults to \"rpm\" under "\r | |
28 | "--bdist-base; must be specified for RPM 2)"),\r | |
29 | ('dist-dir=', 'd',\r | |
30 | "directory to put final RPM files in "\r | |
31 | "(and .spec files if --spec-only)"),\r | |
32 | ('python=', None,\r | |
33 | "path to Python interpreter to hard-code in the .spec file "\r | |
34 | "(default: \"python\")"),\r | |
35 | ('fix-python', None,\r | |
36 | "hard-code the exact path to the current Python interpreter in "\r | |
37 | "the .spec file"),\r | |
38 | ('spec-only', None,\r | |
39 | "only regenerate spec file"),\r | |
40 | ('source-only', None,\r | |
41 | "only generate source RPM"),\r | |
42 | ('binary-only', None,\r | |
43 | "only generate binary RPM"),\r | |
44 | ('use-bzip2', None,\r | |
45 | "use bzip2 instead of gzip to create source distribution"),\r | |
46 | \r | |
47 | # More meta-data: too RPM-specific to put in the setup script,\r | |
48 | # but needs to go in the .spec file -- so we make these options\r | |
49 | # to "bdist_rpm". The idea is that packagers would put this\r | |
50 | # info in setup.cfg, although they are of course free to\r | |
51 | # supply it on the command line.\r | |
52 | ('distribution-name=', None,\r | |
53 | "name of the (Linux) distribution to which this "\r | |
54 | "RPM applies (*not* the name of the module distribution!)"),\r | |
55 | ('group=', None,\r | |
56 | "package classification [default: \"Development/Libraries\"]"),\r | |
57 | ('release=', None,\r | |
58 | "RPM release number"),\r | |
59 | ('serial=', None,\r | |
60 | "RPM serial number"),\r | |
61 | ('vendor=', None,\r | |
62 | "RPM \"vendor\" (eg. \"Joe Blow <joe@example.com>\") "\r | |
63 | "[default: maintainer or author from setup script]"),\r | |
64 | ('packager=', None,\r | |
65 | "RPM packager (eg. \"Jane Doe <jane@example.net>\")"\r | |
66 | "[default: vendor]"),\r | |
67 | ('doc-files=', None,\r | |
68 | "list of documentation files (space or comma-separated)"),\r | |
69 | ('changelog=', None,\r | |
70 | "RPM changelog"),\r | |
71 | ('icon=', None,\r | |
72 | "name of icon file"),\r | |
73 | ('provides=', None,\r | |
74 | "capabilities provided by this package"),\r | |
75 | ('requires=', None,\r | |
76 | "capabilities required by this package"),\r | |
77 | ('conflicts=', None,\r | |
78 | "capabilities which conflict with this package"),\r | |
79 | ('build-requires=', None,\r | |
80 | "capabilities required to build this package"),\r | |
81 | ('obsoletes=', None,\r | |
82 | "capabilities made obsolete by this package"),\r | |
83 | ('no-autoreq', None,\r | |
84 | "do not automatically calculate dependencies"),\r | |
85 | \r | |
86 | # Actions to take when building RPM\r | |
87 | ('keep-temp', 'k',\r | |
88 | "don't clean up RPM build directory"),\r | |
89 | ('no-keep-temp', None,\r | |
90 | "clean up RPM build directory [default]"),\r | |
91 | ('use-rpm-opt-flags', None,\r | |
92 | "compile with RPM_OPT_FLAGS when building from source RPM"),\r | |
93 | ('no-rpm-opt-flags', None,\r | |
94 | "do not pass any RPM CFLAGS to compiler"),\r | |
95 | ('rpm3-mode', None,\r | |
96 | "RPM 3 compatibility mode (default)"),\r | |
97 | ('rpm2-mode', None,\r | |
98 | "RPM 2 compatibility mode"),\r | |
99 | \r | |
100 | # Add the hooks necessary for specifying custom scripts\r | |
101 | ('prep-script=', None,\r | |
102 | "Specify a script for the PREP phase of RPM building"),\r | |
103 | ('build-script=', None,\r | |
104 | "Specify a script for the BUILD phase of RPM building"),\r | |
105 | \r | |
106 | ('pre-install=', None,\r | |
107 | "Specify a script for the pre-INSTALL phase of RPM building"),\r | |
108 | ('install-script=', None,\r | |
109 | "Specify a script for the INSTALL phase of RPM building"),\r | |
110 | ('post-install=', None,\r | |
111 | "Specify a script for the post-INSTALL phase of RPM building"),\r | |
112 | \r | |
113 | ('pre-uninstall=', None,\r | |
114 | "Specify a script for the pre-UNINSTALL phase of RPM building"),\r | |
115 | ('post-uninstall=', None,\r | |
116 | "Specify a script for the post-UNINSTALL phase of RPM building"),\r | |
117 | \r | |
118 | ('clean-script=', None,\r | |
119 | "Specify a script for the CLEAN phase of RPM building"),\r | |
120 | \r | |
121 | ('verify-script=', None,\r | |
122 | "Specify a script for the VERIFY phase of the RPM build"),\r | |
123 | \r | |
124 | # Allow a packager to explicitly force an architecture\r | |
125 | ('force-arch=', None,\r | |
126 | "Force an architecture onto the RPM build process"),\r | |
127 | \r | |
128 | ('quiet', 'q',\r | |
129 | "Run the INSTALL phase of RPM building in quiet mode"),\r | |
130 | ]\r | |
131 | \r | |
132 | boolean_options = ['keep-temp', 'use-rpm-opt-flags', 'rpm3-mode',\r | |
133 | 'no-autoreq', 'quiet']\r | |
134 | \r | |
135 | negative_opt = {'no-keep-temp': 'keep-temp',\r | |
136 | 'no-rpm-opt-flags': 'use-rpm-opt-flags',\r | |
137 | 'rpm2-mode': 'rpm3-mode'}\r | |
138 | \r | |
139 | \r | |
140 | def initialize_options (self):\r | |
141 | self.bdist_base = None\r | |
142 | self.rpm_base = None\r | |
143 | self.dist_dir = None\r | |
144 | self.python = None\r | |
145 | self.fix_python = None\r | |
146 | self.spec_only = None\r | |
147 | self.binary_only = None\r | |
148 | self.source_only = None\r | |
149 | self.use_bzip2 = None\r | |
150 | \r | |
151 | self.distribution_name = None\r | |
152 | self.group = None\r | |
153 | self.release = None\r | |
154 | self.serial = None\r | |
155 | self.vendor = None\r | |
156 | self.packager = None\r | |
157 | self.doc_files = None\r | |
158 | self.changelog = None\r | |
159 | self.icon = None\r | |
160 | \r | |
161 | self.prep_script = None\r | |
162 | self.build_script = None\r | |
163 | self.install_script = None\r | |
164 | self.clean_script = None\r | |
165 | self.verify_script = None\r | |
166 | self.pre_install = None\r | |
167 | self.post_install = None\r | |
168 | self.pre_uninstall = None\r | |
169 | self.post_uninstall = None\r | |
170 | self.prep = None\r | |
171 | self.provides = None\r | |
172 | self.requires = None\r | |
173 | self.conflicts = None\r | |
174 | self.build_requires = None\r | |
175 | self.obsoletes = None\r | |
176 | \r | |
177 | self.keep_temp = 0\r | |
178 | self.use_rpm_opt_flags = 1\r | |
179 | self.rpm3_mode = 1\r | |
180 | self.no_autoreq = 0\r | |
181 | \r | |
182 | self.force_arch = None\r | |
183 | self.quiet = 0\r | |
184 | \r | |
185 | # initialize_options()\r | |
186 | \r | |
187 | \r | |
188 | def finalize_options (self):\r | |
189 | self.set_undefined_options('bdist', ('bdist_base', 'bdist_base'))\r | |
190 | if self.rpm_base is None:\r | |
191 | if not self.rpm3_mode:\r | |
192 | raise DistutilsOptionError, \\r | |
193 | "you must specify --rpm-base in RPM 2 mode"\r | |
194 | self.rpm_base = os.path.join(self.bdist_base, "rpm")\r | |
195 | \r | |
196 | if self.python is None:\r | |
197 | if self.fix_python:\r | |
198 | self.python = sys.executable\r | |
199 | else:\r | |
200 | self.python = "python"\r | |
201 | elif self.fix_python:\r | |
202 | raise DistutilsOptionError, \\r | |
203 | "--python and --fix-python are mutually exclusive options"\r | |
204 | \r | |
205 | if os.name != 'posix':\r | |
206 | raise DistutilsPlatformError, \\r | |
207 | ("don't know how to create RPM "\r | |
208 | "distributions on platform %s" % os.name)\r | |
209 | if self.binary_only and self.source_only:\r | |
210 | raise DistutilsOptionError, \\r | |
211 | "cannot supply both '--source-only' and '--binary-only'"\r | |
212 | \r | |
213 | # don't pass CFLAGS to pure python distributions\r | |
214 | if not self.distribution.has_ext_modules():\r | |
215 | self.use_rpm_opt_flags = 0\r | |
216 | \r | |
217 | self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))\r | |
218 | self.finalize_package_data()\r | |
219 | \r | |
220 | # finalize_options()\r | |
221 | \r | |
222 | def finalize_package_data (self):\r | |
223 | self.ensure_string('group', "Development/Libraries")\r | |
224 | self.ensure_string('vendor',\r | |
225 | "%s <%s>" % (self.distribution.get_contact(),\r | |
226 | self.distribution.get_contact_email()))\r | |
227 | self.ensure_string('packager')\r | |
228 | self.ensure_string_list('doc_files')\r | |
229 | if isinstance(self.doc_files, list):\r | |
230 | for readme in ('README', 'README.txt'):\r | |
231 | if os.path.exists(readme) and readme not in self.doc_files:\r | |
232 | self.doc_files.append(readme)\r | |
233 | \r | |
234 | self.ensure_string('release', "1")\r | |
235 | self.ensure_string('serial') # should it be an int?\r | |
236 | \r | |
237 | self.ensure_string('distribution_name')\r | |
238 | \r | |
239 | self.ensure_string('changelog')\r | |
240 | # Format changelog correctly\r | |
241 | self.changelog = self._format_changelog(self.changelog)\r | |
242 | \r | |
243 | self.ensure_filename('icon')\r | |
244 | \r | |
245 | self.ensure_filename('prep_script')\r | |
246 | self.ensure_filename('build_script')\r | |
247 | self.ensure_filename('install_script')\r | |
248 | self.ensure_filename('clean_script')\r | |
249 | self.ensure_filename('verify_script')\r | |
250 | self.ensure_filename('pre_install')\r | |
251 | self.ensure_filename('post_install')\r | |
252 | self.ensure_filename('pre_uninstall')\r | |
253 | self.ensure_filename('post_uninstall')\r | |
254 | \r | |
255 | # XXX don't forget we punted on summaries and descriptions -- they\r | |
256 | # should be handled here eventually!\r | |
257 | \r | |
258 | # Now *this* is some meta-data that belongs in the setup script...\r | |
259 | self.ensure_string_list('provides')\r | |
260 | self.ensure_string_list('requires')\r | |
261 | self.ensure_string_list('conflicts')\r | |
262 | self.ensure_string_list('build_requires')\r | |
263 | self.ensure_string_list('obsoletes')\r | |
264 | \r | |
265 | self.ensure_string('force_arch')\r | |
266 | # finalize_package_data ()\r | |
267 | \r | |
268 | \r | |
269 | def run (self):\r | |
270 | \r | |
271 | if DEBUG:\r | |
272 | print "before _get_package_data():"\r | |
273 | print "vendor =", self.vendor\r | |
274 | print "packager =", self.packager\r | |
275 | print "doc_files =", self.doc_files\r | |
276 | print "changelog =", self.changelog\r | |
277 | \r | |
278 | # make directories\r | |
279 | if self.spec_only:\r | |
280 | spec_dir = self.dist_dir\r | |
281 | self.mkpath(spec_dir)\r | |
282 | else:\r | |
283 | rpm_dir = {}\r | |
284 | for d in ('SOURCES', 'SPECS', 'BUILD', 'RPMS', 'SRPMS'):\r | |
285 | rpm_dir[d] = os.path.join(self.rpm_base, d)\r | |
286 | self.mkpath(rpm_dir[d])\r | |
287 | spec_dir = rpm_dir['SPECS']\r | |
288 | \r | |
289 | # Spec file goes into 'dist_dir' if '--spec-only specified',\r | |
290 | # build/rpm.<plat> otherwise.\r | |
291 | spec_path = os.path.join(spec_dir,\r | |
292 | "%s.spec" % self.distribution.get_name())\r | |
293 | self.execute(write_file,\r | |
294 | (spec_path,\r | |
295 | self._make_spec_file()),\r | |
296 | "writing '%s'" % spec_path)\r | |
297 | \r | |
298 | if self.spec_only: # stop if requested\r | |
299 | return\r | |
300 | \r | |
301 | # Make a source distribution and copy to SOURCES directory with\r | |
302 | # optional icon.\r | |
303 | saved_dist_files = self.distribution.dist_files[:]\r | |
304 | sdist = self.reinitialize_command('sdist')\r | |
305 | if self.use_bzip2:\r | |
306 | sdist.formats = ['bztar']\r | |
307 | else:\r | |
308 | sdist.formats = ['gztar']\r | |
309 | self.run_command('sdist')\r | |
310 | self.distribution.dist_files = saved_dist_files\r | |
311 | \r | |
312 | source = sdist.get_archive_files()[0]\r | |
313 | source_dir = rpm_dir['SOURCES']\r | |
314 | self.copy_file(source, source_dir)\r | |
315 | \r | |
316 | if self.icon:\r | |
317 | if os.path.exists(self.icon):\r | |
318 | self.copy_file(self.icon, source_dir)\r | |
319 | else:\r | |
320 | raise DistutilsFileError, \\r | |
321 | "icon file '%s' does not exist" % self.icon\r | |
322 | \r | |
323 | \r | |
324 | # build package\r | |
325 | log.info("building RPMs")\r | |
326 | rpm_cmd = ['rpm']\r | |
327 | if os.path.exists('/usr/bin/rpmbuild') or \\r | |
328 | os.path.exists('/bin/rpmbuild'):\r | |
329 | rpm_cmd = ['rpmbuild']\r | |
330 | \r | |
331 | if self.source_only: # what kind of RPMs?\r | |
332 | rpm_cmd.append('-bs')\r | |
333 | elif self.binary_only:\r | |
334 | rpm_cmd.append('-bb')\r | |
335 | else:\r | |
336 | rpm_cmd.append('-ba')\r | |
337 | if self.rpm3_mode:\r | |
338 | rpm_cmd.extend(['--define',\r | |
339 | '_topdir %s' % os.path.abspath(self.rpm_base)])\r | |
340 | if not self.keep_temp:\r | |
341 | rpm_cmd.append('--clean')\r | |
342 | \r | |
343 | if self.quiet:\r | |
344 | rpm_cmd.append('--quiet')\r | |
345 | \r | |
346 | rpm_cmd.append(spec_path)\r | |
347 | # Determine the binary rpm names that should be built out of this spec\r | |
348 | # file\r | |
349 | # Note that some of these may not be really built (if the file\r | |
350 | # list is empty)\r | |
351 | nvr_string = "%{name}-%{version}-%{release}"\r | |
352 | src_rpm = nvr_string + ".src.rpm"\r | |
353 | non_src_rpm = "%{arch}/" + nvr_string + ".%{arch}.rpm"\r | |
354 | q_cmd = r"rpm -q --qf '%s %s\n' --specfile '%s'" % (\r | |
355 | src_rpm, non_src_rpm, spec_path)\r | |
356 | \r | |
357 | out = os.popen(q_cmd)\r | |
358 | try:\r | |
359 | binary_rpms = []\r | |
360 | source_rpm = None\r | |
361 | while 1:\r | |
362 | line = out.readline()\r | |
363 | if not line:\r | |
364 | break\r | |
365 | l = string.split(string.strip(line))\r | |
366 | assert(len(l) == 2)\r | |
367 | binary_rpms.append(l[1])\r | |
368 | # The source rpm is named after the first entry in the spec file\r | |
369 | if source_rpm is None:\r | |
370 | source_rpm = l[0]\r | |
371 | \r | |
372 | status = out.close()\r | |
373 | if status:\r | |
374 | raise DistutilsExecError("Failed to execute: %s" % repr(q_cmd))\r | |
375 | \r | |
376 | finally:\r | |
377 | out.close()\r | |
378 | \r | |
379 | self.spawn(rpm_cmd)\r | |
380 | \r | |
381 | if not self.dry_run:\r | |
382 | if not self.binary_only:\r | |
383 | srpm = os.path.join(rpm_dir['SRPMS'], source_rpm)\r | |
384 | assert(os.path.exists(srpm))\r | |
385 | self.move_file(srpm, self.dist_dir)\r | |
386 | \r | |
387 | if not self.source_only:\r | |
388 | for rpm in binary_rpms:\r | |
389 | rpm = os.path.join(rpm_dir['RPMS'], rpm)\r | |
390 | if os.path.exists(rpm):\r | |
391 | self.move_file(rpm, self.dist_dir)\r | |
392 | # run()\r | |
393 | \r | |
394 | def _dist_path(self, path):\r | |
395 | return os.path.join(self.dist_dir, os.path.basename(path))\r | |
396 | \r | |
397 | def _make_spec_file(self):\r | |
398 | """Generate the text of an RPM spec file and return it as a\r | |
399 | list of strings (one per line).\r | |
400 | """\r | |
401 | # definitions and headers\r | |
402 | spec_file = [\r | |
403 | '%define name ' + self.distribution.get_name(),\r | |
404 | '%define version ' + self.distribution.get_version().replace('-','_'),\r | |
405 | '%define unmangled_version ' + self.distribution.get_version(),\r | |
406 | '%define release ' + self.release.replace('-','_'),\r | |
407 | '',\r | |
408 | 'Summary: ' + self.distribution.get_description(),\r | |
409 | ]\r | |
410 | \r | |
411 | # put locale summaries into spec file\r | |
412 | # XXX not supported for now (hard to put a dictionary\r | |
413 | # in a config file -- arg!)\r | |
414 | #for locale in self.summaries.keys():\r | |
415 | # spec_file.append('Summary(%s): %s' % (locale,\r | |
416 | # self.summaries[locale]))\r | |
417 | \r | |
418 | spec_file.extend([\r | |
419 | 'Name: %{name}',\r | |
420 | 'Version: %{version}',\r | |
421 | 'Release: %{release}',])\r | |
422 | \r | |
423 | # XXX yuck! this filename is available from the "sdist" command,\r | |
424 | # but only after it has run: and we create the spec file before\r | |
425 | # running "sdist", in case of --spec-only.\r | |
426 | if self.use_bzip2:\r | |
427 | spec_file.append('Source0: %{name}-%{unmangled_version}.tar.bz2')\r | |
428 | else:\r | |
429 | spec_file.append('Source0: %{name}-%{unmangled_version}.tar.gz')\r | |
430 | \r | |
431 | spec_file.extend([\r | |
432 | 'License: ' + self.distribution.get_license(),\r | |
433 | 'Group: ' + self.group,\r | |
434 | 'BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot',\r | |
435 | 'Prefix: %{_prefix}', ])\r | |
436 | \r | |
437 | if not self.force_arch:\r | |
438 | # noarch if no extension modules\r | |
439 | if not self.distribution.has_ext_modules():\r | |
440 | spec_file.append('BuildArch: noarch')\r | |
441 | else:\r | |
442 | spec_file.append( 'BuildArch: %s' % self.force_arch )\r | |
443 | \r | |
444 | for field in ('Vendor',\r | |
445 | 'Packager',\r | |
446 | 'Provides',\r | |
447 | 'Requires',\r | |
448 | 'Conflicts',\r | |
449 | 'Obsoletes',\r | |
450 | ):\r | |
451 | val = getattr(self, string.lower(field))\r | |
452 | if isinstance(val, list):\r | |
453 | spec_file.append('%s: %s' % (field, string.join(val)))\r | |
454 | elif val is not None:\r | |
455 | spec_file.append('%s: %s' % (field, val))\r | |
456 | \r | |
457 | \r | |
458 | if self.distribution.get_url() != 'UNKNOWN':\r | |
459 | spec_file.append('Url: ' + self.distribution.get_url())\r | |
460 | \r | |
461 | if self.distribution_name:\r | |
462 | spec_file.append('Distribution: ' + self.distribution_name)\r | |
463 | \r | |
464 | if self.build_requires:\r | |
465 | spec_file.append('BuildRequires: ' +\r | |
466 | string.join(self.build_requires))\r | |
467 | \r | |
468 | if self.icon:\r | |
469 | spec_file.append('Icon: ' + os.path.basename(self.icon))\r | |
470 | \r | |
471 | if self.no_autoreq:\r | |
472 | spec_file.append('AutoReq: 0')\r | |
473 | \r | |
474 | spec_file.extend([\r | |
475 | '',\r | |
476 | '%description',\r | |
477 | self.distribution.get_long_description()\r | |
478 | ])\r | |
479 | \r | |
480 | # put locale descriptions into spec file\r | |
481 | # XXX again, suppressed because config file syntax doesn't\r | |
482 | # easily support this ;-(\r | |
483 | #for locale in self.descriptions.keys():\r | |
484 | # spec_file.extend([\r | |
485 | # '',\r | |
486 | # '%description -l ' + locale,\r | |
487 | # self.descriptions[locale],\r | |
488 | # ])\r | |
489 | \r | |
490 | # rpm scripts\r | |
491 | # figure out default build script\r | |
492 | def_setup_call = "%s %s" % (self.python,os.path.basename(sys.argv[0]))\r | |
493 | def_build = "%s build" % def_setup_call\r | |
494 | if self.use_rpm_opt_flags:\r | |
495 | def_build = 'env CFLAGS="$RPM_OPT_FLAGS" ' + def_build\r | |
496 | \r | |
497 | # insert contents of files\r | |
498 | \r | |
499 | # XXX this is kind of misleading: user-supplied options are files\r | |
500 | # that we open and interpolate into the spec file, but the defaults\r | |
501 | # are just text that we drop in as-is. Hmmm.\r | |
502 | \r | |
503 | install_cmd = ('%s install -O1 --root=$RPM_BUILD_ROOT '\r | |
504 | '--record=INSTALLED_FILES') % def_setup_call\r | |
505 | \r | |
506 | script_options = [\r | |
507 | ('prep', 'prep_script', "%setup -n %{name}-%{unmangled_version}"),\r | |
508 | ('build', 'build_script', def_build),\r | |
509 | ('install', 'install_script', install_cmd),\r | |
510 | ('clean', 'clean_script', "rm -rf $RPM_BUILD_ROOT"),\r | |
511 | ('verifyscript', 'verify_script', None),\r | |
512 | ('pre', 'pre_install', None),\r | |
513 | ('post', 'post_install', None),\r | |
514 | ('preun', 'pre_uninstall', None),\r | |
515 | ('postun', 'post_uninstall', None),\r | |
516 | ]\r | |
517 | \r | |
518 | for (rpm_opt, attr, default) in script_options:\r | |
519 | # Insert contents of file referred to, if no file is referred to\r | |
520 | # use 'default' as contents of script\r | |
521 | val = getattr(self, attr)\r | |
522 | if val or default:\r | |
523 | spec_file.extend([\r | |
524 | '',\r | |
525 | '%' + rpm_opt,])\r | |
526 | if val:\r | |
527 | spec_file.extend(string.split(open(val, 'r').read(), '\n'))\r | |
528 | else:\r | |
529 | spec_file.append(default)\r | |
530 | \r | |
531 | \r | |
532 | # files section\r | |
533 | spec_file.extend([\r | |
534 | '',\r | |
535 | '%files -f INSTALLED_FILES',\r | |
536 | '%defattr(-,root,root)',\r | |
537 | ])\r | |
538 | \r | |
539 | if self.doc_files:\r | |
540 | spec_file.append('%doc ' + string.join(self.doc_files))\r | |
541 | \r | |
542 | if self.changelog:\r | |
543 | spec_file.extend([\r | |
544 | '',\r | |
545 | '%changelog',])\r | |
546 | spec_file.extend(self.changelog)\r | |
547 | \r | |
548 | return spec_file\r | |
549 | \r | |
550 | # _make_spec_file ()\r | |
551 | \r | |
552 | def _format_changelog(self, changelog):\r | |
553 | """Format the changelog correctly and convert it to a list of strings\r | |
554 | """\r | |
555 | if not changelog:\r | |
556 | return changelog\r | |
557 | new_changelog = []\r | |
558 | for line in string.split(string.strip(changelog), '\n'):\r | |
559 | line = string.strip(line)\r | |
560 | if line[0] == '*':\r | |
561 | new_changelog.extend(['', line])\r | |
562 | elif line[0] == '-':\r | |
563 | new_changelog.append(line)\r | |
564 | else:\r | |
565 | new_changelog.append(' ' + line)\r | |
566 | \r | |
567 | # strip trailing newline inserted by first changelog entry\r | |
568 | if not new_changelog[0]:\r | |
569 | del new_changelog[0]\r | |
570 | \r | |
571 | return new_changelog\r | |
572 | \r | |
573 | # _format_changelog()\r | |
574 | \r | |
575 | # class bdist_rpm\r |