Skip to content

Commit c2602b9

Browse files
committed
feat(AppImage): support type 2 image format
Close electron-userland#2136, Close electron-userland#1998, Close electron-userland#832, Close electron-userland#993
1 parent f06324a commit c2602b9

File tree

15 files changed

+184
-154
lines changed

15 files changed

+184
-154
lines changed

.idea/dictionaries/develar.xml

+4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docker/appImage.sh

-6
This file was deleted.

docs/icons.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
Recommended tools: [MakeAppIcon](https://makeappicon.com/), [AppIcon Generator](http://www.tweaknow.com/appicongenerator.php).
1+
Recommended tools: [AppIcon Generator](http://www.tweaknow.com/appicongenerator.php), [MakeAppIcon](https://makeappicon.com/)
2+
.
23

34
## macOS
45

@@ -20,7 +21,7 @@ need to be placed in the [build](/configuration/configuration.md#MetadataDirecto
2021
Linux icon set will be generated automatically based on the macOS `icns` file.
2122

2223
Or you can put them into the `build/icons` directory if you want to specify them yourself.
23-
The filename must contain the size (e.g. `32x32.png`) of the icon). Recommended sizes: 16, 24, 32, 48, 64, 96, 128, 512, 1024 (or just 512).
24+
The filename must contain the size (e.g. `32x32.png`) of the icon). Recommended sizes: 16, 24, 32, 48, 64, 96, 128, 256. (or just 512).
2425

2526
## AppX
2627

packages/builder-util/src/fs.ts

+39-33
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export function copyFile(src: string, dest: string, isEnsureDir = true) {
137137
*
138138
* ensureDir is not called, dest parent dir must exists
139139
*/
140-
export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink): Promise<any> {
140+
export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink, exDevErrorHandler?: (() => boolean) | null): Promise<any> {
141141
if (stats != null) {
142142
const originalModeNumber = stats.mode
143143
const mode = new Mode(stats)
@@ -167,8 +167,23 @@ export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null,
167167

168168
if (isUseHardLink) {
169169
return link(src, dest)
170+
.catch(e => {
171+
if (e.code === "EXDEV") {
172+
const isLog = exDevErrorHandler == null ? true : exDevErrorHandler()
173+
if (isLog && debug.enabled) {
174+
debug(`Cannot copy using hard link: ${e.message}`)
175+
}
176+
return doCopyFile(src, dest, stats)
177+
}
178+
else {
179+
throw e
180+
}
181+
})
170182
}
183+
return doCopyFile(src, dest, stats)
184+
}
171185

186+
function doCopyFile(src: string, dest: string, stats: Stats | null | undefined): Promise<any> {
172187
if (_nodeCopyFile == null) {
173188
return new BluebirdPromise((resolve, reject) => {
174189
const reader = createReadStream(src)
@@ -181,16 +196,15 @@ export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null,
181196
writer.once("close", resolve)
182197
})
183198
}
184-
else {
185-
// node 8.5.0
186-
return _nodeCopyFile(src, dest)
187-
.then((): any => {
188-
if (stats != null) {
189-
return chmod(dest, stats.mode)
190-
}
191-
return null
192-
})
199+
200+
// node 8.5.0+
201+
const promise = _nodeCopyFile(src, dest)
202+
if (stats == null) {
203+
return promise
193204
}
205+
206+
return promise
207+
.then(() => chmod(dest, stats.mode))
194208
}
195209

196210
export class FileCopier {
@@ -201,37 +215,29 @@ export class FileCopier {
201215
}
202216

203217
async copy(src: string, dest: string, stat: Stats | undefined) {
204-
try {
205-
if (this.transformer != null && stat != null && stat.isFile()) {
206-
let data = this.transformer(src)
207-
if (data != null) {
208-
if (typeof (data as any).then === "function") {
209-
data = await data
210-
}
218+
if (this.transformer != null && stat != null && stat.isFile()) {
219+
let data = this.transformer(src)
220+
if (data != null) {
221+
if (typeof (data as any).then === "function") {
222+
data = await data
223+
}
211224

212-
if (data != null) {
213-
await writeFile(dest, data)
214-
return
215-
}
225+
if (data != null) {
226+
await writeFile(dest, data)
227+
return
216228
}
217229
}
218-
await copyOrLinkFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest))
219230
}
220-
catch (e) {
231+
await copyOrLinkFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest), this.isUseHardLink ? () => {
221232
// files are copied concurrently, so, we must not check here currentIsUseHardLink — our code can be executed after that other handler will set currentIsUseHardLink to false
222-
if (e.code === "EXDEV") {
223-
// ...but here we want to avoid excess debug log message
224-
if (this.isUseHardLink) {
225-
debug(`Cannot copy using hard link: ${e}`)
226-
this.isUseHardLink = false
227-
}
228-
229-
await copyOrLinkFile(src, dest, stat, false)
233+
if (this.isUseHardLink) {
234+
this.isUseHardLink = false
235+
return true
230236
}
231237
else {
232-
throw e
238+
return false
233239
}
234-
}
240+
} : null)
235241
}
236242
}
237243

packages/electron-builder/src/targets/LinuxTargetHelper.ts

+39-24
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ import { getTemplatePath } from "../util/pathManager"
99

1010
export const installPrefix = "/opt"
1111

12+
export interface IconInfo {
13+
file: string
14+
size: number
15+
}
16+
1217
export class LinuxTargetHelper {
13-
readonly icons: Promise<Array<Array<string>>>
18+
readonly icons: Promise<Array<IconInfo>>
1419

1520
maxIconPath: string | null = null
1621

@@ -19,7 +24,7 @@ export class LinuxTargetHelper {
1924
}
2025

2126
// must be name without spaces and other special characters, but not product name used
22-
private async computeDesktopIcons(): Promise<Array<Array<string>>> {
27+
private async computeDesktopIcons(): Promise<Array<IconInfo>> {
2328
const packager = this.packager
2429
const customIconSetDir = packager.platformSpecificBuildOptions.icon
2530
if (customIconSetDir != null) {
@@ -55,7 +60,7 @@ export class LinuxTargetHelper {
5560
}
5661

5762
private async iconsFromDir(iconDir: string) {
58-
const mappings: Array<Array<string>> = []
63+
const mappings: Array<IconInfo> = []
5964
let maxSize = 0
6065
for (const file of (await readdir(iconDir))) {
6166
if (file.endsWith(".png") || file.endsWith(".PNG")) {
@@ -66,7 +71,10 @@ export class LinuxTargetHelper {
6671
const size = sizeString == null ? 0 : parseInt(sizeString[0], 10)
6772
if (size > 0) {
6873
const iconPath = `${iconDir}/${file}`
69-
mappings.push([iconPath, `${size}x${size}/apps/${this.packager.executableName}.png`])
74+
mappings.push({
75+
file: iconPath,
76+
size,
77+
})
7078

7179
if (size > maxSize) {
7280
maxSize = size
@@ -100,7 +108,14 @@ export class LinuxTargetHelper {
100108
return options.description || this.packager.appInfo.description
101109
}
102110

103-
async computeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, destination?: string | null, extra?: { [key: string]: string; }): Promise<string> {
111+
async writeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, destination?: string | null, extra?: { [key: string]: string; }): Promise<string> {
112+
const data = await this.computeDesktopEntry(targetSpecificOptions, exec, extra)
113+
const tempFile = destination || await this.packager.getTempFile(`${this.packager.appInfo.productFilename}.desktop`)
114+
await outputFile(tempFile, data)
115+
return tempFile
116+
}
117+
118+
async computeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, extra?: { [key: string]: string; }): Promise<string> {
104119
if (exec != null && exec.length === 0) {
105120
throw new Error("Specified exec is emptyd")
106121
}
@@ -115,7 +130,9 @@ export class LinuxTargetHelper {
115130
Exec: exec == null ? `"${installPrefix}/${productFilename}/${this.packager.executableName}" %U` : exec,
116131
Terminal: "false",
117132
Type: "Application",
118-
Icon: this.packager.executableName, ...extra, ...targetSpecificOptions.desktop
133+
Icon: this.packager.executableName,
134+
...extra,
135+
...targetSpecificOptions.desktop,
119136
}
120137

121138
let category = targetSpecificOptions.category
@@ -143,13 +160,10 @@ export class LinuxTargetHelper {
143160
data += `\n${name}=${value}`
144161
}
145162
data += "\n"
146-
147-
const tempFile = destination || await this.packager.getTempFile(`${productFilename}.desktop`)
148-
await outputFile(tempFile, data)
149-
return tempFile
163+
return data
150164
}
151165

152-
private async createFromIcns(tempDir: string): Promise<Array<Array<string>>> {
166+
private async createFromIcns(tempDir: string): Promise<Array<IconInfo>> {
153167
const iconPath = await this.getIcns()
154168
if (iconPath == null) {
155169
return await this.iconsFromDir(path.join(getTemplatePath("linux"), "electron-icons"))
@@ -210,22 +224,23 @@ export class LinuxTargetHelper {
210224
}
211225

212226
private createMappings(tempDir: string) {
213-
const name = this.packager.executableName
214-
215-
function createMapping(size: string) {
216-
return [process.platform === "darwin" ? `${tempDir}/icon_${size}x${size}.png` : `${tempDir}/icon_${size}x${size}x32.png`, `${size}x${size}/apps/${name}.png`]
227+
function createMapping(size: number): IconInfo {
228+
return {
229+
file: process.platform === "darwin" ? `${tempDir}/icon_${size}x${size}.png` : `${tempDir}/icon_${size}x${size}x32.png`,
230+
size,
231+
}
217232
}
218233

219234
return [
220-
createMapping("16"),
221-
createMapping("24"),
222-
createMapping("32"),
223-
createMapping("48"),
224-
createMapping("64"),
225-
createMapping("96"),
226-
createMapping("128"),
227-
createMapping("256"),
228-
createMapping("512"),
235+
createMapping(16),
236+
createMapping(24),
237+
createMapping(32),
238+
createMapping(48),
239+
createMapping(64),
240+
createMapping(96),
241+
createMapping(128),
242+
createMapping(256),
243+
createMapping(512),
229244
]
230245
}
231246
}

0 commit comments

Comments
 (0)