Skip to content

Commit

Permalink
Use Docker in the build to fix #534.
Browse files Browse the repository at this point in the history
  • Loading branch information
David Braun authored and David Braun committed Apr 4, 2018
1 parent f6549c0 commit 5929257
Show file tree
Hide file tree
Showing 12 changed files with 1,071 additions and 469 deletions.
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@ jobs:
- node_modules
key: v1-dependencies-root-{{ checksum "package.json" }}

- run:
- run:
name: Add Gaia
command: |
sudo wget https://www.dropbox.com/s/vkyuut8hnzse614/gaia-0.5.0-linux-32?dl=1 -O ~/repo/gaia
sudo wget https://tendermint-packages.interblock.io/binaries/gaia_linux_amd64/gaia_decb23bed0179244e4f42d697dcd4bf759200a2d -O ~/repo/gaia
sudo chmod o+wx /home/circleci/repo/gaia
- run: yarn run test
- run: bash <(curl -s https://codecov.io/bash) -t $CODECOV_TOKEN
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
},
env: {
browser: true,
jest: true,
node: true
},
extends: 'standard',
Expand Down
16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,19 +93,24 @@ $ COSMOS_NODE=localhost yarn testnet
---

### Production
Get the Gaia binary from [GitHub](`https://github.com/cosmos/gaia/releases`).

Install [Docker](https://docs.docker.com/get-started/).
Building requires that [Docker](https://www.docker.com/get-docker) is installed
on your system.

Build and run the app.
Execute the following command to see building options.

```shell
yarn run build --help
```

Run the app.
```bash
yarn run build --platform={darwin|win32|linux} -- --binary={path to the gaia binary}
open builds/Cosmos-{platform}-x64/Cosmos.app
```

When you are testing the build system you can skip the repackaging of the JS files.
```bash
$ yarn run build --platform={darwin|win32|linux} --skip-pack --binary=...
$ yarn run build --platform=darwin --skip-pack
```

To test if your build worked run:
Expand Down Expand Up @@ -156,7 +161,6 @@ A list of all environment variables and their purpose:
|COSMOS_NETWORK|{path to network configuration folder}|'../networks/gaia-1'|Network to connect to|
|COSMOS_HOME|{path to config persistence folder}|'$HOME/voyager[-dev]'||
|COSMOS_NODE|{ip of a certain node}||Node to connect to|
|PLATFORM_TARGET|'all', 'win32', 'darwin', 'linux', 'mas'|'all'|Which platform to build for|
|COSMOS_DEVTOOLS|'true', 'false'|'false'|Open the debug panel in the electron view|
|ELECTRON_ENABLE_LOGGING|'true', 'false'|'false'|Redirect the browser view console output to the console|
|PREVIEW|'true', 'false'|'true' if NODE_ENV 'development'|Show/Hide features that are in development|
Expand Down
1 change: 0 additions & 1 deletion config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ let config = {
ignore: /^\/(src|index\.ejs|icons)/,
out: path.join(__dirname, 'builds'),
overwrite: true,
platform: process.env.PLATFORM_TARGET || 'darwin,linux,win32',
packageManager: 'yarn'
},

Expand Down
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,7 @@
"node": ">=9.4.0"
},
"scripts": {
"build:clean": "cross-env PLATFORM_TARGET=clean node tasks/release.js",
"build:darwin": "cross-env PLATFORM_TARGET=darwin node tasks/release.js",
"build:linux": "cross-env PLATFORM_TARGET=linux node tasks/release.js",
"build:mas": "cross-env PLATFORM_TARGET=mas node tasks/release.js",
"build:win32": "cross-env PLATFORM_TARGET=win32 node tasks/release.js",
"build": "cd tasks/build && node build",
"local": "yarn run testnet local",
"testnet": "node tasks/testnet.js",
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter app test",
Expand All @@ -35,6 +31,7 @@
"vuex:module": "node tasks/vuex/module.js"
},
"devDependencies": {
"@nodeguy/cli": "0.2.0",
"babel-core": "6.8.0",
"babel-eslint": "7.2.3",
"babel-jest": "21.2.0",
Expand Down Expand Up @@ -75,11 +72,13 @@
"node-sass": "4.7.2",
"proxyquire": "1.8.0",
"pug": "2.0.0-rc.1",
"shelljs": "0.8.1",
"spectron": "3.8.0",
"style-loader": "0.19.1",
"tape": "4.8.0",
"tape-promise": "2.0.1",
"tar-stream": "1.5.5",
"untildify": "3.0.2",
"url-loader": "0.6.2",
"vue-hot-reload-api": "2.0.7",
"vue-html-loader": "1.2.4",
Expand Down Expand Up @@ -193,4 +192,4 @@
"jest-localstorage-mock"
]
}
}
}
2 changes: 2 additions & 0 deletions tasks/build/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Use Unix line endings for text files because we're using Docker.
* text eol=lf
16 changes: 16 additions & 0 deletions tasks/build/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
FROM node:9.4.0

