diff --git a/README.asciidoc b/README.asciidoc index 8bfee7fbb..e6579115d 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -132,6 +132,7 @@ Contributors, sorted by the number of commits in descending order: * Claude * Peter Vilim * John ShaggyTwoDope Jenkins +* Patric Schmitz * rikn00 * Martin Zimmermann * Joel Torstensson diff --git a/doc/INSTALL.asciidoc b/doc/INSTALL.asciidoc index f75b09e26..6616c50a2 100644 --- a/doc/INSTALL.asciidoc +++ b/doc/INSTALL.asciidoc @@ -13,7 +13,7 @@ qutebrowser should run on these systems: Install the dependencies via apt-get: ---- -# apt-get install python3-pyqt5 python3-pyqt5.qtwebkit python-virtualenv +# apt-get install python3-pyqt5 python3-pyqt5.qtwebkit ---- To generate the documentation for the `:help` command, when using the git @@ -25,14 +25,14 @@ repository (rather than a release): ---- Then run the supplied script to run qutebrowser inside a -http://virtualenv.readthedocs.org/en/latest/[virtualenv]: +https://docs.python.org/3/library/venv.html[virtual environment]: ---- # python3 scripts/init_venv.py ---- This installs all needed Python dependencies in a `.venv` subfolder. The -system-wide Qt5/PyQt5 installations are symlinked into the virtualenv. +system-wide Qt5/PyQt5 installations are symlinked into the virtual environment. You can then create a simple wrapper script to start qutebrowser somewhere in your `$PATH` (e.g. `/usr/local/bin/qutebrowser` or `~/bin/qutebrowser`): @@ -102,19 +102,16 @@ Python 3 (be sure to install pip). * Use the installer from http://www.riverbankcomputing.com/software/pyqt/download5[Riverbank computing] to get Qt and PyQt5. -* Run `pip install virtualenv` or -http://www.lfd.uci.edu/~gohlke/pythonlibs/#virtualenv[the installer from here] -to install virtualenv. Then run the supplied script to run qutebrowser inside a -http://virtualenv.readthedocs.org/en/latest/[virtualenv]: +https://docs.python.org/3/library/venv.html[virtual environment]: ---- # python3 scripts/init_venv.py ---- This installs all needed Python dependencies in a `.venv` subfolder. The -system-wide Qt5/PyQt5 installations are used in the virtualenv. +system-wide Qt5/PyQt5 installations are used in the virtual environment. On OS X ------- diff --git a/scripts/init_venv.py b/scripts/init_venv.py index 89de817aa..da4f459ca 100644 --- a/scripts/init_venv.py +++ b/scripts/init_venv.py @@ -18,7 +18,7 @@ # You should have received a copy of the GNU General Public License # along with qutebrowser. If not, see . -"""Initialize a virtualenv suitable to be used for qutebrowser.""" +"""Initialize a venv suitable to be used for qutebrowser.""" import os import re @@ -30,6 +30,7 @@ import argparse import subprocess import distutils.sysconfig # pylint: disable=import-error # see https://bitbucket.org/logilab/pylint/issue/73/ +import venv sys.path.insert(0, os.path.join(os.path.dirname(__file__), os.pardir)) from scripts import utils @@ -42,28 +43,21 @@ g_args = None def parse_args(): """Parse the commandline arguments.""" parser = argparse.ArgumentParser() - parser.add_argument('--force', help="Force creating a new virtualenv.", + parser.add_argument('--clear', help="Clear venv in case it already exists.", + action='store_true') + parser.add_argument('--upgrade', help="Upgrade venv to use this version of " + "Python, assuming Python has been upgraded in-place.", + action='store_true') + parser.add_argument('--force', help=argparse.SUPPRESS, action='store_true') parser.add_argument('--dev', help="Set up an environment suitable for " - "developing qutebrowser.", + "developing qutebrowser.", action='store_true') - parser.add_argument('path', help="Path to the virtualenv folder", + parser.add_argument('path', help="Path to the venv folder", default='.venv', nargs='?') return parser.parse_args() -def check_exists(): - """Check if the virtualenv already exists.""" - if os.path.exists(g_path): - if g_args.force: - print("Deleting old virtualenv at {}".format(g_path)) - shutil.rmtree(g_path) - else: - print("virtualenv at {} does already exist!".format(g_path), - file=sys.stderr) - sys.exit(1) - - def get_dev_packages(short=False): """Get a list of packages to install. @@ -85,7 +79,7 @@ def install_dev_packages(): def venv_python(*args, output=False): - """Call the virtualenv's python with the given arguments.""" + """Call the venv's python with the given arguments.""" subdir = 'Scripts' if os.name == 'nt' else 'bin' executable = os.path.join(g_path, subdir, os.path.basename(sys.executable)) env = dict(os.environ) @@ -102,6 +96,7 @@ def venv_python(*args, output=False): def test_toolchain(): """Test if imports work properly.""" utils.print_title("Checking toolchain") + packages = ['sip', 'PyQt5.QtCore', 'PyQt5.QtWebKit', 'qutebrowser.app'] if g_args.dev: packages += get_dev_packages(short=True) @@ -113,41 +108,53 @@ def test_toolchain(): def link_pyqt(): - """Symlink the systemwide PyQt/sip into the virtualenv.""" - if os.name == 'nt': - return - utils.print_title("Softlinking PyQt5") + """Symlink the systemwide PyQt/sip into the venv.""" + action = "Copying" if os.name == 'nt' else "Softlinking" + utils.print_title("{} PyQt5".format(action)) sys_path = distutils.sysconfig.get_python_lib() venv_path = venv_python( '-c', 'from distutils.sysconfig import get_python_lib\n' 'print(get_python_lib())', output=True).rstrip() + globbed_sip = (glob.glob(os.path.join(sys_path, 'sip*.so')) + glob.glob(os.path.join(sys_path, 'sip*.pyd'))) if not globbed_sip: print("Did not find sip in {}!".format(sys_path), file=sys.stderr) sys.exit(1) + files = [ 'PyQt5', ] files += [os.path.basename(e) for e in globbed_sip] for fn in files: source = os.path.join(sys_path, fn) - link_name = os.path.join(venv_path, fn) + dest = os.path.join(venv_path, fn) if not os.path.exists(source): raise FileNotFoundError(source) - print('{} -> {}'.format(source, link_name)) - os.symlink(source, link_name) + if os.path.exists(dest): + os.unlink(dest) + print('{} -> {}'.format(source, dest)) + if os.name == 'nt': + if os.path.isdir(source): + shutil.copytree(source, dest) + else: + shutil.copy(source, dest) + else: + os.symlink(source, dest) def create_venv(): - """Create a new virtualenv.""" - utils.print_title("Creating virtualenv") + """Create a new venv.""" + utils.print_title("Creating venv") if os.name == 'nt': - sys_site = ['--system-site-packages'] + symlinks = False else: - sys_site = [] - subprocess.check_call(['virtualenv'] + sys_site + - ['-p', sys.executable, g_path]) + symlinks = True + clear = g_args.clear or g_args.force + builder = venv.EnvBuilder(system_site_packages=False, + clear=clear, upgrade=g_args.upgrade, + symlinks=symlinks, with_pip=True) + builder.create(g_path) def main(): @@ -158,10 +165,21 @@ def main(): print("Refusing to run with empty path!", file=sys.stderr) sys.exit(1) g_path = os.path.abspath(g_args.path) - check_exists() + + if os.path.exists(g_args.path) and not (g_args.force or g_args.clear or + g_args.upgrade): + print("{} does already exist! Use --clear or " + "--upgrade.".format(g_path), file=sys.stderr) + sys.exit(1) + create_venv() - utils.print_title("Calling setup.py") + + utils.print_title("Installing setuptools") + venv_python('-m', 'pip', 'install', 'setuptools') + + utils.print_title("Calling: setup.py develop") venv_python('setup.py', 'develop') + if g_args.dev: utils.print_title("Installing developer packages") install_dev_packages()