1#!/usr/local/bin/python3.8
2"""Script to create a source/binary RPM.
3"""
4# $Id: make_rpm.py 509841 2016-08-09 16:23:05Z boratyng $
5
6from __future__ import print_function
7import sys, os, shutil
8from optparse import OptionParser
9import subprocess
10import tarfile
11SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0]))
12sys.path.append(os.path.join(SCRIPT_DIR, ".."))
13from blast_utils import *   #IGNORE:W0401
14
15VERBOSE = False
16
17# Name of the temporary rpmbuild directory
18RPMBUILD_HOME = "rpmbuild"
19PACKAGE_NAME = ""
20# Name of the source TARBALL to create
21TARBALL = ""
22# Local RPM configuration file
23RPMMACROS = os.path.join(os.path.expanduser("~"), ".rpmmacros")
24
25def setup_rpmbuild():
26    """ Prepare local rpmbuild directory. """
27    cleanup_rpm()
28    os.mkdir(RPMBUILD_HOME)
29    for directory in [ 'BUILD', 'SOURCES', 'SPECS', 'SRPMS', 'tmp', 'RPMS' ]:
30        os.mkdir(os.path.join(RPMBUILD_HOME, directory))
31    cwd = os.getcwd()
32    os.chdir(os.path.join(RPMBUILD_HOME, 'RPMS'))
33    for subdir in [ 'i386', 'i586', 'i686', 'noarch', 'x86_64' ]:
34        os.mkdir(subdir)
35    os.chdir(cwd)
36
37    # Create ~/.rpmmacros
38    with open(RPMMACROS, "w") as out:
39        print("%_topdir %( echo", os.path.join(cwd, RPMBUILD_HOME), ")", file=out)
40        print("%_tmppath %( echo", end=' ', file=out)
41        print(os.path.join(cwd, RPMBUILD_HOME, "tmp"), ")", file=out)
42        print(file=out)
43        print("%packager Christiam E. Camacho (camacho@ncbi.nlm.nih.gov)", file=out)
44        print("%debug_package %{nil}", file=out)
45        if VERBOSE:
46            print("Created", RPMMACROS)
47
48def cleanup_rpm():
49    """ Delete rpm files """
50    if os.path.exists(RPMBUILD_HOME):
51        shutil.rmtree(RPMBUILD_HOME)
52
53    if os.path.exists(RPMMACROS):
54        os.remove(RPMMACROS)
55
56def cleanup_srctarball_contents():
57    """ Remove unnecessary directories/files from svn checkout """
58    import fnmatch
59
60    cmd = "find " + PACKAGE_NAME + " -type d -name .svn | xargs rm -fr "
61    safe_exec(cmd)
62
63    os.remove(os.path.join(PACKAGE_NAME, "Makefile"))
64    for path in ["builds", "scripts"]:
65        path = os.path.join(PACKAGE_NAME, path)
66        if os.path.exists(path):
67            shutil.rmtree(path)
68            if VERBOSE:
69                print("Deleting", path)
70
71    projects_path = os.path.join(PACKAGE_NAME, "c++", "scripts", "projects")
72    for root, dirs, files in os.walk(projects_path):
73        for name in files:
74            name = os.path.join(root, name)
75            if fnmatch.fnmatch(name, "*blast/*"):
76                continue
77            if VERBOSE:
78                print("Deleting file", name)
79            os.remove(name)
80
81        for name in dirs:
82            name = os.path.join(root, name)
83            if fnmatch.fnmatch(name, "*blast*"):
84                continue
85            if VERBOSE:
86                print("Deleting directory", name)
87            shutil.rmtree(name)
88
89
90def decompress_src_tarball(srctarball):
91    """Decompreses the source tarball provided"""
92    tar = tarfile.open(srctarball)
93    os.mkdir(PACKAGE_NAME)
94    cwd = os.getcwd()
95    os.chdir(os.path.join(cwd, PACKAGE_NAME))
96    tar.list()
97    tar.extractall()
98    os.chdir(cwd)
99    cleanup_srctarball_contents()
100
101def compress_sources():
102    """Compress sources to be included in source RPM"""
103    tar = tarfile.open(TARBALL, "w:bz2")
104    tar.add(PACKAGE_NAME)
105    tar.close()
106
107def cleanup():
108    """ Remove all files created. """
109    if os.path.exists(TARBALL):
110        os.remove(TARBALL)
111    if os.path.exists(PACKAGE_NAME):
112        shutil.rmtree(PACKAGE_NAME)
113
114def run_rpm(blast_version):
115    """Run the rpmbuild command"""
116    shutil.rmtree(PACKAGE_NAME)
117    shutil.move(TARBALL, os.path.join(RPMBUILD_HOME, "SOURCES"))
118    rpm_spec = "ncbi-magicblast.spec"
119    src = os.path.join(SCRIPT_DIR, rpm_spec)
120    dest = os.path.join(RPMBUILD_HOME, "SPECS", rpm_spec)
121    shutil.copyfile(src, dest)
122    update_blast_version(dest, blast_version)
123    cmd = "/usr/bin/rpmbuild -ba " + dest
124    safe_exec(cmd)
125
126def move_rpms_to_installdir(installdir):
127    """Copy the resulting RPM files into the installation directory"""
128    installer_dir = os.path.join(installdir, "installer")
129    if not os.path.exists(installer_dir):
130        os.makedirs(installer_dir)
131
132    args = [ "find", RPMBUILD_HOME, "-name", "*.rpm" ]
133    output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
134    for rpm in output.split():
135        rpm = rpm.decode('ascii')
136        if VERBOSE:
137            print("mv", rpm, installer_dir)
138        shutil.move(rpm, installer_dir)
139
140
141def main():
142    """ Creates RPMs for linux. """
143    parser = OptionParser("%prog <blast_version> <installation directory> \
144                          \"<srctarball>\"")
145    parser.add_option("-v", "--verbose", action="store_true", default=False,
146                      help="Show verbose output", dest="VERBOSE")
147    options, args = parser.parse_args()
148    if len(args) != 3:
149        parser.error("Incorrect number of arguments")
150        return 1
151
152    # N.B.: srctarball may be an empty argument (i.e.: "") in case of local
153    # builds, but this script shouldn't be invoked in that case
154    blast_version, installdir, srctarball = args
155    global VERBOSE, PACKAGE_NAME, TARBALL #IGNORE:W0603
156    VERBOSE = options.VERBOSE
157    if VERBOSE:
158        print("Installing RPM to", installdir)
159
160    PACKAGE_NAME = "ncbi-magicblast-" + blast_version
161    TARBALL = PACKAGE_NAME + ".tgz"
162
163    setup_rpmbuild()
164    cleanup()
165    decompress_src_tarball(srctarball)
166    compress_sources()
167    run_rpm(blast_version)
168    move_rpms_to_installdir(installdir)
169    cleanup_rpm()
170    cleanup()
171
172if __name__ == "__main__":
173    sys.exit(main())
174