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,284 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# common utilities for pyfpdf tests
|
||||
# Note: 1) this file imported from both 2 and 3 version of python
|
||||
# 2) import this file before import fpdf
|
||||
# 3) assert this file in tests/cover folder
|
||||
|
||||
import sys, os, subprocess
|
||||
|
||||
PY3K = sys.version_info >= (3, 0)
|
||||
|
||||
basepath = os.path.abspath(os.path.join(__file__, "..", ".."))
|
||||
|
||||
RESHASH = "38db8db76e80a2e75f94d1df9eda307e"
|
||||
|
||||
# if PYFPDFTESTLOCAL is not set - use instaled pyfpdf version
|
||||
PYFPDFTESTLOCAL = ("PYFPDFTESTLOCAL" in os.environ)
|
||||
if PYFPDFTESTLOCAL:
|
||||
sys.path = [os.path.join(basepath, "fpdf_local")] + sys.path
|
||||
|
||||
|
||||
if PY3K:
|
||||
#import common3 as _common
|
||||
def tobytes(value):
|
||||
return value.encode("latin1")
|
||||
def frombytes(value):
|
||||
return value.decode("latin1")
|
||||
from hashlib import md5
|
||||
unicode = str
|
||||
|
||||
else:
|
||||
#import common2 as _common
|
||||
def tobytes(value):
|
||||
return value
|
||||
def frombytes(value):
|
||||
return value
|
||||
try:
|
||||
from hashlib import md5
|
||||
except ImportError:
|
||||
import md5
|
||||
|
||||
def exec_cmd(cmd):
|
||||
"Execute command and return console output (stdout, stderr)"
|
||||
obj = subprocess.Popen(cmd, \
|
||||
stdout = subprocess.PIPE,
|
||||
stderr = subprocess.PIPE)
|
||||
std, err = obj.communicate()
|
||||
return (frombytes(std), frombytes(err))
|
||||
|
||||
def start_by_ext(fn):
|
||||
"Open file in associated progrom"
|
||||
try:
|
||||
try:
|
||||
os.startfile(fn)
|
||||
except WindowsError:
|
||||
os.system("start " + fn)
|
||||
except:
|
||||
subprocess.call(["xdg-open", fn])
|
||||
|
||||
def writer(stream, items):
|
||||
sep = ""
|
||||
for item in items:
|
||||
stream.write(sep)
|
||||
sep = " "
|
||||
if not isinstance(item, str):
|
||||
item = str(item)
|
||||
if not PY3K:
|
||||
if not isinstance(item, unicode):
|
||||
item = str(item)
|
||||
stream.write(item)
|
||||
stream.write("\n")
|
||||
|
||||
def log(*kw):
|
||||
writer(sys.stdout, kw)
|
||||
|
||||
def err(*kw):
|
||||
writer(sys.stderr, kw)
|
||||
|
||||
def test_putinfo(self):
|
||||
"Replace info stamp with defaults for all automated test objects"
|
||||
self._out('/Producer '+self._textstring('PyFPDF TEST http://pyfpdf.googlecode.com/'))
|
||||
if hasattr(self,'title'):
|
||||
self._out('/Title '+self._textstring(self.title))
|
||||
if hasattr(self,'subject'):
|
||||
self._out('/Subject '+self._textstring(self.subject))
|
||||
if hasattr(self,'author'):
|
||||
self._out('/Author '+self._textstring(self.author))
|
||||
if hasattr (self,'keywords'):
|
||||
self._out('/Keywords '+self._textstring(self.keywords))
|
||||
if hasattr(self,'creator'):
|
||||
self._out('/Creator '+self._textstring(self.creator))
|
||||
self._out('/CreationDate '+self._textstring('D:19700101000000'))
|
||||
|
||||
def file_hash(fn):
|
||||
"Calc MD5 hash for file"
|
||||
md = md5()
|
||||
f = open(fn, "rb")
|
||||
try:
|
||||
md.update(f.read())
|
||||
finally:
|
||||
f.close()
|
||||
return md.hexdigest()
|
||||
|
||||
def read_cover_info(fn):
|
||||
"Read cover test info"
|
||||
f = open(fn, "rb")
|
||||
da = {"res": []}
|
||||
mark = "#PyFPDF-cover-test:"
|
||||
encmark = "# -*- coding:"
|
||||
enc = None
|
||||
try:
|
||||
hdr = False
|
||||
for line in f.readlines():
|
||||
if enc is None:
|
||||
if line.decode("latin-1")[:len(encmark)] == unicode(encmark):
|
||||
enc = line.decode("latin-1")[len(encmark):].strip()
|
||||
if enc[-3:] == unicode("-*-"):
|
||||
enc = enc[:-3].strip()
|
||||
try:
|
||||
line.decode(enc)
|
||||
except:
|
||||
enc = None
|
||||
line = line.decode(enc or "UTF-8").strip()
|
||||
if line[:len(mark)] == mark:
|
||||
hdr = True
|
||||
kv = line[len(mark):].split("=", 1)
|
||||
if len(kv) == 2:
|
||||
if kv[0] == "res":
|
||||
da["res"].append(kv[1])
|
||||
else:
|
||||
da[kv[0]] = kv[1]
|
||||
else:
|
||||
if hdr and len(line) == 0:
|
||||
break
|
||||
|
||||
finally:
|
||||
f.close()
|
||||
return da
|
||||
|
||||
def parse_test_args(args, deffn):
|
||||
"Parse test args, return (fn, autotest)"
|
||||
args = args[1:]
|
||||
da = {}
|
||||
da["fn"] = deffn
|
||||
da["autotest"] = False
|
||||
da["check"] = False
|
||||
while len(args) > 0:
|
||||
arg = args[0]
|
||||
if arg == "--help":
|
||||
log("Test usage: [--auto] [--check] [<outputname>]")
|
||||
log(" --auto - no version and timestamp in file, do not open")
|
||||
log(" --check - compare new file with stock")
|
||||
log(" <outputname> - output filename, default \"%s\"" % deffn)
|
||||
sys.exit(0)
|
||||
if arg == "--auto":
|
||||
da["autotest"] = True
|
||||
elif arg == "--check":
|
||||
da["check"] = True
|
||||
else:
|
||||
da["fn"] = arg
|
||||
args = args[1:]
|
||||
return da
|
||||
|
||||
def load_res_file(path):
|
||||
items = {}
|
||||
res = None
|
||||
for line in open(path):
|
||||
line = line.strip()
|
||||
if line[:1] == "#":
|
||||
continue
|
||||
kv = line.split("=", 1)
|
||||
if len(kv) != 2:
|
||||
continue
|
||||
if kv[0] == "res":
|
||||
res = kv[1]
|
||||
if res not in items:
|
||||
items[res] = ["", []]
|
||||
elif res is None:
|
||||
continue
|
||||
elif kv[0] == "hash":
|
||||
items[res][0] = kv[1]
|
||||
elif kv[0] == "tags":
|
||||
items[res][1] += [kv[1].split(",")]
|
||||
return items
|
||||
|
||||
def check_env(settings, args):
|
||||
"Check test environment"
|
||||
verbose = not args["autotest"]
|
||||
# check python version
|
||||
if PY3K:
|
||||
if settings.get("python3", "yes") == "no":
|
||||
# python 3 inacceptable
|
||||
if verbose:
|
||||
err("Python 3.x unsupported %s" % repr(sys.version_info))
|
||||
else:
|
||||
log("NOTFORPY3")
|
||||
return False
|
||||
else:
|
||||
if settings.get("python2", "yes") == "no":
|
||||
# python 2 inacceptable
|
||||
if verbose:
|
||||
err("Python 2.x unsupported %s" % repr(sys.version_info))
|
||||
else:
|
||||
log("NOTFORPY2")
|
||||
return False
|
||||
if settings.get("pil", "no") == "yes":
|
||||
# import PIL
|
||||
try:
|
||||
try:
|
||||
import Image
|
||||
except:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
if Image is None:
|
||||
if verbose:
|
||||
err("PIL or Pillow module is required")
|
||||
else:
|
||||
log("NOPIL")
|
||||
return False
|
||||
# check res
|
||||
reslst = None
|
||||
for res in settings.get("res", []):
|
||||
if reslst is None:
|
||||
# check
|
||||
respath = os.path.join(basepath, "resources.txt")
|
||||
if file_hash(respath) != RESHASH:
|
||||
if verbose:
|
||||
err("File resources.txt damaged (hash mismatch)")
|
||||
else:
|
||||
log("RESHASH")
|
||||
return False
|
||||
# load data
|
||||
reslst = load_res_file(respath)
|
||||
if res not in reslst:
|
||||
err("Resource \"" + res + "\" not found")
|
||||
if not verbose:
|
||||
log("NORES")
|
||||
return False
|
||||
# check hash
|
||||
respath = os.path.join(basepath, res)
|
||||
hs = file_hash(respath)
|
||||
if hs != reslst[res][0]:
|
||||
err("Resource \"" + res + "\" damaged")
|
||||
err(" read = %s" % hs)
|
||||
err(" required = %s" % reslst[res][0])
|
||||
if not verbose:
|
||||
log("RESERR")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def check_result(settings, args):
|
||||
check = True
|
||||
if settings.get("fn"):
|
||||
if args["check"]:
|
||||
# compare with hash
|
||||
hs = file_hash(args["fn"])
|
||||
fhs = settings.get("hash", "")
|
||||
if fhs != "" and hs != fhs:
|
||||
check = False
|
||||
err("Hash mismatch:")
|
||||
err(" new = %s" % hs)
|
||||
err(" required = %s" % fhs)
|
||||
|
||||
if args["autotest"]:
|
||||
if check:
|
||||
log("OK")
|
||||
else:
|
||||
log("HASHERROR")
|
||||
else:
|
||||
if settings.get("fn"):
|
||||
start_by_ext(args["fn"])
|
||||
else:
|
||||
log("Test passed")
|
||||
|
||||
def testmain(fn, testfunc):
|
||||
si = read_cover_info(fn)
|
||||
da = parse_test_args(sys.argv, si.get("fn"))
|
||||
if not check_env(si, da):
|
||||
return
|
||||
testfunc(da["fn"], da["autotest"] or da["check"])
|
||||
check_result(si, da)
|
||||
|
||||
Reference in New Issue
Block a user