-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootstrap.py
172 lines (151 loc) · 5.95 KB
/
bootstrap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python
"""
Bootstrap script for prepare environ for project
"""
import os
import subprocess
import optparse
import sys
import urllib2
BOOTSTRAP_MOD = 'bootstrap'
BOOTSTRAP_ETAG = '._' + BOOTSTRAP_MOD + '.etag'
BOOTSTRAP_PY = BOOTSTRAP_MOD + '.py'
BOOTSTRAP_URL = 'https://raw.github.com/jellycrystal/bootstrap/master/bootstrap.py'
DEFAULT_PRE_REQS = ['virtualenv']
def _warn(msg):
sys.stderr.write("Warn: %s\n" % (msg,))
def _err(msg):
sys.stderr.write("Error: %s\n" % (msg,))
sys.exit(1)
def get_pre_reqs(pre_req_txt):
"""Getting list of pre-requirement executables"""
try:
pre_reqs = open(pre_req_txt).readlines()
except IOError:
_warn("Couldn't find pre-reqs file: %s, use default pre-reqs" % pre_req_txt)
# There are no pre-reqs yet.
pre_reqs = DEFAULT_PRE_REQS
for pre_req in pre_reqs:
pre_req = pre_req.strip()
# Skip empty lines and comments
if not pre_req or pre_req.startswith('#'):
continue
yield pre_req
def check_pre_req(pre_req):
"""Check for pre-requirement"""
if subprocess.call(['which', pre_req],
stderr=subprocess.PIPE, stdout=subprocess.PIPE) == 1:
_err("Couldn't find '%s' in PATH" % pre_req)
def provide_virtualenv(ve_target, no_site=True):
"""Provide virtualenv"""
args = ['--distribute']
if no_site:
args.append('--no-site')
if not os.path.exists(ve_target):
subprocess.call(['virtualenv'] + args + [ve_target])
def install_pip_requirements(ve_target, upgrade=False):
"""Install required Python packages into virtualenv"""
pip_path = os.path.join(ve_target, 'bin', 'pip')
call_args = [pip_path, 'install', '-r', 'requirements.txt']
if upgrade:
call_args.append('--upgrade')
if subprocess.call(call_args):
_err("Failed to install requirements")
def pass_control_to_doit(ve_target):
"""Passing further control to doit"""
try:
import dodo
except ImportError:
return
if hasattr(dodo, 'task_bootstrap'):
doit = os.path.join(ve_target, 'bin', 'doit')
subprocess.call([doit, 'bootstrap'])
def do(func, *args, **kwargs):
"""Announce func.__doc__ and run func with provided arguments"""
doc = getattr(func, '__doc__')
if doc is None:
doc = func.__name__
func_args = ', '.join(str(a) for a in args)
func_kwargs = ', '.join("%s=%s" % (k, str(v))
for k, v in kwargs.iteritems())
msg = "%s... %s %s\n" % (doc, func_args, func_kwargs)
sys.stderr.write(msg)
return func(*args, **kwargs)
def bootstrap(pre_req_txt, ve_target, no_site=True, upgrade=False):
ve_target = os.path.normpath(os.path.abspath(ve_target))
os.environ['BOOTSTRAP_VIRTUALENV_TARGET'] = ve_target
for pre_req in do(get_pre_reqs, pre_req_txt):
do(check_pre_req, pre_req)
do(provide_virtualenv, ve_target, no_site=no_site)
do(install_pip_requirements, ve_target, upgrade=upgrade)
do(pass_control_to_doit, ve_target)
def update(**kwargs):
"""
Self-update bootstrapping script.
"""
# Idea taken from
# http://tarekziade.wordpress.com/2011/02/10/a-simple-self-upgrade-build-pattern/
if kwargs.pop('disable_bootstrap_update', False):
bootstrap(**kwargs)
headers = {}
etag = current_etag = None
# Getting the file age
if os.path.exists(BOOTSTRAP_ETAG):
with open(BOOTSTRAP_ETAG) as fh:
current_etag = fh.read().strip()
headers['If-None-Match'] = current_etag
request = urllib2.Request(BOOTSTRAP_URL, headers=headers)
# Checking the last version on server
try:
sys.stderr.write("Fetching bootstrap's updates from %s..." %
BOOTSTRAP_URL)
url = urllib2.urlopen(request, timeout=5)
etag = url.headers.get('ETag')
except urllib2.HTTPError, e:
if e.getcode() not in (304, 412):
raise
# We're up to date -- 412 precondition failed
etag = current_etag
sys.stderr.write("Done. Up to date.\n")
except urllib2.URLError:
# Timeout error
etag = None
sys.stderr.write("Fail. Connection error.\n")
if etag is not None and current_etag != etag:
sys.stderr.write("Done. New version available.\n")
# We should update our version
content = url.read()
with open(BOOTSTRAP_PY, 'w') as fh:
fh.write(content)
with open(BOOTSTRAP_ETAG, 'w') as fh:
fh.write(etag)
sys.stderr.write("Bootstrap is updated to %s version.\n" % etag)
mod = __import__(BOOTSTRAP_MOD)
mod.bootstrap(**kwargs)
def main(args):
parser = optparse.OptionParser()
parser.add_option("-p", "--pre-requirements", dest="pre_requirements",
default="pre-reqs.txt", action="store", type="string",
help="File with list of pre-reqs")
parser.add_option("-E", "--virtualenv", dest="virtualenv",
default='ve', action="store", type="string",
help="Path to virtualenv to use")
parser.add_option("-s", "--no-site", dest="no_site",
default=False, action="store_true",
help="Don't use global site-packages on create virtualenv")
parser.add_option("-u", "--upgrade", dest="upgrade",
default=False, action="store_true",
help="Upgrade packages")
parser.add_option("-b", "--disable-bootstrap-update",
dest="disable_bootstrap_update", default=False,
action="store_true",
help="Disable self-update of bootstrap script.")
options, args = parser.parse_args(args)
update(
disable_bootstrap_update=options.disable_bootstrap_update,
pre_req_txt=options.pre_requirements,
ve_target=options.virtualenv,
no_site=options.no_site,
upgrade=options.upgrade)
if __name__ == '__main__':
main(sys.argv)