Skip to content

Commit

Permalink
feat(AppImage): support type 2 image format
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Oct 2, 2017
1 parent f06324a commit c2602b9
Show file tree
Hide file tree
Showing 15 changed files with 184 additions and 154 deletions.
4 changes: 4 additions & 0 deletions .idea/dictionaries/develar.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 0 additions & 6 deletions docker/appImage.sh

This file was deleted.

5 changes: 3 additions & 2 deletions docs/icons.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Recommended tools: [MakeAppIcon](https://makeappicon.com/), [AppIcon Generator](http://www.tweaknow.com/appicongenerator.php).
Recommended tools: [AppIcon Generator](http://www.tweaknow.com/appicongenerator.php), [MakeAppIcon](https://makeappicon.com/)
.

## macOS

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

Or you can put them into the `build/icons` directory if you want to specify them yourself.
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).
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).

## AppX

Expand Down
72 changes: 39 additions & 33 deletions packages/builder-util/src/fs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export function copyFile(src: string, dest: string, isEnsureDir = true) {
*
* ensureDir is not called, dest parent dir must exists
*/
export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink): Promise<any> {
export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null, isUseHardLink = _isUseHardLink, exDevErrorHandler?: (() => boolean) | null): Promise<any> {
if (stats != null) {
const originalModeNumber = stats.mode
const mode = new Mode(stats)
Expand Down Expand Up @@ -167,8 +167,23 @@ export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null,

if (isUseHardLink) {
return link(src, dest)
.catch(e => {
if (e.code === "EXDEV") {
const isLog = exDevErrorHandler == null ? true : exDevErrorHandler()
if (isLog && debug.enabled) {
debug(`Cannot copy using hard link: ${e.message}`)
}
return doCopyFile(src, dest, stats)
}
else {
throw e
}
})
}
return doCopyFile(src, dest, stats)
}

function doCopyFile(src: string, dest: string, stats: Stats | null | undefined): Promise<any> {
if (_nodeCopyFile == null) {
return new BluebirdPromise((resolve, reject) => {
const reader = createReadStream(src)
Expand All @@ -181,16 +196,15 @@ export function copyOrLinkFile(src: string, dest: string, stats?: Stats | null,
writer.once("close", resolve)
})
}
else {
// node 8.5.0
return _nodeCopyFile(src, dest)
.then((): any => {
if (stats != null) {
return chmod(dest, stats.mode)
}
return null
})

// node 8.5.0+
const promise = _nodeCopyFile(src, dest)
if (stats == null) {
return promise
}

return promise
.then(() => chmod(dest, stats.mode))
}

export class FileCopier {
Expand All @@ -201,37 +215,29 @@ export class FileCopier {
}

async copy(src: string, dest: string, stat: Stats | undefined) {
try {
if (this.transformer != null && stat != null && stat.isFile()) {
let data = this.transformer(src)
if (data != null) {
if (typeof (data as any).then === "function") {
data = await data
}
if (this.transformer != null && stat != null && stat.isFile()) {
let data = this.transformer(src)
if (data != null) {
if (typeof (data as any).then === "function") {
data = await data
}

if (data != null) {
await writeFile(dest, data)
return
}
if (data != null) {
await writeFile(dest, data)
return
}
}
await copyOrLinkFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest))
}
catch (e) {
await copyOrLinkFile(src, dest, stat, (!this.isUseHardLink || this.isUseHardLinkFunction == null) ? this.isUseHardLink : this.isUseHardLinkFunction(dest), this.isUseHardLink ? () => {
// 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
if (e.code === "EXDEV") {
// ...but here we want to avoid excess debug log message
if (this.isUseHardLink) {
debug(`Cannot copy using hard link: ${e}`)
this.isUseHardLink = false
}

await copyOrLinkFile(src, dest, stat, false)
if (this.isUseHardLink) {
this.isUseHardLink = false
return true
}
else {
throw e
return false
}
}
} : null)
}
}

Expand Down
63 changes: 39 additions & 24 deletions packages/electron-builder/src/targets/LinuxTargetHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ import { getTemplatePath } from "../util/pathManager"

export const installPrefix = "/opt"

export interface IconInfo {
file: string
size: number
}

export class LinuxTargetHelper {
readonly icons: Promise<Array<Array<string>>>
readonly icons: Promise<Array<IconInfo>>

maxIconPath: string | null = null

Expand All @@ -19,7 +24,7 @@ export class LinuxTargetHelper {
}

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

private async iconsFromDir(iconDir: string) {
const mappings: Array<Array<string>> = []
const mappings: Array<IconInfo> = []
let maxSize = 0
for (const file of (await readdir(iconDir))) {
if (file.endsWith(".png") || file.endsWith(".PNG")) {
Expand All @@ -66,7 +71,10 @@ export class LinuxTargetHelper {
const size = sizeString == null ? 0 : parseInt(sizeString[0], 10)
if (size > 0) {
const iconPath = `${iconDir}/${file}`
mappings.push([iconPath, `${size}x${size}/apps/${this.packager.executableName}.png`])
mappings.push({
file: iconPath,
size,
})

if (size > maxSize) {
maxSize = size
Expand Down Expand Up @@ -100,7 +108,14 @@ export class LinuxTargetHelper {
return options.description || this.packager.appInfo.description
}

async computeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, destination?: string | null, extra?: { [key: string]: string; }): Promise<string> {
async writeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, destination?: string | null, extra?: { [key: string]: string; }): Promise<string> {
const data = await this.computeDesktopEntry(targetSpecificOptions, exec, extra)
const tempFile = destination || await this.packager.getTempFile(`${this.packager.appInfo.productFilename}.desktop`)
await outputFile(tempFile, data)
return tempFile
}

async computeDesktopEntry(targetSpecificOptions: LinuxTargetSpecificOptions, exec?: string, extra?: { [key: string]: string; }): Promise<string> {
if (exec != null && exec.length === 0) {
throw new Error("Specified exec is emptyd")
}
Expand All @@ -115,7 +130,9 @@ export class LinuxTargetHelper {
Exec: exec == null ? `"${installPrefix}/${productFilename}/${this.packager.executableName}" %U` : exec,
Terminal: "false",
Type: "Application",
Icon: this.packager.executableName, ...extra, ...targetSpecificOptions.desktop
Icon: this.packager.executableName,
...extra,
...targetSpecificOptions.desktop,
}

let category = targetSpecificOptions.category
Expand Down Expand Up @@ -143,13 +160,10 @@ export class LinuxTargetHelper {
data += `\n${name}=${value}`
}
data += "\n"

const tempFile = destination || await this.packager.getTempFile(`${productFilename}.desktop`)
await outputFile(tempFile, data)
return tempFile
return data
}

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

private createMappings(tempDir: string) {
const name = this.packager.executableName

function createMapping(size: string) {
return [process.platform === "darwin" ? `${tempDir}/icon_${size}x${size}.png` : `${tempDir}/icon_${size}x${size}x32.png`, `${size}x${size}/apps/${name}.png`]
function createMapping(size: number): IconInfo {
return {
file: process.platform === "darwin" ? `${tempDir}/icon_${size}x${size}.png` : `${tempDir}/icon_${size}x${size}x32.png`,
size,
}
}

return [
createMapping("16"),
createMapping("24"),
createMapping("32"),
createMapping("48"),
createMapping("64"),
createMapping("96"),
createMapping("128"),
createMapping("256"),
createMapping("512"),
createMapping(16),
createMapping(24),
createMapping(32),
createMapping(48),
createMapping(64),
createMapping(96),
createMapping(128),
createMapping(256),
createMapping(512),
]
}
}
Expand Down
Loading

0 comments on commit c2602b9

Please sign in to comment.