[game-data-packager] 04/05: Add support for multi-package games, and use it to support Team Arena
Simon McVittie
smcv at debian.org
Sat Jan 3 16:21:07 UTC 2015
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 999ce42ca0e9d6257d6cf2925e5ee87a59ce83ab
Author: Simon McVittie <smcv at debian.org>
Date: Sat Jan 3 16:20:05 2015 +0000
Add support for multi-package games, and use it to support Team Arena
---
Makefile | 4 +
data/{jedi-academy-data.yaml => ja.yaml} | 1 +
data/{jedi-outcast-data.yaml => jk2.yaml} | 1 +
data/quake3-data.copyright | 2 +-
data/quake3-data.postinst | 9 +
data/quake3-data.postrm | 9 +
data/quake3-data.preinst | 9 +
data/quake3-data.prerm | 9 +
data/quake3-team-arena-data.control.m4 | 20 ++
....copyright => quake3-team-arena-data.copyright} | 2 +-
data/{quake3-data.yaml => quake3.yaml} | 74 ++++--
data/{rott-data.yaml => rott.yaml} | 1 +
data/{rtcw-data.yaml => rtcw.yaml} | 1 +
lib/game_data_packager/__init__.py | 249 ++++++++++++++-------
lib/game_data_packager/__main__.py | 109 ++++++++-
lib/via-python | 7 +-
supported/ja | 2 +-
supported/jk2 | 2 +-
supported/quake3 | 10 +-
supported/rott | 4 +-
supported/rtcw | 2 +-
21 files changed, 406 insertions(+), 121 deletions(-)
diff --git a/Makefile b/Makefile
index 68cba87..623a98b 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,10 @@ default: $(DIRS)
chmod 0644 ./out/changelog.gz
install -m644 data/*.yaml out/
install -m644 data/*.copyright out/
+ install -m755 data/*.preinst out/
+ install -m755 data/*.postinst out/
+ install -m755 data/*.prerm out/
+ install -m755 data/*.postrm out/
set -e; for x in data/*.*.m4; do \
o="out/$${x#data/}"; \
o="$${o%.m4}"; \
diff --git a/data/jedi-academy-data.yaml b/data/ja.yaml
similarity index 99%
rename from data/jedi-academy-data.yaml
rename to data/ja.yaml
index b7fade4..0642121 100644
--- a/data/jedi-academy-data.yaml
+++ b/data/ja.yaml
@@ -1,6 +1,7 @@
%YAML 1.2
---
package: jedi-academy-data
+type: full
# There's really no point in compressing the .deb; the only compressible
# things in it are the control files and copyright information,
diff --git a/data/jedi-outcast-data.yaml b/data/jk2.yaml
similarity index 99%
rename from data/jedi-outcast-data.yaml
rename to data/jk2.yaml
index f2ce48e..aa404ed 100644
--- a/data/jedi-outcast-data.yaml
+++ b/data/jk2.yaml
@@ -1,6 +1,7 @@
%YAML 1.2
---
package: jedi-outcast-data
+type: full
# Like Jedi Academy, there isn't much point in compressing this .deb.
compress_deb: false
diff --git a/data/quake3-data.copyright b/data/quake3-data.copyright
index ed8c741..8f3d36a 100644
--- a/data/quake3-data.copyright
+++ b/data/quake3-data.copyright
@@ -1,7 +1,7 @@
This package was generated using game-data-packager.
Copyright © 2008-2013 Jonathan Dowland <jmtd at debian.org>.
-The pk3 files under "/usr/share/games/quake3" are user-supplied
+The pk3 files under "/usr/share/games" are user-supplied
files that are not covered by the copyright or licence of this
package; they are copyright (c) 1999 by id Software, all rights reserved.
diff --git a/data/quake3-data.postinst b/data/quake3-data.postinst
new file mode 100644
index 0000000..a5bbaf4
--- /dev/null
+++ b/data/quake3-data.postinst
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+dpkg-maintscript-helper dir_to_symlink \
+ /usr/share/games/quake3/baseq3 \
+ ../quake3-data/baseq3 \
+ 37 \
+ quake3-data \
+ -- \
+ "$@"
diff --git a/data/quake3-data.postrm b/data/quake3-data.postrm
new file mode 100644
index 0000000..a5bbaf4
--- /dev/null
+++ b/data/quake3-data.postrm
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+dpkg-maintscript-helper dir_to_symlink \
+ /usr/share/games/quake3/baseq3 \
+ ../quake3-data/baseq3 \
+ 37 \
+ quake3-data \
+ -- \
+ "$@"
diff --git a/data/quake3-data.preinst b/data/quake3-data.preinst
new file mode 100644
index 0000000..a5bbaf4
--- /dev/null
+++ b/data/quake3-data.preinst
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+dpkg-maintscript-helper dir_to_symlink \
+ /usr/share/games/quake3/baseq3 \
+ ../quake3-data/baseq3 \
+ 37 \
+ quake3-data \
+ -- \
+ "$@"
diff --git a/data/quake3-data.prerm b/data/quake3-data.prerm
new file mode 100644
index 0000000..a5bbaf4
--- /dev/null
+++ b/data/quake3-data.prerm
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+dpkg-maintscript-helper dir_to_symlink \
+ /usr/share/games/quake3/baseq3 \
+ ../quake3-data/baseq3 \
+ 37 \
+ quake3-data \
+ -- \
+ "$@"
diff --git a/data/quake3-team-arena-data.control.m4 b/data/quake3-team-arena-data.control.m4
new file mode 100644
index 0000000..f73b9e8
--- /dev/null
+++ b/data/quake3-team-arena-data.control.m4
@@ -0,0 +1,20 @@
+Package: quake3-team-arena-data
+Version: VERSION
+Section: non-free/games
+Priority: optional
+Architecture: all
+Multi-Arch: foreign
+Depends: quake3-data (>= 38)
+Installed-Size: 500000
+Maintainer: Debian Games Team <pkg-games-devel at lists.alioth.debian.org>
+Description: Quake III Team Arena commercial data files
+ This package contains the commercial data from id Software's addon pack
+ "Quake III Team Arena" for the game "Quake III Arena", and was generated
+ using the "game-data-packager" program from the Debian package of
+ the same name.
+ .
+ To play Team Arena using this data, install the quake3 package
+ and select it from the Mods menu.
+ .
+ To run a dedicated server, install the quake3-server package
+ and run the server with the option "+set fs_game missionpack".
diff --git a/data/quake3-data.copyright b/data/quake3-team-arena-data.copyright
similarity index 93%
copy from data/quake3-data.copyright
copy to data/quake3-team-arena-data.copyright
index ed8c741..8f3d36a 100644
--- a/data/quake3-data.copyright
+++ b/data/quake3-team-arena-data.copyright
@@ -1,7 +1,7 @@
This package was generated using game-data-packager.
Copyright © 2008-2013 Jonathan Dowland <jmtd at debian.org>.
-The pk3 files under "/usr/share/games/quake3" are user-supplied
+The pk3 files under "/usr/share/games" are user-supplied
files that are not covered by the copyright or licence of this
package; they are copyright (c) 1999 by id Software, all rights reserved.
diff --git a/data/quake3-data.yaml b/data/quake3.yaml
similarity index 59%
rename from data/quake3-data.yaml
rename to data/quake3.yaml
index 1cc21f4..4cab2bb 100644
--- a/data/quake3-data.yaml
+++ b/data/quake3.yaml
@@ -1,25 +1,55 @@
%YAML 1.2
---
-package: quake3-data
-install_to: usr/share/games/quake3
+shortname: quake3
compress_deb: false
-install_files_from_cksums: |
- # Retail
- 1131927141 479493658 baseq3/pak0.pk3
- # Patch
- 3518406034 374405 baseq3/pak1.pk3
- 243530540 7511182 baseq3/pak2.pk3
- 987913107 276305 baseq3/pak3.pk3
- 1445361719 9600350 baseq3/pak4.pk3
- 3989134593 191872 baseq3/pak5.pk3
- 1938352652 7346884 baseq3/pak6.pk3
- 241293937 320873 baseq3/pak7.pk3
- 1541013579 454478 baseq3/pak8.pk3
+packages:
+ quake3-data:
+ type: full
+ # We deliberately only put baseq3 in the search path, not
+ # missionpack, so that the engine doesn't think missionpack
+ # is installed unless its pak0.pk3 is present.
+ symlinks:
+ usr/share/games/quake3/baseq3:
+ usr/share/games/quake3-data/baseq3
+ install_to: usr/share/games/quake3-data
+ install_files_from_cksums: |
+ # Retail
+ 1131927141 479493658 baseq3/pak0.pk3
+ # Patch
+ 3518406034 374405 baseq3/pak1.pk3
+ 243530540 7511182 baseq3/pak2.pk3
+ 987913107 276305 baseq3/pak3.pk3
+ 1445361719 9600350 baseq3/pak4.pk3
+ 3989134593 191872 baseq3/pak5.pk3
+ 1938352652 7346884 baseq3/pak6.pk3
+ 241293937 320873 baseq3/pak7.pk3
+ 1541013579 454478 baseq3/pak8.pk3
+ _ 383888 missionpack/pak1.pk3
+ _ 376234 missionpack/pak2.pk3
+ _ 384282 missionpack/pak3.pk3
+
+ quake3-team-arena-data:
+ type: expansion
+ symlinks:
+ usr/share/games/quake3/missionpack/pak0.pk3:
+ usr/share/games/quake3-team-arena-data/missionpack/pak0.pk3
+ usr/share/games/quake3/missionpack/pak1.pk3:
+ usr/share/games/quake3-data/missionpack/pak1.pk3
+ usr/share/games/quake3/missionpack/pak2.pk3:
+ usr/share/games/quake3-data/missionpack/pak2.pk3
+ usr/share/games/quake3/missionpack/pak3.pk3:
+ usr/share/games/quake3-data/missionpack/pak3.pk3
+ install_to: usr/share/games/quake3-team-arena-data
+ install_files:
+ missionpack/pak0.pk3:
+ size: 351623691
+ distinctive_size: true
files:
linuxq3apoint-1.32b-3.x86.run:
size: 30923961
+ distinctive_size: true
download:
quake3-mirrors:
path: .
@@ -38,6 +68,9 @@ files:
- baseq3/pak6.pk3
- baseq3/pak7.pk3
- baseq3/pak8.pk3
+ - missionpack/pak1.pk3
+ - missionpack/pak2.pk3
+ - missionpack/pak3.pk3
md5: c71fdddccb20e8fc393d846e9c61d685
sha1: 802d84af0d515db50a496c4c55d1f1c4f40a9239
sha256: c36132c5556b35e01950f1e9c646235033a5130f87ad776ba2bc7becf4f4f186
@@ -55,6 +88,10 @@ md5sums: |
873888a73055c023f6c38b8ca3f2ce05 baseq3/pak6.pk3
8fd38c53ed814b64f6ab03b5290965e4 baseq3/pak7.pk3
d8b96d429ca4a9c289071cb7e77e14d2 baseq3/pak8.pk3
+ e8ba9e3bf06210930bc0e7fdbcdd01c2 missionpack/pak0.pk3
+ 8b8a51f9edf2671dfeb53e0405bac3c6 missionpack/pak1.pk3
+ 4e02be54614ca7dbed81b5c44a19302d missionpack/pak2.pk3
+ e7f91f4eb6e3d28d978b8cca54631695 missionpack/pak3.pk3
sha1sums: |
9d588ea65e92944d3e23eeb6ec08f1dd666f4658 baseq3/pak0.pk3
@@ -66,6 +103,10 @@ sha1sums: |
5716d9b9099067549f46ca77cf2cc7f8c0f498da baseq3/pak6.pk3
c20d9301aa833baaffed2194be46c89c42b5b4d1 baseq3/pak7.pk3
657e2d95041ca37f7cfb23fa23850d0aad09e26c baseq3/pak8.pk3
+ f34711efdc2de9ce9283f7b0eb4cd6fd40926fb0 missionpack/pak0.pk3
+ ce4b4cbee92a84479e620c2ca178aae7358576e5 missionpack/pak1.pk3
+ ed74b17a12ed8627ce9b15aa80487e90c65cf01d missionpack/pak2.pk3
+ 50adbfade3d9342a6ab75004e0013557243a30a5 missionpack/pak3.pk3
sha256sums: |
7ce8b3910620cd50a09e4f1100f426e8c6180f68895d589f80e6bd95af54bcae baseq3/pak0.pk3
@@ -77,6 +118,10 @@ sha256sums: |
bb4f0ae2bf603b050fb665436d3178ce7c1c20360e67bacf7c14d93daff38daf baseq3/pak6.pk3
de6283ce23e3486a2622c5dbf73d3721a59f24debd380e90f43a97d952fea283 baseq3/pak7.pk3
812c9e97f231e89cefede3848c6110b7bd34245093af6f22c2cacde3e6b15663 baseq3/pak8.pk3
+ fdb5fe4f15f22bd270628d9b3153b733ca4548207722e768051c08c9dbff9135 missionpack/pak0.pk3
+ 9818e99ba58d91f231a650a3c42559d1c5661cb3c0dfd033ef4225ba8ecdfd60 missionpack/pak1.pk3
+ 6cc56de0bf7b58e30164ab487c51deb0fa7c62dbd7d0a5421a5d5aa58f31a3f4 missionpack/pak2.pk3
+ 77c0bcbb61be81a389d8959b76969a801a5e589d97ab8aeb2cb7ced54f187fc7 missionpack/pak3.pk3
# Not used yet
sha512sums: |
@@ -89,6 +134,7 @@ sha512sums: |
7a229cebaa262716aa80bfd59ba1f5207c988e48580e2a801de644f3f1c0ac82d64e0cc83b8cc780400f5a0bb1e09a98b1f640edace30101b517eec73a514f06 baseq3/pak6.pk3
f9442fa0dfa6391056a082fa552014e27ad2620cb291302655c16265afd5c8bdb304ef3b06ae1255d57d50c00ecae030d4337708d01bd67af252fc006be87244 baseq3/pak7.pk3
dcae254ac87a1d8453d5fb301105d9f1e55234e8044d6631f07f645f56c37b3b11aa168df1fe4ce9838f9f7c5e5ae4d6837286aef6297cae44094f750692ab5f baseq3/pak8.pk3
+ 16b36521c2d659f314d7380245f36e587ac7ebbea30cb323db4b84c2c63e4f947f28afb6fd17cbe86fe4b2ad2cccb8de3c809da7eba22f7f644c619d1be07bf8 missionpack/pak0.pk3
...
# vim:set sw=2 sts=2 et:
diff --git a/data/rott-data.yaml b/data/rott.yaml
similarity index 99%
rename from data/rott-data.yaml
rename to data/rott.yaml
index fdc4838..2769f3e 100644
--- a/data/rott-data.yaml
+++ b/data/rott.yaml
@@ -2,6 +2,7 @@
---
package: rott-data
install_to: usr/share/games/rott
+type: demo
install_files_from_cksums: |
742977862 27028 DEMO1_3.DMO
diff --git a/data/rtcw-data.yaml b/data/rtcw.yaml
similarity index 99%
rename from data/rtcw-data.yaml
rename to data/rtcw.yaml
index b2c5d3b..151f908 100644
--- a/data/rtcw-data.yaml
+++ b/data/rtcw.yaml
@@ -1,6 +1,7 @@
%YAML 1.2
---
package: rtcw-data
+type: full
# Like Jedi Academy, there isn't much point in compressing this .deb.
compress_deb: false
diff --git a/lib/game_data_packager/__init__.py b/lib/game_data_packager/__init__.py
index 23ba75e..d49e7a8 100644
--- a/lib/game_data_packager/__init__.py
+++ b/lib/game_data_packager/__init__.py
@@ -148,7 +148,7 @@ class WantedFile(HashedFile):
self.distinctive_name = True
self.distinctive_size = False
self.download = None
- self._install_as = None
+ self.install_as = name
self.install_to = None
self._look_for = []
self.optional = False
@@ -168,24 +168,6 @@ class WantedFile(HashedFile):
self._look_for = set(x.lower() for x in value)
@property
- def install(self):
- return (self._install_as is not None)
- @install.setter
- def install(self, value):
- if value:
- if self._install_as is None:
- self._install_as = self.name
- else:
- self._install_as = None
-
- @property
- def install_as(self):
- return self._install_as
- @install_as.setter
- def install_as(self, value):
- self._install_as = value
-
- @property
def size(self):
return self._size
@size.setter
@@ -205,7 +187,6 @@ class WantedFile(HashedFile):
'distinctive_name': self.distinctive_name,
'distinctive_size': self.distinctive_size,
'download': self.download,
- 'install': self.install,
'install_as': self.install_as,
'install_to': self.install_to,
'look_for': list(self.look_for),
@@ -217,13 +198,62 @@ class WantedFile(HashedFile):
}
class GameDataPackage(object):
+ def __init__(self, name):
+ # The name of the binary package
+ self.name = name
+
+ # Where we install files.
+ # For instance, if this is 'usr/share/games/quake3' and we have
+ # a WantedFile with install_as='baseq3/pak1.pk3' then we would
+ # put 'usr/share/games/quake3/baseq3/pak1.pk3' in the .deb.
+ # The default is 'usr/share/games/' plus the binary package's name.
+ self.install_to = 'usr/share/games/' + name
+
+ # symlink => real file (the opposite way round that debhelper does it,
+ # because the links must be unique but the real files are not
+ # necessarily)
+ self.symlinks = {}
+
+ # set of names of WantedFile instances to be installed
+ self._install = set()
+
+ # type of package: full, demo or expansion
+ # full packages include quake-registered, quake2-full-data, quake3-data
+ # demo packages include quake-shareware, quake2-demo-data
+ # expansion packages include quake-armagon, quake-music, quake2-rogue
+ self._type = 'full'
+
+ @property
+ def install(self):
+ return self._install
+ @install.setter
+ def install(self, value):
+ self._install = set(value)
+
+ @property
+ def type(self):
+ return self._type
+ @type.setter
+ def type(self, value):
+ assert value in ('full', 'demo', 'expansion'), value
+ self._type = value
+
+ def to_yaml(self):
+ return {
+ 'install': sorted(self.install),
+ 'install_to': self.install_to,
+ 'name': self.name,
+ 'symlinks': self.symlinks,
+ }
+
+class GameData(object):
def __init__(self,
- name,
+ shortname,
datadir='/usr/share/games/game-data-packager',
etcdir='/etc/game-data-packager',
workdir=None):
- # The name of the binary package
- self.name = name
+ # The name of the game
+ self.shortname = shortname
# game-data-packager's configuration directory
self.etcdir = etcdir
@@ -237,11 +267,27 @@ class GameDataPackage(object):
# Clean up these directories on exit.
self._cleanup_dirs = set()
+ # binary package name => GameDataPackage
+ self.packages = {}
+
# If true, we may compress the .deb. If false, don't.
self.compress_deb = True
- self.yaml = yaml.load(open(os.path.join(self.datadir, name + '.yaml')))
- assert self.yaml['package'] == name
+ self.yaml = yaml.load(open(os.path.join(self.datadir,
+ shortname + '.yaml')))
+
+ if 'package' in self.yaml:
+ package = GameDataPackage(self.yaml['package'])
+ self.packages[self.yaml['package']] = package
+ assert 'packages' not in self.yaml
+ else:
+ assert self.yaml['packages']
+ assert 'install_files' not in self.yaml
+
+ # these do not make sense at top level if there is more than
+ # one package
+ assert 'symlinks' not in self.yaml
+ assert 'install_files_from_cksums' not in self.yaml
# Map from WantedFile name to instance.
# { 'baseq3/pak1.pk3' => WantedFile instance }
@@ -260,39 +306,23 @@ class GameDataPackage(object):
# Failed downloads
self.download_failed = set()
- # Where we install files.
- # For instance, if this is 'usr/share/games/quake3' and we have
- # a WantedFile with install_as='baseq3/pak1.pk3' then we would
- # put 'usr/share/games/quake3/baseq3/pak1.pk3' in the .deb.
- # The default is 'usr/share/games/' plus the binary package's name.
- self.install_to = 'usr/share/games/' + name
-
- if 'install_to' in self.yaml:
- self.install_to = self.yaml['install_to']
-
- # symlink => real file (the opposite way round that debhelper does it,
- # because the links must be unique but the real files are not
- # necessarily)
- self.symlinks = {}
-
self._populate_files(self.yaml.get('files'))
self._populate_files(self.yaml.get('install_files'), install=True)
- if 'symlinks' in self.yaml:
- self.symlinks = self.yaml['symlinks']
+ if 'package' in self.yaml:
+ self._populate_package(next(iter(self.packages.values())),
+ self.yaml)
- if 'install_files_from_cksums' in self.yaml:
- for line in self.yaml['install_files_from_cksums'].splitlines():
- stripped = line.strip()
- if stripped == '' or stripped.startswith('#'):
- continue
+ if 'packages' in self.yaml:
+ for binary, data in self.yaml['packages'].items():
+ # these should only be at top level, since they are global
+ assert 'md5sums' not in data, binary
+ assert 'sha1sums' not in data, binary
+ assert 'sha256sums' not in data, binary
- _, size, filename = line.split(None, 2)
- f = self._ensure_file(filename)
- size = int(size)
- assert (f.size == size or f.size is None), (f.size, size)
- f.size = size
- f.install = True
+ package = GameDataPackage(binary)
+ self.packages[binary] = package
+ self._populate_package(package, data)
for alg in ('md5', 'sha1', 'sha256'):
if alg + 'sums' in self.yaml:
@@ -318,6 +348,10 @@ class GameDataPackage(object):
yaml.safe_dump(self.to_yaml()))
# consistency check
+ for package in self.packages.values():
+ for installable in package.install:
+ assert installable in self.files, installable
+
for filename, wanted in self.files.items():
if wanted.alternatives:
for alt in wanted.alternatives:
@@ -352,6 +386,7 @@ class GameDataPackage(object):
def to_yaml(self):
files = {}
providers = {}
+ packages = {}
for filename, f in self.files.items():
files[filename] = f.to_yaml()
@@ -359,18 +394,57 @@ class GameDataPackage(object):
for provided, by in self.providers.items():
providers[provided] = list(by)
+ for name, package in self.packages.items():
+ packages[name] = package.to_yaml()
+
return {
- 'package': self.name,
+ 'packages': packages,
'providers': providers,
'files': files,
- 'install_to': self.install_to,
}
- def _populate_files(self, d, **kwargs):
+ def _populate_package(self, package, d):
+ if 'type' in d:
+ package.type = d['type']
+
+ if 'symlinks' in d:
+ package.symlinks = d['symlinks']
+
+ if 'install_to' in d:
+ package.install_to = d['install_to']
+
+ if 'install_files_from_cksums' in d:
+ for line in d['install_files_from_cksums'].splitlines():
+ stripped = line.strip()
+ if stripped == '' or stripped.startswith('#'):
+ continue
+
+ _, size, filename = line.split(None, 2)
+ f = self._ensure_file(filename)
+ size = int(size)
+ assert (f.size == size or f.size is None), (f.size, size)
+ f.size = size
+ package.install.add(filename)
+
+ self._populate_files(d.get('install_files'), install=True,
+ install_package=package)
+
+ def _populate_files(self, d, install=False, install_package=None,
+ **kwargs):
if d is None:
return
+ if install and install_package is None:
+ assert len(self.packages) == 1
+ install_package = next(iter(self.packages.values()))
+
for filename, data in d.items():
+ if data.get('install', install):
+ if install_package is None:
+ assert len(self.packages) == 1
+ install_package = next(iter(self.packages.values()))
+ install_package.install.add(filename)
+
f = self._ensure_file(filename)
for k in kwargs:
@@ -381,7 +455,6 @@ class GameDataPackage(object):
'distinctive_name',
'distinctive_size',
'download',
- 'install',
'install_as',
'install_to',
'look_for',
@@ -451,6 +524,10 @@ class GameDataPackage(object):
return True
def consider_file(self, path, really_should_match_something):
+ if not os.path.exists(path):
+ # dangling symlink
+ return
+
match_path = '/' + path.lower()
size = os.path.getsize(path)
@@ -497,19 +574,27 @@ class GameDataPackage(object):
logger.warning('file "%s" does not exist or is not a file or ' +
'directory', path)
- def fill_gaps(self, download=False, log=True):
+ def fill_gaps(self, package, download=False, log=True):
+ assert package is not None
+
+ logger.debug('trying to fill any gaps for %s', package.name)
+
possible = True
- for (filename, wanted) in self.files.items():
- if wanted.install and filename not in self.found:
+ for filename in package.install:
+ if filename not in self.found:
+ wanted = self.files[filename]
+
for alt in wanted.alternatives:
if alt in self.found:
break
else:
- logger.debug('gap needs to be filled: %s', filename)
+ logger.debug('gap needs to be filled for %s: %s',
+ package.name, filename)
- for (filename, wanted) in self.files.items():
- if wanted.install and filename not in self.found:
+ for filename in package.install:
+ if filename not in self.found:
+ wanted = self.files[filename]
alt_possible = False
for alt in wanted.alternatives:
@@ -517,12 +602,13 @@ class GameDataPackage(object):
if alt in self.found:
alt_possible = True
break
- elif self.fill_gap(self.files[alt], download=download):
+ elif self.fill_gap(self.files[alt], download=download,
+ log=log):
alt_possible = True
if alt_possible:
pass
- elif not self.fill_gap(wanted, download=download):
+ elif not self.fill_gap(wanted, download=download, log=log):
possible = False
return possible
@@ -806,16 +892,15 @@ class GameDataPackage(object):
return True
- def check_complete(self, log=False):
+ def check_complete(self, package, log=False):
# Got everything?
complete = True
- for (filename, wanted) in self.files.items():
- if not wanted.install:
- continue
-
+ for filename in package.install:
if filename in self.found:
continue
+ wanted = self.files[filename]
+
for alt in wanted.alternatives:
if alt in self.found:
break
@@ -838,13 +923,13 @@ class GameDataPackage(object):
return complete
- def fill_dest_dir(self, destdir):
- if not self.check_complete(log=True):
+ def fill_dest_dir(self, package, destdir):
+ if not self.check_complete(package, log=True):
return False
- docdir = os.path.join(destdir, 'usr/share/doc', self.name)
+ docdir = os.path.join(destdir, 'usr/share/doc', package.name)
mkdir_p(docdir)
- shutil.copyfile(os.path.join(self.datadir, self.name + '.copyright'),
+ shutil.copyfile(os.path.join(self.datadir, package.name + '.copyright'),
os.path.join(docdir, 'copyright'))
shutil.copyfile(os.path.join(self.datadir, 'changelog.gz'),
os.path.join(docdir, 'changelog.gz'))
@@ -855,12 +940,16 @@ class GameDataPackage(object):
assert destdir == self.workdir + '/slipstream.unpacked'
debdir = os.path.join(self.workdir, 'DEBIAN')
mkdir_p(debdir)
- shutil.copyfile(os.path.join(self.datadir, self.name + '.control'),
+ shutil.copyfile(os.path.join(self.datadir, package.name + '.control'),
os.path.join(debdir, 'control'))
- for (filename, wanted) in self.files.items():
- if not wanted.install:
- continue
+ for ms in ('preinst', 'postinst', 'prerm', 'postrm'):
+ maintscript = os.path.join(self.datadir, package.name + '.' + ms)
+ if os.path.isfile(maintscript):
+ shutil.copy(maintscript, os.path.join(debdir, ms))
+
+ for filename in package.install:
+ wanted = self.files[filename]
if filename in self.found:
copy_from = self.found[filename]
@@ -878,7 +967,7 @@ class GameDataPackage(object):
logger.debug('Found %s at %s', wanted.name, copy_from)
copy_to = os.path.join(destdir,
(wanted.install_to if wanted.install_to is not None
- else self.install_to),
+ else package.install_to),
wanted.install_as)
copy_to_dir = os.path.dirname(copy_to)
logger.debug('Copying to %s', copy_to)
@@ -889,7 +978,7 @@ class GameDataPackage(object):
subprocess.check_call(['cp', '--reflink=auto', copy_from,
copy_to])
- for symlink, real_file in self.symlinks.items():
+ for symlink, real_file in package.symlinks.items():
symlink = symlink.lstrip('/')
real_file = real_file.lstrip('/')
diff --git a/lib/game_data_packager/__main__.py b/lib/game_data_packager/__main__.py
index 5e760ef..c41fa90 100644
--- a/lib/game_data_packager/__main__.py
+++ b/lib/game_data_packager/__main__.py
@@ -16,10 +16,14 @@
# /usr/share/common-licenses/GPL-2.
import argparse
+import logging
import os
import sys
-from . import GameDataPackage
+from . import GameData
+
+logging.basicConfig()
+logger = logging.getLogger('game-data-packager')
def go(argv):
parser = argparse.ArgumentParser(description='Package game files.',
@@ -29,28 +33,113 @@ def go(argv):
metavar='DIRECTORY|FILE')
args = parser.parse_args(argv[1:])
- with GameDataPackage(argv[0],
+ with GameData(argv[0],
datadir=os.environ['DATADIR'],
workdir=os.environ['WORKDIR'],
etcdir=os.environ['ETCDIR'],
- ) as package:
+ ) as game:
if args.repack:
- args.paths.insert(0, '/' + package.install_to)
+ can_repack = False
+ absent = set()
+
+ for package in game.packages.values():
+ path = '/' + package.install_to
+ if os.path.isdir(path):
+ args.paths.insert(0, path)
+ can_repack = True
+ elif (package.name == 'quake3-data' and
+ os.path.isdir('/usr/share/games/quake3')):
+ # FIXME: this is a hack, it would be better to
+ # have alternative locations defined in the YAML
+ args.paths.insert(0, path)
+ can_repack = True
+ else:
+ absent.add(path)
+
+ if not can_repack:
+ raise SystemExit('cannot repack %s: could not open %r' %
+ (package, sorted(absent)))
for arg in args.paths:
- package.consider_file_or_dir(arg)
+ game.consider_file_or_dir(arg)
- if not package.fill_gaps(log=True):
- # cannot possibly continue
- sys.exit(1)
+ possible = set()
+
+ for package in game.packages.values():
+ if argv[0] in game.packages and package.name != argv[0]:
+ continue
+
+ if game.fill_gaps(package, log=False):
+ logger.debug('%s is possible', package.name)
+ possible.add(package)
- package.fill_gaps(download=True)
+ if not possible:
+ logger.debug('No packages were possible')
+ # Repeat the process for the first (hopefully only)
+ # demo/shareware package, so we can log its errors.
+ for package in game.packages.values():
+ if package.type == 'demo':
+ if game.fill_gaps(package=package, log=True):
+ logger.error('%s unexpectedly succeeded on second ' +
+ 'attempt. Please report this as a bug',
+ package.name)
+ possible.add(package)
+ else:
+ sys.exit(1)
+ else:
+ # If no demo, repeat the process for the first
+ # (hopefully only) full package, so we can log *its* errors.
+ for package in game.packages.values():
+ if package.type == 'full':
+ if game.fill_gaps(package=package, log=True):
+ logger.error('%s unexpectedly succeeded on ' +
+ 'second attempt. Please report this as '
+ 'a bug', package.name)
+ possible.add(package)
+ else:
+ sys.exit(1)
+ else:
+ raise SystemExit('Unable to complete any packages. ' +
+ 'Please provide more files or directories.')
- if not package.fill_dest_dir(os.environ['DESTDIR']):
+ package = None
+
+ # We can only build one package for now, because the shell script
+ # wrapper can only do one. Pick the "best": full if we have the
+ # right stuff, or expansion if we have the right stuff, or demo.
+ if len(possible) == 1:
+ for p in possible:
+ package = p
+ else:
+ for p in possible:
+ if p.type == 'full':
+ package = p
+ break
+ else:
+ for p in possible:
+ if p.type == 'expansion':
+ package = p
+ break
+ else:
+ # just pick the first one
+ for p in possible:
+ package = p
+
+ logger.debug('chose to produce %s', package.name)
+
+ if not game.fill_gaps(package=package, download=True, log=True):
+ raise SystemExit('Failed to download necessary files for %s',
+ package.name)
+
+ if not game.fill_dest_dir(package, os.environ['DESTDIR']):
sys.exit(1)
# FIXME: make the .deb (currently done in shell script by the wrapper)
+ # This is a hack to communicate the name of the .deb to the shell
+ # script...
+ open(os.environ['WORKDIR'] + '/DEB_NAME', 'w').write(package.name)
+
if __name__ == '__main__':
go(sys.argv[1:])
diff --git a/lib/via-python b/lib/via-python
index 6604e95..cd9ef74 100644
--- a/lib/via-python
+++ b/lib/via-python
@@ -32,7 +32,7 @@ gdp_data_driven () {
if [ -n "${DEBUG:-}" ]; then
export DEBUG
fi
- python3 -m game_data_packager "$deb" "$@"
+ python3 -m game_data_packager "$@"
exit $?
)
@@ -47,6 +47,10 @@ gdp_data_driven () {
# We still do this bit in shell script, for now
+ if [ -e "$WORKDIR/DEB_NAME" ]; then
+ deb="$(cat "$WORKDIR/DEB_NAME")"
+ fi
+
if [ "" = "$OUTDIR" ]; then
OUTFILE="$WORKDIR/out.deb"
else
@@ -64,6 +68,7 @@ gdp_data_driven () {
( cd "$WORKDIR" && slipstream_instsize )
( cd "$WORKDIR" && slipstream_repack "$OUTFILE" )
+ rm -f "$WORKDIR/DEB_NAME"
rm -f "$WORKDIR/DO-NOT-COMPRESS"
rm -fr "$WORKDIR/tmp"
rm -fr "$DESTDIR"
diff --git a/supported/ja b/supported/ja
index 180ea4b..e30f07a 100644
--- a/supported/ja
+++ b/supported/ja
@@ -34,5 +34,5 @@ game-data-packager ${SHORTNAME} --repack\n\
}
go () {
- gdp_data_driven "$@"
+ gdp_data_driven ja "$@"
}
diff --git a/supported/jk2 b/supported/jk2
index b38f789..a803ff9 100644
--- a/supported/jk2
+++ b/supported/jk2
@@ -34,5 +34,5 @@ game-data-packager ${SHORTNAME} --repack\n\
}
go () {
- gdp_data_driven "$@"
+ gdp_data_driven jk2 "$@"
}
diff --git a/supported/quake3 b/supported/quake3
index f30b736..3e85d7c 100644
--- a/supported/quake3
+++ b/supported/quake3
@@ -2,17 +2,9 @@
SHORTNAME=quake3
LONGNAME="Quake III Arena"
-deb=quake3-data
-basedir='/usr/share/games/quake3'
. $LIBDIR/via-python
-usage() {
-echo "quake3 game arguments:"
-printf "\tmountpoint - Quake III Arena CD mount-point or baseq3/pak0.pk3 filename\n"
-printf "\tpoint release - ${POINTFILE}\n"
-}
-
go () {
- gdp_data_driven "$@"
+ gdp_data_driven quake3 "$@"
}
diff --git a/supported/rott b/supported/rott
index cd3a248..fd34534 100644
--- a/supported/rott
+++ b/supported/rott
@@ -23,7 +23,7 @@ go() {
rott_usage >&2
exit 1
fi
- gdp_data_driven --
+ gdp_data_driven rott --
;;
2)
if [ "$1" != "-f" ]; then
@@ -31,7 +31,7 @@ go() {
rott_usage >&2
exit 1
fi
- gdp_data_driven "$2"
+ gdp_data_driven rott "$2"
;;
*)
usage >&2
diff --git a/supported/rtcw b/supported/rtcw
index dd991ac..aa43540 100644
--- a/supported/rtcw
+++ b/supported/rtcw
@@ -36,5 +36,5 @@ game-data-packager ${SHORTNAME} --repack\n\
}
go () {
- gdp_data_driven "$@"
+ gdp_data_driven rtcw "$@"
}
--
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