first py impl of redirect lines, misc improvements

This commit is contained in:
Mathew Guest
2020-02-24 03:16:20 -07:00
parent 7b2643cf45
commit a81e2d4c46
13 changed files with 422 additions and 108 deletions
+10
View File
@@ -0,0 +1,10 @@
import hashlib
def md5sum_file(filename):
with open(filename, mode='rb') as f:
d = hashlib.md5()
for buf in iter(partial(f.read, 128), b''):
d.update(buf)
h = d.hexdigest()
return h
+11 -26
View File
@@ -1,56 +1,41 @@
from . import hub_machine
import app_skellington
from app_skellington import _util
from . import model
class SmileyFace(app_skellington.ApplicationContainer):
def __init__(self, *args, **kwargs):
filename = 'config.spec'
self.configspec_filepath = _util.get_asset(__name__, filename)
config_filepath = self._get_config_filepath(
'smileyface-ut4',
'app_author',
'hub-config.ini'
)
super().__init__(
configspec_filepath=self.configspec_filepath,
config_filepath=config_filepath,
app_name = 'SmileyFace UT4 Server Panel',
app_author = 'Mathew Guest',
app_version = '0.1',
*args,
**kwargs
)
# super().__init__(
# app_name = 'SmileyFace UT4 Server Panel',
# app_author = 'Mathew Guest',
# app_version = '0.1'
# )
self._load_config()
def _load_config(self, config_file=None):
"""
Parse the config file, (todo) environment variables, and command-line
arguments to determine runtime configuration.
"""
if config_file is None:
config_file = self._get_config_filepath(
'smileyface-ut4',
'app_author',
'hub-config.ini'
)
rc = self.ctx.config.load_config_from_file(config_file)
def _cli_options(self):
pass
def _command_menu(self):
sm_root = self.cli.init_submenu('command')
# sm_root.register_command(model.foo)
# sm_root.register_command(model.bar)
_util.register_class_as_commands(
self, sm_root,
model.UT4ServerMachine
hub_machine.UT4ServerMachine
)
def _services(self):
self['model'] = lambda: model.UTServerMachine(self.ctx)
self['model'] = lambda: hub_machine.UTServerMachine(self.ctx)
def interactive_shell(self):
pass
View File
+82
View File
@@ -0,0 +1,82 @@
import configparser
import re
class UnrealIniFile:
def __init__(self, filename=None):
self._config = None
self.filename = filename
@property
def filename(self):
return self._filename
@filename.setter
def filename(self, val):
self._filename = val
if val is not None:
self._config = configparser.RawConfigParser(
strict=False
)
self._config.optionxform = str # Trick to preserve case in key names
self._config.read(self._filename)
class GameIniSpecial:
def __init__(self, filename):
self._redirect_lines = []
self._filename = None
self.filename = filename
@property
def filename(self):
return self._filename
@filename.setter
def filename(self, val):
self._filename = val
def clear_redirect_references(self):
self._redirect_lines = []
def add_redirect_reference(
self, pkg_basename, redirect_url, redirect_protocol,
relative_path, md5sum
):
args = {
'pkg_basename': pkg_basename,
'redirect_protocol': redirect_protocol,
'redirect_url': redirect_url,
'relative_path': relative_path,
'md5sum': md5sum
}
########### START multi-line awkward indent
line = '\
RedirectReferences=(PackageName="{pkg_basename}",\
PackageURLProtocol="{redirect_protocol}",\
PackageURL="{redirect_url}/{relative_path}",\
PackageChecksum="{md5sum}")'.format(**args)
########### END multi-line awkward indent
return self.add_redirect_reference_line(line)
def add_redirect_reference_line(self, line):
self._redirect_lines.append(line)
return line
def write(self, fp):
newcontents = None
with open(self.filename, 'r') as inifile:
curcontents = inifile.read()
lines_str = '\n'.join(self._redirect_lines)
newcontents = re.sub(
'RedirectReferences = :PARAM:',
lines_str,
curcontents
)
has_data = True
if has_data:
with open(self.filename, 'w') as fp:
fp.write(newcontents)
@@ -1,3 +1,7 @@
from .config_editor import UnrealIniFile, GameIniSpecial
from . import config_editor
from . import _util
from app_skellington import _util
from functools import partial
import collections
@@ -80,7 +84,6 @@ rsync -ravzp {remote_game_host}:{remote_game_dir}/LinuxServer/UnrealTournament/S
})
self._invoke_command(cmd)
# Delete logs on remote game server if successfully transferred to local:
self.ctx.log['ut4'].info('')
cmd = '''
@@ -252,14 +255,26 @@ ssh {remote_game_host} chown ut4.ut4 {remote_game_dir} -R
config_dir = self.ctx.config['app']['config_dir']
for fn in files:
self.ctx.log['ut4'].info('Installing file: %s', fn)
# src = '/'.join([config_dir, fn])
# dst = '/'.join([project_dir, 'instance']) # needs corrected
src = os.path.join(config_dir, fn)
dst = os.path.join(project_dir, 'instance/LinuxServer/UnrealTournament/Saved/Config/LinuxServer', fn)
cmd = 'cp {src} {dst}'.format(**{
'src': '/'.join([config_dir, fn]),
'dst': '/'.join([project_dir, 'instance']) # needs corrected
'src': src,
'dst': dst
})
self._invoke_command(cmd)
# Monkey-patch Game.ini to ensure it has a place for RedirectReferences
if fn == 'Game.ini':
ini = UnrealIniFile(dst)
sect_name = '/Script/UnrealTournament.UTBaseGameMode'
opt_name = 'RedirectReferences'
if not ini._config.has_section(sect_name):
ini._config.add_section(sect_name)
if not ini._config.has_option(sect_name, opt_name):
ini._config.set(sect_name, opt_name, ':PARAM:')
with open(dst, 'w') as fp:
ini._config.write(fp)
def _install_paks(self):
project_dir = self.ctx.config['app']['project_dir']
@@ -278,64 +293,39 @@ ssh {remote_game_host} chown ut4.ut4 {remote_game_dir} -R
self._invoke_command(cmd)
def _install_redirect_lines(self):
return self.install_redirect_lines()
def install_redirect_lines(self):
self.ctx.log['ut4'].info('Generating redirect references...')
redirect_protocol = self.ctx.config['app']['redirect_protocol']
redirect_url = self.ctx.config['app']['redirect_url']
project_dir = self.ctx.config['app']['project_dir']
mod_dir = '/'.join([project_dir, 'files'])
files = glob.iglob('{}/**/*.pak'.format(mod_dir))
game_ini_filepath = '/'.join([project_dir, 'instance/LinuxServer/UnrealTournament/Saved/Config/LinuxServer/Game.ini'])
game_ini = GameIniSpecial(game_ini_filepath)
game_ini.clear_redirect_references()
files = glob.glob('{}/**/*.pak'.format(mod_dir))
redirect_lines = []
for idx, filename in enumerate(files):
if idx > 5:
break
md5sum = self._md5sum_file(filename)
# if idx > 5:
# break
md5sum = _util.md5sum_file(filename)
p = pathlib.Path(filename)
relative_path = p.relative_to(mod_dir)
basename = p.name
pkg_basename = p.name
line = game_ini.add_redirect_reference(**{
'pkg_basename': pkg_basename,
'redirect_protocol': redirect_protocol,
'redirect_url': redirect_url,
'relative_path': relative_path,
'md5sum': md5sum
})
line = '\
RedirectReferences=(PackageName="{basename}",\
PackageURLProtocol="{redirect_protocol}",\
PackageURL="{redirect_url}/{relative_path}",\
PackageChecksum="{md5sum}")'\
.format(**{
'basename': basename,
'redirect_protocol': redirect_protocol,
'redirect_url': redirect_url,
'relative_path': relative_path,
'md5sum': md5sum
})
self.ctx.log['ut4'].debug("redirect line = '%s'", line)
redirect_lines.append(line)
# end loop - for filename in files:
# START HERE --trying to dynamically add redirect references and
# gonna need to be able to work with the ini file, including support
# for duplicate keys. Alternatively, maybe do the redirect lines through
# a patch
data = game_ini.write(sys.stdout)
# I found out the hard way, configobj doesn't seem the best suited for
# duplicate keys...
# install into Game.ini
game_ini_filepath = '/'.join([project_dir, 'files/config/Game.ini'])
# game_ini_data = configobj.ConfigObj(game_ini_filepath)
config = configparser.ConfigParser(
# game_ini_filepath,
# dict_type=MultiOrderedDict,
strict=False
)
s = config.sections()
print(s)
# config.set('/Script/UnrealTournament.UTBaseGameMode', 'RedirectReferences', line)
config.read(game_ini_filepath)
l = config.write(sys.stdout)
print('l', l)
def _install_rulesets(self):
self.ctx.log['ut4'].info('Concatenating rulesets for game modes...')
project_dir = self.ctx.config['app']['project_dir']
@@ -378,14 +368,6 @@ PackageChecksum="{md5sum}")'\
cwd = None # todo(mg) ?
os.system(cmd)
def _md5sum_file(self, filename):
with open(filename, mode='rb') as f:
d = hashlib.md5()
for buf in iter(partial(f.read, 128), b''):
d.update(buf)
h = d.hexdigest()
return h
def _needs_first_run(self):
return False # TODO(MG): Hard-coded