Erster Commit: nativer Linux-Port aus macOS-Bytecode
Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,520 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os, sys
|
||||
import cover
|
||||
import shutil
|
||||
import traceback
|
||||
|
||||
def search_python_posix():
|
||||
lst = []
|
||||
path = os.environ.get("PATH")
|
||||
for item in path.split(":"):
|
||||
try:
|
||||
for interp in os.listdir(item):
|
||||
if interp[:6] != "python":
|
||||
continue
|
||||
if interp[-7:] == "-config":
|
||||
continue
|
||||
fp = os.path.join(item, interp)
|
||||
# test if already in list
|
||||
same = False
|
||||
for lidx, l_interp in enumerate(lst):
|
||||
if os.path.samefile(l_interp, fp):
|
||||
same = True
|
||||
# use shorter name
|
||||
if len(l_interp) < len(fp):
|
||||
lst[lidx] = fp
|
||||
break
|
||||
if same:
|
||||
continue
|
||||
lst.append(fp)
|
||||
except OSError:
|
||||
pass
|
||||
return lst
|
||||
|
||||
def search_python_win():
|
||||
lst = []
|
||||
try:
|
||||
try:
|
||||
import _winreg as winreg
|
||||
except ImportError:
|
||||
import winreg
|
||||
def findreg(key, lst):
|
||||
PATH = "SOFTWARE\\Python\\PythonCore"
|
||||
try:
|
||||
rl = winreg.OpenKey(key, PATH)
|
||||
except WindowsError:
|
||||
return lst
|
||||
try:
|
||||
for i in range(winreg.QueryInfoKey(rl)[0]):
|
||||
ver = winreg.EnumKey(rl, i)
|
||||
rv = winreg.QueryValue(key, PATH + "\\" + ver + "\\InstallPath")
|
||||
fp = os.path.join(rv, "python.exe")
|
||||
#print fp
|
||||
if os.path.exists(fp) and not fp in lst:
|
||||
lst.append(fp)
|
||||
except WindowsError:
|
||||
pass
|
||||
return lst
|
||||
lst = findreg(winreg.HKEY_LOCAL_MACHINE, lst)
|
||||
lst = findreg(winreg.HKEY_CURRENT_USER, lst)
|
||||
except:
|
||||
traceback.print_exc(file = sys.stdout)
|
||||
# fallback
|
||||
cover.log("Search python at system drive")
|
||||
try:
|
||||
path = os.environ.get("SystemDrive", "C:")
|
||||
for item in os.listdir(path):
|
||||
if item[:6].lower() != "python":
|
||||
continue
|
||||
fp = os.path.join(path, item, "python.exe")
|
||||
if os.path.exists(fp) and not fp in lst:
|
||||
lst.append(fp)
|
||||
except:
|
||||
traceback.print_exc(file = sys.stdout)
|
||||
|
||||
return lst
|
||||
|
||||
def search_python():
|
||||
if sys.platform.startswith("linux"):
|
||||
lst = search_python_posix()
|
||||
elif sys.platform.startswith("win"):
|
||||
lst = search_python_win()
|
||||
else:
|
||||
lst = search_python_posix()
|
||||
if len(lst) == 0:
|
||||
# fallback
|
||||
lst.append(sys.executable)
|
||||
return lst
|
||||
|
||||
def find_python_version(pylst):
|
||||
lst = []
|
||||
ids = []
|
||||
for interp in pylst:
|
||||
try:
|
||||
std, err = cover.exec_cmd([interp, "-V"])
|
||||
version = err.strip()
|
||||
if not version:
|
||||
# python 3.4+
|
||||
version = std.strip()
|
||||
if version[:6] == "Python":
|
||||
shver = version[6:].strip().replace(" ", "-")
|
||||
nid = shver
|
||||
nidn = 0
|
||||
while nid in ids:
|
||||
nidn += 1
|
||||
nid = shver + "-%d" % nidn
|
||||
ids.append(nid)
|
||||
lst.append((interp, nid, version))
|
||||
else:
|
||||
cover.err("Not a python", version)
|
||||
# no python found
|
||||
continue
|
||||
except:
|
||||
traceback.print_exc(file = sys.stdout)
|
||||
return lst
|
||||
|
||||
def search_tests():
|
||||
base = os.path.join(cover.basepath, "cover")
|
||||
lst = []
|
||||
for item in os.listdir(base):
|
||||
if item[:5] != "test_" or item[-3:] != ".py":
|
||||
continue
|
||||
lst.append(os.path.join(base, item))
|
||||
lst.sort()
|
||||
return lst
|
||||
|
||||
def do_test_one(testfile, interp, info, dest):
|
||||
path = interp[0]
|
||||
nid = interp[1]
|
||||
destpath = dest[0]
|
||||
destenv = dest[1]
|
||||
# check PIL
|
||||
if info.get("pil", "no") == "yes":
|
||||
if destenv.get("pil", "no") != "yes":
|
||||
return ("skip", "no PIL or PIllow found")
|
||||
# check python version
|
||||
tool2to3 = (info.get("2to3", "no") == "yes")
|
||||
py2 = (info.get("python2", "yes") == "yes")
|
||||
py3 = (info.get("python3", "yes") == "yes")
|
||||
plat = info.get("platform", "*")
|
||||
if plat == "":
|
||||
plat = "*"
|
||||
if plat != "*":
|
||||
plats = plat.split(",")
|
||||
accept = False
|
||||
for plat in plats:
|
||||
if sys.platform == plat:
|
||||
accept = True
|
||||
break
|
||||
if not accept:
|
||||
return ("skip", "not for \"" + sys.platform + "\"")
|
||||
copy = False
|
||||
if nid[:2] == "3.":
|
||||
if not py3:
|
||||
return ("skip", "not for python 3")
|
||||
if not tool2to3:
|
||||
copy = True
|
||||
else:
|
||||
return ("unimplemented", "todo")
|
||||
if nid[:2] == "2.":
|
||||
if not py2:
|
||||
return ("skip", "not for python 2")
|
||||
copy = True
|
||||
|
||||
# check if fpdf instaled
|
||||
if destenv.get("ver", "None") == "None":
|
||||
return ("nofpdf", "")
|
||||
|
||||
# copy files
|
||||
testname = os.path.basename(testfile)
|
||||
testfmt = info.get("format", "raw")
|
||||
newfile = os.path.join(destpath, testname)
|
||||
newres = os.path.join(destpath, info.get("fn", testname + "." + testfmt.lower()))
|
||||
if copy:
|
||||
shutil.copy(testfile, destpath)
|
||||
# start execution
|
||||
std, err = cover.exec_cmd([path, "-B", newfile, "--check", "--auto", newres])
|
||||
f = open(os.path.join(destpath, "testlog.txt"), "a")
|
||||
f.write("#" * 40 + "\n")
|
||||
f.write(testname + "\n")
|
||||
f.write("=" * 40 + "\n")
|
||||
f.write(std)
|
||||
f.write("-" * 40 + "\n")
|
||||
f.write(err)
|
||||
f.close()
|
||||
|
||||
answ = std.strip()
|
||||
if answ.find("\n") >= 0 or len(answ) == 0:
|
||||
return ("fail", "bad output")
|
||||
else:
|
||||
if answ == "HASHERROR":
|
||||
# get new hash
|
||||
nh = ""
|
||||
for line in err.split("\n"):
|
||||
line = line.strip()
|
||||
if line[:5] == "new =":
|
||||
nh = line[5:].strip()
|
||||
return ("hasherror", nh)
|
||||
return (answ.lower(), "")
|
||||
|
||||
|
||||
def prepare_dest(interp):
|
||||
destpath = os.path.join(cover.basepath, "out-" + interp[1])
|
||||
if not os.path.exists(destpath):
|
||||
os.makedirs(destpath)
|
||||
# copy common set
|
||||
src = os.path.join(cover.basepath, "cover")
|
||||
shutil.copy(os.path.join(src, "common.py"), destpath)
|
||||
shutil.copy(os.path.join(src, "checkenv.py"), destpath)
|
||||
f = open(os.path.join(destpath, "testlog.txt"), "w")
|
||||
f.write("Version: " + interp[1] + "\n")
|
||||
f.write("Path: " + interp[0] + "\n")
|
||||
f.write(str(interp[2:]) + "\n")
|
||||
|
||||
# run checkenv
|
||||
std, err = cover.exec_cmd([interp[0], "-B", os.path.join(destpath, "checkenv.py")])
|
||||
env = {}
|
||||
if len(err.strip()) == 0:
|
||||
# OK
|
||||
f.write("Check environment - ok:\n")
|
||||
f.write(std)
|
||||
lineno = 0
|
||||
for line in std.split("\n"):
|
||||
lineno += 1
|
||||
line = line.strip()
|
||||
if lineno == 1:
|
||||
if line != "CHECK":
|
||||
break
|
||||
line = line.strip()
|
||||
kv = line.split("=", 1)
|
||||
if len(kv) == 2:
|
||||
env[kv[0].lower().strip()] = kv[1].strip()
|
||||
else:
|
||||
f.write("ERROR:\n")
|
||||
f.write(err)
|
||||
f.close()
|
||||
return (destpath, env)
|
||||
|
||||
def do_test(testfile, interps, dests, stats, hint = ""):
|
||||
cover.log("Test", hint, ":", os.path.basename(testfile))
|
||||
info = cover.read_cover_info(testfile)
|
||||
resall = ""
|
||||
# prepare
|
||||
# do tests
|
||||
hasherr = []
|
||||
for interp in interps:
|
||||
if len(interps) < 6:
|
||||
resall += (interp[1] + " - ")
|
||||
res, desc = do_test_one(testfile, interp, info, dests[interp[1]])
|
||||
if res == "hasherror":
|
||||
hasherr.append(desc)
|
||||
#cover.log("HASH =", desc)
|
||||
# update statistic
|
||||
stats["_"]["_"] += 1
|
||||
stats["_"][res] = stats["_"].get(res, 0) + 1
|
||||
stats[interp[1]]["_"] += 1
|
||||
stats[interp[1]][res] = stats[interp[1]].get(res, 0) + 1
|
||||
resall += (res + " " * 10)[:6].upper()
|
||||
resall += " "
|
||||
cover.log(resall)
|
||||
# test if all hash
|
||||
if len(interps) == len(hasherr):
|
||||
cover.err("All hashes wrong")
|
||||
|
||||
def print_interps(interps):
|
||||
cover.log(">> Interpretors:", len(interps))
|
||||
dests = {}
|
||||
stats = {"_": {"_": 0}}
|
||||
for idx, interp in enumerate(interps):
|
||||
cover.log("%d) %s - %s" % (idx + 1, interp[1], interp[0]))
|
||||
cover.log()
|
||||
|
||||
def do_all_test(interps, tests):
|
||||
print_interps(interps)
|
||||
dests = {}
|
||||
stats = {"_": {"_": 0}}
|
||||
for idx, interp in enumerate(interps):
|
||||
dests[interp[1]] = prepare_dest(interp)
|
||||
stats[interp[1]] = {"_": 0}
|
||||
|
||||
cover.log(">> Tests:", len(tests))
|
||||
for idx, test in enumerate(tests):
|
||||
do_test(test, interps, dests, stats, "%d / %d" % (idx + 1, len(tests)))
|
||||
cover.log()
|
||||
|
||||
cover.log(">> Statistics:")
|
||||
def stat_str(stat):
|
||||
keys = list(stat.keys())
|
||||
keys.sort()
|
||||
st = "total - %d" % stat["_"]
|
||||
for key in keys:
|
||||
if key == "_":
|
||||
continue
|
||||
st += (", %s - %d" % (key, stat[key]))
|
||||
|
||||
return st
|
||||
for interp in interps:
|
||||
cover.log(interp[1] + ":", stat_str(stats[interp[1]]))
|
||||
cover.log("-"*10)
|
||||
cover.log("All:", stat_str(stats["_"]))
|
||||
|
||||
# check if no FPDF at all
|
||||
total = stats["_"]["_"]
|
||||
fpdf = stats["_"].get("nofpdf", 0)
|
||||
skip = stats["_"].get("skip", 0)
|
||||
if skip == total:
|
||||
cover.log("All tests skipped. Install some modules (PIL, PyBIDI, Gluon etc)")
|
||||
elif fpdf + skip == total:
|
||||
hint_prepare()
|
||||
|
||||
|
||||
def list_tests():
|
||||
tst = search_tests()
|
||||
cover.log(">> Tests:", len(tst))
|
||||
for idx, test in enumerate(tst):
|
||||
test = os.path.basename(test)
|
||||
if test[:5].lower() == "test_":
|
||||
test = test[5:]
|
||||
if test[-3:].lower() == ".py":
|
||||
test = test[:-3]
|
||||
cover.log("%d) %s" % (idx + 1, test))
|
||||
cover.log()
|
||||
|
||||
def usage():
|
||||
cover.log("Usage: runtest.py [...]")
|
||||
cover.log(" --listtests - list all tests")
|
||||
cover.log(" --listinterps - list all availiable interpretors")
|
||||
cover.log(" --test issuexx - add test issuexx")
|
||||
cover.log(" --test @file - add test from file")
|
||||
cover.log(" --interp path - test against specified interpretors")
|
||||
cover.log(" --interp @file - read interpretors list from file")
|
||||
cover.log(" --downloadfonts - download font set")
|
||||
cover.log(" --help - this page")
|
||||
|
||||
|
||||
def hint_prepare():
|
||||
if cover.PYFPDFTESTLOCAL:
|
||||
if sys.platform.startswith("win"):
|
||||
prefix = ""
|
||||
suffix = ".bat"
|
||||
else:
|
||||
prefix = "./"
|
||||
suffix = ".sh"
|
||||
cover.log("*** Please, prepare local copy for tests")
|
||||
cover.log("*** " + prefix + "prepare_local" + suffix)
|
||||
else:
|
||||
cover.log("*** Please, install PyFPDF with")
|
||||
cover.log("*** python setup.py install")
|
||||
cover.log("*** or set PYFPDFTESTLOCAL variable to use local copy")
|
||||
if sys.platform.startswith("win"):
|
||||
cover.log("*** set PYFPDFTESTLOCAL=1")
|
||||
else:
|
||||
cover.log("*** export PYFPDFTESTLOCAL=1")
|
||||
|
||||
|
||||
def read_list(fn):
|
||||
f = open(fn, "r")
|
||||
try:
|
||||
return f.readlines()
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
def hasher(path, args):
|
||||
tags = []
|
||||
while len(args):
|
||||
arg = args[0]
|
||||
args = args[1:]
|
||||
if arg == "--tag":
|
||||
if len(args) == 0:
|
||||
cover.log("Param without value")
|
||||
return
|
||||
value = args[0]
|
||||
args = args[1:]
|
||||
if value not in tags:
|
||||
tags.append(value)
|
||||
else:
|
||||
cover.log("Unknown param")
|
||||
return
|
||||
|
||||
lst = []
|
||||
if os.path.isdir(path):
|
||||
files = [(x.lower(), x) for x in os.listdir(path)]
|
||||
files.sort()
|
||||
for s, item in files:
|
||||
fp = os.path.join(path, item)
|
||||
# clear path
|
||||
bp = fp
|
||||
if sys.platform.startswith("win"):
|
||||
bp = fp.replace("\\", "/")
|
||||
lst += [[bp, cover.file_hash(fp)]]
|
||||
else:
|
||||
lst = [[path, cover.file_hash(path)]]
|
||||
for item, hs in lst:
|
||||
cover.log("res=" + item)
|
||||
cover.log("hash=" + hs)
|
||||
cover.log("tags=" + ",".join(tags))
|
||||
cover.log()
|
||||
|
||||
def download_fonts():
|
||||
URL = "http://pyfpdf.googlecode.com/files/fpdf_unicode_font_pack.zip"
|
||||
fntdir = os.path.join(cover.basepath, "font")
|
||||
zippath = os.path.join(cover.basepath, URL.split('/')[-1])
|
||||
if not os.path.exists(fntdir):
|
||||
os.makedirs(fntdir)
|
||||
if not os.path.exists(zippath):
|
||||
import urllib2
|
||||
u = urllib2.urlopen(URL)
|
||||
meta = u.info()
|
||||
file_size = int(meta.getheaders("Content-Length")[0])
|
||||
cover.log("Downloading:", file_size, "bytes")
|
||||
f = open(zippath, "wb")
|
||||
file_size_dl = 0
|
||||
while True:
|
||||
buff = u.read(64 * 1024)
|
||||
if not buff:
|
||||
break
|
||||
file_size_dl += len(buff)
|
||||
f.write(buff)
|
||||
cover.log(" ", file_size_dl * 100. / file_size, "%")
|
||||
f.close()
|
||||
# unpack
|
||||
cover.log("Extracting")
|
||||
import zipfile
|
||||
fh = open(zippath, "rb")
|
||||
z = zipfile.ZipFile(fh)
|
||||
for name in z.namelist():
|
||||
if name[:5] != "font/":
|
||||
continue
|
||||
if name[5:].find("/") >= 0:
|
||||
continue
|
||||
cover.log(" ", name[5:])
|
||||
outfile = open(os.path.join(fntdir, name[5:]), "wb")
|
||||
outfile.write(z.read(name))
|
||||
outfile.close()
|
||||
cover.log("Done")
|
||||
|
||||
def main():
|
||||
cover.log("Test PyFPDF")
|
||||
|
||||
testsn = []
|
||||
interpsn = []
|
||||
args = sys.argv[1:]
|
||||
while len(args):
|
||||
arg = args[0]
|
||||
args = args[1:]
|
||||
if arg == "--hash":
|
||||
if len(args) == 0:
|
||||
cover.log("Param without value")
|
||||
return usage()
|
||||
return hasher(args[0], args[1:])
|
||||
if arg == "--help":
|
||||
return usage()
|
||||
elif arg == "--test":
|
||||
if len(args) > 0:
|
||||
value = args[0]
|
||||
args = args[1:]
|
||||
else:
|
||||
cover.log("Param without value")
|
||||
return usage()
|
||||
if value[:1] == "@":
|
||||
# from file
|
||||
testsn += read_list(value[1:])
|
||||
else:
|
||||
testsn.append(value)
|
||||
elif arg == "--interp":
|
||||
if len(args) > 0:
|
||||
value = args[0]
|
||||
args = args[1:]
|
||||
else:
|
||||
cover.log("Param without value")
|
||||
return usage()
|
||||
if value[:1] == "@":
|
||||
# from file
|
||||
interpsn += read_list(value[1:])
|
||||
else:
|
||||
interpsn.append(value)
|
||||
elif arg == "--listtests":
|
||||
return list_tests()
|
||||
elif arg == "--listinterps":
|
||||
return print_interps(find_python_version(search_python()))
|
||||
elif arg == "--downloadfonts":
|
||||
return download_fonts()
|
||||
else:
|
||||
cover.log("Unknown param")
|
||||
return usage()
|
||||
|
||||
if len(testsn) == 0:
|
||||
tests = search_tests()
|
||||
else:
|
||||
# cheack all tests
|
||||
tests = []
|
||||
for test in testsn:
|
||||
test = test.strip()
|
||||
fn = os.path.join(cover.basepath, "cover", "test_" + test + ".py")
|
||||
if os.path.exists(fn):
|
||||
tests.append(fn)
|
||||
else:
|
||||
cover.err("Test \"%s\" not found" % test)
|
||||
return
|
||||
|
||||
if len(interpsn) == 0:
|
||||
interps = find_python_version(search_python())
|
||||
else:
|
||||
# cheack all tests
|
||||
interps = []
|
||||
for interp in interpsn:
|
||||
fn = os.path.abspath(interp)
|
||||
if os.path.exists(fn):
|
||||
interps.append(fn)
|
||||
else:
|
||||
cover.err("Interpretor \"%s\" not found" % test)
|
||||
return
|
||||
interps = find_python_version(interps)
|
||||
|
||||
do_all_test(interps, tests)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user