node-sword-interface 1.0.46 → 1.0.47
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/binding.gyp +1 -1
- package/package.json +1 -1
- package/scripts/get_sword_build_win32.js +160 -0
package/binding.gyp
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
'message': 'Downloading sword-build-win32 artifacts from GitHub ...',
|
|
45
45
|
'inputs': [],
|
|
46
46
|
'outputs': ['sword-build-win32'],
|
|
47
|
-
'action': ['
|
|
47
|
+
'action': ['node', '<(module_root_dir)/scripts/get_sword_build_win32.js'],
|
|
48
48
|
}
|
|
49
49
|
]
|
|
50
50
|
}]
|
package/package.json
CHANGED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// This file is part of node-sword-interface.
|
|
3
|
+
// This script downloads a release asset (zip) from GitHub, extracts it and
|
|
4
|
+
// renames the directory to sword-build-win32 inside the current working directory.
|
|
5
|
+
//
|
|
6
|
+
// License: GPL-2.0+
|
|
7
|
+
|
|
8
|
+
const https = require('https');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const { execFileSync } = require('child_process');
|
|
12
|
+
|
|
13
|
+
const RELEASE_TAG = 'v1.8.900-2022-11-06';
|
|
14
|
+
const API_URL = `https://api.github.com/repos/ezra-bible-app/sword-build-win32/releases/tags/${RELEASE_TAG}`;
|
|
15
|
+
|
|
16
|
+
function fetchJson(url, headers = {}) {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
|
+
const req = https.get(url, {
|
|
19
|
+
headers: {
|
|
20
|
+
'User-Agent': 'node-sword-interface',
|
|
21
|
+
'Accept': 'application/vnd.github+json',
|
|
22
|
+
...headers,
|
|
23
|
+
}
|
|
24
|
+
}, res => {
|
|
25
|
+
let data = '';
|
|
26
|
+
res.on('data', chunk => data += chunk);
|
|
27
|
+
res.on('end', () => {
|
|
28
|
+
if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
|
|
29
|
+
try {
|
|
30
|
+
resolve(JSON.parse(data));
|
|
31
|
+
} catch (e) {
|
|
32
|
+
reject(e);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
reject(new Error(`Request failed: ${res.statusCode} ${data}`));
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
req.on('error', reject);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function downloadFile(url, outPath, headers = {}, maxRedirects = 5) {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
let redirects = 0;
|
|
46
|
+
|
|
47
|
+
const doRequest = (reqUrl) => {
|
|
48
|
+
const file = fs.createWriteStream(outPath);
|
|
49
|
+
const req = https.get(reqUrl, {
|
|
50
|
+
headers: {
|
|
51
|
+
'User-Agent': 'node-sword-interface',
|
|
52
|
+
'Accept': 'application/octet-stream',
|
|
53
|
+
...headers,
|
|
54
|
+
}
|
|
55
|
+
}, res => {
|
|
56
|
+
// Handle redirects
|
|
57
|
+
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
58
|
+
file.close(); // ensure stream closed before re-request
|
|
59
|
+
fs.unlink(outPath, () => {
|
|
60
|
+
if (redirects >= maxRedirects) {
|
|
61
|
+
reject(new Error(`Too many redirects downloading: ${reqUrl}`));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
redirects++;
|
|
65
|
+
const nextUrl = res.headers.location.startsWith('http')
|
|
66
|
+
? res.headers.location
|
|
67
|
+
: new URL(res.headers.location, reqUrl).toString();
|
|
68
|
+
doRequest(nextUrl);
|
|
69
|
+
});
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (res.statusCode && (res.statusCode < 200 || res.statusCode >= 300)) {
|
|
74
|
+
file.close();
|
|
75
|
+
fs.unlink(outPath, () => reject(new Error(`Download failed: ${res.statusCode}`)));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
res.pipe(file);
|
|
80
|
+
file.on('finish', () => file.close(resolve));
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
req.on('error', err => {
|
|
84
|
+
file.close();
|
|
85
|
+
fs.unlink(outPath, () => reject(err));
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
doRequest(url);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function main() {
|
|
94
|
+
try {
|
|
95
|
+
const isCI = process.env.CI === 'true';
|
|
96
|
+
const githubToken = process.env.GITHUB_TOKEN;
|
|
97
|
+
const authHeader = (isCI && githubToken) ? { Authorization: `Bearer ${githubToken}` } : {};
|
|
98
|
+
|
|
99
|
+
if (isCI) {
|
|
100
|
+
console.log('GitHub actions build ... using GITHUB_TOKEN for authentication!');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const release = await fetchJson(API_URL, authHeader);
|
|
104
|
+
if (!release.assets || !release.assets.length) {
|
|
105
|
+
throw new Error('No assets found in release.');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const asset = release.assets[0];
|
|
109
|
+
const zipName = asset.name;
|
|
110
|
+
const zipUrl = asset.browser_download_url;
|
|
111
|
+
|
|
112
|
+
const cwd = process.cwd();
|
|
113
|
+
|
|
114
|
+
// Remove existing folder if present
|
|
115
|
+
const existingDir = path.join(cwd, 'sword-build-win32');
|
|
116
|
+
if (fs.existsSync(existingDir)) {
|
|
117
|
+
fs.rmSync(existingDir, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const zipPath = path.join(cwd, zipName);
|
|
121
|
+
console.log(`Downloading ${zipUrl} -> ${zipPath}`);
|
|
122
|
+
await downloadFile(zipUrl, zipPath, authHeader);
|
|
123
|
+
|
|
124
|
+
// Extract ZIP file
|
|
125
|
+
const extractedDirName = zipName.replace(/\.zip$/i, '');
|
|
126
|
+
try {
|
|
127
|
+
if (process.platform === 'win32') {
|
|
128
|
+
execFileSync('powershell', ['-NoProfile', '-Command', `Expand-Archive -Path '${zipPath}' -DestinationPath '.' -Force`], { stdio: 'inherit' });
|
|
129
|
+
} else {
|
|
130
|
+
// Prefer system unzip if available
|
|
131
|
+
try {
|
|
132
|
+
execFileSync('unzip', ['-o', zipPath], { stdio: 'inherit' });
|
|
133
|
+
} catch (unzipErr) {
|
|
134
|
+
// Fallback to 7z if unzip is not present
|
|
135
|
+
execFileSync('7z', ['x', zipPath], { stdio: 'inherit' });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} catch (e) {
|
|
139
|
+
throw new Error(`Extraction failed: ${e.message}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Remove zip file
|
|
143
|
+
fs.unlinkSync(zipPath);
|
|
144
|
+
|
|
145
|
+
// Rename extracted folder
|
|
146
|
+
if (!fs.existsSync(path.join(cwd, extractedDirName))) {
|
|
147
|
+
throw new Error(`Expected extracted directory '${extractedDirName}' not found.`);
|
|
148
|
+
}
|
|
149
|
+
fs.renameSync(path.join(cwd, extractedDirName), existingDir);
|
|
150
|
+
|
|
151
|
+
console.log('Download of Windows library artifacts completed!');
|
|
152
|
+
} catch (err) {
|
|
153
|
+
console.error('Error:', err.message);
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (require.main === module) {
|
|
159
|
+
main();
|
|
160
|
+
}
|