- vendor/so-novel: 上游 v1.12.0 (规则驱动的书源抓取/下载引擎) - tools/src: ToolMain 封装 search/download/toc/sources,stdout 只输出 JSON - tools/build.ps1: 自动定位/下载 JDK21,按平台显式激活 javet 原生库 profile - bin/novel.ps1|.cmd: 命令行入口(人读输出或 -Json) - SKILL.md/README.md: 使用说明与下载原理分析
128 lines
4.8 KiB
PowerShell
128 lines
4.8 KiB
PowerShell
# Shared helpers for the ebook-skill command line (Windows PowerShell 5.1+ / pwsh 7+).
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
function Get-ProjectRoot {
|
|
param([string]$Start = $PSScriptRoot)
|
|
$dir = (Resolve-Path $Start).Path
|
|
while ($dir) {
|
|
if (Test-Path (Join-Path $dir 'vendor\so-novel\pom.xml')) { return $dir }
|
|
$parent = Split-Path $dir -Parent
|
|
if ($parent -eq $dir -or -not $parent) { break }
|
|
$dir = $parent
|
|
}
|
|
throw "Cannot locate project root (vendor/so-novel/pom.xml not found above $Start). Run: git submodule update --init"
|
|
}
|
|
|
|
function Get-ToolPaths {
|
|
param([string]$Root = (Get-ProjectRoot))
|
|
[pscustomobject]@{
|
|
Root = $Root
|
|
Vendor = Join-Path $Root 'vendor\so-novel'
|
|
Tools = Join-Path $Root 'tools'
|
|
Runtime = Join-Path $Root 'tools\runtime'
|
|
Build = Join-Path $Root 'tools\build'
|
|
Classes = Join-Path $Root 'tools\build\classes'
|
|
AppJar = Join-Path $Root 'tools\runtime\app.jar'
|
|
ToolJar = Join-Path $Root 'tools\runtime\sonovel-tool.jar'
|
|
Config = Join-Path $Root 'tools\runtime\config.ini'
|
|
Rules = Join-Path $Root 'tools\runtime\rules'
|
|
Books = Join-Path $Root 'books'
|
|
}
|
|
}
|
|
|
|
function Test-Jdk21 {
|
|
param([string]$JdkHome)
|
|
if (-not $JdkHome) { return $false }
|
|
$java = Join-Path $JdkHome 'bin\java.exe'
|
|
if (-not (Test-Path $java)) { return $false }
|
|
try {
|
|
$out = (& $java -version 2>&1 | Out-String)
|
|
} catch {
|
|
return $false
|
|
}
|
|
if ($out -match 'version "(?:1\.)?(\d+)') {
|
|
return ([int]$Matches[1] -ge 21)
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Find-Jdk21 {
|
|
param([switch]$AllowDownload)
|
|
|
|
$candidates = New-Object System.Collections.Generic.List[string]
|
|
if ($env:EBOOK_NOVEL_JAVA_HOME) { $candidates.Add($env:EBOOK_NOVEL_JAVA_HOME) }
|
|
if ($env:JAVA_HOME) { $candidates.Add($env:JAVA_HOME) }
|
|
|
|
$patterns = @(
|
|
(Join-Path $PSScriptRoot '.jdk\*\*'),
|
|
(Join-Path $PSScriptRoot '.jdk'),
|
|
'C:\Program Files\Java\jdk-21*',
|
|
'C:\Program Files\Eclipse Adoptium\jdk-21*',
|
|
'C:\Program Files\JetBrains\*\jbr',
|
|
(Join-Path $env:LOCALAPPDATA 'mise\installs\java\21*'),
|
|
(Join-Path $env:LOCALAPPDATA 'mise\installs\java\2*')
|
|
)
|
|
foreach ($pattern in $patterns) {
|
|
foreach ($dir in (Get-ChildItem -Path $pattern -Directory -ErrorAction SilentlyContinue)) {
|
|
$candidates.Add($dir.FullName)
|
|
}
|
|
}
|
|
|
|
foreach ($candidate in $candidates) {
|
|
if (Test-Jdk21 -JdkHome $candidate) { return (Resolve-Path $candidate).Path }
|
|
}
|
|
|
|
if ($AllowDownload) { return (Install-Jdk21) }
|
|
return $null
|
|
}
|
|
|
|
# Downloads a portable Temurin JDK 21 (used only when no local JDK 21 exists).
|
|
function Install-Jdk21 {
|
|
$dest = Join-Path $PSScriptRoot '.jdk'
|
|
New-Item -ItemType Directory -Force $dest | Out-Null
|
|
|
|
Write-Host '[setup] no JDK 21 found, downloading Temurin 21 from the Tsinghua mirror ...' -ForegroundColor Yellow
|
|
$mirror = 'https://mirrors.tuna.tsinghua.edu.cn/Adoptium/21/jdk/x64/windows/'
|
|
$listing = (Invoke-WebRequest -Uri $mirror -UseBasicParsing -TimeoutSec 60).Content
|
|
$names = [regex]::Matches($listing, 'OpenJDK21U-jdk_x64_windows_hotspot_[0-9._]+\.zip') |
|
|
ForEach-Object { $_.Value } | Sort-Object -Unique
|
|
if (-not $names) { throw "Could not find a JDK 21 archive at $mirror" }
|
|
$zipName = $names[$names.Count - 1]
|
|
|
|
$zip = Join-Path $env:TEMP $zipName
|
|
if (-not (Test-Path $zip)) {
|
|
Invoke-WebRequest -Uri ($mirror + $zipName) -OutFile $zip -UseBasicParsing -TimeoutSec 1800
|
|
}
|
|
Expand-Archive -Path $zip -DestinationPath $dest -Force
|
|
|
|
$java = Get-ChildItem -Path (Join-Path $dest '*\bin\java.exe') -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if (-not $java) { throw "JDK extraction failed under $dest" }
|
|
$JdkHome = Split-Path (Split-Path $java.FullName -Parent) -Parent
|
|
Write-Host "[setup] JDK 21 installed at $JdkHome" -ForegroundColor Green
|
|
return $JdkHome
|
|
}
|
|
|
|
function Get-JavaCommand {
|
|
param([string]$Root = (Get-ProjectRoot))
|
|
$jdkHome = Find-Jdk21
|
|
if (-not $jdkHome) {
|
|
throw 'JDK 21 is required. Run tools\build.ps1 (it can download one), or set EBOOK_NOVEL_JAVA_HOME.'
|
|
}
|
|
return (Join-Path $jdkHome 'bin\java.exe')
|
|
}
|
|
|
|
function Find-JarTool {
|
|
# JBR ships without jar.exe, so fall back to any other JDK on the machine.
|
|
foreach ($pattern in @('C:\Program Files\Java\*\bin\jar.exe',
|
|
(Join-Path $env:LOCALAPPDATA 'mise\installs\java\*\bin\jar.exe'),
|
|
'C:\Program Files\Eclipse Adoptium\*\bin\jar.exe')) {
|
|
$exe = Get-ChildItem -Path $pattern -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($exe) { return $exe.FullName }
|
|
}
|
|
$cmd = Get-Command jar.exe -ErrorAction SilentlyContinue
|
|
if ($cmd) { return $cmd.Source }
|
|
return $null
|
|
}
|
|
|