Completed
Push — master ( 9decde...ada47f )
by John
02:36
created

get_ucrt_dlls()   A

Complexity

Conditions 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
c 1
b 0
f 1
dl 0
loc 7
rs 9.4285
1
#!/usr/bin/env python3
2
"""Generate .exe files with PyInstaller."""
3
4
from os import remove, listdir, devnull, getcwd, makedirs
5
from os.path import join, basename, exists
6
from platform import architecture
7
from shutil import copy, rmtree, copytree
8
from subprocess import call, STDOUT
9
from requests import certs, get
10
from bbarchivist.bbconstants import VERSION, LONGVERSION, CAP, JSONDIR, COMMITDATE
11
from bbarchivist.utilities import prep_seven_zip, get_seven_zip
12
13
14
def write_versions():
15
    """
16
    Write temporary version files.
17
    """
18
    with open("version.txt", "w") as afile:
19
        afile.write(VERSION)
20
    with open("longversion.txt", "w") as afile:
21
        afile.write("{0}\n{1}".format(LONGVERSION, COMMITDATE))
22
23
24
def clean_versions():
25
    """
26
    Remove temporary version files.
27
    """
28
    remove("version.txt")
29
    remove("longversion.txt")
30
31
32
def bitsdir(indir):
33
    """
34
    Create directories based on indir segregated on bit type.
35
36
    :param indir: Directory to modify.
37
    :type indir: str
38
    """
39
    if architecture()[0] == "64bit":
40
        indirx = "{0}-64".format(indir)
41
    else:
42
        indirx = indir
43
    if exists(indirx):
44
        clean_outdir(indirx)
45
    makedirs(indirx)
46
    return indirx
47
48
49
def get_ucrt_dlls():
50
    """
51
    Get some magic voodoo Windows DLLs.
52
    """
53
    tail = "x64" if architecture()[0] == "64bit" else "x86"
54
    folder = join("C:\\", "Program Files (x86)", "Windows Kits", "10", "Redist", "ucrt", "DLLs", tail)
55
    return folder
56
57
58
def generate_specs():
59
    """
60
    Generate pyinstaller spec files.
61
    """
62
    scripts = ["archivist", "autolookup", "barlinker", "carrierchecker", "certchecker", "devloader", "downloader", "droidlookup", "droidscraper", "escreens", "kernchecker", "lazyloader", "linkgen", "metachecker", "swlookup", "tclscan", "tcldelta"]
63
    here = getcwd().replace("\\", "\\\\")
64
    dlldir = get_ucrt_dlls().replace("\\", "\\\\")
65
    for script in scripts:
66
        template = "# -*- mode: python -*-\n\nblock_cipher = None\n\n\na = Analysis(['bbarchivist\\\\scripts\\\\{0}.py'],\n             pathex=['{1}', '{2}'],\n             binaries=None,\n             datas=None,\n             hiddenimports=[],\n             hookspath=[],\n             runtime_hooks=[],\n             excludes=[],\n             win_no_prefer_redirects=False,\n             win_private_assemblies=False,\n             cipher=block_cipher)\npyz = PYZ(a.pure, a.zipped_data,\n             cipher=block_cipher)\nexe = EXE(pyz,\n          a.scripts,\n          a.binaries,\n          a.zipfiles,\n          a.datas,\n          name='{0}',\n          debug=False,\n          strip=False,\n          upx=False,\n          console=True )\n".format(script, here, dlldir)
67
        with open("{0}.spec".format(script), "w") as afile:
68
            afile.write(template)
69
70
71
def clean_specs():
72
    """
73
    Remove pyinstaller spec files.
74
    """
75
    specs = [x for x in listdir() if x.endswith(".spec")]
76
    for spec in specs:
77
        remove(spec)
78
79
80
def get_sevenzip():
81
    """
82
    Get 7-Zip.
83
    """
84
    szver = "1701"
85
    szurl = "http://www.7-zip.org/a/7z{0}-extra.7z".format(szver)
86
    psz = prep_seven_zip()
87
    if psz:
88
        get_sevenzip_write(szurl)
89
    else:
90
        print("GO TO {0} AND DO IT MANUALLY".format(szurl))
91
        raise SystemError
92
93
94
def get_sevenzip_write(szurl):
95
    """
96
    Download 7-Zip file.
97
98
    :param szurl: Link to 7z download.
99
    :type szurl: str
100
    """
101
    szexe = get_seven_zip()
102
    szfile = basename(szurl)
103
    with open(szfile, "wb") as afile:
104
        req = get(szurl, stream=True)
105
        for chunk in req.iter_content(chunk_size=1024):
106
            afile.write(chunk)
107
    cmd = "{0} x {1} -o7z".format(szexe, szfile)
108
    with open(devnull, "wb") as dnull:
109
        call(cmd, stdout=dnull, stderr=STDOUT, shell=True)
110
    remove(basename(szurl))
111
112
113
def call_specs(distdir, builddir):
114
    """
115
    Call pyinstaller to make specs.
116
117
    :param distdir: Path to distribute files.
118
    :type distdir: str
119
120
    :param builddir: Path to build files.
121
    :type builddir: str
122
    """
123
    specs = [x for x in listdir() if x.endswith(".spec")]
124
    for spec in specs:  # use UPX 3.93 or up
125
        cmd = "pyinstaller --onefile --workpath {2} --distpath {1} {0}".format(spec, distdir, builddir)
126
        call(cmd, shell=True)
127
128
129
def sz_wrapper(outdir):
130
    """
131
    Copy 7-Zip to outdir.
132
133
    :param outdir: Output directory.
134
    :type outdir: str
135
    """
136
    try:
137
        get_sevenzip()
138
    except SystemError:
139
        pass
140
    else:
141
        sz_wrapper_writer(outdir)
142
143
144
def sz_wrapper_writer(outdir):
145
    """
146
    Copy 7-Zip to outdir, the actual function.
147
148
    :param outdir: Output directory.
149
    :type outdir: str
150
    """
151
    copy(join("7z", "7za.exe"), outdir)
152
    if architecture()[0] == "64bit":
153
        copy(join("7z", "x64", "7za.exe"), join(outdir, "7za64.exe"))
154
    rmtree("7z", ignore_errors=True)
155
156
157
def copy_json(outdir):
158
    """
159
    Copy JSON folder to outdir.
160
161
    :param outdir: Output directory.
162
    :type outdir: str
163
    """
164
    copytree(JSONDIR, join(outdir, "json"))
165
166
167
def clean_outdir(outdir):
168
    """
169
    Nuke outdir, if it exists.
170
171
    :param outdir: Output directory.
172
    :type outdir: str
173
    """
174
    if exists(outdir):
175
        rmtree(outdir, ignore_errors=True)
176
177
178
def main():
179
    """
180
    Create .exes with dynamic spec files.
181
    """
182
    outdir = bitsdir("pyinst-dist")
183
    builddir = bitsdir("pyinst-build")
184
    write_versions()
185
    generate_specs()
186
    call_specs(outdir, builddir)
187
    copy("version.txt", outdir)
188
    copy("longversion.txt", outdir)
189
    copy(CAP.location, outdir)
190
    copy_json(outdir)
191
    copy(certs.where(), join(outdir, "cacerts.pem"))
192
    sz_wrapper(outdir)
193
    clean_versions()
194
    clean_specs()
195
196
197
if __name__ == "__main__":
198
    main()
199