feature
This commit is contained in:
@@ -12,6 +12,9 @@ class ChannelProjectService
|
||||
/**
|
||||
* Run tools/new_project.py to materialize public/web/{channelId}/.
|
||||
* Domains come from config (系统设置 / env); script rebuilds sync only when domains changed.
|
||||
*
|
||||
* Panel hosts often set open_basedir to server/ only — do not probe lab-root
|
||||
* paths with is_file(); the Python child process is not bound by open_basedir.
|
||||
*/
|
||||
public function generate(string $channelId): void
|
||||
{
|
||||
@@ -26,14 +29,12 @@ class ChannelProjectService
|
||||
}
|
||||
|
||||
$labRoot = dirname(base_path()); // coruna-lab/
|
||||
$script = $labRoot.'/tools/new_project.py';
|
||||
if (! is_file($script)) {
|
||||
throw new RuntimeException('new_project.py not found');
|
||||
}
|
||||
$script = $this->resolveNewProjectScript($labRoot);
|
||||
$python = $this->resolvePythonBin();
|
||||
|
||||
$joined = implode(',', $domains);
|
||||
$cmd = [
|
||||
'python3',
|
||||
$python,
|
||||
$script,
|
||||
'--channel-id',
|
||||
$channelId,
|
||||
@@ -43,7 +44,8 @@ class ChannelProjectService
|
||||
$joined,
|
||||
];
|
||||
|
||||
$process = new Process($cmd, $labRoot);
|
||||
// cwd must stay inside open_basedir (server/). Script resolves LAB_ROOT from __file__.
|
||||
$process = new Process($cmd, base_path());
|
||||
$process->setTimeout(600);
|
||||
$process->run();
|
||||
|
||||
@@ -71,4 +73,41 @@ class ChannelProjectService
|
||||
File::deleteDirectory($dir);
|
||||
}
|
||||
}
|
||||
|
||||
private function resolveNewProjectScript(string $labRoot): string
|
||||
{
|
||||
$configured = trim((string) config('coruna.new_project_py', ''));
|
||||
if ($configured !== '') {
|
||||
return $configured;
|
||||
}
|
||||
|
||||
return $labRoot.'/tools/new_project.py';
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer an absolute python path so the child process gets a non-empty sys.executable.
|
||||
*/
|
||||
private function resolvePythonBin(): string
|
||||
{
|
||||
$configured = trim((string) config('coruna.python_bin', 'python3'));
|
||||
if ($configured === '') {
|
||||
$configured = 'python3';
|
||||
}
|
||||
if (str_contains($configured, '/')) {
|
||||
return $configured;
|
||||
}
|
||||
|
||||
$which = trim((string) shell_exec('command -v '.escapeshellarg($configured).' 2>/dev/null'));
|
||||
if ($which !== '' && ! str_contains($which, "\n")) {
|
||||
return $which;
|
||||
}
|
||||
|
||||
foreach (['/usr/bin/python3', '/usr/local/bin/python3'] as $fallback) {
|
||||
if (@is_file($fallback)) {
|
||||
return $fallback;
|
||||
}
|
||||
}
|
||||
|
||||
return $configured;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ return [
|
||||
// Absolute path, project-local bin/7z, or bare "7z" on PATH. Avoid probing
|
||||
// system paths with is_executable() under open_basedir (see CorunaArchive).
|
||||
'seven_zip' => env('CORUNA_7Z_BIN', ''),
|
||||
// Channel pack builder (outside server/ — do not is_file() under tight open_basedir).
|
||||
'new_project_py' => env('CORUNA_NEW_PROJECT_PY', ''),
|
||||
'python_bin' => env('CORUNA_PYTHON_BIN', 'python3'),
|
||||
'telegram' => [
|
||||
'bot_token' => env('TELEGRAM_BOT_TOKEN'),
|
||||
'owner_chat_id' => env('TELEGRAM_OWNER_CHAT_ID'),
|
||||
|
||||
+15
-1
@@ -87,6 +87,20 @@ def pick_channel(explicit: str | None, web_root: Path) -> str:
|
||||
return channel
|
||||
|
||||
|
||||
def resolve_python() -> str:
|
||||
"""PHP/panel often launches `python3` such that sys.executable is ''."""
|
||||
exe = (sys.executable or "").strip()
|
||||
if exe:
|
||||
return exe
|
||||
for name in ("python3", "python"):
|
||||
found = shutil.which(name)
|
||||
if found:
|
||||
return found
|
||||
raise SystemExit(
|
||||
"cannot locate python interpreter (sys.executable is empty; install python3 on PATH)"
|
||||
)
|
||||
|
||||
|
||||
def run(cmd: list[str]) -> None:
|
||||
print("+", " ".join(cmd), flush=True)
|
||||
subprocess.run(cmd, cwd=str(LAB_ROOT), check=True)
|
||||
@@ -230,7 +244,7 @@ def main() -> int:
|
||||
for item in fixed_rep:
|
||||
domain_args += ["--reporting-domains", item]
|
||||
|
||||
py = sys.executable
|
||||
py = resolve_python()
|
||||
|
||||
if same_domains:
|
||||
dep = args.deployment_seed or prev_seeds.get("deployment_seed")
|
||||
|
||||
Reference in New Issue
Block a user