@clazic/urban 0.2.22 → 0.2.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/scripts/setup-poppler.js +35 -88
package/package.json
CHANGED
package/scripts/setup-poppler.js
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// setup-poppler.js: Windows에서 poppler (pdftoppm) 자동 설치
|
|
3
|
-
//
|
|
4
|
-
// 실패해도 설치 자체를 중단하지 않음 (exit 0 보장)
|
|
3
|
+
// PowerShell 내장 Invoke-WebRequest + Expand-Archive 사용 (외부 의존성 없음)
|
|
5
4
|
|
|
6
5
|
import { execSync } from 'child_process';
|
|
7
|
-
import { existsSync, mkdirSync,
|
|
8
|
-
import {
|
|
9
|
-
import { homedir, tmpdir } from 'os';
|
|
6
|
+
import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
7
|
+
import { homedir } from 'os';
|
|
10
8
|
import { join } from 'path';
|
|
11
|
-
import https from 'https';
|
|
12
9
|
|
|
13
10
|
const URBAN_HOME = process.env.URBAN_HOME ?? join(homedir(), '.urban');
|
|
14
11
|
const POPPLER_DIR = join(URBAN_HOME, 'bin', 'poppler');
|
|
15
12
|
const BIN_PATH_FILE = join(URBAN_HOME, 'bin', 'poppler-bin-path.txt');
|
|
16
13
|
|
|
17
|
-
/**
|
|
14
|
+
/** 재귀 탐색으로 pdftoppm.exe가 있는 폴더 반환 */
|
|
18
15
|
function findBinDir(dir) {
|
|
19
16
|
if (!existsSync(dir)) return null;
|
|
20
17
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
@@ -29,65 +26,14 @@ function findBinDir(dir) {
|
|
|
29
26
|
return null;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
|
-
/** 시스템 PATH 또는 로컬 설치 여부 확인 */
|
|
33
29
|
function hasPdftoppm() {
|
|
34
30
|
try { execSync('where pdftoppm', { stdio: 'ignore', shell: true }); return true; } catch {}
|
|
35
31
|
return findBinDir(POPPLER_DIR) !== null;
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
/** GitHub API에서 최신 릴리즈 zip URL 조회 */
|
|
39
|
-
function getLatestZipUrl() {
|
|
40
|
-
return new Promise((resolve, reject) => {
|
|
41
|
-
https.get({
|
|
42
|
-
hostname: 'api.github.com',
|
|
43
|
-
path: '/repos/oschwartz10612/poppler-windows/releases/latest',
|
|
44
|
-
headers: { 'User-Agent': 'urban-postinstall' },
|
|
45
|
-
}, (res) => {
|
|
46
|
-
let data = '';
|
|
47
|
-
res.on('data', d => data += d);
|
|
48
|
-
res.on('end', () => {
|
|
49
|
-
try {
|
|
50
|
-
const json = JSON.parse(data);
|
|
51
|
-
const asset = json.assets?.find(a => a.name.endsWith('.zip'));
|
|
52
|
-
resolve(asset?.browser_download_url ?? null);
|
|
53
|
-
} catch (e) { reject(e); }
|
|
54
|
-
});
|
|
55
|
-
}).on('error', reject);
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/** HTTPS 다운로드 (리다이렉트 최대 5회) */
|
|
60
|
-
function download(url, dest, hops = 5) {
|
|
61
|
-
return new Promise((resolve, reject) => {
|
|
62
|
-
if (hops <= 0) { reject(new Error('Too many redirects')); return; }
|
|
63
|
-
https.get(url, { headers: { 'User-Agent': 'urban-postinstall' } }, (res) => {
|
|
64
|
-
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
65
|
-
download(res.headers.location, dest, hops - 1).then(resolve, reject);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
if (res.statusCode !== 200) { reject(new Error(`HTTP ${res.statusCode}`)); return; }
|
|
69
|
-
const file = createWriteStream(dest);
|
|
70
|
-
res.pipe(file);
|
|
71
|
-
file.on('finish', () => file.close(resolve));
|
|
72
|
-
file.on('error', reject);
|
|
73
|
-
}).on('error', reject);
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** unzipper로 압축 해제 */
|
|
78
|
-
async function extractZip(zipPath, destDir) {
|
|
79
|
-
const { default: unzipper } = await import('unzipper');
|
|
80
|
-
const { createReadStream } = await import('fs');
|
|
81
|
-
mkdirSync(destDir, { recursive: true });
|
|
82
|
-
await createReadStream(zipPath)
|
|
83
|
-
.pipe(unzipper.Extract({ path: destDir }))
|
|
84
|
-
.promise();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
34
|
async function main() {
|
|
88
35
|
if (hasPdftoppm()) {
|
|
89
36
|
console.log('[urban] pdftoppm 이미 설치됨 — 건너뜀');
|
|
90
|
-
// 로컬 설치 경로가 있으면 경로 파일 업데이트
|
|
91
37
|
const binDir = findBinDir(POPPLER_DIR);
|
|
92
38
|
if (binDir) {
|
|
93
39
|
mkdirSync(join(URBAN_HOME, 'bin'), { recursive: true });
|
|
@@ -96,46 +42,47 @@ async function main() {
|
|
|
96
42
|
return;
|
|
97
43
|
}
|
|
98
44
|
|
|
99
|
-
console.log('[urban] poppler (
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
execSync(
|
|
104
|
-
'winget install --exact --silent --accept-package-agreements --accept-source-agreements "oschwartz10612.poppler"',
|
|
105
|
-
{ stdio: 'pipe', shell: true, timeout: 120_000 }
|
|
106
|
-
);
|
|
107
|
-
console.log('[urban] poppler 설치 완료 (winget)');
|
|
108
|
-
return;
|
|
109
|
-
} catch {
|
|
110
|
-
console.log('[urban] winget 실패 → GitHub 릴리즈에서 직접 다운로드...');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// ── 2. GitHub 릴리즈 직접 다운로드 ────────────────────────────────
|
|
114
|
-
const url = await getLatestZipUrl();
|
|
115
|
-
if (!url) throw new Error('GitHub 릴리즈 URL을 가져오지 못했습니다');
|
|
116
|
-
|
|
117
|
-
console.log(`[urban] 다운로드 중: ${url}`);
|
|
118
|
-
const zipPath = join(tmpdir(), 'poppler-windows.zip');
|
|
119
|
-
await download(url, zipPath);
|
|
45
|
+
console.log('[urban] poppler 다운로드 중 (GitHub → ~/.urban/bin/poppler)...');
|
|
46
|
+
mkdirSync(POPPLER_DIR, { recursive: true });
|
|
47
|
+
mkdirSync(join(URBAN_HOME, 'bin'), { recursive: true });
|
|
120
48
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
49
|
+
const psQ = (s) => String(s).replace(/'/g, "''");
|
|
50
|
+
|
|
51
|
+
// PowerShell: GitHub API → WebClient 다운로드 → Expand-Archive
|
|
52
|
+
// Invoke-WebRequest 대신 WebClient 사용 — 이진 파일 다운로드가 빠르고 진행 표시줄 없음
|
|
53
|
+
const ps = `
|
|
54
|
+
$ErrorActionPreference = 'Stop'
|
|
55
|
+
$ProgressPreference = 'SilentlyContinue'
|
|
56
|
+
$api = Invoke-RestMethod -Uri 'https://api.github.com/repos/oschwartz10612/poppler-windows/releases/latest' -Headers @{'User-Agent'='urban-installer'}
|
|
57
|
+
$url = ($api.assets | Where-Object { $_.name -like '*.zip' })[0].browser_download_url
|
|
58
|
+
$zip = Join-Path $env:TEMP 'poppler-windows.zip'
|
|
59
|
+
$dest = '${psQ(POPPLER_DIR)}'
|
|
60
|
+
Write-Host "[urban] poppler 다운로드 중: $url"
|
|
61
|
+
$wc = New-Object System.Net.WebClient
|
|
62
|
+
$wc.Headers.Add('User-Agent', 'urban-installer')
|
|
63
|
+
$wc.DownloadFile($url, $zip)
|
|
64
|
+
Write-Host "[urban] 압축 해제 중..."
|
|
65
|
+
Expand-Archive -Path $zip -DestinationPath $dest -Force
|
|
66
|
+
Remove-Item $zip -ErrorAction SilentlyContinue
|
|
67
|
+
Write-Host "[urban] poppler 설치 완료: $dest"
|
|
68
|
+
`.trim();
|
|
69
|
+
|
|
70
|
+
const encoded = Buffer.from(ps, 'utf16le').toString('base64');
|
|
71
|
+
execSync(`powershell -NoProfile -ExecutionPolicy Bypass -EncodedCommand ${encoded}`, {
|
|
72
|
+
stdio: 'inherit',
|
|
73
|
+
timeout: 300_000,
|
|
74
|
+
});
|
|
124
75
|
|
|
125
|
-
// pdftoppm.exe 위치 탐색
|
|
126
76
|
const binDir = findBinDir(POPPLER_DIR);
|
|
127
|
-
if (!binDir) throw new Error('
|
|
77
|
+
if (!binDir) throw new Error('pdftoppm.exe를 찾을 수 없습니다');
|
|
128
78
|
|
|
129
|
-
// 데몬 시작 스크립트가 PATH에 주입할 수 있도록 경로 저장
|
|
130
|
-
mkdirSync(join(URBAN_HOME, 'bin'), { recursive: true });
|
|
131
79
|
writeFileSync(BIN_PATH_FILE, binDir, 'utf8');
|
|
132
|
-
|
|
133
80
|
console.log(`[urban] poppler 설치 완료 → ${binDir}`);
|
|
134
81
|
}
|
|
135
82
|
|
|
136
83
|
if (process.platform === 'win32') {
|
|
137
84
|
await main().catch(err => {
|
|
138
85
|
console.warn('[urban] poppler 자동 설치 실패 (계속 진행):', err.message);
|
|
139
|
-
console.warn('[urban] 수동 설치:
|
|
86
|
+
console.warn('[urban] 수동 설치: https://github.com/oschwartz10612/poppler-windows/releases');
|
|
140
87
|
});
|
|
141
88
|
}
|