Completed
Push — master ( 7bf81e...fdb8ce )
by John
02:23
created

bit_tail()   A

Complexity

Conditions 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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