Passed
Push — master ( 816317...cc1553 )
by John
03:01
created

pyinstaller_exe.get_ucrt_dlls()   A

Complexity

Conditions 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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