Skip to content

Commit 9557b1e

Browse files
マルチエンジン:VVPPに7zを使えるように (#1253)
Co-authored-by: Hiroshiba <[email protected]>
1 parent 64e0447 commit 9557b1e

File tree

12 files changed

+603
-312
lines changed

12 files changed

+603
-312
lines changed

build/7zr.exe

-512 KB
Binary file not shown.

build/download7z.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// @ts-check
2+
/**
3+
* OSに合った7-Zipのバイナリとライセンスをダウンロードするスクリプト。
4+
*/
5+
const path = require("path");
6+
const fs = require("fs");
7+
const { spawnSync } = require("child_process");
8+
9+
(async () => {
10+
// node-fetchはESModuleなので、import()で読み込む
11+
const { default: fetch } = await import("node-fetch");
12+
const distPath = path.resolve(__dirname, "vendored", "7z");
13+
let url;
14+
let filesToExtract;
15+
switch (process.platform) {
16+
case "win32": {
17+
// 7za.exeは7z形式で圧縮されているので、7zr.exeが必要になる。
18+
// Mac/Linuxと違い、インストーラー以外には7z形式でしか配布されていない。
19+
// Actionsでインストーラーを動かすことはできないので、単独で配布されている7zr.exeを使い、
20+
// 7z形式で圧縮されている7za.exeを展開する。
21+
const sevenzrUrl = "https://www.7-zip.org/a/7zr.exe";
22+
const sevenzrPath = path.resolve(distPath, "7zr.exe");
23+
if (!fs.existsSync(sevenzrPath)) {
24+
console.log("Downloading 7zr from " + sevenzrUrl);
25+
const res = await fetch(sevenzrUrl);
26+
const buffer = await res.arrayBuffer();
27+
28+
await fs.promises.writeFile(sevenzrPath, Buffer.from(buffer));
29+
}
30+
31+
url = "https://www.7-zip.org/a/7z2201-extra.7z";
32+
// 7za.dll、7zxa.dllはなくても動くので、除外する
33+
// filesToExtract = ["7za.exe", "7za.dll", "7zxa.dll", "License.txt"];
34+
filesToExtract = ["7za.exe", "License.txt"];
35+
36+
break;
37+
}
38+
case "linux": {
39+
url = "https://www.7-zip.org/a/7z2201-linux-x64.tar.xz";
40+
filesToExtract = ["7zzs", "License.txt"];
41+
break;
42+
}
43+
case "darwin": {
44+
url = "https://www.7-zip.org/a/7z2107-mac.tar.xz";
45+
filesToExtract = ["7zz", "License.txt"];
46+
break;
47+
}
48+
default: {
49+
throw new Error("Unsupported platform");
50+
}
51+
}
52+
53+
const existingFiles = await fs.promises.readdir(distPath);
54+
55+
const notDownloaded = filesToExtract.filter(
56+
(file) => !existingFiles.includes(file)
57+
);
58+
59+
if (notDownloaded.length === 0) {
60+
console.log("7z already downloaded");
61+
return;
62+
}
63+
64+
console.log("Downloading 7z from " + url);
65+
const res = await fetch(url);
66+
const buffer = await res.arrayBuffer();
67+
const sevenZipPath = path.resolve(distPath, path.basename(url));
68+
await fs.promises.writeFile(sevenZipPath, Buffer.from(buffer));
69+
70+
console.log("Extracting 7z");
71+
const extractor = url.endsWith(".7z")
72+
? spawnSync(
73+
path.resolve(distPath, "7zr.exe"),
74+
["x", "-y", "-o" + distPath, sevenZipPath, ...filesToExtract],
75+
{
76+
stdio: ["ignore", "inherit", "inherit"],
77+
}
78+
)
79+
: spawnSync(
80+
"tar",
81+
["xvf", sevenZipPath, "-v", "-C", distPath, ...filesToExtract],
82+
{
83+
stdio: ["ignore", "inherit", "inherit"],
84+
}
85+
);
86+
87+
if (extractor.status !== 0) {
88+
console.error("Failed to extract 7z");
89+
process.exit(1);
90+
}
91+
})();

build/generateLicenses.js

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
const process = require("process");
44
const { execFileSync } = require("child_process");
55
const fs = require("fs");
6+
const path = require("path");
67
const yargs = require("yargs/yargs");
78
const { hideBin } = require("yargs/helpers");
89
const argv = yargs(hideBin(process.argv))
@@ -57,12 +58,40 @@ const licenseJson = execFileSync(
5758

5859
const checkerLicenses = JSON.parse(licenseJson);
5960

60-
const licenses = Object.entries(checkerLicenses).map(([, license]) => ({
61-
name: license.name,
62-
version: license.version,
63-
license: license.licenses,
64-
text: license.licenseText,
65-
}));
61+
const externalLicenses = [];
62+
63+
externalLicenses.push({
64+
name: "7-Zip",
65+
version: execFileSync(
66+
path.join(
67+
__dirname,
68+
"vendored",
69+
"7z",
70+
{
71+
win32: "7za.exe",
72+
linux: "7zzs",
73+
darwin: "7zz",
74+
}[process.platform]
75+
),
76+
77+
{
78+
encoding: "utf-8",
79+
}
80+
).match(/7-Zip\s+(?:\(.\))?\s*([0-9.]+)/)[1],
81+
license: "LGPL-2.1",
82+
text: fs.readFileSync(path.join(__dirname, "vendored", "7z", "License.txt"), {
83+
encoding: "utf-8",
84+
}),
85+
});
86+
87+
const licenses = Object.entries(checkerLicenses)
88+
.map(([, license]) => ({
89+
name: license.name,
90+
version: license.version,
91+
license: license.licenses,
92+
text: license.licenseText,
93+
}))
94+
.concat(externalLicenses);
6695

6796
const outputPath = argv.output_path;
6897
fs.writeFileSync(outputPath, JSON.stringify(licenses));

build/installer.nsh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@
107107
StrCpy $archiveSize $0
108108

109109
; 展開後の合計サイズを取得
110-
File /oname=$PLUGINSDIR\7zr.exe "${BUILD_RESOURCES_DIR}\7zr.exe"
110+
File /oname=$PLUGINSDIR\7za.exe "${BUILD_RESOURCES_DIR}\vendored\7z\7za.exe"
111111
${getUncompressedSizeFrom7z} $0 $1
112-
${If} $0 == "Failed to execute 7zr.exe"
112+
${If} $0 == "Failed to execute 7za.exe"
113113
${OrIf} $0 == "Failed to open file list"
114114
StrCpy $0 "Failed"
115115
Goto updateDefinedVariables7z_finish

build/vendored/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
*
2+
!README.md
3+
!.gitignore
4+
!*/.gitkeep

build/vendored/7z/.gitkeep

Whitespace-only changes.

build/vendored/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# build/vendored
2+
3+
このディレクトリはダウンロードしたファイルを格納するためのものです。
4+
5+
| ディレクトリ名 | 内容 | ダウンローダー |
6+
| -------------- | ------------------------------ | --------------------- |
7+
| `7z` | [7-Zip](http://www.7-zip.org/) | `build/download7z.js` |

electron-builder.config.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
// @ts-check
12
const path = require("path");
23
const fs = require("fs");
34

@@ -24,6 +25,19 @@ const isMac = process.platform === "darwin";
2425
// cf: https://k-hyoda.hatenablog.com/entry/2021/10/23/000349#%E8%BF%BD%E5%8A%A0%E5%B1%95%E9%96%8B%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%85%88%E3%81%AE%E8%A8%AD%E5%AE%9A
2526
const extraFilePrefix = isMac ? "MacOS/" : "";
2627

28+
const sevenZipFile = fs
29+
.readdirSync(path.resolve(__dirname, "build", "vendored", "7z"))
30+
.find(
31+
// Windows: 7za.exe, Linux: 7zzs, macOS: 7zz
32+
(fileName) => ["7za.exe", "7zzs", "7zz"].includes(fileName)
33+
);
34+
35+
if (!sevenZipFile) {
36+
throw new Error(
37+
"7z binary file not found. Run `node ./build/download7z.js` first."
38+
);
39+
}
40+
2741
/** @type {import("electron-builder").Configuration} */
2842
const builderOptions = {
2943
beforeBuild: async () => {
@@ -72,6 +86,10 @@ const builderOptions = {
7286
from: VOICEVOX_ENGINE_DIR,
7387
to: extraFilePrefix,
7488
},
89+
{
90+
from: path.resolve(__dirname, "build", "vendored", "7z", sevenZipFile),
91+
to: extraFilePrefix + sevenZipFile,
92+
},
7593
],
7694
// electron-builder installer
7795
productName: "VOICEVOX",

0 commit comments

Comments
 (0)