Last active
June 14, 2018 16:42
-
-
Save geophree/5bd74882d9dcea855e1c15ca3cce93df to your computer and use it in GitHub Desktop.
Build Graveyard Keeper directory structure from installer on linux
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Big thanks to @TechnicianLP for the inspiration! See https://gist.github.com/TechnicianLP/5882de4075b6ed3700bba2bbc310e616 | |
# This script builds the Graveyard Keeper directory/file tree using the .msi installer db. | |
# NOTE: Before running this script: | |
# Install wine (GK works for me with 3.9, probably needs at least 3.0) | |
# unzip the installer, then run: | |
# wine installer_filename.exe /extract | |
# This will give you the .cab and the .msi | |
# Extract the .cab with a archive program (7z probably works, Archive Manager in Ubuntu definitely does) | |
# Install msitools if you haven't already, this script needs msiinfo (https://wiki.gnome.org/msitools) | |
# Run this script in the same directory as the .msi file and all the files extracted from the .cab | |
# NOTE: To finish installing and running GK: | |
# Move the directory it created to wine | |
# mv "Graveyard Keeper Alpha" ~/".wine/drive_c/Program Files (x86)/" | |
# I run GK (windowed) with the following command line | |
# wine explorer /desktop=grave,1920x1080 Graveyard\ Keeper.exe | |
# The first time I ran it it downloaded a few things, but works fine. | |
# Enjoy a great game! | |
# NOTE: GK stores your savegames in a different place, so you can just replace the game directory completely and you won't lose anything | |
import subprocess | |
GAME_DIR = 'Graveyard Keeper Alpha' | |
MSI_FILENAME = 'Graveyard Keeper Alpha.msi' | |
def shellEscape(string): | |
return "'" + string.replace("'", """'"'"'""") + "'" | |
def runMsi(*command): | |
return subprocess.run("msiinfo " + shellEscape(command[0]) + " " + shellEscape(MSI_FILENAME) + " " + " ".join(map(shellEscape, command[1:])), shell=True, stdout=subprocess.PIPE).stdout.decode("utf-8") | |
def makeTable(tableName, transform=lambda x: x): | |
table = {} | |
rows = iter(runMsi("export", tableName).splitlines()) | |
column_names = next(rows).split("\t") | |
next(rows) # Column types | |
next(rows) # Not sure what this line is. | |
for i in rows: | |
columns = i.split("\t") | |
entry = dict(zip(column_names, columns)) | |
entry = transform(entry) | |
if not entry: continue | |
table[columns[0]] = entry | |
return table | |
# Strip weird old-dos filename prefixes | |
def fixFilename(filename): | |
delimIndex = filename.find('|') | |
if delimIndex == -1: return filename | |
return filename[delimIndex+1:] | |
def createTransformFilename(filenameField): | |
def tranformFilename(x): | |
x[filenameField] = fixFilename(x[filenameField]) | |
return x | |
return tranformFilename | |
def makeFullDirectoryMap(directories): | |
map = {} | |
def getFullPath(key): | |
if key in map: | |
return map[key] | |
i = directories[key] | |
parent = i['Directory_Parent'] | |
defaultDir = i['DefaultDir'] | |
fullPath = defaultDir | |
if parent: | |
fullPath = getFullPath(parent) + '/' + fullPath | |
map[key] = fullPath | |
return fullPath | |
for i in directories.keys(): | |
getFullPath(i) | |
return map | |
# 'web.config': {'Attributes': '0', | |
# 'Component_': 'DefaultWsdlHelpGenerator.aspx_1', | |
# 'File': 'web.config', | |
# 'FileName': 'web.config', | |
# 'FileSize': '11686', | |
# 'Language': '', | |
# 'Sequence': '10', | |
# 'Version': ''}, | |
# 'websocketsharp.dll': {'Attributes': '0', | |
# 'Component': 'websocketsharp.dll', | |
# 'ComponentId': '{4ED20095-7B23-4B62-9168-D98B50BF28E7}', | |
# 'Condition': '', | |
# 'Directory_': 'Managed_Dir', | |
# 'KeyPath': 'websocketsharp.dll'}} | |
def makeFileMap(files, components, directoryMap): | |
map = {} | |
for src, i in files.items(): | |
map[src] = directoryMap[components[i['Component_']]['Directory_']] + '/' + i['FileName'] | |
return map | |
def makeFileAndDirectoryMap(): | |
files = makeTable("File", createTransformFilename('FileName')) | |
components = makeTable("Component") | |
directories = makeTable("Directory", createTransformFilename('DefaultDir')) | |
directories['APPDIR']['DefaultDir'] = GAME_DIR | |
directories['APPDIR']['Directory_Parent'] = '' | |
directoryMap = makeFullDirectoryMap(directories) | |
fileMap = makeFileMap(files, components, directoryMap) | |
return fileMap, directoryMap | |
def main(argv): | |
import os | |
fileMap, directoryMap = makeFileAndDirectoryMap() | |
print('Making directories:') | |
for i in sorted(directoryMap.values()): | |
if i.startswith(GAME_DIR): | |
print(i) | |
os.makedirs(i, exist_ok=True) | |
print('Moving files:') | |
for src, dest in fileMap.items(): | |
print(src + ' -> ' + dest) | |
os.rename(src, dest) | |
return 0 | |
if __name__ == '__main__': | |
import sys | |
sys.exit(main(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment