]> kaliko git repositories - mpd-sima.git/blob - vinstall.py
Better error handling with python2
[mpd-sima.git] / vinstall.py
1 # Copyright (C) 2013 Vinay Sajip. New BSD License.
2 # Copyright (C) 2014 Kaliko Jack
3 #
4 from __future__ import print_function
5
6 REQ_VER = (3,3)
7 import sys
8 if sys.version_info < REQ_VER:
9     print('Need at least python {0}.{1} to run this script'.format(*REQ_VER), file=sys.stderr)
10     sys.exit(1)
11
12 import os
13 import os.path
14 import venv
15
16 from subprocess import Popen, PIPE
17 from threading import Thread
18 from urllib.parse import urlparse
19 from urllib.request import urlretrieve
20 from shutil import rmtree
21
22 class ExtendedEnvBuilder(venv.EnvBuilder):
23     """
24     This builder installs setuptools and pip so that you can pip or
25     easy_install other packages into the created environment.
26     """
27
28     def __init__(self, *args, **kwargs):
29         self.verbose = kwargs.pop('verbose', False)
30         super().__init__(*args, **kwargs)
31
32     def post_setup(self, context):
33         """
34         Set up any packages which need to be pre-installed into the
35         environment being created.
36
37         :param context: The information for the environment creation request
38                         being processed.
39         """
40         os.environ['VIRTUAL_ENV'] = context.env_dir
41         self.install_setuptools(context)
42         self.install_pip(context)
43         setup = os.path.abspath(os.path.join(context.env_dir, '../setup.py'))
44         self.install_script(context, 'sima', setup=setup)
45
46     def reader(self, stream, context):
47         """
48         Read lines from a subprocess' output stream and write progress
49         information to sys.stderr.
50         """
51         while True:
52             s = stream.readline()
53             if not s:
54                 break
55             if not self.verbose:
56                 sys.stderr.write('.')
57             else:
58                 sys.stderr.write(s.decode('utf-8'))
59             sys.stderr.flush()
60         stream.close()
61
62     def install_script(self, context, name, url=None, setup=None):
63         if url:
64             binpath = context.bin_path
65             _, _, path, _, _, _ = urlparse(url)
66             fn = os.path.split(path)[-1]
67             distpath = os.path.join(binpath, fn)
68             # Download script into the env's binaries folder
69             urlretrieve(url, distpath)
70         if url:
71             args = [context.env_exe, fn]
72         else:
73             args = [context.env_exe, setup, 'install']
74             binpath = os.path.dirname(setup)
75         if self.verbose:
76             term = '\n'
77         else:
78             term = ''
79         sys.stderr.write('Installing %s ...%s' % (name, term))
80         sys.stderr.flush()
81         # Install in the env
82         p = Popen(args, stdout=PIPE, stderr=PIPE, cwd=binpath)
83         t1 = Thread(target=self.reader, args=(p.stdout, 'stdout'))
84         t1.start()
85         t2 = Thread(target=self.reader, args=(p.stderr, 'stderr'))
86         t2.start()
87         p.wait()
88         t1.join()
89         t2.join()
90         sys.stderr.write('done.\n')
91         if url:
92             # Clean up - no longer needed
93             os.unlink(distpath)
94
95     def install_setuptools(self, context):
96         """
97         Install setuptools in the environment.
98
99         :param context: The information for the environment creation request
100                         being processed.
101         """
102         url = 'https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py'
103         self.install_script(context, 'setuptools', url)
104         # clear up the setuptools archive which gets downloaded
105         pred = lambda o: o.startswith('setuptools-') and o.endswith('.tar.gz')
106         files = filter(pred, os.listdir(context.bin_path))
107         for f in files:
108             f = os.path.join(context.bin_path, f)
109             os.unlink(f)
110
111     def install_pip(self, context):
112         """
113         Install pip in the environment.
114
115         :param context: The information for the environment creation request
116                         being processed.
117         """
118         url = 'https://raw.github.com/pypa/pip/master/contrib/get-pip.py'
119         self.install_script(context, 'pip', url)
120         # pip installs to "local/bin" on Linux, but it needs to be accessible
121         # from "bin" since the "activate" script prepends "bin" to $PATH
122         pip_path = os.path.join(context.env_dir, 'local', 'bin', 'pip')
123         if sys.platform != 'win32' and os.path.exists(pip_path):
124             self.symlink_or_copy(pip_path, os.path.join(context.bin_path, 'pip'))
125
126
127 def main(args=None):
128     root = os.path.dirname(os.path.abspath(__file__))
129     vdir = os.path.join(root, 'venv')
130     builder = ExtendedEnvBuilder(clear=True, verbose=False)
131     builder.create(vdir)
132     # clean up
133     for residu in ['MPD_sima.egg-info', 'dist', 'build']:
134         if os.path.exists(os.path.join(root, residu)):
135             rmtree(os.path.join(root, residu))
136     # Write wrapper
137     with open(os.path.join(root, 'vmpd-sima'),'w') as fd:
138         fd.write('#!/bin/sh\n')
139         fd.write('. "{}/venv/bin/activate"\n'.format(root))
140         fd.write('"{}/venv/bin/mpd-sima" "$@"'.format(root))
141     os.chmod(os.path.join(root, 'vmpd-sima'), 0o744)
142
143 if __name__ == '__main__':
144     rc = 1
145     try:
146         main()
147         rc = 0
148     except ImportError as e:
149         print('Error: %s' % e)
150     sys.exit(rc)