Skip to content

Commit 5572b8e

Browse files
author
PyCompiler ARK++
committed
feat(sysdeps): automate non-interactive installs with retries, timeouts, and detailed debug
feat(pyarmor): expand DEFAULT_SETTINGS (globbing, excludes, advanced flags, timeout, workspace opts) and wire to runtime chore(windows): winget auto-accept agreements for silent installs refactor(sysdeps): auto-resend sudo password prompts; broaden package manager detection (add yum)
1 parent b418883 commit 5572b8e

2 files changed

Lines changed: 279 additions & 30 deletions

File tree

API/pyarmor/__init__.py

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,63 @@
4444

4545

4646
DEFAULT_SETTINGS = {
47+
# Inputs can be explicit paths OR discovered via globbing when glob_mode=True
4748
"inputs": ["main.py"],
49+
"inputs_glob": ["**/*.py"], # evaluated within the workspace when glob_mode=True
50+
"glob_mode": False,
51+
52+
# Output directory (relative to workspace by default)
4853
"out_dir": "obfuscated",
54+
55+
# Recursion and symlink handling
4956
"recursive": True,
50-
"exclude_patterns": ["venv/**", "build/**", "dist/**", "tests/**", "__pycache__/**"],
57+
"follow_symlinks": False,
58+
59+
# Exclusions (broad by default; keep overkill to avoid polluting the output)
60+
"exclude_patterns": [
61+
"venv/**",
62+
"build/**",
63+
"dist/**",
64+
"tests/**",
65+
"__pycache__/**",
66+
".git/**",
67+
".hg/**",
68+
".svn/**",
69+
".idea/**",
70+
".vscode/**",
71+
"node_modules/**",
72+
"*.egg-info/**",
73+
],
74+
75+
# Manifest file path; when manifest_auto=True a manifest may be generated from inputs/excludes
5176
"manifest": "",
52-
"advanced": {},
77+
"manifest_auto": False,
78+
79+
# Advanced options forwarded to `pyarmor gen` (None values are ignored)
80+
# Keep keys here for convenience; they are not applied unless set by the user.
81+
"advanced": {
82+
"platform": None, # e.g., "linux.x86_64", "windows.x86_64" or comma-separated
83+
"obf-code": None, # 0|1|2
84+
"obf-module": None, # 0|1
85+
"restrict-mode": None, # 0|1|2
86+
"mix-str": None, # True to enable string mixing
87+
"keep-runtime": None, # True to keep runtime package alongside outputs
88+
"no-cross-protection": None, # True to disable cross protection
89+
"bootstrap-code": None, # Python statements injected at startup
90+
"enable-suffix": None, # True to append obfuscated suffix
91+
"enable-assert-hook": None, # True to protect assert
92+
"plugin": None, # Optional PyArmor plugin name
93+
},
94+
95+
# Dry run will only log the command and not execute
5396
"dry_run": False,
97+
98+
# Execution controls
99+
"timeout_s": 1800, # Max seconds for obfuscation command
100+
101+
# Workspace controls
102+
"workspace": "", # Optional: override selected workspace (absolute or relative)
103+
"post_switch_workspace": True, # Switch to out_dir on success
54104
}
55105

56106
# -----------------------------
@@ -215,6 +265,12 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
215265
manifest: str = subcfg.get("manifest", DEFAULT_SETTINGS["manifest"]) or ""
216266
advanced: dict[str, Any] = subcfg.get("advanced", DEFAULT_SETTINGS["advanced"]) or {}
217267
dry_run: bool = bool(subcfg.get("dry_run", DEFAULT_SETTINGS["dry_run"]))
268+
# Overkill/versatile options
269+
glob_mode: bool = bool(subcfg.get("glob_mode", DEFAULT_SETTINGS.get("glob_mode", False)))
270+
inputs_glob: list[str] = subcfg.get("inputs_glob", DEFAULT_SETTINGS.get("inputs_glob", ["**/*.py"])) or DEFAULT_SETTINGS.get("inputs_glob", ["**/*.py"])
271+
follow_symlinks: bool = bool(subcfg.get("follow_symlinks", DEFAULT_SETTINGS.get("follow_symlinks", False)))
272+
timeout_s: int = int(subcfg.get("timeout_s", DEFAULT_SETTINGS.get("timeout_s", 1800)))
273+
post_switch_workspace: bool = bool(subcfg.get("post_switch_workspace", DEFAULT_SETTINGS.get("post_switch_workspace", True)))
218274

219275
# Sanitize and resolve paths relative to workspace
220276
ws = sctx.workspace_root
@@ -228,6 +284,43 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
228284
sctx.log_warn(f"[pyarmor] Input does not exist: {it}")
229285
except Exception:
230286
sctx.log_warn(f"[pyarmor] Invalid input: {it}")
287+
# Optional: discover inputs by globbing inside the workspace
288+
if glob_mode:
289+
discovered: list[str] = []
290+
try:
291+
# Prefer SDK iter_files when available
292+
try:
293+
it = sctx.iter_files(patterns=list(inputs_glob or ["**/*.py"]), exclude=list(exclude_patterns or []), enforce_workspace=True)
294+
for p in it:
295+
try:
296+
if p and getattr(p, "is_file", lambda: False)():
297+
discovered.append(str(p))
298+
except Exception:
299+
pass
300+
except Exception:
301+
# Fallback to pathlib globbing
302+
for pat in list(inputs_glob or ["**/*.py"]):
303+
try:
304+
for p in ws.glob(pat):
305+
try:
306+
if p.is_file():
307+
rp = str(p)
308+
# Exclude patterns match on full path
309+
if not any(p.match(ex) for ex in (exclude_patterns or [])):
310+
discovered.append(rp)
311+
except Exception:
312+
pass
313+
except Exception:
314+
pass
315+
except Exception:
316+
pass
317+
if discovered:
318+
# Deduplicate while keeping order
319+
seen = set()
320+
for x in discovered:
321+
if x not in seen:
322+
seen.add(x)
323+
abs_inputs.append(x)
231324
if not abs_inputs:
232325
sctx.log_warn("[pyarmor] No valid inputs to obfuscate; skipping")
233326
return
@@ -308,7 +401,7 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
308401
manifest=(str(sctx.safe_path(manifest)) if manifest else None) if manifest else None,
309402
advanced=advanced,
310403
cwd=str(ws),
311-
timeout_s=1800,
404+
timeout_s=timeout_s,
312405
)
313406
try:
314407
ph.update(1, "Done")
@@ -328,8 +421,8 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
328421
sctx.log_info(f"[pyarmor] Report saved: {rpt}")
329422
except Exception:
330423
pass
331-
# On success, switch the selected workspace to the obfuscated output directory
332-
if ok:
424+
# On success, optionally switch the selected workspace to the obfuscated output directory
425+
if ok and post_switch_workspace:
333426
try:
334427
switched = set_selected_workspace(str(out_path))
335428
if switched:
@@ -338,6 +431,8 @@ def on_pre_compile(self, ctx: PreCompileContext) -> None:
338431
sctx.log_warn(f"[pyarmor] Workspace switch refused: {out_path}")
339432
except Exception as e:
340433
sctx.log_warn(f"[pyarmor] Failed to switch workspace: {e}")
434+
elif ok:
435+
sctx.log_info("[pyarmor] post_switch_workspace=False; keeping current workspace")
341436
if not ok:
342437
try:
343438
out = (report.get("stdout") or "") + "\n" + (report.get("stderr") or "")

0 commit comments

Comments
 (0)