# Install Wine so that we can build for the 'win32' platform.
# https://wiki.debian.org/Wine#Installation_on_Debian_Jessie_and_newer
RUN dpkg --add-architecture i386 \
&& apt-get update \
&& apt-get --yes install \
wine \
wine32 \
libwine

RUN touch /usr/local/bin/gaia
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY entrypoint.sh /
ENTRYPOINT [ "/entrypoint.sh" ]
26 changes: 26 additions & 0 deletions tasks/build/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict'

const { cli } = require(`@nodeguy/cli`)
const options = require(`./options.json`)
const path = require(`path`)
const shell = require(`shelljs`)
const untildify = require(`untildify`)

cli(options, async ({ commit, gaia, platform, 'skip-pack': skipPack }) => {
shell.exec(`docker build --tag cosmos/voyager-builder .`)
shell.mkdir(`-p`, `../../builds`)
const cwd = process.cwd()

shell.exec(`docker run \
--interactive \
--mount type=bind,readonly,source=${untildify(gaia)},target=/mnt/gaia \
--mount type=bind,readonly,source=${path.resolve(cwd, '../../.git')},target=/mnt/.git \
--mount type=bind,source=${path.resolve(cwd, '../../builds')},target=/mnt/builds \
--rm \
cosmos/voyager-builder \
"${commit}" \
--gaia=/mnt/gaia \
--platform=${platform} \
--skip-pack=${skipPack}
`)
})
12 changes: 12 additions & 0 deletions tasks/build/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh
set -o errexit

git clone /mnt/.git .

# Use the specified commit of Voyager.
git checkout "$1"
shift

ln --symbolic /mnt/builds
yarn install
node tasks/build/release.js "$@"
6 changes: 6 additions & 0 deletions tasks/build/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"commit": ["commit from which to build", "HEAD"],
"gaia": ["path to the gaia binary"],
"platform": ["the target platform {darwin|linux|win32}"],
"skip-pack": ["skip the repackaging of the JS files", false]
}
145 changes: 65 additions & 80 deletions tasks/release.js → tasks/build/release.js
Original file line number Diff line number Diff line change
@@ -1,74 +1,41 @@
'use strict'

const { exec } = require('child_process')
const { cli } = require(`@nodeguy/cli`)
const config = require(`../../config`)
const { createHash } = require('crypto')
const optionsSpecification = require(`./options.json`)
const path = require('path')
const packager = require('electron-packager')
const shell = require(`shelljs`)
const fs = require('fs-extra')
var glob = require('glob')
var JSZip = require('jszip')
const zlib = require('zlib')
var tar = require('tar-stream')
var duplexer = require('duplexer')
const packageJson = require('../package.json')

let skipPack = false
let binaryPath = null
process.argv.forEach(function (val) {
if (val === '--skip-pack') {
console.log('Skipping packaging')
skipPack = true
}
if (val.startsWith('--binary')) {
binaryPath = val.replace('--binary=', '')
fs.accessSync(binaryPath)
console.log('Using prebuilt binary', binaryPath)
}
})

if (!binaryPath) {
console.error(`\x1b[31mPlease specify a gaia binary for this platform using the "--binary" flag
Example: npm run build:darwin -- --binary=./gaia
\x1b[0m`)
process.exit(1)
}

