Skip to content

Commit

Permalink
Fix bug on MacOS where selecting .app file wouldn't be recognized, by…
Browse files Browse the repository at this point in the history
… making user path selection more robust
  • Loading branch information
drojf committed Mar 28, 2019
1 parent f0106a5 commit 06e6aa2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 19 deletions.
34 changes: 34 additions & 0 deletions gameScanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,37 @@ def scanForFullInstallConfigs(subModConfigList, possiblePaths=None):
pass

return returnedFullConfigs

def scanUserSelectedPath(subModConfigList, gameExecutablePath):
# type: (List[SubModConfig], [str]) -> ([FullInstallConfiguration], str)
"""
Scans a user-selected path for configs. Unlike the normal "scanForFullInstallConfigs()" function,
this will attempt to search all parent directories, incase a user has selected a subdirectory of the game directory
by accident.
:param subModConfigList:
:param gameExecutablePath:
:return: A tuple - The first is an array of valid FullInstallConfigurations.
- The second is an error message (on success a 'success' message is generated)
"""
if gameExecutablePath:
if os.path.isfile(gameExecutablePath):
gameExecutablePath = os.path.dirname(gameExecutablePath)

# Search upwards for the game path, in case user has selected a deep subfolder of the game path
alreadyScanned = set()
for scanAttempt in range(10):
fullInstallConfigs = scanForFullInstallConfigs(subModConfigList=subModConfigList, possiblePaths=[gameExecutablePath])
if fullInstallConfigs:
return fullInstallConfigs, "scanUserSelectedPath(): Path [{}] Ok".format(gameExecutablePath)

alreadyScanned.add(gameExecutablePath)
gameExecutablePath = os.path.dirname(gameExecutablePath)
if gameExecutablePath in alreadyScanned:
break

# Failed to find path. Notify user which paths tried to be searched to find the file.
errorStrings = ["scanUserSelectedPath(): Can't install the mod. Searched:"] + sorted(list(alreadyScanned))
errorMessage = '\n - '.join(errorStrings)
return None, errorMessage

return None, "scanUserSelectedPath(): game executable path is falsey: [{}]".format(gameExecutablePath)
22 changes: 15 additions & 7 deletions httpGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import tkFileDialog as filedialog

collapseWhiteSpaceRegex = re.compile(r"[\s\b]+")
def _TKAskGameExe(subMod):
def _TKAskPath(subMod):
# TODO: on 2.7 you can use .withdraw on the root window, but on python 3 it prevents the filedialog from showing!
# TODO: for now, put up with the root window showing when choosing path manually
root = Tk()
Expand All @@ -46,8 +46,6 @@ def _TKAskGameExe(subMod):

# returns empty string if user didn't select any file or folder. If a file is selected, convert it to the parent folder
installFolder = filedialog.askopenfilename(filetypes=fileList)
if os.path.isfile(installFolder):
installFolder = os.path.normpath(os.path.join(installFolder, os.pardir))

root.destroy()

Expand Down Expand Up @@ -271,12 +269,19 @@ def __init__(self, allSubModConfigs):
self.messageBuffer = []
self.threadHandle = None

def try_start_install(self, subMod, installPath):
# TODO: this function should return an error message describing why the install couldn't be started
def try_start_install(self, subMod, installPath, pathIsManual):
import higurashiInstaller
import uminekoInstaller
import threading

fullInstallConfigs = gameScanner.scanForFullInstallConfigs([subMod], possiblePaths=[installPath])
# if the path was user selected, do some extra processing on the path
if pathIsManual:
fullInstallConfigs, errorMessage = gameScanner.scanUserSelectedPath([subMod], installPath)
print(errorMessage)
else:
fullInstallConfigs = gameScanner.scanForFullInstallConfigs([subMod], possiblePaths=[installPath])

if not fullInstallConfigs:
return False

Expand Down Expand Up @@ -359,11 +364,14 @@ def getGamePathsHandler(requestData):
def startInstallHandler(requestData):
id = requestData['id']
subMod = self.idToSubMod[id]
pathIsManual = False
installPath = requestData.get('installPath', None)

if installPath is None:
installPath = _TKAskGameExe(subMod)
pathIsManual = True
installPath = _TKAskPath(subMod)

return { 'installStarted' : self.try_start_install(subMod, installPath) }
return { 'installStarted' : self.try_start_install(subMod, installPath, pathIsManual) }

# requestData: Not necessary - will be ignored
# responseData: Returns a list of dictionaries. Each dictionary may have different fields depending on the
Expand Down
23 changes: 11 additions & 12 deletions installerGUI.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,17 @@ def askGameExeAndValidate():
fileList = [("Game Executable", x) for x in extensionList]
fileList.append(("Any In Game Folder", "*.*"))

gameExecutablePath = filedialog.askopenfilename(filetypes=fileList)
if gameExecutablePath:
if not os.path.isdir(gameExecutablePath):
gameExecutablePath= os.path.normpath(os.path.join(gameExecutablePath, os.pardir))

fullInstallConfigs = gameScanner.scanForFullInstallConfigs(subModConfigList=[subMod], possiblePaths=[gameExecutablePath])
if fullInstallConfigs:
print("Path Ok: ", gameExecutablePath)
self.confirmationPage(fullInstallConfigs[0])
else:
print("Path INVALID:", gameExecutablePath)
messagebox.showerror("Error", "Can't install the mod to the path\n" + gameExecutablePath)
userSelectedPath = filedialog.askopenfilename(filetypes=fileList)
if not userSelectedPath:
return

fullInstallConfigs, errorMessage = gameScanner.scanUserSelectedPath(subModConfigList=[subMod], gameExecutablePath=userSelectedPath)
print(errorMessage)
if fullInstallConfigs:
self.confirmationPage(fullInstallConfigs[0])
return
else:
messagebox.showerror("Error", errorMessage)

# do search over all possible install locations that the selected submod can be installed.
fullInstallConfigs = gameScanner.scanForFullInstallConfigs([subMod])
Expand Down

0 comments on commit 06e6aa2

Please sign in to comment.