[game-data-packager] 20/25: Move control-file writing from PackagingTask to PackagingSystem
Simon McVittie
smcv at debian.org
Sun Oct 9 21:26:07 UTC 2016
This is an automated email from the git hooks/post-receive script.
smcv pushed a commit to branch master
in repository game-data-packager.
commit d1fa5149058ac5545f3e64aff35a543394af5b88
Author: Simon McVittie <smcv at debian.org>
Date: Sun Oct 9 18:46:36 2016 +0100
Move control-file writing from PackagingTask to PackagingSystem
---
game_data_packager/build.py | 427 +------------------------------
game_data_packager/packaging/__init__.py | 81 ++++++
game_data_packager/packaging/arch.py | 39 +++
game_data_packager/packaging/deb.py | 165 ++++++++++++
game_data_packager/packaging/rpm.py | 123 +++++++++
5 files changed, 419 insertions(+), 416 deletions(-)
diff --git a/game_data_packager/build.py b/game_data_packager/build.py
index 43f5ad3..4469ae1 100644
--- a/game_data_packager/build.py
+++ b/game_data_packager/build.py
@@ -1277,209 +1277,6 @@ class PackagingTask(object):
def fill_extra_files(self, package, destdir):
pass
- def fill_dest_dir_arch(self, package, destdir, compress, arch):
- PKGINFO = os.path.join(destdir, '.PKGINFO')
- short_desc, _ = self.generate_description(package)
- size = check_output(['du','-bs','.'], cwd=destdir)
- size = int(size.split()[0])
- with open(PKGINFO, 'w', encoding='utf-8') as pkginfo:
- pkginfo.write('# Generated by game-data-packager %s\n' % package.version.split('+')[-1])
- pkginfo.write('# using fakeroot version %s\n' %
- self.builder_packaging.current_version('fakeroot'))
- pkginfo.write('# %s\n' % time.strftime("%a %b %d %H:%M:%S UTC %Y", time.gmtime()))
- pkginfo.write('pkgname = %s\n' % package.name)
- pkginfo.write('pkgver = %s-1\n' % package.version)
- pkginfo.write('pkgdesc = %s\n' % short_desc)
- pkginfo.write('url = https://wiki.debian.org/Games/GameDataPackager\n')
- pkginfo.write('builddate = %i\n' % int(time.time()))
- pkginfo.write('packager = Alexandre Detiste <alexandre at detiste.be>\n')
- pkginfo.write('size = %i\n' % size)
- pkginfo.write('arch = %s\n' % arch)
- if os.path.isdir(os.path.join(destdir, 'usr/share/licenses')):
- pkginfo.write('license = custom\n')
- pkginfo.write('group = games\n')
- if package.expansion_for:
- pkginfo.write('depend = %s\n' % package.expansion_for)
- else:
- engine = self.packaging.substitute(
- package.engine or self.game.engine,
- package.name)
-
- if engine and len(engine.split()) == 1:
- pkginfo.write('depend = %s\n' % engine)
-
- files = set()
- for dirpath, dirnames, filenames in os.walk(destdir):
- for fn in filenames:
- full = os.path.join(dirpath, fn)
- full = full[len(destdir)+1:]
- files.add(full)
-
- MTREE = os.path.join(destdir, '.MTREE')
- subprocess.check_call(['fakeroot', 'bsdtar', '-czf', MTREE, '--format=mtree',
- '--options=!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link']
- + sorted(files), env={'LANG':'C'}, cwd=destdir)
-
- def __merge_relations(self, package, rel):
- return set(self.packaging.format_relations(package.relations[rel]))
-
- def fill_dest_dir_rpm(self, package, destdir, compress, architecture, release):
- specfile = os.path.join(self.get_workdir(), '%s.spec' % package.name)
- short_desc, long_desc = self.generate_description(package)
- short_desc = short_desc[0].upper() + short_desc[1:]
-
- if self.game.wikibase:
- url = self.game.wikibase + (self.game.wiki or '')
- elif self.game.wikipedia:
- url = self.game.wikipedia
- else:
- url = 'https://wiki.debian.org/Games/GameDataPackager'
-
- # /usr/games & /usr/share/games should only
- # be seen in rpm's built for Mageia
- SYSTEM_DIRS = set(['/usr',
- '/usr/bin',
- '/usr/games',
- '/usr/lib',
- '/usr/share',
- '/usr/share/applications',
- '/usr/share/doc',
- '/usr/share/doc/packages',
- '/usr/share/games',
- '/usr/share/icons',
- '/usr/share/icons/hicolor',
- '/usr/share/icons/hicolor/scalable',
- '/usr/share/icons/hicolor/scalable/apps',
- '/usr/share/licenses',
- '/usr/share/pixmaps'])
-
- files = set()
- for dirpath, dirnames, filenames in os.walk(destdir):
- dir = dirpath[len(destdir):]
- if not dir:
- # /
- continue
- elif dir in SYSTEM_DIRS:
- for fn in filenames + dirnames:
- full = os.path.join(dirpath, fn)
- file = full[len(destdir):]
- if file not in SYSTEM_DIRS:
- files.add(file)
- else:
- for file in files:
- if dir.startswith(file):
- break
- else:
- files.add(dir)
-
- logger.debug('%%files in specfile:\n%s', '\n'.join(sorted(files)))
-
- with open(specfile, 'w', encoding='utf-8') as spec:
- spec.write('Summary: %s\n' % short_desc)
- spec.write('Name: %s\n' % package.name)
- spec.write('Version: %s\n' % package.version)
- spec.write('Url: %s\n' % url)
- spec.write('Release: %s\n' % release)
- spec.write('License: Commercial\n')
- if self.packaging.derives_from('mageia'):
- spec.write('Packager: game-data-packager\n')
- spec.write('Group: Games/%s\n' % self.game.genre)
- else:
- spec.write('Group: Amusements/Games\n')
- spec.write('BuildArch: %s\n' % architecture)
-
- for p in self.__merge_relations(package, 'provides'):
- spec.write('Provides: %s\n' % p)
-
- if package.mutually_exclusive:
- spec.write('Conflicts: %s\n' % p)
-
- if package.expansion_for:
- spec.write('Requires: %s\n' % package.expansion_for)
- else:
- engine = self.packaging.substitute(
- package.engine or self.game.engine,
- package.name)
-
- if engine and len(engine.split()) == 1:
- spec.write('Requires: %s\n' % engine)
-
- for p in self.__merge_relations(package, 'depends'):
- spec.write('Requires: %s\n' % p)
-
- for p in (self.__merge_relations(package, 'conflicts') |
- self.__merge_relations(package, 'breaks')):
- spec.write('Conflicts: %s\n' % p)
-
- for p in self.__merge_relations(package, 'recommends'):
- # FIXME: some RPM distributions do have recommends;
- # which ones?
- pass
-
- for p in self.__merge_relations(package, 'suggests'):
- # FIXME: likewise
- pass
-
- # FIXME: replaces?
-
- if not compress or not self.compress_deb or package.rip_cd:
- spec.write('%define _binary_payload w0.gzdio\n')
- elif self.compress_deb == ['-Zgzip', '-z1']:
- spec.write('%define _binary_payload w1.gzdio\n')
- spec.write('%description\n')
- spec.write('%s\n' % long_desc)
- spec.write('%files\n')
- spec.write('\n'.join(files))
- spec.write('\n\n')
-
- spec.write('%changelog\n')
- try:
- login = os.getlogin()
- except FileNotFoundError:
- login = 'game-data-packager'
- spec.write('* %s %s@%s - %s-%s\n' %
- (time.strftime("%a %b %d %Y", time.gmtime()),
- login, os.uname()[1], package.version, release))
- spec.write('- Package generated by game-data-packager'
- ' for local use only\n')
-
- return specfile
-
- def fill_dest_dir_deb(self, package, destdir):
- if package.component == 'local':
- self.packaging.override_lintian(destdir, package.name,
- 'unknown-section', 'local/%s' % package.section)
-
- # same output as in dh_md5sums
-
- # we only compute here the md5 we don't have yet,
- # for the (small) GDP-generated files
- for dirpath, dirnames, filenames in os.walk(destdir):
- if os.path.basename(dirpath) == 'DEBIAN':
- continue
- for fn in filenames:
- full = os.path.join(dirpath, fn)
- if os.path.islink(full):
- continue
- file = full[len(destdir)+1:]
- if file not in package.md5sums:
- with open(full, 'rb') as opened:
- hf = HashedFile.from_file(full, opened)
- package.md5sums[file] = hf.md5
-
- debdir = os.path.join(destdir, 'DEBIAN')
- mkdir_p(debdir)
- md5sums = os.path.join(destdir, 'DEBIAN/md5sums')
- with open(md5sums, 'w', encoding='utf8') as outfile:
- for file in sorted(package.md5sums.keys()):
- outfile.write('%s %s\n' % (package.md5sums[file], file))
- os.chmod(md5sums, 0o644)
-
- control = os.path.join(destdir, 'DEBIAN/control')
- self.generate_control(package, destdir).dump(fd=open(control, 'wb'),
- encoding='utf-8')
- os.chmod(control, 0o644)
-
def fill_dest_dir(self, package, destdir):
pkgdocdir = self.packaging.substitute('$pkgdocdir', package.name)
dest_pkgdocdir = os.path.join(destdir, pkgdocdir.strip('/'))
@@ -1588,212 +1385,6 @@ class PackagingTask(object):
self.fill_extra_files(package, destdir)
- def generate_control(self, package, destdir):
- # import lazily, it's only needed for Debian packages
- from debian.deb822 import Deb822
-
- try:
- control_in = open(os.path.join(DATADIR,
- package.name + '.control.in'), encoding='utf-8')
- control = Deb822(control_in)
- for key in control.keys():
- assert key == 'Description', 'specify "%s" only in YAML' % key
- except FileNotFoundError:
- control = Deb822()
-
- control['Package'] = package.name
- control['Version'] = package.version
- control['Priority'] = 'optional'
- control['Maintainer'] = 'Debian Games Team <pkg-games-devel at lists.alioth.debian.org>'
-
- installed_size = 0
- # algorithm from https://bugs.debian.org/650077 designed to be
- # filesystem-independent
- for dirpath, dirnames, filenames in os.walk(destdir):
- if dirpath == destdir and 'DEBIAN' in dirnames:
- dirnames.remove('DEBIAN')
- # estimate 1 KiB per directory
- installed_size += len(dirnames)
- for f in filenames:
- stat_res = os.lstat(os.path.join(dirpath, f))
- if (stat.S_ISLNK(stat_res.st_mode) or
- stat.S_ISREG(stat_res.st_mode)):
- # take the real size and round up to next 1 KiB
- installed_size += ((stat_res.st_size + 1023) // 1024)
- else:
- # this will probably never happen in gdp, but assume
- # 1 KiB per non-regular, non-directory, non-symlink file
- installed_size += 1
- control['Installed-Size'] = str(installed_size)
-
- if package.component == 'main':
- control['Section'] = package.section
- else:
- control['Section'] = package.component + '/' + package.section
-
- if package.architecture == 'all':
- control['Architecture'] = 'all'
- control['Multi-Arch'] = 'foreign'
- else:
- control['Architecture'] = self.packaging.get_architecture(package.architecture)
-
- dep = dict()
-
- for rel in package.relations:
- if rel == 'build_depends':
- continue
-
- dep[rel] = self.__merge_relations(package, rel)
- logger.debug('%s %s %s', package.name, rel, ', '.join(dep[rel]))
-
- if package.mutually_exclusive:
- dep['conflicts'] |= package.demo_for
- dep['conflicts'] |= package.better_versions
-
- if package.mutually_exclusive:
- dep['replaces'] |= dep['provides']
-
- engine = self.packaging.substitute(
- package.engine or self.game.engine,
- package.name)
-
- if engine and '>=' in engine:
- engine, ver = engine.split(maxsplit=1)
- ver = ver.strip('(>=) ')
- dep['breaks'].add('%s (<< %s~)' % (engine, ver))
-
- # We only 'recommends' & not 'depends'; to avoid
- # that GDP-generated packages get removed
- # if engine goes through some gcc/png/ffmpeg/... migration
- # and must be temporarily removed.
- # It's not like 'apt-get install ...' can revert this removal;
- # user may need to dig again for the original media....
- if package.engine:
- dep['recommends'].add(engine)
- elif not package.expansion_for and self.game.engine:
- dep['recommends'].add(engine)
-
- if package.expansion_for:
- # check if default heuristic has been overriden in yaml
- for p in dep['depends']:
- if package.expansion_for == p.split()[0]:
- break
- else:
- dep['depends'].add(package.expansion_for)
-
- # dependencies derived from *other* package's data
- for other_package in self.game.packages.values():
- if other_package.expansion_for:
- if package.name == other_package.expansion_for:
- dep['suggests'].add(other_package.name)
- else:
- for p in package.relations['provides']:
- if p.package == other_package.expansion_for:
- dep['suggests'].add(other_package.name)
-
- if other_package.mutually_exclusive:
- if package.name in other_package.better_versions:
- dep['replaces'].add(other_package.name)
-
- if package.name in other_package.demo_for:
- dep['replaces'].add(other_package.name)
-
- # Shortcut: if A Replaces B, A automatically Conflicts B
- dep['conflicts'] |= dep['replaces']
-
- # keep only strongest depedency
- dep['recommends'] -= dep['depends']
- dep['suggests'] -= dep['recommends']
- dep['suggests'] -= dep['depends']
-
- for k, v in dep.items():
- if v:
- control[k.title()] = ', '.join(sorted(v))
-
- if 'Description' not in control:
- short_desc, long_desc = self.generate_description(package)
- control['Description'] = short_desc + '\n ' + long_desc.replace('\n', '\n ')
-
- return control
-
- def generate_description(self, package):
- longname = package.longname or self.game.longname
-
- if package.short_description is not None:
- short_desc = package.short_description
- elif package.section == 'games':
- short_desc = 'game %s for %s' % (package.data_type, longname)
- else:
- short_desc = longname
-
- if package.long_description is not None:
- long_desc = package.long_description
- long_desc = long_desc.rstrip('\n')
- return (short_desc, long_desc)
-
- long_desc = 'This package was built using game-data-packager.\n'
- if package.component == 'local':
- long_desc += 'It contains proprietary game data and must not be redistributed.\n'
- long_desc += '.\n'
- elif package.component == 'non-free':
- long_desc += 'It contains proprietary game data that may be redistributed\n'
- long_desc += 'only under some conditions.\n'
- long_desc += '.\n'
- else:
- long_desc += 'It contains free game data and may be redistributed.\n'
- long_desc += '.\n'
-
- if package.description:
- for line in package.description.splitlines():
- line = line.rstrip() or '.'
- long_desc += (line + '\n')
- long_desc += '.\n'
-
- if self.game.genre:
- long_desc += ' Genre: ' + self.game.genre + '\n'
-
- if package.section == 'doc':
- long_desc += ' Documentation: ' + longname + '\n'
- elif package.expansion_for and package.expansion_for in self.game.packages:
- game_name = (self.game.packages[package.expansion_for].longname
- or self.game.longname)
- if game_name not in long_desc:
- long_desc += ' Game: ' + game_name + '\n'
- if longname != game_name:
- long_desc += ' Expansion: ' + longname + '\n'
- else:
- long_desc += ' Game: ' + longname + '\n'
-
- copyright = package.copyright or self.game.copyright
- copyright = copyright.split(' ', 2)[2]
- if copyright not in long_desc:
- long_desc += ' Published by: ' + copyright
-
- engine = self.packaging.substitute(
- package.engine or self.game.engine,
- package.name)
-
- if engine and package.data_type not in ('music', 'documentation'):
- long_desc += '\n.\n'
- if '|' in engine:
- virtual = engine.split('|')[-1].strip()
- has_virtual = (virtual.split('-')[-1] == 'engine')
- else:
- has_virtual = False
- engine = engine.split('|')[0].split('(')[0].strip()
- if engine.startswith('gemrb'):
- engine = 'gemrb'
- if has_virtual:
- long_desc += 'Intended for use with some ' + virtual + ',\n'
- long_desc += 'such as for example: ' + engine
- else:
- long_desc += 'Intended for use with: ' + engine
-
- if package.used_sources:
- long_desc += '\nBuilt from: ' + ', '.join(package.used_sources)
-
- return (short_desc, long_desc)
-
def look_for_engines(self, packages, force=False):
engines = set()
@@ -2228,7 +1819,7 @@ class PackagingTask(object):
possible.discard(package)
for package in set(possible):
- build_depends = self.__merge_relations(package, 'build_depends')
+ build_depends = self.packaging.merge_relations(package, 'build_depends')
for tool in build_depends:
tool = tool.strip()
@@ -2265,13 +1856,13 @@ class PackagingTask(object):
continue
# keep only preferred language for this virtual package
- provides = self.__merge_relations(package, 'provides')
+ provides = self.packaging.merge_relations(package, 'provides')
if provides:
for other_p in possible:
if other_p.name == package.name:
continue
- other_provides = self.__merge_relations(other_p,
+ other_provides = self.packaging.merge_relations(other_p,
'provides')
if other_provides - provides:
# it provides something this one doesn't
@@ -2570,7 +2161,7 @@ class PackagingTask(object):
self.check_component(package)
self.fill_dest_dir(package, destdir)
- self.fill_dest_dir_deb(package, destdir)
+ self.packaging.fill_dest_dir_deb(game, package, destdir)
normalize_permissions(destdir)
# it had better have a /usr and a DEBIAN directory or
@@ -2611,7 +2202,8 @@ class PackagingTask(object):
def build_arch(self, package, arch, destination, compress=True):
destdir = os.path.join(self.get_workdir(), '%s.pkg.d' % package.name)
self.fill_dest_dir(package, destdir)
- self.fill_dest_dir_arch(package, destdir, compress, arch)
+ self.packaging.fill_dest_dir_arch(game, package, destdir, compress,
+ arch)
normalize_permissions(destdir)
assert os.path.isdir(os.path.join(destdir, 'usr')), destdir
@@ -2667,8 +2259,11 @@ class PackagingTask(object):
if self.packaging.distro is not None:
release = release + '.' + self.packaging.distro
- specfile = self.fill_dest_dir_rpm(package, destdir, compress,
- arch, release)
+ if compress:
+ compress = self.compress_deb
+
+ specfile = self.packaging.fill_dest_dir_rpm(game, package,
+ self.get_workdir(), destdir, compress, arch, release)
normalize_permissions(destdir)
assert os.path.isdir(os.path.join(destdir, 'usr')), destdir
diff --git a/game_data_packager/packaging/__init__.py b/game_data_packager/packaging/__init__.py
index 09e72a1..0e04501 100644
--- a/game_data_packager/packaging/__init__.py
+++ b/game_data_packager/packaging/__init__.py
@@ -215,6 +215,87 @@ class PackagingSystem(metaclass=ABCMeta):
return k
return package
+ def merge_relations(self, package, rel):
+ return set(self.format_relations(package.relations[rel]))
+
+ def generate_description(self, game, package):
+ longname = package.longname or game.longname
+
+ if package.short_description is not None:
+ short_desc = package.short_description
+ elif package.section == 'games':
+ short_desc = 'game %s for %s' % (package.data_type, longname)
+ else:
+ short_desc = longname
+
+ if package.long_description is not None:
+ long_desc = package.long_description
+ long_desc = long_desc.rstrip('\n')
+ return (short_desc, long_desc)
+
+ long_desc = 'This package was built using game-data-packager.\n'
+ if package.component == 'local':
+ long_desc += 'It contains proprietary game data and must not be redistributed.\n'
+ long_desc += '.\n'
+ elif package.component == 'non-free':
+ long_desc += 'It contains proprietary game data that may be redistributed\n'
+ long_desc += 'only under some conditions.\n'
+ long_desc += '.\n'
+ else:
+ long_desc += 'It contains free game data and may be redistributed.\n'
+ long_desc += '.\n'
+
+ if package.description:
+ for line in package.description.splitlines():
+ line = line.rstrip() or '.'
+ long_desc += (line + '\n')
+ long_desc += '.\n'
+
+ if game.genre:
+ long_desc += ' Genre: ' + game.genre + '\n'
+
+ if package.section == 'doc':
+ long_desc += ' Documentation: ' + longname + '\n'
+ elif package.expansion_for and package.expansion_for in game.packages:
+ game_name = (game.packages[package.expansion_for].longname
+ or game.longname)
+ if game_name not in long_desc:
+ long_desc += ' Game: ' + game_name + '\n'
+ if longname != game_name:
+ long_desc += ' Expansion: ' + longname + '\n'
+ else:
+ long_desc += ' Game: ' + longname + '\n'
+
+ copyright = package.copyright or game.copyright
+ copyright = copyright.split(' ', 2)[2]
+ if copyright not in long_desc:
+ long_desc += ' Published by: ' + copyright
+
+ engine = self.substitute(
+ package.engine or game.engine,
+ package.name)
+
+ if engine and package.data_type not in ('music', 'documentation'):
+ long_desc += '\n.\n'
+ if '|' in engine:
+ virtual = engine.split('|')[-1].strip()
+ has_virtual = (virtual.split('-')[-1] == 'engine')
+ else:
+ has_virtual = False
+ engine = engine.split('|')[0].split('(')[0].strip()
+ if engine.startswith('gemrb'):
+ engine = 'gemrb'
+ if has_virtual:
+ long_desc += 'Intended for use with some ' + virtual + ',\n'
+ long_desc += 'such as for example: ' + engine
+ else:
+ long_desc += 'Intended for use with: ' + engine
+
+ if package.used_sources:
+ long_desc += '\nBuilt from: ' + ', '.join(package.used_sources)
+
+ return (short_desc, long_desc)
+
def get_packaging_system(format, distro=None):
mod = 'game_data_packager.packaging.{}'.format(format)
return importlib.import_module(mod).get_packaging_system(distro)
diff --git a/game_data_packager/packaging/arch.py b/game_data_packager/packaging/arch.py
index 351aa06..b1e9627 100644
--- a/game_data_packager/packaging/arch.py
+++ b/game_data_packager/packaging/arch.py
@@ -109,5 +109,44 @@ class ArchPackaging(PackagingSystem):
return self.rename_package(pr.package)
+ def fill_dest_dir_arch(self, game, package, destdir, compress, arch):
+ PKGINFO = os.path.join(destdir, '.PKGINFO')
+ short_desc, _ = self.generate_description(game, package)
+ size = check_output(['du','-bs','.'], cwd=destdir)
+ size = int(size.split()[0])
+ with open(PKGINFO, 'w', encoding='utf-8') as pkginfo:
+ pkginfo.write('pkgname = %s\n' % package.name)
+ pkginfo.write('pkgver = %s-1\n' % package.version)
+ pkginfo.write('pkgdesc = %s\n' % short_desc)
+ pkginfo.write('url = https://wiki.debian.org/Games/GameDataPackager\n')
+ pkginfo.write('builddate = %i\n' % int(time.time()))
+ pkginfo.write('packager = Alexandre Detiste <alexandre at detiste.be>\n')
+ pkginfo.write('size = %i\n' % size)
+ pkginfo.write('arch = %s\n' % arch)
+ if os.path.isdir(os.path.join(destdir, 'usr/share/licenses')):
+ pkginfo.write('license = custom\n')
+ pkginfo.write('group = games\n')
+ if package.expansion_for:
+ pkginfo.write('depend = %s\n' % package.expansion_for)
+ else:
+ engine = self.substitute(
+ package.engine or game.engine,
+ package.name)
+
+ if engine and len(engine.split()) == 1:
+ pkginfo.write('depend = %s\n' % engine)
+
+ files = set()
+ for dirpath, dirnames, filenames in os.walk(destdir):
+ for fn in filenames:
+ full = os.path.join(dirpath, fn)
+ full = full[len(destdir)+1:]
+ files.add(full)
+
+ MTREE = os.path.join(destdir, '.MTREE')
+ subprocess.check_call(['fakeroot', 'bsdtar', '-czf', MTREE, '--format=mtree',
+ '--options=!all,use-set,type,uid,gid,mode,time,size,md5,sha256,link']
+ + sorted(files), env={'LANG':'C'}, cwd=destdir)
+
def get_packaging_system(distro=None):
return ArchPackaging()
diff --git a/game_data_packager/packaging/deb.py b/game_data_packager/packaging/deb.py
index 3780895..a2b28b2 100644
--- a/game_data_packager/packaging/deb.py
+++ b/game_data_packager/packaging/deb.py
@@ -207,5 +207,170 @@ class DebPackaging(PackagingSystem):
return self.rename_package(pr.package)
+ def __generate_control(self, game, package, destdir):
+ if Deb822 is None:
+ raise FileNotFoundError('Cannot generate .deb packages without '
+ 'python3-debian')
+
+ try:
+ control_in = open(os.path.join(DATADIR,
+ package.name + '.control.in'), encoding='utf-8')
+ control = Deb822(control_in)
+ for key in control.keys():
+ assert key == 'Description', 'specify "%s" only in YAML' % key
+ except FileNotFoundError:
+ control = Deb822()
+
+ control['Package'] = package.name
+ control['Version'] = package.version
+ control['Priority'] = 'optional'
+ control['Maintainer'] = 'Debian Games Team <pkg-games-devel at lists.alioth.debian.org>'
+
+ installed_size = 0
+ # algorithm from https://bugs.debian.org/650077 designed to be
+ # filesystem-independent
+ for dirpath, dirnames, filenames in os.walk(destdir):
+ if dirpath == destdir and 'DEBIAN' in dirnames:
+ dirnames.remove('DEBIAN')
+ # estimate 1 KiB per directory
+ installed_size += len(dirnames)
+ for f in filenames:
+ stat_res = os.lstat(os.path.join(dirpath, f))
+ if (stat.S_ISLNK(stat_res.st_mode) or
+ stat.S_ISREG(stat_res.st_mode)):
+ # take the real size and round up to next 1 KiB
+ installed_size += ((stat_res.st_size + 1023) // 1024)
+ else:
+ # this will probably never happen in gdp, but assume
+ # 1 KiB per non-regular, non-directory, non-symlink file
+ installed_size += 1
+ control['Installed-Size'] = str(installed_size)
+
+ if package.component == 'main':
+ control['Section'] = package.section
+ else:
+ control['Section'] = package.component + '/' + package.section
+
+ if package.architecture == 'all':
+ control['Architecture'] = 'all'
+ control['Multi-Arch'] = 'foreign'
+ else:
+ control['Architecture'] = self.get_architecture(
+ package.architecture)
+
+ dep = dict()
+
+ for rel in package.relations:
+ if rel == 'build_depends':
+ continue
+
+ dep[rel] = self.merge_relations(package, rel)
+ logger.debug('%s %s %s', package.name, rel, ', '.join(dep[rel]))
+
+ if package.mutually_exclusive:
+ dep['conflicts'] |= package.demo_for
+ dep['conflicts'] |= package.better_versions
+
+ if package.mutually_exclusive:
+ dep['replaces'] |= dep['provides']
+
+ engine = self.substitute(
+ package.engine or game.engine,
+ package.name)
+
+ if engine and '>=' in engine:
+ engine, ver = engine.split(maxsplit=1)
+ ver = ver.strip('(>=) ')
+ dep['breaks'].add('%s (<< %s~)' % (engine, ver))
+
+ # We only 'recommends' & not 'depends'; to avoid
+ # that GDP-generated packages get removed
+ # if engine goes through some gcc/png/ffmpeg/... migration
+ # and must be temporarily removed.
+ # It's not like 'apt-get install ...' can revert this removal;
+ # user may need to dig again for the original media....
+ if package.engine:
+ dep['recommends'].add(engine)
+ elif not package.expansion_for and game.engine:
+ dep['recommends'].add(engine)
+
+ if package.expansion_for:
+ # check if default heuristic has been overriden in yaml
+ for p in dep['depends']:
+ if package.expansion_for == p.split()[0]:
+ break
+ else:
+ dep['depends'].add(package.expansion_for)
+
+ # dependencies derived from *other* package's data
+ for other_package in game.packages.values():
+ if other_package.expansion_for:
+ if package.name == other_package.expansion_for:
+ dep['suggests'].add(other_package.name)
+ else:
+ for p in package.relations['provides']:
+ if p.package == other_package.expansion_for:
+ dep['suggests'].add(other_package.name)
+
+ if other_package.mutually_exclusive:
+ if package.name in other_package.better_versions:
+ dep['replaces'].add(other_package.name)
+
+ if package.name in other_package.demo_for:
+ dep['replaces'].add(other_package.name)
+
+ # Shortcut: if A Replaces B, A automatically Conflicts B
+ dep['conflicts'] |= dep['replaces']
+
+ # keep only strongest depedency
+ dep['recommends'] -= dep['depends']
+ dep['suggests'] -= dep['recommends']
+ dep['suggests'] -= dep['depends']
+
+ for k, v in dep.items():
+ if v:
+ control[k.title()] = ', '.join(sorted(v))
+
+ if 'Description' not in control:
+ short_desc, long_desc = self.generate_description(game, package)
+ control['Description'] = short_desc + '\n ' + long_desc.replace('\n', '\n ')
+
+ return control
+
+ def fill_dest_dir_deb(self, game, package, destdir):
+ if package.component == 'local':
+ self.override_lintian(destdir, package.name,
+ 'unknown-section', 'local/%s' % package.section)
+
+ # same output as in dh_md5sums
+
+ # we only compute here the md5 we don't have yet,
+ # for the (small) GDP-generated files
+ for dirpath, dirnames, filenames in os.walk(destdir):
+ if os.path.basename(dirpath) == 'DEBIAN':
+ continue
+ for fn in filenames:
+ full = os.path.join(dirpath, fn)
+ if os.path.islink(full):
+ continue
+ file = full[len(destdir)+1:]
+ if file not in package.md5sums:
+ with open(full, 'rb') as opened:
+ hf = HashedFile.from_file(full, opened)
+ package.md5sums[file] = hf.md5
+
+ debdir = os.path.join(destdir, 'DEBIAN')
+ mkdir_p(debdir)
+ md5sums = os.path.join(destdir, 'DEBIAN/md5sums')
+ with open(md5sums, 'w', encoding='utf8') as outfile:
+ for file in sorted(package.md5sums.keys()):
+ outfile.write('%s %s\n' % (package.md5sums[file], file))
+ os.chmod(md5sums, 0o644)
+
+ control = os.path.join(destdir, 'DEBIAN/control')
+ self.__generate_control(game, package, destdir).dump(
+ fd=open(control, 'wb'), encoding='utf-8')
+ os.chmod(control, 0o644)
+
def get_packaging_system(distro=None):
return DebPackaging()
diff --git a/game_data_packager/packaging/rpm.py b/game_data_packager/packaging/rpm.py
index ddb9b6a..128d972 100644
--- a/game_data_packager/packaging/rpm.py
+++ b/game_data_packager/packaging/rpm.py
@@ -101,6 +101,129 @@ class RpmPackaging(PackagingSystem):
return self.rename_package(pr.package)
+ def fill_dest_dir_rpm(self, game, package, workdir, destdir, compress,
+ architecture, release):
+ specfile = os.path.join(workdir, '%s.spec' % package.name)
+ short_desc, long_desc = self.generate_description(game, package)
+ short_desc = short_desc[0].upper() + short_desc[1:]
+
+ if game.wikibase:
+ url = game.wikibase + (game.wiki or '')
+ elif game.wikipedia:
+ url = game.wikipedia
+ else:
+ url = 'https://wiki.debian.org/Games/GameDataPackager'
+
+ # /usr/games & /usr/share/games should only
+ # be seen in rpm's built for Mageia
+ SYSTEM_DIRS = set(['/usr',
+ '/usr/bin',
+ '/usr/games',
+ '/usr/lib',
+ '/usr/share',
+ '/usr/share/applications',
+ '/usr/share/doc',
+ '/usr/share/doc/packages',
+ '/usr/share/games',
+ '/usr/share/icons',
+ '/usr/share/icons/hicolor',
+ '/usr/share/icons/hicolor/scalable',
+ '/usr/share/icons/hicolor/scalable/apps',
+ '/usr/share/licenses',
+ '/usr/share/pixmaps'])
+
+ files = set()
+ for dirpath, dirnames, filenames in os.walk(destdir):
+ dir = dirpath[len(destdir):]
+ if not dir:
+ # /
+ continue
+ elif dir in SYSTEM_DIRS:
+ for fn in filenames + dirnames:
+ full = os.path.join(dirpath, fn)
+ file = full[len(destdir):]
+ if file not in SYSTEM_DIRS:
+ files.add(file)
+ else:
+ for file in files:
+ if dir.startswith(file):
+ break
+ else:
+ files.add(dir)
+
+ logger.debug('%%files in specfile:\n%s', '\n'.join(sorted(files)))
+
+ with open(specfile, 'w', encoding='utf-8') as spec:
+ spec.write('Summary: %s\n' % short_desc)
+ spec.write('Name: %s\n' % package.name)
+ spec.write('Version: %s\n' % package.version)
+ spec.write('Url: %s\n' % url)
+ spec.write('Release: %s\n' % release)
+ spec.write('License: Commercial\n')
+ if self.derives_from('mageia'):
+ spec.write('Packager: game-data-packager\n')
+ spec.write('Group: Games/%s\n' % game.genre)
+ else:
+ spec.write('Group: Amusements/Games\n')
+ spec.write('BuildArch: %s\n' % architecture)
+
+ for p in self.merge_relations(package, 'provides'):
+ spec.write('Provides: %s\n' % p)
+
+ if package.mutually_exclusive:
+ spec.write('Conflicts: %s\n' % p)
+
+ if package.expansion_for:
+ spec.write('Requires: %s\n' % package.expansion_for)
+ else:
+ engine = self.substitute(
+ package.engine or game.engine,
+ package.name)
+
+ if engine and len(engine.split()) == 1:
+ spec.write('Requires: %s\n' % engine)
+
+ for p in self.merge_relations(package, 'depends'):
+ spec.write('Requires: %s\n' % p)
+
+ for p in (self.merge_relations(package, 'conflicts') |
+ self.merge_relations(package, 'breaks')):
+ spec.write('Conflicts: %s\n' % p)
+
+ for p in self.merge_relations(package, 'recommends'):
+ # FIXME: some RPM distributions do have recommends;
+ # which ones?
+ pass
+
+ for p in self.merge_relations(package, 'suggests'):
+ # FIXME: likewise
+ pass
+
+ # FIXME: replaces?
+
+ if not compress or package.rip_cd:
+ spec.write('%define _binary_payload w0.gzdio\n')
+ elif compress == ['-Zgzip', '-z1']:
+ spec.write('%define _binary_payload w1.gzdio\n')
+ spec.write('%description\n')
+ spec.write('%s\n' % long_desc)
+ spec.write('%files\n')
+ spec.write('\n'.join(files))
+ spec.write('\n\n')
+
+ spec.write('%changelog\n')
+ try:
+ login = os.getlogin()
+ except FileNotFoundError:
+ login = 'game-data-packager'
+ spec.write('* %s %s@%s - %s-%s\n' %
+ (time.strftime("%a %b %d %Y", time.gmtime()),
+ login, os.uname()[1], package.version, release))
+ spec.write('- Package generated by game-data-packager'
+ ' for local use only\n')
+
+ return specfile
+
# XXX: dnf is written in python3 and has a stable public api,
# it is likely faster to use it instead of calling 'dnf' pgm.
#
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/game-data-packager.git
More information about the Pkg-games-commits
mailing list