root/packaging/centuryegg/find-srpms

Revision 13540, 20.9 KB (checked in by build, 8 months ago)

Correct our wrong way of trying to fix the protobuf spec file

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:mime-type set to text/python-source
Line 
1#!/usr/bin/env python
2
3import glob
4import logging
5import os
6import re
7import shutil
8try:
9    import subprocess
10except ImportError:
11    from fake_subprocess import subprocess
12import sys
13
14redhat_latest_version = 6
15fedora_latest_version = 14
16
17script = sys.argv[0]
18script = os.path.abspath(script)
19src_dir = os.path.dirname(script)
20os.chdir(src_dir)
21
22logging.getLogger().setLevel(logging.INFO)
23log_dir = os.path.join(src_dir, "logs")
24rpm_dir = os.path.join(src_dir, "rpms")
25srpm_dir = os.path.join(src_dir, "srpms")
26tmp_dir = os.path.join(src_dir, "tmp")
27rpmbuild_dir = os.path.join(os.getenv("HOME"), "rpmbuild")
28
29distro_order = []
30distro_download_urls = {}
31fedora_version = None
32if os.path.exists('/etc/redhat-release') and not os.path.exists('/etc/fedora-release'):
33    version = open('/etc/redhat-release').read().split(" ")[2]
34    if version == "Enterprise":         # Naming standard changed in RHEL 6
35        version = open('/etc/redhat-release').read().split(" ")[6]
36    if "." in version:
37        version = version.split(".")[0]
38    version = int(version)
39    if version > redhat_latest_version:
40        logging.error("Version of RedHat is %d, which is greater than latest supported version %d" % (version ,redhat_latest_version))
41        sys.exit(1)
42    distro_order = [str(v) for v in range(version, redhat_latest_version+1)]
43    download_urls = ["ftp://ftp.is.co.za/mirror/centos/$distro_version/os/SRPMS/"]
44    for d in distro_order:
45        distro_download_urls[d] = download_urls
46    if version < 6:
47        fedora_version = 6
48    else:
49        fedora_version = 14
50elif os.path.exists('/etc/fedora-release'):
51    version = open('/etc/fedora-release').read().split(" ")
52    for part in version:
53        if "." in part:
54            part = part.split(".")[0]
55        if part.isdigit():
56            version = int(part)
57            break
58    if not isinstance(version, int):
59        raise RuntimeError("Could not extract version from release %r" % version)
60    fedora_version = version
61if fedora_version:
62    if fedora_version > fedora_latest_version:
63        logging.error("Version of Fedora is %d, which is greater than latest supported version %d" % (fedora_version ,fedora_latest_version))
64        sys.exit(1)
65    f_distro_order = [str(v) for v in range(fedora_version, fedora_latest_version+1)]
66    distro_order.extend(f_distro_order)
67    for d in f_distro_order:
68        if int(d) >= 12:
69            distro_download_urls[d] = ["ftp://mirrors.kernel.org/fedora/releases/$distro_version/Everything/source/SRPMS/",
70                                       "ftp://mirrors.kernel.org/fedora/updates/$distro_version/SRPMS/",
71                                       "ftp://mirrors.kernel.org/fedora/updates/$distro_version/SRPMS.newkey/"]
72        else:
73            distro_download_urls[d] = ["ftp://archive.kernel.org/fedora-archive/fedora/linux/releases/$distro_version/Everything/source/SRPMS",
74                                       "ftp://archive.kernel.org/fedora-archive/fedora/linux/updates/$distro_version/SRPMS/",
75                                       "ftp://archive.kernel.org/fedora-archive/fedora/linux/updates/$distro_version/SRPMS.newkey/"]
76
77packages = sys.argv[1:]
78if not packages:
79    packages = [line.strip() for line in open(os.path.join(src_dir, "requirements-srpm"), "r").readlines() if line.strip()]
80
81def ensure_dir(dirname):
82    if not os.path.exists(dirname):
83        os.mkdir(dirname)
84
85ensure_dir(srpm_dir)
86ensure_dir(rpm_dir)
87ensure_dir(log_dir)
88
89os.chdir(srpm_dir)
90if sys.version_info[0] == 2 and sys.version_info[1] < 5:
91    if os.path.exists('/etc/redhat-release') and not os.path.exists('/etc/fedora-release'):
92        quote_defines = version < 5
93    else:
94        quote_defines = False
95    no_name_change = False
96    try_install = False
97    replace_python = True
98    python_exe = subprocess.Popen(["which", "python"+os.environ["PYTHON_SUFFIX"]], stdout=subprocess.PIPE).communicate()[0].replace("\n","")
99    if quote_defines:
100        rpmdefines = ["--define",'"__python %s"' % (python_exe)]
101    else:
102        rpmdefines = ["--define",'__python %s' % (python_exe)]
103    python_version = os.environ["PYTHON_VERSION"]
104else:
105    no_name_change = True
106    try_install = True
107    replace_python = False
108    python_exe = subprocess.Popen(["which", "python"], stdout=subprocess.PIPE).communicate()[0].replace("\n","")
109    rpmdefines = []
110    python_version = "%d.%d" % (sys.version_info[0], sys.version_info[1])
111    quote_defines = False
112
113# If this is CentOS < 5 or equivalent, blas-devel=blas, lapack-devel=lapack and gcc-gfortran=gcc4-gfortran
114old_fortran = version < 5
115# If this is < Fedora 8, python-setuptools-devel = python-setuptools
116old_python_setuptools = version < 8
117old_x11 = version < 5
118python_suffix = os.environ.get("PYTHON_SUFFIX","")
119python_suffix2 = os.environ.get("PYTHON_SUFFIX2","")
120
121REQUIREMENT_PARSER = re.compile("([^<=>]*)([<=>]+.*)?")
122
123def fix_package_name(package_name, force_version_marker=False):
124    """Fixes the package name to refer to python $PYTHON_SUFFIX - if the force_version_marker argument is True, $PYTHON_SUFFIX2 will be appended if no other method is found"""
125    # Replace the word python, but not python followed by a variable, as we don't know the purpose of the variable
126    if package_name == "Distutils":
127        return None
128    elif no_name_change:
129        return package_name
130    elif package_name == "tkinter":
131        return "tkinter"+python_suffix
132    elif re.match(r".*\bpython\b[^%]", package_name) or package_name.endswith("python"):
133        return re.sub(r"\bpython\b","python"+python_suffix,package_name)
134    elif re.match(r".*\bpython2\b[^%]", package_name) or package_name.endswith("python2"):
135        return re.sub(r"\bpython2\b","python"+python_suffix,package_name)
136    elif package_name.endswith("py"):
137        return package_name + python_suffix
138    elif package_name in ["protobuf", "cairo"]:
139        # we'll manually change the protobuf-python package, but not the rest
140        return package_name
141    elif old_x11 and re.match(r".*\blibX(11|render)-devel\b", package_name):
142        return re.sub(r"\blibX(11|render)-devel\b","xorg-x11-devel",package_name)
143    elif package_name.startswith("py"):
144        if package_name.endswith("-devel"):
145            return package_name.replace("-devel",python_suffix2+"-devel")
146        if package_name.endswith("-doc"):
147            return package_name.replace("-doc",python_suffix2+"-doc")
148        if package_name.endswith("-codegen"):
149            return package_name.replace("-codegen",python_suffix2+"-codegen")
150        return package_name + python_suffix2
151    elif force_version_marker:
152        return package_name + python_suffix2
153    return package_name
154
155not_found_packages = []
156failed_builds = []
157
158for p in packages:
159    min_p_version = None
160    min_package_version = 0
161    if ">=" in p:
162        p, min_p_version = p.split(">=")
163        min_p_version = min_p_version.strip()
164        if "-" in min_p_version:
165            min_p_version, min_package_version = min_p_version.split("-")
166            min_package_version = int(min_package_version)
167        min_p_version = [int(m) for m in min_p_version.split(".")]
168    p = p.strip()
169    new_p = fix_package_name(p, True)
170    existing_packages = glob.glob("../rpms/%s-*.rpm" % new_p)
171    if existing_packages:
172        logging.info("Not building %s because of existing packages %r" % (p, existing_packages))
173        continue
174    logfile = open(os.path.join(log_dir, "%s-fetch-srpm.log" % (p,)), "w")
175    if try_install:
176        if subprocess.Popen(["yum","info",p], stdout=subprocess.PIPE).communicate()[0] != "":
177            subprocess.call(["yum","install","-y",p], stdout=logfile, stderr=logfile)
178            continue
179    # Check for existence of a built package
180    for distro_version in distro_order:
181        print ("downloading %s from %s" % (p, distro_version))
182        # TODO: use yumdownloader to get mirroring etc - turns out to be tricky
183        # yumdownloader -c yum/yum-fedora-$distro_version.conf --source -e fedora-source --destdir=$HOME/Packaging/centuryegg/srpms $p
184        for parent_url in distro_download_urls[distro_version]:
185            url = "%s/%s-*.src.rpm" % (parent_url.replace("$distro_version", distro_version), p)
186            print ("trying %s" % (url,))
187            subprocess.call(["wget", "-c", url], stdout=logfile, stderr=logfile)
188        srpms = glob.glob("%s*.src.rpm" % (p,))
189        for s in srpms[:]:
190            if "*" in s:
191                srpms.remove(s)
192            elif not re.match("^%s-[0-9]" % p, s):
193                srpms.remove(s)
194            elif min_p_version:
195                s_version = s.replace(p,"")
196                s_package_version = s_version.split("-")[2].split(".")[0]
197                s_version = s_version.split("-")[1]
198                sd_version = []
199                for sd_p in re.split("[^0-9]",s_version):
200                    if sd_p.isdigit():
201                        sd_version.append(int(sd_p))
202                s_version = sd_version
203                for n, v in enumerate(min_p_version):
204                    if n > len(s_version):
205                        srpms.remove(s)
206                        break
207                    elif v > s_version[n]:
208                        srpms.remove(s)
209                        break
210                    elif v == s_version[n] and min_package_version > int(s_package_version):
211                        srpms.remove(s)
212                        break
213                    elif v < s_version[n]:
214                        break
215        if srpms:
216            break
217    src_rpm_files = srpms
218    src_rpm_files.sort()
219    if not src_rpm_files:
220        print ("could not find source rpm for %s" % (p,))
221        not_found_packages.append(p)
222        continue
223    src_rpm = src_rpm_files[-1]
224    subprocess.call(["rpm", "-ivh", "--nomd5", src_rpm])
225    specfile_name = os.path.join(rpmbuild_dir, "SPECS", "%s.spec" % (p,))
226    if not os.path.exists(specfile_name):
227        # Try strip version number off
228        specfile_name = os.path.join(rpmbuild_dir, "SPECS", "%s.spec" % (p[:-1],))
229    new_specfile_name = "%s.spec" % (new_p,)
230    lines = open(specfile_name, "r").readlines()
231    specfile = open(new_specfile_name, "w")
232    requirements = ""
233    package_name = ""
234    defines = {}
235    if p == "python-sqlalchemy" and version <= 4:
236        # In RedHat 4, strip off the first 8 lines - boolean logic old rpmtools can't handle
237        lines = [lines[1]] + lines[8:]
238    for line in lines:
239        if line.startswith("%define"):
240            key, value = line.replace("%define", "", 1).strip().split(" ", 1)
241            defines[key] = value
242        if line.startswith("%setup"):
243            if "-n" not in line:
244                line = line.rstrip("\n") + " -n %{name}-%{version}\n"
245        if replace_python and "python " in line and "with_python" not in line:
246            line = line.replace("/usr/bin/python ","%{__python} ").replace("python ", "%{__python} ")
247            line_parts = line.split()
248            if "install" in line_parts:
249                if not "-O1" in line_parts:
250                    line = line.replace("install", "install -O1", 1)
251            if ">=" in line_parts:
252                line = " ".join(line_parts[:line_parts.index(">=")])
253        if replace_python and "python -c " in line:
254            line = line.replace("python -c ", "%{__python} -c ")
255        # HACK for python-imaging and numpy - we always use setuptools, as sure as eggs is eggs:
256        if line.startswith("%if") and "%{?fedora}" in line and ">=" in line:
257            line = '%if "eggs" == "eggs"\n'
258        if replace_python and re.compile("^%(package|description|files).*").match(line) and "python" in line:
259            line = re.sub(r"\bpython\b", "python"+python_suffix, line)
260        if re.compile("^(Name|Provides|Requires|BuildRequires|BuildPre).*").match(line):
261            if line.startswith("Name:"):
262                package_name = line.replace("Name:", "", 1).strip()
263                new_package_name = fix_package_name(package_name, True)
264                if package_name != new_package_name:
265                    line = line.replace(package_name, new_package_name)
266                    line += "\n%%define name %s\n" % (package_name,)
267            elif line.startswith("Require") and "python-abi" in line:
268                # We take care of abi considerations, and this just confuses things
269                continue
270            elif replace_python and line.startswith("Build") and "pygtk2" in line:
271                # We don't compile with pygtk2 or tk support when replacing python - it conflicts too complicatedly
272                continue
273            else:
274                new_words = []
275                for word in line.split():
276                    if word.endswith(","):
277                        new_word = fix_package_name(word[:-1])
278                        if new_word:
279                            new_word += ","
280                    else:
281                        new_word = fix_package_name(word)
282                    if new_word:
283                        new_words.append(new_word)
284                line = " ".join(new_words) + "\n"
285            if line.startswith("Build"):
286                if old_fortran:
287                    line = line.replace("lapack-devel","lapack").replace("blas-devel","blas").replace("gcc-gfortran","gcc4-gfortran")
288                if old_python_setuptools:
289                    line = line.replace("setuptools-devel","setuptools")
290                requirements += " " + line[line.find(":")+1:]
291            elif line.startswith("Require"):
292                line = line.replace("%{name}", new_package_name)
293        # monkey-patch, we should have better ways for this
294        if line.startswith("%build") and package_name in ["pygtk2","pycairo", "pygobject2"]:
295            line += "export PYTHON=%{__python}\n"
296        if package_name == "python-matplotlib" and line.startswith(r"%{__python} setup.py build"):
297            specfile.write("sed -i -e 's/gtk = True/gtk = False/' -e 's/tkagg = True/tkagg = False/' -e 's/GTKAgg/Agg/' setup.cfg\n")
298        if line.startswith("%build") and package_name == "python-ldap":
299            specfile.write('sed -ie "/OPT_X_TLS_CRL\(CHECK\|_NONE\|_PEER\|_ALL\)/d" Modules/constants.c\n')
300        if line.startswith("%{python_sitelib}") and package_name == "pyparsing" and line.rstrip().endswith(".py"):
301            specfile.write("%%{python_sitelib}/%s-*-py%s.egg-info\n" % (package_name, python_version))
302        if line.startswith("%{python_sitelib}") and package_name in ["pytz", "python-dateutil"]:
303            specfile.write("%%{python_sitelib}/%s-*-py%s.egg-info\n" % (package_name.replace("-","_"), python_version))
304        if line.startswith("%{python_sitearch}") and package_name == "numpy":
305            specfile.write("%%{python_sitearch}/numpy-*-py%s.egg-info\n" % python_version)
306        if line.startswith("%{python_sitearch}") and package_name == "python-numarray":
307            specfile.write("%%{python_sitearch}/numarray-*-py%s.egg-info\n" % python_version)
308        if line.startswith('%if "%{fedora}" > "8"') and package_name == "python-xlrd":
309            # This is checking setuptools version, but we're using a modern one
310            line = line.replace("%{fedora}","9")
311        if line.startswith("%{python_sitearch}") and package_name == "python-imaging" and (line.rstrip().endswith(".py") or line.rstrip().endswith(".py*")):
312            specfile.write("%%{python_sitearch}/PIL/PIL-*-py%s.egg-info\n" % python_version)
313            # Redhat 5 and below version of python-imaging don't include this file
314            # FIXME: We should automatically get the retrieved package version to do this (the relevant version change is 1.1.5 -> 1.1.6)
315            if version > 5:
316                specfile.write("%%{python_sitearch}/pysane-*-py%s.egg-info\n" % python_version)
317        if "_tkagg.so" in line and package_name == "python-matplotlib":
318            if line.startswith("%exclude"):
319                specfile.write("%%{python_sitearch}/matplotlib-*-py%s.egg-info\n" % python_version)
320            continue
321        if "_xmlplus" in line and package_name == "PyXML" and version > 4:
322            specfile.write("%%{_libdir}/python%%pyver/site-packages/%s-*-py%s.egg-info\n" % (package_name, python_version))
323        if "_bindir" in line and package_name == "PyXML":
324            line = "%exclude "+line
325        if line.startswith("%{python_sitearch}") and package_name == "python-crypto" and (line.rstrip().endswith(".py") or line.rstrip().endswith("Crypto/*.py*")):
326            specfile.write("%%{python_sitearch}/pycrypto-*-py%s.egg-info\n" % python_version)
327        if package_name == "python-nose" and "nosetests-2.6" in line:
328            line = line.replace("2.6",os.environ["MIN_PYTHON_VERSION"])
329        if "with_python3 1" in line:
330            line = line.replace("with_python3 1","with_python3 0")
331        if package_name == "pyparsing" and line.startswith("%{python3_sitelib}"):
332            continue
333        if package_name == "python-sqlite2" and line.startswith("%dir %{python_sitearch}"):
334            specfile.write("%%{python_sitearch}/pysqlite-*-py%s.egg-info\n" % python_version)
335        if package_name == "protobuf" and "py2.5" in line:
336            line = line.replace("py2.5", "py%s" % python_version)
337        if version <= 4 and package_name == "python-sqlalchemy" and "filter_setup" in line or "filter_provides" in line:
338            continue
339        specfile.write(line)
340    specfile.close()
341    log_filename = os.path.join(log_dir, "%s-build-srpm.log" % (p,))
342    logfile = open(log_filename, "w")
343    if requirements.strip():
344        # TODO: split the requirements up, without splitting version requirements
345        requirements = requirements.replace(",", " ")
346        requirement_parts = [part for part in requirements.split() if part]
347        requirements = []
348        for part in requirement_parts:
349            if part[:1].isalpha():
350                requirements.append(" ")
351            if "%{" in part:
352                part = subprocess.Popen(["rpmbuild", "--nodeps", "-E", part, new_specfile_name], stdout=subprocess.PIPE).communicate()[0]
353                for key in re.compile("%{([^}]*)}").findall(part):
354                    if key in defines:
355                        part = part.replace("%%{%s}" % (key,), defines[key])
356            requirements.append(part)
357        requirements = "".join(requirements).strip().split()
358        requirement_names = []
359        for part in requirements:
360            m = REQUIREMENT_PARSER.match(part)
361            if m:
362                requirement_names.append(m.group(1))
363            else:
364                requirement_names.append(part)
365        for package in requirement_names[:]:
366            if subprocess.Popen(["rpm","-qa",package], stdout=subprocess.PIPE).communicate()[0]:
367                print "Requirement %s already installed" % package
368                requirement_names.remove(package)
369        build_reqs = []
370        print "resolving requirements:", requirements, " - searching without conditions as ", requirement_names
371        for line in subprocess.Popen(["yum", "resolvedep"] + requirement_names, stdout=subprocess.PIPE).communicate()[0].splitlines():
372            if " " in line:
373                continue
374            build_reqs.append(line)
375        if build_reqs:
376            retcode = subprocess.call(["sudo", "yum", "install", "-y"] + build_reqs)
377    if p == "protobuf":
378        if quote_defines:
379            rpmdefines.extend(["--define", '"_without_java 1"'])
380            rpmdefines.extend(["--define", '"_without_gtest 1"'])
381            rpmdefines.extend(["--define", '"_without_python 0"'])
382        else:
383            rpmdefines.extend(["--define", "_without_java 1"])
384            rpmdefines.extend(["--define", "_without_gtest 1"])
385            rpmdefines.extend(["--define", '_without_python 0'])
386    print "Build arguments: ",["rpmbuild"]+rpmdefines+["-ba",new_specfile_name]
387    retcode = subprocess.call(["rpmbuild"] + rpmdefines + ["-ba", new_specfile_name], stdout=logfile, stderr=logfile)
388    if retcode:
389        logging.warning("Error building source package for %s: tail of log file follows" % (p,))
390        print "".join(open(log_filename, "rb").readlines()[-10:])
391        failed_builds.append(p)
392        continue
393    rpm_arch = subprocess.Popen(["rpmbuild", "-E", "%{_arch}"], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0].strip()
394    rpmarch_dir = os.path.join(rpmbuild_dir, "RPMS", rpm_arch)
395    rpmnoarch_dir = os.path.join(rpmbuild_dir, "RPMS", "noarch")
396    if os.path.exists(rpmarch_dir):
397        for rpm_filename in [filename for filename in os.listdir(rpmarch_dir) if filename.startswith(new_p) and filename.endswith(".rpm")]:
398            logging.info("Copying built %s" % (rpm_filename,))
399            shutil.copyfile(os.path.join(rpmarch_dir, rpm_filename), os.path.join(rpm_dir, rpm_filename))
400    if os.path.exists(rpmnoarch_dir):
401        for rpm_filename in [filename for filename in os.listdir(rpmnoarch_dir) if filename.startswith(new_p) and filename.endswith(".rpm")]:
402            logging.info("Copying built %s" % (rpm_filename,))
403            shutil.copyfile(os.path.join(rpmnoarch_dir, rpm_filename), os.path.join(rpm_dir, rpm_filename))
404
405if not_found_packages:
406    sys.stderr.write("Packages not found: %s\n" % ",".join(not_found_packages))
407if failed_builds:
408    sys.stderr.write("Packages failed to build: %s\n" % ",".join(failed_builds))
409if not_found_packages or failed_builds:
410    sys.exit(1)
411
Note: See TracBrowser for help on using the browser.