|
| 1 | +import { execSync } from "node:child_process"; |
1 | 2 | import fs from "node:fs"; |
2 | 3 | import path from "node:path"; |
3 | 4 | import { MakerDeb } from "@electron-forge/maker-deb"; |
4 | 5 | import { MakerSquirrel } from "@electron-forge/maker-squirrel"; |
5 | 6 | import { MakerZIP } from "@electron-forge/maker-zip"; |
6 | 7 | import { AutoUnpackNativesPlugin } from "@electron-forge/plugin-auto-unpack-natives"; |
7 | 8 | import { WebpackPlugin } from "@electron-forge/plugin-webpack"; |
8 | | -import type { ForgeConfig } from "@electron-forge/shared-types"; |
| 9 | +import type { ForgeConfig, ForgeMakeResult } from "@electron-forge/shared-types"; |
| 10 | +import packageJSON from "./package.json"; |
9 | 11 | import { mainConfig } from "./webpack/webpack.main.config"; |
10 | 12 | import { preloadConfig } from "./webpack/webpack.preload.config"; |
11 | 13 | import { rendererConfig } from "./webpack/webpack.renderer.config"; |
12 | 14 |
|
13 | | -// ! its not possible to build all targets at once anymore, because of `better-sqlite3` rebuild |
| 15 | +// ! its not possible to build all targets arch at once for windows anymore, because of `better-sqlite3` rebuild |
| 16 | + |
| 17 | +const MAIN_OUT_DIR = path.resolve("./out/all"); |
| 18 | + |
| 19 | +const { productName: appName } = packageJSON; |
14 | 20 |
|
15 | 21 | const config: ForgeConfig = { |
16 | 22 | packagerConfig: { |
17 | | - name: "Yomikiru", |
| 23 | + name: appName, |
18 | 24 | asar: true, |
19 | 25 | // needed for migrating better-sqlite3 |
20 | 26 | extraResource: ["./drizzle"], |
21 | | - executableName: process.platform === "win32" ? "Yomikiru" : "yomikiru", |
| 27 | + executableName: process.platform === "win32" ? appName : appName.toLowerCase(), |
22 | 28 | }, |
23 | | - // rebuildConfig: { |
24 | | - // extraModules: ["better-sqlite3"], |
25 | | - // force: true, |
26 | | - // }, |
27 | 29 | plugins: [ |
28 | 30 | new AutoUnpackNativesPlugin({}), |
29 | 31 | new WebpackPlugin({ |
@@ -69,117 +71,102 @@ const config: ForgeConfig = { |
69 | 71 | ), |
70 | 72 | ], |
71 | 73 | hooks: { |
72 | | - postMake: async (_config, makeResults) => { |
73 | | - // const appName = config.packagerConfig.name; |
74 | | - const appName = "Yomikiru"; |
75 | | - const appVersion = makeResults[0].packageJSON.version; |
76 | | - |
77 | | - const MAP = { |
78 | | - "win32+zip+ia32": { |
79 | | - name: `${appName}-win32-v${appVersion}-Portable.zip`, |
80 | | - text: "Download 32-bit Portable (zip)", |
81 | | - icon: "windows&logoColor=blue", |
82 | | - }, |
83 | | - "win32+zip+x64": { |
84 | | - name: `${appName}-win32-v${appVersion}-Portable-x64.zip`, |
85 | | - text: "Download 64-bit Portable (zip)", |
86 | | - icon: "windows&logoColor=blue", |
87 | | - }, |
88 | | - "win32+exe+ia32": { |
89 | | - name: `${appName}-v${appVersion}-Setup.exe`, |
90 | | - text: "Download 32-bit Setup (exe)", |
91 | | - icon: "windows&logoColor=blue", |
92 | | - }, |
93 | | - "win32+exe+x64": { |
94 | | - name: `${appName}-v${appVersion}-Setup-x64.exe`, |
95 | | - text: "Download 64-bit Setup (exe)", |
96 | | - icon: "windows&logoColor=blue", |
97 | | - }, |
98 | | - "linux+deb+x64": { |
99 | | - name: `${appName}-v${appVersion}-amd64.deb`, |
100 | | - text: "Download 64-bit Linux (Debian)", |
101 | | - icon: "debian&logoColor=red", |
102 | | - }, |
103 | | - "linux+deb+amd64": { |
104 | | - name: `${appName}-v${appVersion}-amd64.deb`, |
105 | | - text: "Download 64-bit Linux (Debian)", |
106 | | - icon: "debian&logoColor=red", |
107 | | - }, |
108 | | - "darwin+zip+x64": { |
109 | | - name: `${appName}-v${appVersion}-macOS-x64.zip`, |
110 | | - text: "Download 64-bit macOS (zip)", |
111 | | - icon: "apple&logoColor=black", |
112 | | - }, |
| 74 | + postMake: async (_config: unknown, makeResults: ForgeMakeResult[]) => { |
| 75 | + const BUILD_ARTIFACTS_DIR = path.resolve("./build-artifacts"); |
| 76 | + |
| 77 | + if (!fs.existsSync(BUILD_ARTIFACTS_DIR)) { |
| 78 | + fs.mkdirSync(BUILD_ARTIFACTS_DIR, { recursive: true }); |
| 79 | + } |
| 80 | + |
| 81 | + if (!fs.existsSync(MAIN_OUT_DIR)) { |
| 82 | + fs.mkdirSync(MAIN_OUT_DIR, { recursive: true }); |
| 83 | + } |
| 84 | + |
| 85 | + const platform = makeResults[0].platform; |
| 86 | + const arch = makeResults[0].arch; |
| 87 | + const timestamp = Date.now(); |
| 88 | + const filename = `${platform}-${arch}-${timestamp}.json`; |
| 89 | + const filePath = path.join(BUILD_ARTIFACTS_DIR, filename); |
| 90 | + |
| 91 | + // normalize paths to be relative to process.cwd() for cross-platform compatibility |
| 92 | + const normalizePath = (filePath: string): string => { |
| 93 | + const cwd = process.cwd(); |
| 94 | + if (path.isAbsolute(filePath)) { |
| 95 | + const relative = path.relative(cwd, filePath); |
| 96 | + return relative.startsWith("..") ? filePath : relative; |
| 97 | + } |
| 98 | + return filePath; |
113 | 99 | }; |
114 | 100 |
|
115 | | - const makeDlBtn = ({ |
116 | | - text, |
117 | | - name, |
118 | | - icon, |
119 | | - url, |
120 | | - }: { |
121 | | - text: string; |
122 | | - name: string; |
123 | | - icon: string; |
124 | | - url: string; |
125 | | - }) => |
126 | | - `[.replace( |
127 | | - /-/g, |
128 | | - "--", |
129 | | - )}-${encodeURIComponent(name).replace(/-/g, "--")}-brightgreen?logo=${icon})](${ |
130 | | - url |
131 | | - }/releases/download/v${appVersion}/${name})\n`; |
132 | | - |
133 | | - const mainOutDir = path.resolve("./out/all"); |
134 | | - |
135 | | - // const filesToUploadTxt = "files-to-upload.txt"; |
136 | | - const downloadBtnsTxt = "download-btns.txt"; |
137 | | - const initialDownloadBtns = |
138 | | - `## Downloads\n\n` + |
139 | | - // linux is built in another job and downloaded here as artifact |
140 | | - makeDlBtn({ |
141 | | - ...MAP["linux+deb+amd64"], |
142 | | - url: makeResults[0].packageJSON.author.url, |
143 | | - }) + |
144 | | - "\n"; |
145 | | - |
146 | | - if (!fs.existsSync(downloadBtnsTxt)) fs.writeFileSync(downloadBtnsTxt, initialDownloadBtns, "utf-8"); |
147 | | - // if (!fs.existsSync(filesToUploadTxt)) |
148 | | - // fs.writeFileSync( |
149 | | - // filesToUploadTxt, |
150 | | - // path.join(mainOutDir, MAP["linux+deb+amd64"].name.replace(/\\/g, "/")) + " ", |
151 | | - // "utf-8", |
152 | | - // ); |
153 | | - |
154 | | - if (!fs.existsSync(mainOutDir)) fs.mkdirSync(mainOutDir); |
155 | | - |
156 | | - makeResults.forEach((res, idx) => { |
157 | | - // on windows squirrel, there are 3 artifacts and 2nd is the executable |
158 | | - const mainIdx = res.artifacts.length === 1 ? 0 : 1; |
159 | | - const key = |
160 | | - `${res.platform}+${path.extname(res.artifacts[mainIdx]).replace(".", "")}+${res.arch}` as keyof typeof MAP; |
161 | | - if (!MAP[key]) { |
162 | | - console.error(`Unknown artifact: ${key}`); |
163 | | - process.exit(1); |
| 101 | + const artifactsToSave = makeResults.map((result) => ({ |
| 102 | + platform: result.platform, |
| 103 | + arch: result.arch, |
| 104 | + artifacts: result.artifacts.map(normalizePath), |
| 105 | + })); |
| 106 | + |
| 107 | + let pacmanArtifactPath: string | null = null; |
| 108 | + if (platform === "linux") { |
| 109 | + const appName = makeResults[0].packageJSON.productName; |
| 110 | + const appVersion = makeResults[0].packageJSON.version; |
| 111 | + const expectedPkgName = `${appName}-v${appVersion}-x86_64.pkg.tar.xz`; |
| 112 | + const pkgFile = path.join(MAIN_OUT_DIR, expectedPkgName); |
| 113 | + |
| 114 | + const debArtifact = makeResults[0].artifacts.find((a: string) => a.endsWith(".deb")); |
| 115 | + if (debArtifact && fs.existsSync(debArtifact) && !fs.existsSync(pkgFile)) { |
| 116 | + try { |
| 117 | + const tempDir = path.join(MAIN_OUT_DIR, `temp-pacman-${Date.now()}`); |
| 118 | + fs.mkdirSync(tempDir, { recursive: true }); |
| 119 | + |
| 120 | + execSync(`dpkg-deb -x "${debArtifact}" "${tempDir}/extracted"`, { stdio: "inherit" }); |
| 121 | + execSync(`dpkg-deb -e "${debArtifact}" "${tempDir}/control"`, { stdio: "inherit" }); |
| 122 | + |
| 123 | + const pkgDir = path.join(tempDir, "pkg"); |
| 124 | + const extractedDir = path.join(tempDir, "extracted"); |
| 125 | + if (fs.existsSync(extractedDir)) { |
| 126 | + fs.mkdirSync(pkgDir, { recursive: true }); |
| 127 | + const usrDir = path.join(pkgDir, "usr"); |
| 128 | + fs.cpSync(extractedDir, usrDir, { recursive: true }); |
| 129 | + } |
| 130 | + |
| 131 | + const pkgInfoPath = path.join(pkgDir, ".PKGINFO"); |
| 132 | + const stats = fs.statSync(debArtifact); |
| 133 | + const pkgInfo = `pkgname = ${appName.toLowerCase()} |
| 134 | +pkgver = ${appVersion} |
| 135 | +pkgdesc = ${packageJSON.description} |
| 136 | +url = ${packageJSON.author.url} |
| 137 | +packager = ${packageJSON.author.name} |
| 138 | +arch = x86_64 |
| 139 | +size = ${stats.size} |
| 140 | +license = ${packageJSON.license} |
| 141 | +`; |
| 142 | + fs.writeFileSync(pkgInfoPath, pkgInfo); |
| 143 | + |
| 144 | + const mtreePath = path.join(pkgDir, ".MTREE"); |
| 145 | + fs.writeFileSync(mtreePath, "#mtree\n"); |
| 146 | + |
| 147 | + execSync( |
| 148 | + `cd "${pkgDir}" && tar -cJf "${pkgFile}" .PKGINFO .MTREE usr 2>/dev/null || (tar -cf - .PKGINFO .MTREE usr | xz > "${pkgFile}")`, |
| 149 | + { stdio: "inherit" }, |
| 150 | + ); |
| 151 | + |
| 152 | + console.log(`Created pacman package: ${pkgFile}`); |
| 153 | + pacmanArtifactPath = normalizePath(pkgFile); |
| 154 | + |
| 155 | + fs.rmSync(tempDir, { recursive: true, force: true }); |
| 156 | + } catch (error) { |
| 157 | + console.warn(`Failed to create pacman package: ${error}`); |
| 158 | + } |
| 159 | + } else if (fs.existsSync(pkgFile)) { |
| 160 | + pacmanArtifactPath = normalizePath(pkgFile); |
164 | 161 | } |
165 | | - const { name, text, icon } = MAP[key]; |
166 | | - |
167 | | - const newPath = path.join(mainOutDir, name); |
168 | | - fs.renameSync(res.artifacts[mainIdx], newPath); |
169 | | - |
170 | | - makeResults[idx].artifacts[mainIdx] = newPath; |
171 | | - |
172 | | - // fs.appendFileSync(filesToUploadTxt, newPath.replace(/\\/g, "/") + " ", "utf-8"); |
| 162 | + } |
173 | 163 |
|
174 | | - const downloadBtn = makeDlBtn({ |
175 | | - text, |
176 | | - name, |
177 | | - icon, |
178 | | - url: res.packageJSON.author.url, |
179 | | - }); |
| 164 | + if (pacmanArtifactPath) { |
| 165 | + artifactsToSave[0].artifacts.push(pacmanArtifactPath); |
| 166 | + } |
180 | 167 |
|
181 | | - fs.appendFileSync(downloadBtnsTxt, downloadBtn, "utf-8"); |
182 | | - }); |
| 168 | + fs.writeFileSync(filePath, JSON.stringify(artifactsToSave, null, 2), "utf-8"); |
| 169 | + console.log(`Saved build artifacts to: ${filePath}`); |
183 | 170 |
|
184 | 171 | return makeResults; |
185 | 172 | }, |
|
0 commit comments