Platform specific directories now have one module for each platform.
Added some notes about install mode and build scripts sys.executable is no longer used. Added getSrcFolder for finding the src/ folder of a source checkout.
This commit is contained in:
parent
1e4ae2e688
commit
d1eda07ac1
@ -1,41 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def getUserFilesDirectory():
|
|
||||||
if sys.platform == "win32":
|
|
||||||
import win32api
|
|
||||||
# On Windows, sys.executable is codepage-encoded.
|
|
||||||
# It cannot represent all possible filenames, so get the exe filename
|
|
||||||
# using this wide-character API, which returns a `unicode`
|
|
||||||
exe = win32api.GetModuleFileNameW(None)
|
|
||||||
else:
|
|
||||||
# On OS X, the FS encoding is always UTF-8
|
|
||||||
# OS X filenames are defined to be UTF-8 encoded.
|
|
||||||
# On Linux, the FS encoding is given by the current locale
|
|
||||||
# Linux filenames are defined to be bytestrings.
|
|
||||||
exe = sys.executable.decode(sys.getfilesystemencoding())
|
|
||||||
|
|
||||||
assert os.path.exists(exe), "%r does not exist" % exe
|
|
||||||
if hasattr(sys, 'frozen'):
|
|
||||||
folder = os.path.dirname(exe)
|
|
||||||
else:
|
|
||||||
if exe.endswith("python") or exe.endswith("python.exe"):
|
|
||||||
script = sys.argv[0]
|
|
||||||
# assert the source checkout is not in a non-representable path...
|
|
||||||
assert os.path.exists(script), "Source checkout path cannot be represented with 'mbcs' encoding. Put the source checkout somewhere else."
|
|
||||||
folder = os.path.dirname(os.path.dirname(os.path.dirname(script))) # from src/mcedit, ../../
|
|
||||||
else:
|
|
||||||
folder = os.path.dirname(exe)
|
|
||||||
|
|
||||||
dataDir = os.path.join(folder, "MCEdit User Data")
|
|
||||||
|
|
||||||
if not os.path.exists(dataDir):
|
|
||||||
os.makedirs(dataDir)
|
|
||||||
return dataDir
|
|
||||||
|
|
||||||
def getUserSchematicsDirectory():
|
|
||||||
return os.path.join(getUserFilesDirectory(), "schematics")
|
|
||||||
|
|
||||||
def getUserPluginsDirectory():
|
|
||||||
return os.path.join(getUserFilesDirectory(), "plugins")
|
|
24
src/mcedit2/util/directories/__init__.py
Normal file
24
src/mcedit2/util/directories/__init__.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
"""
|
||||||
|
directories
|
||||||
|
|
||||||
|
Get platform specific user data folders.
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
if sys.platform == "win32":
|
||||||
|
from .win32 import getUserFilesDirectory
|
||||||
|
elif sys.platform == "darwin":
|
||||||
|
from .mac import getUserFilesDirectory
|
||||||
|
else:
|
||||||
|
from .posix import getUserFilesDirectory
|
||||||
|
|
||||||
|
|
||||||
|
def getUserSchematicsDirectory():
|
||||||
|
return os.path.join(getUserFilesDirectory(), "schematics")
|
||||||
|
|
||||||
|
def getUserPluginsDirectory():
|
||||||
|
return os.path.join(getUserFilesDirectory(), "plugins")
|
28
src/mcedit2/util/directories/mac.py
Normal file
28
src/mcedit2/util/directories/mac.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
mac
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# no build scripts for OS X yet. assuming py2app or py2installer will be used.
|
||||||
|
#
|
||||||
|
# store user files in source checkout folder
|
||||||
|
|
||||||
|
def getUserFilesDirectory():
|
||||||
|
|
||||||
|
# TODO if sys.getattr('frozen', False):
|
||||||
|
# TODO os.getenv('RESOURCEPATH') or sys.getattr('_MEIPASS'), etc etc...
|
||||||
|
|
||||||
|
# On OS X, the FS encoding is always UTF-8
|
||||||
|
# OS X filenames are defined to be UTF-8 encoded.
|
||||||
|
# We internally handle filenames as unicode.
|
||||||
|
|
||||||
|
script = sys.argv[0].decode(sys.getfilesystemencoding())
|
||||||
|
|
||||||
|
folder = os.path.dirname(os.path.dirname(os.path.dirname(script))) # main script is src/mcedit/main.py, so, ../../
|
||||||
|
dataDir = os.path.join(folder, "MCEdit User Data")
|
||||||
|
return dataDir
|
35
src/mcedit2/util/directories/posix.py
Normal file
35
src/mcedit2/util/directories/posix.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
"""
|
||||||
|
posix
|
||||||
|
"""
|
||||||
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# no build scripts for linux yet. no idea if frozen apps will be built for linux.
|
||||||
|
# assume always running from source checkout and put user files in source checkout.
|
||||||
|
|
||||||
|
# xxx for .whl or distro-specific distrib, put user files in ~/.mcedit2
|
||||||
|
|
||||||
|
def getUserFilesDirectory():
|
||||||
|
# On Linux, the FS encoding is given by the current locale
|
||||||
|
# Linux filenames are defined to be bytestrings.
|
||||||
|
|
||||||
|
# TODO: if not os.path.exists(os.path.join(mumble_mumble, ".git")):
|
||||||
|
|
||||||
|
# We handle filenames internally as 'unicode', so decode 'sys.argv[0]'
|
||||||
|
# If a linux filename cannot be decoded with the current locale, ignore it.
|
||||||
|
# If this filename is the script filename, you lose.
|
||||||
|
try:
|
||||||
|
# assert the source checkout is not in a non-representable path...
|
||||||
|
script = sys.argv[0].decode(sys.getfilesystemencoding())
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
print("Script filename %r cannot be decoded with the current locale %s! Please use sensible filenames." % (
|
||||||
|
sys.argv[0], sys.getfilesystemencoding()))
|
||||||
|
raise
|
||||||
|
|
||||||
|
folder = os.path.dirname(os.path.dirname(os.path.dirname(script))) # main script is src/mcedit/main.py, so, ../../
|
||||||
|
dataDir = os.path.join(folder, "MCEdit User Data")
|
||||||
|
return dataDir
|
57
src/mcedit2/util/directories/win32.py
Normal file
57
src/mcedit2/util/directories/win32.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# when running from source, put the user files in the source checkout
|
||||||
|
# when running from a built app ("frozen"), decide from install mode
|
||||||
|
|
||||||
|
# TODO how to do install mode?
|
||||||
|
# 1. two different downloads
|
||||||
|
# - .exe installer for system-wide/per-user install
|
||||||
|
# - .zip for self-contained/portable install
|
||||||
|
# 2. one download. prompt on first app startup for install mode. create INSTALL_MODE file in
|
||||||
|
# exe folder. check contents of file for install mode and prompt if file is missing.
|
||||||
|
# 3. like MCEdit1. option in app to change install mode and move user folder into app or docs folder
|
||||||
|
# check for presence of user folder in app folder on startup to decide install mode.
|
||||||
|
# 4. ALWAYS self-contained/portable install. same as MultiMC.
|
||||||
|
#
|
||||||
|
# ... also, get auto updater working. manually updating a self-contained install may be weird.
|
||||||
|
|
||||||
|
# I think 4 is the best.
|
||||||
|
from mcedit2.util import resources
|
||||||
|
|
||||||
|
PORTABLE_INSTALL = True
|
||||||
|
|
||||||
|
_userFilesDirectory = None
|
||||||
|
def getUserFilesDirectory():
|
||||||
|
global _userFilesDirectory
|
||||||
|
if _userFilesDirectory is not None:
|
||||||
|
return _userFilesDirectory
|
||||||
|
|
||||||
|
if hasattr(sys, 'frozen'):
|
||||||
|
# On Windows, filenames are UTF-16 encoded.
|
||||||
|
# Filenames are defined as UTF-16.
|
||||||
|
# However, sys.executable is codepage-encoded. Codepages cannot represent all possible
|
||||||
|
# filenames, so we must get the exe filename using this wide-character API.
|
||||||
|
# Wide-character APIs in pywin32 always return a `unicode`.
|
||||||
|
#
|
||||||
|
# Filenames must be passed to Python's filesystem functions as `unicode` to call the
|
||||||
|
# wide-character forms of the underlying Win32 APIs.
|
||||||
|
#
|
||||||
|
# We take care not to store filenames as `bytes`, as this causes the filesystem functions
|
||||||
|
# to use the legacy codepage APIs.
|
||||||
|
|
||||||
|
import win32api
|
||||||
|
exe = win32api.GetModuleFileNameW(None)
|
||||||
|
assert os.path.exists(exe), "MCEdit executable %r does not exist! Something is very wrong." % exe
|
||||||
|
folder = os.path.dirname(exe)
|
||||||
|
|
||||||
|
else:
|
||||||
|
folder = os.path.dirname(resources.getSrcFolder())
|
||||||
|
|
||||||
|
dataDir = os.path.join(folder, "MCEdit User Data")
|
||||||
|
|
||||||
|
if not os.path.exists(dataDir):
|
||||||
|
os.makedirs(dataDir)
|
||||||
|
|
||||||
|
_userFilesDirectory = dataDir
|
||||||
|
return dataDir
|
@ -8,15 +8,50 @@ import sys
|
|||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def getSrcFolder():
|
||||||
|
"""
|
||||||
|
Find the 'src/' folder of a source checkout.
|
||||||
|
|
||||||
|
...should maybe assert that '.git' exists?
|
||||||
|
:return: unicode
|
||||||
|
"""
|
||||||
|
import mcedit2
|
||||||
|
mod = os.path.realpath(mcedit2.__file__) # src/mcedit2/__init__.py
|
||||||
|
|
||||||
|
# On Windows, sys.argv[0] is always codepage-encoded, as is the __file__ attribute of any module.
|
||||||
|
# in fact, the entire module import subsystem of python2.7 is either restricted to codepages
|
||||||
|
# or to ASCII (haven't found out which) as `import` seems to break with non-ascii paths.
|
||||||
|
|
||||||
|
# On OS X, it is always UTF-8 encoded and filenames are *always* UTF-8 encoded.
|
||||||
|
|
||||||
|
# On Linux, it is locale-encoded and filenames are defined as bytestrings, so it is possible
|
||||||
|
# to have a filename that cannot be interpreted as unicode. If the user writes a filename
|
||||||
|
# that is not locale-encoded, he loses.
|
||||||
|
|
||||||
|
mod = mod.decode(sys.getfilesystemencoding())
|
||||||
|
|
||||||
|
# Assert the source checkout is not in a non-representable path...
|
||||||
|
assert os.path.exists(mod), ("Source checkout path cannot be represented as unicode. "
|
||||||
|
"Put the source checkout somewhere else.")
|
||||||
|
return os.path.dirname((os.path.dirname(mod)))
|
||||||
|
|
||||||
def resourcePath(filename):
|
def resourcePath(filename):
|
||||||
|
"""
|
||||||
|
Return the absolute path of a filename included as a resource.
|
||||||
|
|
||||||
|
"Resource" is not well-defined. When packaged with PyInstaller, the filename is found
|
||||||
|
relative to the app's folder (_MEIPASS). When running from source, it is relative to the
|
||||||
|
'src' folder. I'd imagine that when installed as a .whl (on linux) we need to use
|
||||||
|
pkg_resources to get filenames.
|
||||||
|
|
||||||
|
:param filename:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
filename = filename.replace('/', os.path.sep)
|
filename = filename.replace('/', os.path.sep)
|
||||||
basedir = getattr(sys, "_MEIPASS", None) # if pyinstaller'd
|
basedir = getattr(sys, "_MEIPASS", None) # if pyinstaller'd
|
||||||
if basedir is None:
|
if basedir is None:
|
||||||
import mcedit2
|
# should work across platforms
|
||||||
mod = mcedit2.__file__
|
basedir = getSrcFolder()
|
||||||
basedir = os.path.dirname(mod) + "/.."
|
|
||||||
basedir = os.path.normpath(basedir)
|
|
||||||
path = os.path.join(basedir, filename)
|
path = os.path.join(basedir, filename)
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise RuntimeError("Could not get resource path for %s\n(Tried %s which does not exist)" % (filename, path))
|
raise RuntimeError("Could not get resource path for %s\n(Tried %s which does not exist)" % (filename, path))
|
||||||
|
Reference in New Issue
Block a user