From: kaliko Date: Wed, 17 Dec 2014 16:58:21 +0000 (+0100) Subject: New virtualenv installer in pure python X-Git-Tag: 0.13.0~6 X-Git-Url: https://git.kaliko.me/?a=commitdiff_plain;h=59c6c698300f703949c43da0770f8b0eb130f0e0;p=mpd-sima.git New virtualenv installer in pure python --- diff --git a/INSTALL b/INSTALL index c622d77..ac0b895 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -Design for python >= 3.3 +Design for python >= 3.2 Requires: python-musicpd >= 0.4.0 [0], requests >= 2.2.0 [1] @@ -9,18 +9,20 @@ Requires: python-musicpd >= 0.4.0 [0], Virtualenv installation: -Run ./vinstall.sh to generate the python virtualenv and install requirements. +Run "python3 ./vinstall.py" to generate the python virtualenv and install +requirements (need at least python 3.3). -Default looks for python3 on the system. -It will setup a virtualenv within a "venv" directory (same level as vinstall.sh file). +It will setup a virtualenv within a "venv" directory (same level as vinstall.py file). It should also write a shell wrapper to run mpd-sima within the virtualenv. ./vmpd-sima --help -You might specify a python3 interpreter if the binary name differs from python3: +You might prefer manual installation: - PY3=/usr/bin/python ./vinstall.sh + # On your system may be "pyenv", "python3 -m venv" or "virtualenv" + # Refer to the relevant manual to install a python env, 3.2 minimum. -You can locate the virtalenv somewhere else: - - INSTALL_DIR=/tmp/crap_test/ ./vinstall.sh + ./venv + . ./venv/bin/activate + ./setup.py install + ./venv/bin/mpd-sima --help diff --git a/doc/Changelog b/doc/Changelog index 67b2cb2..06417aa 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,7 @@ MPD_sima v0.13.0 * Use of MusicBrainzIdentifier by default Please consider tagging your library with these metadata + * New virtualenv installer in pure python -- kaliko jack UNRELEASED diff --git a/vinstall.py b/vinstall.py new file mode 100755 index 0000000..842495c --- /dev/null +++ b/vinstall.py @@ -0,0 +1,149 @@ +# +# Copyright (C) 2013 Vinay Sajip. New BSD License. +# Copyright (C) 2014 Kaliko Jack +# +REQ_VER = (3,3) +import sys +if sys.version_info < REQ_VER: + print('Need at least python {0}.{1} to run this script'.format(*REQ_VER), file=sys.stderr) + sys.exit(1) + +import os +import os.path +import venv + +from subprocess import Popen, PIPE +from threading import Thread +from urllib.parse import urlparse +from urllib.request import urlretrieve +from shutil import rmtree + +class ExtendedEnvBuilder(venv.EnvBuilder): + """ + This builder installs setuptools and pip so that you can pip or + easy_install other packages into the created environment. + """ + + def __init__(self, *args, **kwargs): + self.verbose = kwargs.pop('verbose', False) + super().__init__(*args, **kwargs) + + def post_setup(self, context): + """ + Set up any packages which need to be pre-installed into the + environment being created. + + :param context: The information for the environment creation request + being processed. + """ + os.environ['VIRTUAL_ENV'] = context.env_dir + self.install_setuptools(context) + self.install_pip(context) + setup = os.path.abspath(os.path.join(context.env_dir, '../setup.py')) + self.install_script(context, 'sima', setup=setup) + + def reader(self, stream, context): + """ + Read lines from a subprocess' output stream and write progress + information to sys.stderr. + """ + while True: + s = stream.readline() + if not s: + break + if not self.verbose: + sys.stderr.write('.') + else: + sys.stderr.write(s.decode('utf-8')) + sys.stderr.flush() + stream.close() + + def install_script(self, context, name, url=None, setup=None): + if url: + binpath = context.bin_path + _, _, path, _, _, _ = urlparse(url) + fn = os.path.split(path)[-1] + distpath = os.path.join(binpath, fn) + # Download script into the env's binaries folder + urlretrieve(url, distpath) + if url: + args = [context.env_exe, fn] + else: + args = [context.env_exe, setup, 'install'] + binpath = os.path.dirname(setup) + if self.verbose: + term = '\n' + else: + term = '' + sys.stderr.write('Installing %s ...%s' % (name, term)) + sys.stderr.flush() + # Install in the env + p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath) + t1 = Thread(target=self.reader, args=(p.stdout, 'stdout')) + t1.start() + t2 = Thread(target=self.reader, args=(p.stderr, 'stderr')) + t2.start() + p.wait() + t1.join() + t2.join() + sys.stderr.write('done.\n') + if url: + # Clean up - no longer needed + os.unlink(distpath) + + def install_setuptools(self, context): + """ + Install setuptools in the environment. + + :param context: The information for the environment creation request + being processed. + """ + url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py' + self.install_script(context, 'setuptools', url) + # clear up the setuptools archive which gets downloaded + pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz') + files = filter(pred, os.listdir(context.bin_path)) + for f in files: + f = os.path.join(context.bin_path, f) + os.unlink(f) + + def install_pip(self, context): + """ + Install pip in the environment. + + :param context: The information for the environment creation request + being processed. + """ + url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py' + self.install_script(context, 'pip', url) + # pip installs to "local/bin" on Linux, but it needs to be accessible + # from "bin" since the "activate" script prepends "bin" to $PATH + pip_path = os.path.join(context.env_dir, 'local', 'bin', 'pip') + if sys.platform != 'win32' and os.path.exists(pip_path): + self.symlink_or_copy(pip_path, os.path.join(context.bin_path, 'pip')) + + +def main(args=None): + root = os.path.dirname(os.path.abspath(__file__)) + vdir = os.path.join(root, 'venv') + builder = ExtendedEnvBuilder(clear=True, verbose=False) + builder.create(vdir) + # clean up + for residu in ['MPD_sima.egg-info', 'dist', 'build']: + if os.path.exists(os.path.join(root, residu)): + rmtree(os.path.join(root, residu)) + # Write wrapper + with open(os.path.join(root, 'vmpd-sima'),'w') as fd: + fd.write('#!/bin/sh\n') + fd.write('. "{}/venv/bin/activate"\n'.format(root)) + fd.write('"{}/venv/bin/mpd-sima" "$@"'.format(root)) + os.chmod(os.path.join(root, 'vmpd-sima'), 0o744) + +if __name__ == '__main__': + rc = 1 + try: + main() + rc = 0 + except ImportError as e: + print('Error: %s' % e) + sys.exit(rc) diff --git a/vinstall.sh b/vinstall.sh deleted file mode 100755 index 1afb3b8..0000000 --- a/vinstall.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/sh -# -# vinstall.sh -# -# version: 0.2 : Date: 2013/11/13 -# -# TODO: -# * -DEBUG=${DEBUG:-"0"} # Set to 1 in order to enable DEBUG message. - ## Use "export DEBUG=1" in the calling script to enable it - ## or run: - # >$ DEBUG=1 script_name.sh - ## Only error message will be printed with DEBUG="0" - - -PY3=${PY3:-$(which python3)} - -# Test virtualenv presence -[ -x "$(which virtualenv)" ] || { echo "Cannot find virtualenv executable!"; exit 1; } -[ -x "$(which ${PY3})" ] || { echo "Cannot find a python3.3 interpreter!"; exit 1; } -[ "$DEBUG" != "0" ] && echo "python: $PY3" - -INSTALL_DIR=${INSTALL_DIR:-$(dirname $0)} -# canonicalize path -INSTALL_DIR=$(readlink -f ${INSTALL_DIR}) -[ "$DEBUG" != "0" ] && echo "install dir: $INSTALL_DIR" - -VENV_OPTIONS="--python=$PY3 --prompt="sima_venv" --no-site-packages --clear" -[ "$DEBUG" = "0" ] && VENV_OPTIONS="$VENV_OPTIONS --quiet" - -virtualenv $VENV_OPTIONS $INSTALL_DIR/venv || { echo "something went wrong generating virtualenv"; exit 1; } - -. $INSTALL_DIR/venv/bin/activate - -PIP_OPTIONS="" -[ "$DEBUG" = "0" ] && PIP_OPTIONS="$PIP_OPTIONS --quiet" - -pip install -e . || exit 1 - -echo Installing mpd-sima -$(dirname $0)/setup.py --quiet install || exit 1 - -deactivate - -SIMA_LAUNCHER=mpd-sima -SIMA_VLAUNCHER=$INSTALL_DIR/vmpd-sima - -cat << EOF > "$SIMA_VLAUNCHER" -#!/bin/sh -. $INSTALL_DIR/venv/bin/activate -$INSTALL_DIR/$SIMA_LAUNCHER "\$@" -EOF -chmod +x $SIMA_VLAUNCHER - -echo Cleaning up -rm -rf $(dirname $0)/dist -rm -rf $(dirname $0)/build -rm -rf $(dirname $0)/sima.egg-info - -echo - -# vim: fileencoding=utf8