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
|
from distutils.cmd import Command
import os, sys
class depends(Command):
"""Download and install dependencies, if needed"""
description = "download and install dependencies, if needed"
user_options = [
('temp=', 't',
"directory where dependencies will be downloaded and built"),
('ignore-extra-args', 'i',
"ignore options that won't be passed to child setup scripts"),
]
path_attrs = [
# Note: these must be in *reverse* order, as they are pushed onto the
# *front* of a copy of sys.path.
('install','install_libbase'), # installation base if extra_path
('install_lib','install_dir'), # where modules are installed
]
# Command options that can be safely passed to dependencies' setup scripts
safe_opts = {
'install': [
'prefix','exec-prefix','home','install-base','install-platbase',
'root','optimize','force','verbose','quiet'
],
'build': ['compiler','debug','force','verbose','quiet'],
}
# Options with string arguments that are *not* directories or files, and
# so should *not* have absolute-path fixups applied.
non_fs_opts = {'build':['compiler'] }
def initialize_options(self):
self.temp = None; self.ignore_extra_args = None
def finalize_options(self):
self.set_undefined_options('build',('build_temp', 'temp'))
self.set_search_path()
self.set_subcommand_args()
def set_subcommand_args(self):
safe = {'install':[]} # ensure we at least perform an install
unsafe = {}
copts = self.distribution.get_cmdline_options()
if 'depends' in copts:
del copts['depends']
for cmd,opts in copts.items():
safe_opts = self.safe_opts.get(cmd,())
non_fs_opts = self.non_fs_opts.get(cmd,())
for opt,val in opts.items():
if opt in safe_opts:
cmdline = safe.setdefault(cmd,[])
if val is not None and opt not in non_fs_opts:
val = os.path.abspath(val)
else:
cmdline = unsafe.setdefault(cmd,[])
cmdline.append('--'+opt)
if val is not None:
cmdline.append(val)
self.safe_options = safe
self.unsafe_options = unsafe
def set_search_path(self):
"""Determine paths to check for installed dependencies"""
path = sys.path[:] # copy sys path
for cmd,attr in self.path_attrs:
dir = getattr(self.get_finalized_command(cmd),attr,None)
if dir and dir not in path:
path.insert(0,dir) # prepend
self.search_path = path
def run(self):
self.announce("checking for installed dependencies")
needed = [
dep for dep in self.distribution.requires if self.is_needed(dep)
]
if not needed:
self.announce("all dependencies are present and up-to-date")
return
argv = [sys.executable,'setup.py']
for cmd,line in self.safe_options.items():
argv.append(cmd); argv.extend(line)
self.announce(
"dependencies will be installed using:\n "+' '.join(argv)+'\n'
)
# Alert for unsupported commands/options, unless '-i' was used
if self.unsafe_options:
self.warn_unsafe_options_used()
if not self.ignore_extra_args:
raise SystemExit(
"Unsupported options for building dependencies; please"
" add 'depends -i'\nto your command line if you want to"
" force the build to proceed.\nOtherwise, you will need"
" to omit the unsupported options,\nor install the"
" dependencies manually."
)
# Alert the user to missing items
fmt = "\t%s\t%s\n"
items = [fmt % (dep.full_name(),dep.homepage) for dep in needed]
items.insert(0,"Please install the following packages *first*:\n")
items.append('')
raise SystemExit('\n'.join(items)) # dump msg to stderr and exit
def warn_unsafe_options_used(self):
lines = []; write = lines.append
write("the following command options are not supported for building")
write("dependencies, and will be IGNORED:")
for cmd,line in self.unsafe_options.items():
write('\t%s %s' % (cmd,' '.join(line)))
write('')
self.warn('\n'.join(lines))
def is_needed(self,dep):
"""Does the specified dependency need to be installed/updated?"""
self.announce("searching for "+dep.full_name())
version = dep.get_version(self.search_path)
if version is None:
self.announce(name+" not found!")
return True
if str(version)=="unknown":
status = dep.name+" is installed"
else:
status = dep.name+" version "+str(version)+" found"
if dep.version_ok(version):
self.announce(status+" (OK)")
return False
else:
self.announce(status+" (update needed)")
return True
|