4 Create rpm packages of pyi2ncommon for various python versions.
8 make_dist.py [RELEASE [PY_VERSION_1 [PY_VERSION_2 ...]]]
10 RELEASE defaults to current git commit hash, default versions to build for are
11 3.6 for avocado and 3.3 for i2n system. All python versions used must be
12 installed on local machine.
14 Calls setup.py with different args. Adds %check section to .spec file. Runs
17 This script relies on one feature I accidentally stumbled over: it appears that
18 setting install-lib to /usr/lib/python{VERSION}/site-packages is translated by
19 setup.py to installation requirement python(abi) = {VERSION}
21 .. codeauthor:: Intra2net AG <info@intra2net.com>
25 from os.path import join, isfile
27 from subprocess import call, check_output
28 from tempfile import mkstemp
29 from configparser import ConfigParser
30 from glob import iglob
33 INSTALL_DIR_PATTERN = '/usr/lib/python{}/site-packages'
35 RPM_OPTIONS = dict(packager='Intra2net', group='Intra2net',
36 vendor='Intra2net AG')
39 SPEC_FILE = join(DIST_DIR, 'pyi2ncommon.spec')
41 CFG_FILE = 'setup.cfg'
44 # spec file created automatically by make_dist.sh -- do not modify!
48 SPEC_CHECK_SECTION = b"""%check
49 PYTHONPATH=./src:$PYTHONPATH && python3 -m unittest discover test
54 def check_py_version(py_version):
55 """Test that python version is installed."""
57 result = call(['python{}'.format(py_version), '--version'])
61 raise RuntimeError('Python version {} not installed, '
62 'run {} VERSION'.format(py_version, sys.argv[0]))
65 def run_unittests(py_version):
66 """Run unittests with given python version. Re-Run with LANG=C."""
67 # Run twice: first with environment copied from call (env=None) and one
68 # in empoverished environment without unicode capability
69 for env in None, dict(LANG='C', PATH=os.environ['PATH']):
71 print('Running unittests with python {} and env={}'
72 .format(py_version, env))
73 result = call(['python{}'.format(py_version), '-m', 'unittest',
75 except Exception as exc:
76 raise RuntimeError('Unittests with python {} and env={} failed. {}'
77 .format(py_version, env, exc))
79 raise RuntimeError('Unittests with python {} and env={} failed '
80 '(command returned {}).'
81 .format(py_version, env, result))
84 def run_setup(command, cmd_line_args=None, install_options=None,
87 Run python3 setup.py with command and options.
89 Need this function since setup.py bdist_rpm does not accept --prefix and
90 --install-lib options. Need to write them into cfg file from which they
91 are then read ... Grrr!
93 config = ConfigParser()
94 rpm_options = dict(RPM_OPTIONS.items())
96 rpm_options['requires'] = 'python3-zipfile35'
98 config['bdist_rpm'] = rpm_options
100 config['install'] = install_options
103 with open(CFG_FILE, mode='xt') as write_handle:
105 config.write(write_handle)
106 cmd = ['python3', 'setup.py', command]
110 raise RuntimeError('Running setup.py failed (cmd: {})'
111 .format(' '.join(cmd)))
118 def create_rpm(py_version, release):
119 """Create rpm that will install pyi2ncommon for given python version."""
120 print('Creating RPM for python version {}'.format(py_version))
122 # define options for where to install library;
123 # It appears this is automatically translated into requirement
124 # python(abi) = version !
125 install_options = {'prefix': '/'}
126 install_options['install-lib'] = INSTALL_DIR_PATTERN.format(py_version)
128 # if py_version is smaller than 3.5, need zipfile35 as extra dependency
129 need_zip35 = py_version.startswith('2') or py_version.startswith('3.0') or\
130 py_version.startswith('3.1') or py_version.startswith('3.2') or \
131 py_version.startswith('3.3') or py_version.startswith('3.4')
134 start_time = time.time()
135 run_setup('bdist_rpm', install_options=install_options,
136 cmd_line_args=['--release', release], need_zip35=need_zip35)
138 # find rpm and rename it
141 for filename in iglob(join(DIST_DIR, 'pyi2ncommon-*.noarch.rpm')):
142 filetime = os.stat(filename).st_mtime
143 if filetime > newest_time:
144 newest_time = filetime
145 newest_names = [filename, ]
146 elif filetime == newest_time:
147 newest_names.append(filename)
150 raise RuntimeError('No pyi2ncommon rpm file found in {}'
152 elif newest_time < start_time:
153 raise RuntimeError('Newest pyi2ncommon rpm file in {} is too old'
155 elif len(newest_names) > 1:
156 raise RuntimeError('Multiple newest pyi2ncommon rpm files: {}'
157 .format(newest_names))
158 newest_name = newest_names[0]
159 mod_name = newest_name[:-11] + '.py' + py_version.replace('.', '') + \
161 os.rename(newest_name, mod_name)
165 def create_spec(release):
166 """Create .spec file and modify it."""
167 print('adapting spec file')
169 run_setup('bdist_rpm', cmd_line_args=['--spec-only', '--release', release])
175 temp_handle, temp_file = mkstemp(dir=DIST_DIR, text=False,
176 prefix='pyi2ncommon-adapt-',
178 os.write(temp_handle, SPEC_START)
179 did_write_check = False
180 with open(SPEC_FILE, 'rb') as reader:
182 print('spec file: {}'.format(line.rstrip()))
183 if line.strip() == b'%install':
184 os.write(temp_handle, SPEC_CHECK_SECTION)
185 did_write_check = True
186 os.write(temp_handle, line)
187 os.close(temp_handle)
190 if not did_write_check:
191 raise RuntimeError('Could not find place to write %check section')
195 os.rename(temp_file, SPEC_FILE)
199 if temp_handle is not None:
200 os.close(temp_handle)
201 if temp_name is not None and isfile(temp_file):
208 Main function, called when running file as script
210 see module doc for more info
213 py_versions = ['3.7', ]
214 if len(sys.argv) > 1:
215 if sys.argv[1] in ('--help', '-h'):
216 print('make_dist.py [releasename [py-ver1 [py-ver2...]]]')
217 print(' e.g.: make_dist.py featuretest 3.7')
219 release = sys.argv[1].replace('-', '_')
221 release = check_output(['git', 'log', '--pretty=format:%h', '-n', '1'],
222 universal_newlines=True)
223 if len(sys.argv) > 2:
224 py_versions = sys.argv[2:]
226 for py_version in py_versions:
227 check_py_version(py_version)
228 run_unittests(py_version)
229 files_created.append(create_rpm(py_version, release))
230 files_created.append(create_spec(release))
232 for filename in files_created:
233 print('Created {}'.format(filename))
234 print('(+ probably source rpm and tar.gz)')
238 if __name__ == '__main__':