if (process.env.PLATFORM_TARGET === 'clean') {
require('del').sync(['builds/*', '!.gitkeep'])
console.log('\x1b[33m`builds` directory cleaned.\n\x1b[0m')
} else {
if (skipPack) {
build(process.env.PLATFORM_TARGET)
} else {
pack()
}
}
const packageJson = require('../../package.json')

/**
* Build webpack in production
*/
function pack () {
const pack = async (options) => {
console.log('\x1b[33mBuilding webpack in production mode...\n\x1b[0m')
let pack = exec('npm run pack')

pack.stdout.on('data', data => console.log(data))
pack.stderr.on('data', data => console.error(data))
pack.on('exit', code => {
if (code === null || code <= 0) {
build(process.env.PLATFORM_TARGET)
}
})
shell.exec('npm run pack')
build(options)
}

/**
* Use electron-packager to build electron app
*/
function build (platform) {
let options = require('../config').building

options.afterCopy = [
copyBinary('gaia', binaryPath)
]
function build ({ platform, gaia }) {
console.log('Using prebuilt binary', gaia)

let options = Object.assign({}, config.building, {
afterCopy: [
copyBinary('gaia', gaia)
],
platform
})

console.log('\x1b[34mBuilding electron app(s)...\n\x1b[0m')
packager(options, async (err, appPaths) => {
Expand All @@ -84,7 +51,7 @@ function build (platform) {
await zipFolder(appPath, options.out, packageJson.version)
} else {
await tarFolder(appPath, options.out, packageJson.version)
.catch(err => console.error(err))
.catch(err => console.error(err))
}
}))

Expand Down Expand Up @@ -124,30 +91,30 @@ function zipFolder (inDir, outDir, version) {
return reject(err)
}
files
.forEach(file => {
.forEach(file => {
// make the zip deterministic by changing all file times
if (fs.lstatSync(file).isDirectory()) {
zip.file(path.relative(inDir, file), null, {
dir: true,
date: new Date('1993-06-16')
})
} else {
zip.file(path.relative(inDir, file), fs.readFileSync(file), {
date: new Date('1987-08-16')
})
}
})
if (fs.lstatSync(file).isDirectory()) {
zip.file(path.relative(inDir, file), null, {
dir: true,
date: new Date('1993-06-16')
})
} else {
zip.file(path.relative(inDir, file), fs.readFileSync(file), {
date: new Date('1987-08-16')
})
}
})
resolve()
})
})
zip.generateNodeStream({type: 'nodebuffer', streamFiles: true})
.pipe(fs.createWriteStream(outFile))
.on('finish', function () {
sha256File(outFile).then((hash) => {
console.log('Zip successful!', outFile, 'SHA256:', hash)
resolve()
zip.generateNodeStream({ type: 'nodebuffer', streamFiles: true })
.pipe(fs.createWriteStream(outFile))
.on('finish', function () {
sha256File(outFile).then((hash) => {
console.log('Zip successful!', outFile, 'SHA256:', hash)
resolve()
})
})
})
})
}

Expand Down Expand Up @@ -190,17 +157,17 @@ async function tarFolder (inDir, outDir, version) {
// make tar deterministic
await new Promise((resolve) => {
pack
.pipe(deterministicTar())
// save tar to disc
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream(outFile))
.on('finish', function () {
console.log('write finished')
sha256File(outFile).then((hash) => {
console.log('Zip successful!', outFile, 'SHA256:', hash)
resolve()
.pipe(deterministicTar())
// save tar to disc
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream(outFile))
.on('finish', function () {
console.log('write finished')
sha256File(outFile).then((hash) => {
console.log('Zip successful!', outFile, 'SHA256:', hash)
resolve()
})
})
})
})
}

Expand Down Expand Up @@ -230,3 +197,21 @@ function deterministicTar () {

return duplexer(extract, pack)
}

cli(optionsSpecification, async options => {
const { platform, 'skip-pack': skipPack } = options

if (platform === 'clean') {
require('del').sync(['builds/*', '!.gitkeep'])
console.log('\x1b[33m`builds` directory cleaned.\n\x1b[0m')
} else {
console.log(`Building for platform "${platform}".`)

if (skipPack) {
console.log('Skipping packaging')
build(options)
} else {
await pack(options)
}
}
})
Loading

0 comments on commit 5929257

Please sign in to comment.