Skip to content

Commit

Permalink
feat(linux): Build snap packages for Linux #509
Browse files Browse the repository at this point in the history
  • Loading branch information
develar committed Nov 18, 2016
1 parent 171ad14 commit 1bd54f7
Show file tree
Hide file tree
Showing 19 changed files with 234 additions and 94 deletions.
10 changes: 10 additions & 0 deletions .idea/dictionaries/develar.xml

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

14 changes: 0 additions & 14 deletions .idea/runConfigurations/linuxPackagerTest.xml

This file was deleted.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ A complete solution to package and build a ready for distribution Electron app f
* Numerous target formats:
* All platforms: `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`, `dir` (unpacked directory).
* [macOS](https://github.com/electron-userland/electron-builder/wiki/Options#MacOptions-target): `dmg`, `pkg`, `mas`.
* [Linux](https://github.com/electron-userland/electron-builder/wiki/Options#LinuxBuildOptions-target): `AppImage`, `deb`, `rpm`, `freebsd`, `pacman`, `p5p`, `apk`.
* [Linux](https://github.com/electron-userland/electron-builder/wiki/Options#LinuxBuildOptions-target): [AppImage](http://appimage.org), [snap](http://snapcraft.io), `deb`, `rpm`, `freebsd`, `pacman`, `p5p`, `apk`.
* [Windows](https://github.com/electron-userland/electron-builder/wiki/Options#WinBuildOptions-target): NSIS, Squirrel.Windows.
* [Two package.json Structure](https://github.com/electron-userland/electron-builder/wiki/Two-package.json-Structure) is supported, but you are not forced to use it even if you have native production dependencies.
* [Publishing artifacts](https://github.com/electron-userland/electron-builder/wiki/Publishing-Artifacts) to GitHub Releases and Bintray.
Expand Down
9 changes: 4 additions & 5 deletions docker/base/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM buildpack-deps:xenial-curl
FROM buildpack-deps:yakkety-curl

# rpm is required for FPM to build rpm package
# yasm is required to build p7zip
Expand All @@ -15,10 +15,9 @@ ENV USE_SYSTEM_7ZA true
ENV DEBUG_COLORS true
ENV FORCE_COLOR true

RUN apt-key adv --keyserver pgp.mit.edu --recv D101F7899D41F3C3 && echo "deb http://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

RUN apt-get update -y && \
apt-get install --no-install-recommends -y yarn xorriso bsdtar build-essential autoconf libssl-dev icnsutils graphicsmagick gcc-multilib g++-multilib libgnome-keyring-dev lzip rpm yasm && \
RUN apt-key adv --keyserver pgp.mit.edu --recv D101F7899D41F3C3 && apt-key adv --fetch-keys http://dl.yarnpkg.com/debian/pubkey.gpg && echo "deb http://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update -y && \
apt-get install --no-install-recommends -y git snapcraft yarn xorriso bsdtar build-essential autoconf libssl-dev icnsutils graphicsmagick gcc-multilib g++-multilib libgnome-keyring-dev lzip rpm yasm && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
curl -L http://tukaani.org/xz/xz-$XZ_VERSION.tar.xz | tar -xJ && cd xz-$XZ_VERSION && ./configure && make && make install && cd .. && rm -rf xz-$XZ_VERSION && ldconfig && \
Expand Down
2 changes: 1 addition & 1 deletion docker/wine/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ FROM electronuserland/electron-builder:latest

# libgnome-keyring-dev — to build keytar
RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys F9CB8DB0 && \
echo "deb http://ppa.launchpad.net/ubuntu-wine/ppa/ubuntu xenial main " | tee /etc/apt/sources.list.d/wine.list && \
echo "deb http://ppa.launchpad.net/ubuntu-wine/ppa/ubuntu yakkety main " | tee /etc/apt/sources.list.d/wine.list && \
dpkg --add-architecture i386 && \
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \
echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list && \
Expand Down
2 changes: 1 addition & 1 deletion docs/Options.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ Linux specific build options.
| category | <a name="LinuxBuildOptions-category"></a>The [application category](https://specifications.freedesktop.org/menu-spec/latest/apa.html#main-category-registry).
| packageCategory | <a name="LinuxBuildOptions-packageCategory"></a>The [package category](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Section). Not applicable for AppImage.
| description | <a name="LinuxBuildOptions-description"></a>As [description](#AppMetadata-description) from application package.json, but allows you to specify different for Linux.
| target | <a name="LinuxBuildOptions-target"></a><p>Target package type: list of <code>AppImage</code>, <code>deb</code>, <code>rpm</code>, <code>freebsd</code>, <code>pacman</code>, <code>p5p</code>, <code>apk</code>, <code>7z</code>, <code>zip</code>, <code>tar.xz</code>, <code>tar.lz</code>, <code>tar.gz</code>, <code>tar.bz2</code>, <code>dir</code>. Defaults to <code>AppImage</code>.</p> <p>The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default.</p> <p>Only <code>deb</code> and <code>AppImage</code> is tested. Feel free to file issues for <code>rpm</code> and other package formats.</p>
| target | <a name="LinuxBuildOptions-target"></a><p>Target package type: list of <code>AppImage</code>, <code>snap</code>, <code>deb</code>, <code>rpm</code>, <code>freebsd</code>, <code>pacman</code>, <code>p5p</code>, <code>apk</code>, <code>7z</code>, <code>zip</code>, <code>tar.xz</code>, <code>tar.lz</code>, <code>tar.gz</code>, <code>tar.bz2</code>, <code>dir</code>. Defaults to <code>AppImage</code>.</p> <p>The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default.</p>
| synopsis | <a name="LinuxBuildOptions-synopsis"></a>*deb-only.* The [short description](https://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Description).
| maintainer | <a name="LinuxBuildOptions-maintainer"></a>The maintainer. Defaults to [author](#AppMetadata-author).
| vendor | <a name="LinuxBuildOptions-vendor"></a>The vendor. Defaults to [author](#AppMetadata-author).
Expand Down
16 changes: 6 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"lint": "node ./test/lint.js",
"pretest": "yarn run compile && yarn run lint",
"check-deps": "node ./test/out/helpers/checkDeps.js",
"test": "node ./test/out/helpers/runTests.js",
"test": "node --trace-warnings ./test/out/helpers/runTests.js",
"test-linux": "docker run --rm -ti -v ${PWD}:/project -v ${PWD##*/}-node-modules:/project/node_modules -v ~/.electron:/root/.electron electronuserland/electron-builder:wine /test.sh",
"pack-updater": "cd nsis-auto-updater && yarn --production && cd ..",
"semantic-release": "semantic-release pre && npm publish && semantic-release post",
Expand Down Expand Up @@ -68,7 +68,7 @@
"cli-cursor": "^1.0.2",
"cuint": "^0.2.2",
"debug": "^2.3.2",
"electron-download": "2.1.2",
"electron-download-tf": "3.1.0",
"electron-macos-sign": "1.0.1",
"fs-extra-p": "^2.0.7",
"hosted-git-info": "^2.1.5",
Expand Down Expand Up @@ -143,13 +143,6 @@
]
]
},
"ava": {
"verbose": true,
"cache": false,
"files": [
"test/out/*.js"
]
},
"jest": {
"testEnvironment": "node",
"testPathDirs": [
Expand All @@ -167,5 +160,8 @@
"release": {
"verifyConditions": []
},
"typings": "./out/electron-builder.d.ts"
"typings": "./out/electron-builder.d.ts",
"publishConfig": {
"tag": "next"
}
}
5 changes: 5 additions & 0 deletions src/linuxPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import AppImageTarget from "./targets/appImage"
import { rename } from "fs-extra-p"
import { LinuxBuildOptions } from "./options/linuxOptions"
import sanitizeFileName from "sanitize-filename"
import SnapTarget from "./targets/snap"

export class LinuxPackager extends PlatformPackager<LinuxBuildOptions> {
readonly executableName: string
Expand Down Expand Up @@ -49,6 +50,10 @@ export class LinuxPackager extends PlatformPackager<LinuxBuildOptions> {
const targetClass: typeof AppImageTarget = require("./targets/appImage").default
mapper("appimage", outDir => new targetClass(this, getHelper(), outDir))
}
else if (name === "snap") {
const targetClass: typeof SnapTarget = require("./targets/snap").default
mapper("snap", outDir => new targetClass(this, getHelper(), outDir))
}
else if (name === "deb" || name === "rpm" || name === "sh" || name === "freebsd" || name === "pacman" || name === "apk" || name === "p5p") {
const targetClass: typeof FpmTarget = require("./targets/fpm").default
mapper(name, outDir => new targetClass(name, this, getHelper(), outDir))
Expand Down
27 changes: 24 additions & 3 deletions src/options/linuxOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@ export interface LinuxBuildOptions extends PlatformSpecificBuildOptions {
readonly description?: string | null

/*
Target package type: list of `AppImage`, `deb`, `rpm`, `freebsd`, `pacman`, `p5p`, `apk`, `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`, `dir`. Defaults to `AppImage`.
Target package type: list of `AppImage`, `snap`, `deb`, `rpm`, `freebsd`, `pacman`, `p5p`, `apk`, `7z`, `zip`, `tar.xz`, `tar.lz`, `tar.gz`, `tar.bz2`, `dir`. Defaults to `AppImage`.
The most effective [xz](https://en.wikipedia.org/wiki/Xz) compression format used by default.
Only `deb` and `AppImage` is tested. Feel free to file issues for `rpm` and other package formats.
*/
readonly target?: Array<string> | null

Expand Down Expand Up @@ -73,3 +71,26 @@ export interface LinuxBuildOptions extends PlatformSpecificBuildOptions {
*/
readonly executableName?: string | null
}

export interface SnapOptions extends LinuxBuildOptions {
/*
The type of confinement supported by the snap. Can be either `devmode` (i.e. this snap doesn’t support running under confinement) or `strict` (i.e. full confinement supported via interfaces).
*/
confinement?: "devmode" | "strict" | null

/*
The 78 character long summary. Defaults to [productName](#AppMetadata-productName).
*/
summary?: string | null

/*
The quality grade of the snap. It can be either `devel` (i.e. a development version of the snap, so not to be published to the “stable” or “candidate” channels) or “stable” (i.e. a stable release or release candidate, which can be released to all channels).
Defaults to `stable`.
*/
grade?: "devel" | "stable" | null

/*
The list of features that must be supported by the core in order for this snap to install.
*/
assumes?: Array<string> | null
}
2 changes: 1 addition & 1 deletion src/packager/dirPackager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { debug7zArgs, spawn } from "../util/util"
import { path7za } from "7zip-bin"
import * as path from "path"

const downloadElectron: (options: any) => Promise<any> = BluebirdPromise.promisify(require("electron-download"))
const downloadElectron: (options: any) => Promise<any> = BluebirdPromise.promisify(require("electron-download-tf"))

function createDownloadOpts(opts: any, platform: string, arch: string, electronVersion: string) {
const downloadOpts = Object.assign({
Expand Down
6 changes: 5 additions & 1 deletion src/targets/LinuxTargetHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export class LinuxTargetHelper {
return iconPath == null ? await this.packager.getDefaultIcon("icns") : path.resolve(this.packager.projectDir, iconPath)
}

getDescription(options: LinuxBuildOptions) {
return options.description || this.packager.appInfo.description
}

async computeDesktopEntry(platformSpecificBuildOptions: LinuxBuildOptions, exec?: string, extra?: { [key: string]: string; }): Promise<string> {
const appInfo = this.packager.appInfo

Expand All @@ -71,7 +75,7 @@ export class LinuxTargetHelper {

const desktopMeta: any = Object.assign({
Name: appInfo.productName,
Comment: platformSpecificBuildOptions.description || appInfo.description,
Comment: this.getDescription(platformSpecificBuildOptions),
Exec: exec == null ? `"${installPrefix}/${productFilename}/${this.packager.executableName}"` : exec,
Terminal: "false",
Type: "Application",
Expand Down
16 changes: 8 additions & 8 deletions src/targets/appImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@ export default class AppImageTarget extends TargetEx {
}

async build(appOutDir: string, arch: Arch): Promise<any> {
log(`Building AppImage`)
log(`Building AppImage for arch ${Arch[arch]}`)

const packager = this.packager

// avoid spaces in the file name
const image = path.join(this.outDir, packager.generateName("AppImage", arch, true))
await unlinkIfExists(image)
const resultFile = path.join(this.outDir, packager.generateName("AppImage", arch, true))
await unlinkIfExists(resultFile)

const appImagePath = await appImagePathPromise
const args = [
"-joliet", "on",
"-volid", "AppImage",
"-dev", image,
"-dev", resultFile,
"-padding", "0",
"-map", appOutDir, "/usr/bin",
"-map", path.join(__dirname, "..", "..", "templates", "linux", "AppRun.sh"), "/AppRun",
Expand All @@ -70,13 +70,13 @@ export default class AppImageTarget extends TargetEx {
await new BluebirdPromise((resolve, reject) => {
const rd = createReadStream(path.join(appImagePath, arch === Arch.ia32 ? "32" : "64", "runtime"))
rd.on("error", reject)
const wr = createWriteStream(image, {flags: "r+"})
const wr = createWriteStream(resultFile, {flags: "r+"})
wr.on("error", reject)
wr.on("finish", resolve)
rd.pipe(wr)
})

const fd = await open(image, "r+")
const fd = await open(resultFile, "r+")
try {
const magicData = new Buffer([0x41, 0x49, 0x01])
await write(fd, magicData, 0, magicData.length, 8)
Expand All @@ -85,8 +85,8 @@ export default class AppImageTarget extends TargetEx {
await close(fd)
}

await chmod(image, "0755")
await chmod(resultFile, "0755")

packager.dispatchArtifactCreated(image, packager.generateName("AppImage", arch, true))
packager.dispatchArtifactCreated(resultFile, packager.generateName("AppImage", arch, true))
}
}
2 changes: 1 addition & 1 deletion src/targets/fpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export default class FpmTarget extends TargetEx {
"--force",
"--after-install", scripts[0],
"--after-remove", scripts[1],
"--description", smarten(target === "rpm" ? options.description! : `${synopsis || ""}\n ${options.description}`),
"--description", smarten(target === "rpm" ? this.helper.getDescription(options)! : `${synopsis || ""}\n ${this.helper.getDescription(options)}`),
"--maintainer", author,
"--vendor", options.vendor || author,
"--version", appInfo.version,
Expand Down
Loading

0 comments on commit 1bd54f7

Please sign in to comment.