unified installer
This commit is contained in:
parent
11145a25be
commit
4a1f13b0c8
|
@ -1,173 +0,0 @@
|
|||
$InstallScript = @"
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import tempfile
|
||||
import tarfile
|
||||
import shutil
|
||||
from subprocess import Popen
|
||||
try: # py3
|
||||
from urllib.request import urlopen
|
||||
from winreg import OpenKey, CloseKey, QueryValueEx, SetValueEx, \
|
||||
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_EXPAND_SZ
|
||||
except ImportError: # py2
|
||||
from urllib import urlopen
|
||||
from _winreg import OpenKey, CloseKey, QueryValueEx, SetValueEx, \
|
||||
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_EXPAND_SZ
|
||||
|
||||
import ctypes
|
||||
from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM, LPVOID
|
||||
|
||||
|
||||
VENV_URL = 'https://pypi.python.org/pypi/virtualenv/json'
|
||||
APPDATA = os.environ['LocalAppData']
|
||||
APP = 'lektor-cli'
|
||||
LIB = 'lib'
|
||||
ROOT_KEY = HKEY_CURRENT_USER
|
||||
SUB_KEY = 'Environment'
|
||||
LRESULT = LPARAM
|
||||
HWND_BROADCAST = 0xFFFF
|
||||
WM_SETTINGCHANGE = 0x1A
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
if PY2:
|
||||
input = raw_input
|
||||
|
||||
|
||||
def get_confirmation():
|
||||
while 1:
|
||||
user_input = input('Continue? [Yn] ').lower().strip()
|
||||
if user_input in ('', 'y'):
|
||||
break
|
||||
elif user_input == 'n':
|
||||
print()
|
||||
print('Aborted!')
|
||||
sys.exit()
|
||||
|
||||
def find_location():
|
||||
install_dir = os.path.join(APPDATA, APP)
|
||||
return install_dir, os.path.join(install_dir, LIB)
|
||||
|
||||
def deletion_error(func, path, excinfo):
|
||||
print('Problem deleting {}'.format(path))
|
||||
print('Please try and delete {} manually'.format(path))
|
||||
print('Aborted!')
|
||||
sys.exit()
|
||||
|
||||
def wipe_installation(install_dir):
|
||||
shutil.rmtree(install_dir, onerror=deletion_error)
|
||||
|
||||
def check_installation(install_dir):
|
||||
if os.path.exists(install_dir):
|
||||
print(' Lektor seems to be installed already.')
|
||||
print(' Continuing will delete:')
|
||||
print(' %s' % install_dir)
|
||||
print()
|
||||
get_confirmation()
|
||||
print()
|
||||
wipe_installation(install_dir)
|
||||
|
||||
def fail(message):
|
||||
print('Error: %s' % message)
|
||||
sys.exit(1)
|
||||
|
||||
def add_to_path(location):
|
||||
reg_key = OpenKey(ROOT_KEY, SUB_KEY, 0, KEY_ALL_ACCESS)
|
||||
|
||||
try:
|
||||
path_value, _ = QueryValueEx(reg_key, 'Path')
|
||||
except WindowsError:
|
||||
path_value = ''
|
||||
|
||||
paths = path_value.split(';')
|
||||
if location not in paths:
|
||||
paths.append(location)
|
||||
path_value = ';'.join(paths)
|
||||
SetValueEx(reg_key, 'Path', 0, REG_EXPAND_SZ, path_value)
|
||||
|
||||
SendMessage = ctypes.windll.user32.SendMessageW
|
||||
SendMessage.argtypes = HWND, UINT, WPARAM, LPVOID
|
||||
SendMessage.restype = LRESULT
|
||||
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, u'Environment')
|
||||
|
||||
def _fetch_virtualenv():
|
||||
for url in json.load(urlopen(VENV_URL))['urls']:
|
||||
if url['python_version'] == 'source':
|
||||
virtualenv_url = url['url']
|
||||
#stripping '.tar.gz'
|
||||
virtualenv_filename = url['filename'][:-7]
|
||||
break
|
||||
else:
|
||||
fail('Could not find virtualenv')
|
||||
|
||||
t = tempfile.mkdtemp()
|
||||
with open(os.path.join(t, 'virtualenv.tar.gz'), 'wb') as f:
|
||||
download = urlopen(virtualenv_url)
|
||||
f.write(download.read())
|
||||
download.close()
|
||||
with tarfile.open(os.path.join(t, 'virtualenv.tar.gz'), 'r:gz') as tar:
|
||||
tar.extractall(path=t)
|
||||
|
||||
return os.path.join(t, virtualenv_filename)
|
||||
|
||||
def install_virtualenv(target_dir):
|
||||
# recent python versions include virtualenv
|
||||
cmd = [sys.executable, '-m', 'venv', target_dir]
|
||||
|
||||
try:
|
||||
import venv
|
||||
except ImportError:
|
||||
venv_dir = _fetch_virtualenv()
|
||||
venv_file = os.path.join(venv_dir, 'virtualenv.py')
|
||||
# in recent versions "virtualenv.py" moved to the "src" subdirectory
|
||||
if not os.path.exists(venv_file):
|
||||
venv_file = os.path.join(venv_dir, 'src', 'virtualenv.py')
|
||||
|
||||
cmd = [sys.executable, venv_file, target_dir]
|
||||
|
||||
Popen(cmd).wait()
|
||||
|
||||
def install(install_dir, lib_dir):
|
||||
os.makedirs(install_dir)
|
||||
os.makedirs(lib_dir)
|
||||
|
||||
install_virtualenv(lib_dir)
|
||||
|
||||
scripts = os.path.join(lib_dir, 'Scripts')
|
||||
Popen([os.path.join(scripts, 'pip.exe'),
|
||||
'install', '--upgrade', 'Lektor'],
|
||||
cwd=scripts).wait()
|
||||
|
||||
with open(os.path.join(install_dir, 'lektor.cmd'), 'w') as link_file:
|
||||
link_file.write('@echo off\n')
|
||||
link_file.write('\"' + os.path.join(scripts, 'lektor.exe') + '\"' + ' %*')
|
||||
|
||||
add_to_path(install_dir)
|
||||
|
||||
|
||||
def main():
|
||||
print()
|
||||
print('Welcome to Lektor')
|
||||
print()
|
||||
print('This script will install Lektor on your computer.')
|
||||
print()
|
||||
|
||||
install_dir, lib_dir = find_location()
|
||||
|
||||
check_installation(install_dir)
|
||||
|
||||
print(' Installing at:')
|
||||
print(' %s' % install_dir)
|
||||
print()
|
||||
get_confirmation()
|
||||
|
||||
install(install_dir, lib_dir)
|
||||
|
||||
print()
|
||||
print('All done!')
|
||||
|
||||
main()
|
||||
"@
|
||||
|
||||
|
||||
if (Get-Command python) { python -c $InstallScript } else { "To use this script you need to have Python installed"; exit }
|
|
@ -1,174 +0,0 @@
|
|||
#!/bin/sh
|
||||
# This script helps you install Lektor on your computer. Right now it
|
||||
# only supports Linux and OS X and only on OS X will it install the
|
||||
# desktop version.
|
||||
#
|
||||
# For more information see https://www.getlektor.com/
|
||||
|
||||
# Wrap everything in a function so that we do not accidentally execute
|
||||
# something we should not in case a truncated version of the script
|
||||
# is executed.
|
||||
I() {
|
||||
set -u
|
||||
|
||||
if ! hash python 2> /dev/null; then
|
||||
echo "Error: To use this script you need to have Python installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
python - <<'EOF'
|
||||
if 1:
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import tempfile
|
||||
import shutil
|
||||
from subprocess import CalledProcessError, check_output, Popen
|
||||
try:
|
||||
from urllib.request import urlopen
|
||||
except ImportError:
|
||||
from urllib import urlopen
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
if PY2:
|
||||
input = raw_input
|
||||
|
||||
sys.stdin = open('/dev/tty', 'r')
|
||||
|
||||
VENV_URL = "https://pypi.python.org/pypi/virtualenv/json"
|
||||
KNOWN_BINS = ['/usr/local/bin', '/opt/local/bin',
|
||||
os.path.join(os.environ['HOME'], '.bin'),
|
||||
os.path.join(os.environ['HOME'], '.local', 'bin')]
|
||||
|
||||
if os.environ.get('LEKTOR_SILENT') == None:
|
||||
prompt = True
|
||||
else:
|
||||
prompt = False
|
||||
|
||||
def find_user_paths():
|
||||
rv = []
|
||||
for item in os.environ['PATH'].split(':'):
|
||||
if os.access(item, os.W_OK) \
|
||||
and item not in rv \
|
||||
and '/sbin' not in item:
|
||||
rv.append(item)
|
||||
return rv
|
||||
|
||||
def bin_sort_key(path):
|
||||
try:
|
||||
return KNOWN_BINS.index(path)
|
||||
except ValueError:
|
||||
return float('inf')
|
||||
|
||||
def find_locations(paths):
|
||||
paths.sort(key=bin_sort_key)
|
||||
for path in paths:
|
||||
if path.startswith(os.environ['HOME']):
|
||||
return path, os.path.join(os.environ['HOME'],
|
||||
'.local', 'lib', 'lektor')
|
||||
elif path.endswith('/bin'):
|
||||
return path, os.path.join(
|
||||
os.path.dirname(path), 'lib', 'lektor')
|
||||
None, None
|
||||
|
||||
def get_confirmation():
|
||||
while 1:
|
||||
user_input = input('Continue? [Yn] ').lower().strip()
|
||||
if user_input in ('', 'y'):
|
||||
break
|
||||
elif user_input == 'n':
|
||||
print('')
|
||||
print('Aborted!')
|
||||
sys.exit()
|
||||
|
||||
def deletion_error(func, path, excinfo):
|
||||
print('Problem deleting {}'.format(path))
|
||||
print('Please try and delete {} manually'.format(path))
|
||||
print('Aborted!')
|
||||
sys.exit()
|
||||
|
||||
def wipe_installation(lib_dir, symlink_path):
|
||||
if os.path.lexists(symlink_path):
|
||||
os.remove(symlink_path)
|
||||
if os.path.exists(lib_dir):
|
||||
shutil.rmtree(lib_dir, onerror=deletion_error)
|
||||
|
||||
def check_installation(lib_dir, bin_dir):
|
||||
symlink_path = os.path.join(bin_dir, 'lektor')
|
||||
if os.path.exists(lib_dir) or os.path.lexists(symlink_path):
|
||||
print(' Lektor seems to be installed already.')
|
||||
print(' Continuing will delete:')
|
||||
print(' %s' % lib_dir)
|
||||
print(' and remove this symlink:')
|
||||
print(' %s' % symlink_path)
|
||||
print('')
|
||||
if prompt:
|
||||
get_confirmation()
|
||||
print('')
|
||||
wipe_installation(lib_dir, symlink_path)
|
||||
|
||||
def fail(message):
|
||||
print('Error: %s' % message)
|
||||
sys.exit(1)
|
||||
|
||||
def install(virtualenv_url, lib_dir, bin_dir):
|
||||
t = tempfile.mkdtemp()
|
||||
Popen('curl -sf "%s" | tar -xzf - --strip-components=1' %
|
||||
virtualenv_url, shell=True, cwd=t).wait()
|
||||
|
||||
try:
|
||||
os.makedirs(lib_dir)
|
||||
except OSError:
|
||||
pass
|
||||
try: # virtualenv 16.1.0, 17+
|
||||
check_output([sys.executable, './src/virtualenv.py', lib_dir], cwd=t)
|
||||
except CalledProcessError: # older virtualenv
|
||||
Popen([sys.executable, './virtualenv.py', lib_dir], cwd=t).wait()
|
||||
Popen([os.path.join(lib_dir, 'bin', 'pip'),
|
||||
'install', '--upgrade', 'Lektor']).wait()
|
||||
os.symlink(os.path.join(lib_dir, 'bin', 'lektor'),
|
||||
os.path.join(bin_dir, 'lektor'))
|
||||
|
||||
def main():
|
||||
print('')
|
||||
print('Welcome to Lektor')
|
||||
print('')
|
||||
print('This script will install Lektor on your computer.')
|
||||
print('')
|
||||
|
||||
paths = find_user_paths()
|
||||
if not paths:
|
||||
fail('None of the items in $PATH are writable. Run with '
|
||||
'sudo or add a $PATH item that you have access to.')
|
||||
|
||||
bin_dir, lib_dir = find_locations(paths)
|
||||
if bin_dir is None or lib_dir is None:
|
||||
fail('Could not determine installation location for Lektor.')
|
||||
|
||||
check_installation(lib_dir, bin_dir)
|
||||
|
||||
print('Installing at:')
|
||||
print(' bin: %s' % bin_dir)
|
||||
print(' app: %s' % lib_dir)
|
||||
print('')
|
||||
|
||||
if prompt: get_confirmation()
|
||||
|
||||
for url in json.loads(urlopen(VENV_URL).read().decode('utf-8'))['urls']:
|
||||
if url['python_version'] == 'source':
|
||||
virtualenv = url['url']
|
||||
break
|
||||
else:
|
||||
fail('Could not find virtualenv')
|
||||
|
||||
install(virtualenv, lib_dir, bin_dir)
|
||||
|
||||
print('')
|
||||
print('All done!')
|
||||
|
||||
main()
|
||||
EOF
|
||||
}
|
||||
|
||||
I
|
|
@ -0,0 +1,383 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import math
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
from subprocess import call
|
||||
|
||||
|
||||
_is_win = sys.platform == 'win32'
|
||||
|
||||
if not _is_win:
|
||||
sys.stdin = open('/dev/tty', 'r')
|
||||
|
||||
if sys.version_info[0] == 2:
|
||||
input = raw_input
|
||||
|
||||
prompt = os.environ.get('LEKTOR_SILENT') is None
|
||||
|
||||
def get_confirmation():
|
||||
if prompt is False:
|
||||
return
|
||||
|
||||
while True:
|
||||
user_input = input('Continue? [Yn] ').lower().strip()
|
||||
|
||||
if user_input in ('', 'y'):
|
||||
print('')
|
||||
return
|
||||
|
||||
if user_input == 'n':
|
||||
print('')
|
||||
print('Aborted!')
|
||||
sys.exit()
|
||||
|
||||
def fail(message):
|
||||
print('Error: %s' % message)
|
||||
sys.exit(1)
|
||||
|
||||
def multiprint(*lines):
|
||||
for line in lines:
|
||||
print(line)
|
||||
|
||||
|
||||
class Installer(object):
|
||||
APP_NAME = 'lektor'
|
||||
VIRTUALENV_URL = 'https://bootstrap.pypa.io/virtualenv.pyz'
|
||||
|
||||
def __init__(self):
|
||||
multiprint('',
|
||||
'Welcome to Lektor',
|
||||
'',
|
||||
'This script will install Lektor on your computer.',
|
||||
'')
|
||||
|
||||
self.compute_location()
|
||||
|
||||
self.prompt_installation()
|
||||
get_confirmation()
|
||||
|
||||
if self.check_installation():
|
||||
self.prompt_wipe()
|
||||
get_confirmation()
|
||||
|
||||
self.wipe_installation()
|
||||
|
||||
self.create_virtualenv()
|
||||
self.install_lektor()
|
||||
|
||||
multiprint('',
|
||||
'All done!')
|
||||
|
||||
def compute_location(self):
|
||||
# this method must set self.lib_dir
|
||||
raise NotImplementedError()
|
||||
|
||||
def check_installation(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def wipe_installation(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def prompt_installation(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def prompt_wipe(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def create_virtualenv(self):
|
||||
self.mkvirtualenv(self.lib_dir)
|
||||
|
||||
def install_lektor(self):
|
||||
call([self.get_pip(), 'install', '--upgrade', 'Lektor'])
|
||||
|
||||
def get_pip(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@classmethod
|
||||
def mkvirtualenv(cls, target_dir):
|
||||
"""
|
||||
Tries to create a virtualenv by using the built-in `venv` module,
|
||||
or using the `virtualenv` executable if present, or falling back
|
||||
to downloading the official zipapp.
|
||||
"""
|
||||
|
||||
created = False
|
||||
|
||||
try:
|
||||
from venv import EnvBuilder
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
# TODO: design decision needed:
|
||||
# on Debian and Ubuntu systems Python is missing `ensurepip`,
|
||||
# prompting the user to install `python3-venv` instead.
|
||||
# we could do the same, or go the download route...
|
||||
import ensurepip
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
venv = EnvBuilder(with_pip=True,
|
||||
symlinks=False if _is_win else True)
|
||||
venv.create(target_dir)
|
||||
created = True
|
||||
|
||||
if not created:
|
||||
try:
|
||||
from shutil import which
|
||||
except ImportError:
|
||||
from distutils.spawn import find_executable as which
|
||||
|
||||
venv_exec = which("virtualenv")
|
||||
if venv_exec:
|
||||
retval = call([venv_exec, '-p', sys.executable, target_dir])
|
||||
if retval:
|
||||
sys.exit(1)
|
||||
created = True
|
||||
|
||||
if not created:
|
||||
zipapp = cls.fetch_virtualenv()
|
||||
retval = call([sys.executable, zipapp, target_dir])
|
||||
os.unlink(zipapp)
|
||||
if retval:
|
||||
sys.exit(1)
|
||||
|
||||
@classmethod
|
||||
def fetch_virtualenv(cls):
|
||||
try:
|
||||
from urllib.request import urlretrieve
|
||||
except ImportError:
|
||||
from urllib import urlretrieve
|
||||
|
||||
fname = os.path.basename(cls.VIRTUALENV_URL)
|
||||
root, ext = os.path.splitext(fname)
|
||||
|
||||
zipapp = tempfile.mktemp(prefix=root+"-", suffix=ext)
|
||||
|
||||
with Progress() as hook:
|
||||
sys.stdout.write("Downloading virtualenv: ")
|
||||
urlretrieve(cls.VIRTUALENV_URL, zipapp, reporthook=hook)
|
||||
|
||||
return zipapp
|
||||
|
||||
@staticmethod
|
||||
def deletion_error(func, path, excinfo):
|
||||
print('Problem deleting {}'.format(path))
|
||||
print('Please try and delete {} manually'.format(path))
|
||||
print('Aborted!')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
_home = os.environ.get('HOME')
|
||||
|
||||
class PosixInstaller(Installer):
|
||||
KNOWN_BIN_PATHS = ['/usr/local/bin', '/opt/local/bin']
|
||||
if _home: # this is always true, but it needs not blow up on windows
|
||||
KNOWN_BIN_PATHS.extend([
|
||||
os.path.join(_home, '.bin'),
|
||||
os.path.join(_home, '.local', 'bin'),
|
||||
])
|
||||
|
||||
def prompt_installation(self):
|
||||
multiprint('Installing at:',
|
||||
' bin: %s' % self.bin_dir,
|
||||
' app: %s' % self.lib_dir,
|
||||
'')
|
||||
|
||||
def prompt_wipe(self):
|
||||
multiprint('Lektor seems to be installed already.',
|
||||
'Continuing will delete:',
|
||||
' %s' % self.lib_dir,
|
||||
'and remove this symlink:',
|
||||
' %s' % self.symlink_path,
|
||||
'')
|
||||
|
||||
def compute_location(self):
|
||||
"""
|
||||
Finds the preferred directory in the user's $PATH,
|
||||
and derives the lib dir from it.
|
||||
"""
|
||||
|
||||
paths = [
|
||||
item for item in os.environ['PATH'].split(':')
|
||||
if not item.endswith('/sbin') and os.access(item, os.W_OK)
|
||||
]
|
||||
|
||||
if not paths:
|
||||
fail('None of the items in $PATH are writable. Run with '
|
||||
'sudo or add a $PATH item that you have access to.')
|
||||
|
||||
def _sorter(path):
|
||||
try:
|
||||
return self.KNOWN_BIN_PATHS.index(path)
|
||||
except ValueError:
|
||||
return float('inf')
|
||||
|
||||
paths.sort(key=_sorter)
|
||||
|
||||
lib_dir = None
|
||||
|
||||
home = os.environ['HOME']
|
||||
for path in paths:
|
||||
if path.startswith(home):
|
||||
lib_dir = os.path.join(home, '.local', 'lib', self.APP_NAME)
|
||||
break
|
||||
|
||||
if path.endswith('/bin'):
|
||||
parent = os.path.dirname(path)
|
||||
lib_dir = os.path.join(parent, 'lib', self.APP_NAME)
|
||||
break
|
||||
|
||||
if lib_dir is None:
|
||||
fail('Could not determine installation location for Lektor.')
|
||||
|
||||
self.bin_dir = path
|
||||
self.lib_dir = lib_dir
|
||||
|
||||
@property
|
||||
def symlink_path(self):
|
||||
return os.path.join(self.bin_dir, self.APP_NAME)
|
||||
|
||||
def check_installation(self):
|
||||
return os.path.exists(self.lib_dir) \
|
||||
or os.path.lexists(self.symlink_path)
|
||||
|
||||
def wipe_installation(self):
|
||||
if os.path.lexists(self.symlink_path):
|
||||
os.remove(self.symlink_path)
|
||||
if os.path.exists(self.lib_dir):
|
||||
shutil.rmtree(self.lib_dir, onerror=self.deletion_error)
|
||||
|
||||
def get_pip(self):
|
||||
return os.path.join(self.lib_dir, 'bin', 'pip')
|
||||
|
||||
def install_lektor(self):
|
||||
import pdb
|
||||
super(PosixInstaller, self).install_lektor()
|
||||
|
||||
bin = os.path.join(self.lib_dir, 'bin', 'lektor')
|
||||
os.symlink(bin, self.symlink_path)
|
||||
|
||||
|
||||
class WindowsInstaller(Installer):
|
||||
APP_NAME = 'lektor-cli' # backwards-compatibility with previous installer
|
||||
LIB_DIR = 'lib'
|
||||
|
||||
def prompt_installation(self):
|
||||
multiprint('Installing at:',
|
||||
' %s' % self.install_dir,
|
||||
'')
|
||||
|
||||
def prompt_wipe(self):
|
||||
multiprint('Lektor seems to be installed already.',
|
||||
'Continuing will delete:',
|
||||
' %s' % self.install_dir,
|
||||
'')
|
||||
|
||||
def compute_location(self):
|
||||
install_dir = os.path.join(os.environ['LocalAppData'], self.APP_NAME)
|
||||
lib_dir = os.path.join(install_dir, self.LIB_DIR)
|
||||
|
||||
self.install_dir = install_dir
|
||||
self.lib_dir = lib_dir
|
||||
|
||||
def check_installation(self):
|
||||
return os.path.exists(self.install_dir)
|
||||
|
||||
def wipe_installation(self):
|
||||
shutil.rmtree(self.install_dir, onerror=self.deletion_error)
|
||||
|
||||
def get_pip(self):
|
||||
return os.path.join(self.lib_dir, 'Scripts', 'pip.exe')
|
||||
|
||||
def install_lektor(self):
|
||||
super(WindowsInstaller, self).install_lektor()
|
||||
|
||||
exe = os.path.join(self.lib_dir, 'Scripts', 'lektor.exe')
|
||||
link = os.path.join(self.install_dir, 'lektor.cmd')
|
||||
|
||||
with open(link, 'w') as link_file:
|
||||
link_file.write('@echo off\n')
|
||||
link_file.write('"%s" %%*' % exe)
|
||||
|
||||
self.add_to_path(self.install_dir)
|
||||
|
||||
@staticmethod
|
||||
def add_to_path(location):
|
||||
try:
|
||||
from winreg import (
|
||||
OpenKey, CloseKey, QueryValueEx, SetValueEx,
|
||||
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_EXPAND_SZ,
|
||||
)
|
||||
except ImportError: # py2
|
||||
from _winreg import (
|
||||
OpenKey, CloseKey, QueryValueEx, SetValueEx,
|
||||
HKEY_CURRENT_USER, KEY_ALL_ACCESS, REG_EXPAND_SZ,
|
||||
)
|
||||
import ctypes
|
||||
from ctypes.wintypes import HWND, UINT, WPARAM, LPARAM, LPVOID
|
||||
|
||||
HWND_BROADCAST = 0xFFFF
|
||||
WM_SETTINGCHANGE = 0x1A
|
||||
|
||||
reg_key = OpenKey(HKEY_CURRENT_USER, 'Environment', 0, KEY_ALL_ACCESS)
|
||||
|
||||
try:
|
||||
path_value, _ = QueryValueEx(reg_key, 'Path')
|
||||
except WindowsError:
|
||||
path_value = ''
|
||||
|
||||
paths = path_value.split(';')
|
||||
if location not in paths:
|
||||
paths.append(location)
|
||||
path_value = ';'.join(paths)
|
||||
SetValueEx(reg_key, 'Path', 0, REG_EXPAND_SZ, path_value)
|
||||
|
||||
SendMessage = ctypes.windll.user32.SendMessageW
|
||||
SendMessage.argtypes = HWND, UINT, WPARAM, LPVOID
|
||||
SendMessage.restype = LPARAM
|
||||
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, u'Environment')
|
||||
|
||||
|
||||
class Progress(object):
|
||||
"A context manager to be used as a urlretrieve reporthook."
|
||||
|
||||
def __init__(self):
|
||||
self.started = False
|
||||
|
||||
def progress(self, count, bsize, total):
|
||||
size = count * bsize
|
||||
|
||||
if size > total:
|
||||
progress = 100
|
||||
else:
|
||||
progress = math.floor(100 * size / total)
|
||||
|
||||
out = sys.stdout
|
||||
if self.started:
|
||||
out.write("\b" * 4)
|
||||
|
||||
out.write("%3d" % progress + "%")
|
||||
out.flush()
|
||||
|
||||
self.started = True
|
||||
|
||||
def finish(self):
|
||||
sys.stdout.write("\n")
|
||||
|
||||
def __enter__(self):
|
||||
return self.progress
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.finish()
|
||||
|
||||
|
||||
install = WindowsInstaller if _is_win \
|
||||
else PosixInstaller
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
install()
|
Loading…
Reference in New Issue