diff --git a/build.sh b/build.sh index a7a0a10e4..3219679e4 100755 --- a/build.sh +++ b/build.sh @@ -1,79 +1,49 @@ #!/usr/bin/env bash ARCHIVE_BUILD_FOLDER="/tmp/portainer-builds" -VERSION=$1 -if [[ $# -ne 1 ]] ; then - echo "Usage: $(basename $0) " - exit 1 -fi - -# parameters platform, architecture +# parameter: "platform-architecture" function build_and_push_images() { - PLATFORM=$1 - ARCH=$2 - - docker build -t portainer/portainer:${PLATFORM}-${ARCH}-${VERSION} -f build/linux/Dockerfile . - docker push portainer/portainer:${PLATFORM}-${ARCH}-${VERSION} - docker build -t portainer/portainer:${PLATFORM}-${ARCH} -f build/linux/Dockerfile . - docker push portainer/portainer:${PLATFORM}-${ARCH} + docker build -t "portainer/portainer:$1-${VERSION}" -f build/linux/Dockerfile . + docker tag "portainer/portainer:$1-${VERSION}" "portainer/portainer:$1" + docker push "portainer/portainer:$1-${VERSION}" + docker push "portainer/portainer:$1" } -# parameters: platform, architecture +# parameter: "platform-architecture" function build_archive() { - PLATFORM=$1 - ARCH=$2 - - BUILD_FOLDER=${ARCHIVE_BUILD_FOLDER}/${PLATFORM}-${ARCH} - + BUILD_FOLDER="${ARCHIVE_BUILD_FOLDER}/$1" rm -rf ${BUILD_FOLDER} && mkdir -pv ${BUILD_FOLDER}/portainer mv dist/* ${BUILD_FOLDER}/portainer/ cd ${BUILD_FOLDER} - tar cvpfz portainer-${VERSION}-${PLATFORM}-${ARCH}.tar.gz portainer - mv portainer-${VERSION}-${PLATFORM}-${ARCH}.tar.gz ${ARCHIVE_BUILD_FOLDER}/ + tar cvpfz "portainer-${VERSION}-$1.tar.gz" portainer + mv "portainer-${VERSION}-$1.tar.gz" ${ARCHIVE_BUILD_FOLDER}/ cd - } -mkdir -pv /tmp/portainer-builds +function build_all() { + mkdir -pv "${ARCHIVE_BUILD_FOLDER}" + for tag in $@; do + grunt "release:`echo "$tag" | tr '-' ':'`" + name="portainer"; if [ "$(echo "$tag" | cut -c1)" = "w" ]; then name="${name}.exe"; fi + mv dist/portainer-$tag* dist/$name + if [ `echo $tag | cut -d \- -f 1` == 'linux' ]; then build_and_push_images "$tag"; fi + build_archive "$tag" + done + docker rmi $(docker images -q -f dangling=true) +} -PLATFORM="linux" -ARCH="amd64" -grunt release-${PLATFORM}-${ARCH} -build_and_push_images ${PLATFORM} ${ARCH} -build_archive ${PLATFORM} ${ARCH} +if [[ $# -ne 1 ]] ; then + echo "Usage: $(basename $0) " + echo " $(basename $0) \"echo 'Custom' && \"" + exit 1 +else + VERSION="$1" + if [ `echo "$@" | cut -c1-4` == 'echo' ]; then + bash -c "$@"; + else + build_all 'linux-amd64 linux-386 linux-arm linux-arm64 linux-ppc64le darwin-amd64 windows-amd64' + exit 0 + fi +fi -PLATFORM="linux" -ARCH="386" -grunt release-${PLATFORM}-${ARCH} -build_and_push_images ${PLATFORM} ${ARCH} -build_archive ${PLATFORM} ${ARCH} - -PLATFORM="linux" -ARCH="arm" -grunt release-${PLATFORM}-${ARCH} -build_and_push_images ${PLATFORM} ${ARCH} -build_archive ${PLATFORM} ${ARCH} - -PLATFORM="linux" -ARCH="arm64" -grunt release-${PLATFORM}-${ARCH} -build_and_push_images ${PLATFORM} ${ARCH} -build_archive ${PLATFORM} ${ARCH} - -PLATFORM="linux" -ARCH="ppc64le" -grunt release-${PLATFORM}-${ARCH} -build_and_push_images ${PLATFORM} ${ARCH} -build_archive ${PLATFORM} ${ARCH} - -PLATFORM="darwin" -ARCH="amd64" -grunt release-${PLATFORM}-${ARCH} -build_archive ${PLATFORM} ${ARCH} - -PLATFORM="windows" -ARCH="amd64" -grunt release-${PLATFORM}-${ARCH} -build_archive ${PLATFORM} ${ARCH} - -exit 0 diff --git a/build/build_in_container.sh b/build/build_in_container.sh new file mode 100755 index 000000000..a313dcb59 --- /dev/null +++ b/build/build_in_container.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +binary="portainer-$1-$2" + +mkdir -p dist + +docker run -tv $(pwd)/api:/src -e BUILD_GOOS="$1" -e BUILD_GOARCH="$2" portainer/golang-builder:cross-platform /src/cmd/portainer + +mv "api/cmd/portainer/$binary" dist/ +#sha256sum "dist/$binary" > portainer-checksum.txt diff --git a/gruntfile.js b/gruntfile.js index ce105e653..70ad61d4c 100644 --- a/gruntfile.js +++ b/gruntfile.js @@ -11,218 +11,93 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-html2js'); grunt.loadNpmTasks('grunt-shell'); - grunt.loadNpmTasks('grunt-if'); grunt.loadNpmTasks('grunt-filerev'); grunt.loadNpmTasks('grunt-usemin'); grunt.loadNpmTasks('grunt-replace'); grunt.loadNpmTasks('grunt-config'); grunt.loadNpmTasks('grunt-postcss'); - grunt.registerTask('default', ['eslint', 'build']); + grunt.registerTask('before-copy', [ + 'html2js', + 'useminPrepare:release', + 'concat', + 'postcss:build', + 'clean:tmpl', + 'replace', + 'uglify' + ]); + grunt.registerTask('after-copy', [ + 'filerev', + 'usemin', + 'clean:tmp' + ]); + grunt.registerTask('build-webapp', [ + 'config:prod', + 'clean:all', + 'before-copy', + 'copy:assets', + 'after-copy' + ]); grunt.registerTask('build', [ 'config:dev', 'clean:app', - 'if:linuxAmd64BinaryNotExist', + 'shell:buildBinary:linux:amd64', 'html2js', 'useminPrepare:dev', 'concat', 'clean:tmpl', 'replace', 'copy', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('build-webapp', [ - 'config:prod', - 'clean:all', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy:assets', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-linux-386', [ - 'config:prod', - 'clean:all', - 'if:linux386BinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy:assets', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-linux-amd64', [ - 'config:prod', - 'clean:all', - 'if:linuxAmd64BinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy:assets', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-linux-arm', [ - 'config:prod', - 'clean:all', - 'if:linuxArmBinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-linux-arm64', [ - 'config:prod', - 'clean:all', - 'if:linuxArm64BinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-linux-ppc64le', [ - 'config:prod', - 'clean:all', - 'if:linuxPpc64leBinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-windows-amd64', [ - 'config:prod', - 'clean:all', - 'if:windowsAmd64BinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy', - 'filerev', - 'usemin', - 'clean:tmp' - ]); - grunt.registerTask('release-darwin-amd64', [ - 'config:prod', - 'clean:all', - 'if:darwinAmd64BinaryNotExist', - 'html2js', - 'useminPrepare:release', - 'concat', - 'postcss:build', - 'clean:tmpl', - 'replace', - 'uglify', - 'copy', - 'filerev', - 'usemin', - 'clean:tmp' + 'after-copy' ]); + grunt.task.registerTask('release', 'release::', function(p, a) { + grunt.task.run(['config:prod', 'clean:all', 'shell:buildBinary:'+p+':'+a, 'before-copy', 'copy:assets', 'after-copy' ]); + }); grunt.registerTask('lint', ['eslint']); - grunt.registerTask('run', ['if:linuxAmd64BinaryNotExist', 'build', 'shell:buildImage', 'shell:run']); - grunt.registerTask('run-dev', ['if:linuxAmd64BinaryNotExist', 'shell:run', 'watch:build']); + grunt.registerTask('run-dev', ['build', 'shell:run', 'watch:build']); grunt.registerTask('clear', ['clean:app']); - // Print a timestamp (useful for when watching) - grunt.registerTask('timestamp', function () { - grunt.log.subhead(Date()); - }); - // Project configuration. grunt.initConfig({ distdir: 'dist', pkg: grunt.file.readJSON('package.json'), config: { - dev: { - options: { - variables: { - 'environment': 'development' - } - } - }, - prod: { - options: { - variables: { - 'environment': 'production' - } - } - } + dev: { options: { variables: { 'environment': 'development' }}}, + prod: { options: { variables: { 'environment': 'production' }}} }, src: { js: ['app/**/*.js', '!app/**/*.spec.js'], jsTpl: ['<%= distdir %>/templates/**/*.js'], jsVendor: [ + 'bower_components/angular-multi-select/isteven-multi-select.js', + 'bower_components/bootbox.js/bootbox.js', 'bower_components/jquery/dist/jquery.min.js', 'bower_components/bootstrap/dist/js/bootstrap.min.js', 'bower_components/Chart.js/Chart.min.js', - 'bower_components/lodash/dist/lodash.min.js', - 'bower_components/splitargs/src/splitargs.js', 'bower_components/filesize/lib/filesize.min.js', + 'bower_components/lodash/dist/lodash.min.js', 'bower_components/moment/min/moment.min.js', - 'bower_components/xterm.js/dist/xterm.js', - 'bower_components/bootbox.js/bootbox.js', - 'bower_components/angular-multi-select/isteven-multi-select.js', + 'bower_components/splitargs/src/splitargs.js', 'bower_components/toastr/toastr.min.js', + 'bower_components/xterm.js/dist/xterm.js', 'assets/js/legend.js' // Not a bower package ], html: ['index.html'], tpl: ['app/components/**/*.html', 'app/directives/**/*.html'], css: ['assets/css/app.css'], cssVendor: [ + 'bower_components/angular-multi-select/isteven-multi-select.css', + 'bower_components/angular-ui-select/dist/select.min.css', 'bower_components/bootstrap/dist/css/bootstrap.css', 'bower_components/font-awesome/css/font-awesome.min.css', 'bower_components/rdash-ui/dist/css/rdash.min.css', - 'bower_components/angular-ui-select/dist/select.min.css', - 'bower_components/xterm.js/dist/xterm.css', - 'bower_components/angular-multi-select/isteven-multi-select.css', - 'bower_components/toastr/toastr.min.css' + 'bower_components/toastr/toastr.min.css', + 'bower_components/xterm.js/dist/xterm.css' ] }, clean: { all: ['<%= distdir %>/*'], - app: ['<%= distdir %>/*', '!<%= distdir %>/portainer'], + app: ['<%= distdir %>/*', '!<%= distdir %>/portainer*'], tmpl: ['<%= distdir %>/templates'], tmp: ['<%= distdir %>/js/*', '!<%= distdir %>/js/app.*.js', '<%= distdir %>/css/*', '!<%= distdir %>/css/app.*.css'] }, @@ -273,24 +148,21 @@ module.exports = function (grunt) { }, assets: { files: [ - {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/bootstrap/fonts/'}, - {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/font-awesome/fonts/'}, - {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/rdash-ui/dist/fonts/'}, - { - dest: '<%= distdir %>/images/', - src: ['**'], - expand: true, - cwd: 'assets/images/' - }, - {dest: '<%= distdir %>/ico', src: '**', expand: true, cwd: 'assets/ico'} + {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/bootstrap/fonts/'}, + {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/font-awesome/fonts/'}, + {dest: '<%= distdir %>/fonts/', src: '*.{ttf,woff,woff2,eof,svg}', expand: true, cwd: 'bower_components/rdash-ui/dist/fonts/'}, + {dest: '<%= distdir %>/images/', src: '**', expand: true, cwd: 'assets/images/'}, + {dest: '<%= distdir %>/ico', src: '**', expand: true, cwd: 'assets/ico'} ] } }, + eslint: { + src: ['gruntfile.js', '<%= src.js %>'], + options: { configFile: '.eslintrc.yml' } + }, html2js: { app: { - options: { - base: '.' - }, + options: { base: '.' }, src: ['<%= src.tpl %>'], dest: '<%= distdir %>/templates/app.js', module: '<%= pkg.name %>.templates' @@ -301,26 +173,23 @@ module.exports = function (grunt) { src: ['<%= src.cssVendor %>', '<%= src.css %>'], dest: '<%= distdir %>/css/<%= pkg.name %>.css' }, - dist: { - options: { - process: true - }, - src: ['<%= src.js %>', '<%= src.jsTpl %>'], - dest: '<%= distdir %>/js/<%= pkg.name %>.js' - }, vendor: { src: ['<%= src.jsVendor %>'], dest: '<%= distdir %>/js/vendor.js' }, + dist: { + options: { process: true }, + src: ['<%= src.js %>', '<%= src.jsTpl %>'], + dest: '<%= distdir %>/js/<%= pkg.name %>.js' + }, index: { + options: { process: true }, src: ['index.html'], - dest: '<%= distdir %>/index.html', - options: { - process: true - } + dest: '<%= distdir %>/index.html' }, angular: { - src: ['bower_components/angular/angular.min.js', + src: [ + 'bower_components/angular/angular.min.js', 'bower_components/angular-sanitize/angular-sanitize.min.js', 'bower_components/angular-cookies/angular-cookies.min.js', 'bower_components/angular-local-storage/dist/angular-local-storage.min.js', @@ -341,16 +210,12 @@ module.exports = function (grunt) { dest: '<%= distdir %>/js/<%= pkg.name %>.js' }, vendor: { - options: { - preserveComments: 'some' // Preserve license comments - }, + options: { preserveComments: 'some' }, // Preserve license comments src: ['<%= src.jsVendor %>'], dest: '<%= distdir %>/js/vendor.js' }, angular: { - options: { - preserveComments: 'some' // Preserve license comments - }, + options: { preserveComments: 'some' }, // Preserve license comments src: ['<%= concat.angular.src %>'], dest: '<%= distdir %>/js/angular.js' } @@ -368,142 +233,27 @@ module.exports = function (grunt) { } }, watch: { - all: { - files: ['<%= src.js %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'], - tasks: ['default', 'timestamp'] - }, build: { files: ['<%= src.js %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'], tasks: ['build'] - }, - buildSwarm: { - files: ['<%= src.js %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'], - tasks: ['build', 'shell:buildImage', 'shell:runSwarm', 'shell:cleanImages'] - }, - buildSsl: { - files: ['<%= src.js %>', '<%= src.css %>', '<%= src.tpl %>', '<%= src.html %>'], - tasks: ['build', 'shell:buildImage', 'shell:runSsl', 'shell:cleanImages'] } }, - eslint: { - src: ['gruntfile.js', '<%= src.js %>'], - options: { - configFile: '.eslintrc.yml' - } - }, shell: { - buildImage: { - command: 'docker build --rm -t portainer -f build/linux/Dockerfile .' - }, - buildLinuxAmd64Binary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src portainer/golang-builder /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer dist/' - ].join(' && ') - }, - buildLinux386Binary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="linux" -e BUILD_GOARCH="386" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-linux-386 > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-linux-386 dist/portainer' - ].join(' && ') - }, - buildLinuxArmBinary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="linux" -e BUILD_GOARCH="arm" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-linux-arm > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-linux-arm dist/portainer' - ].join(' && ') - }, - buildLinuxArm64Binary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="linux" -e BUILD_GOARCH="arm64" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-linux-arm64 > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-linux-arm64 dist/portainer' - ].join(' && ') - }, - buildLinuxPpc64leBinary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="linux" -e BUILD_GOARCH="ppc64le" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-linux-ppc64le > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-linux-ppc64le dist/portainer' - ].join(' && ') - }, - buildDarwinAmd64Binary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="darwin" -e BUILD_GOARCH="amd64" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-darwin-amd64 > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-darwin-amd64 dist/portainer' - ].join(' && ') - }, - buildWindowsAmd64Binary: { - command: [ - 'docker run --rm -v $(pwd)/api:/src -e BUILD_GOOS="windows" -e BUILD_GOARCH="amd64" portainer/golang-builder:cross-platform /src/cmd/portainer', - 'shasum api/cmd/portainer/portainer-windows-amd64 > portainer-checksum.txt', - 'mkdir -p dist', - 'mv api/cmd/portainer/portainer-windows-amd64 dist/portainer.exe' - ].join(' && ') - }, + buildBinary: { + command: function (p, a) { + var binfile = 'dist/portainer-'+p+'-'+a; + if (grunt.file.isFile( ( p === 'windows' ) ? binfile+'.exe' : binfile )) { + return 'echo \'BinaryExists\''; + } else { + return 'build/build_in_container.sh ' + p + ' ' + a; + } + } + }, run: { command: [ - 'docker stop portainer', - 'docker rm portainer', - 'docker run -d -p 9000:9000 -v $(pwd)/dist:/app -v /tmp/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock:z --name portainer centurylink/ca-certs /app/portainer --no-analytics -a /app' + 'docker rm -f portainer', + 'docker run -d -p 9000:9000 -v $(pwd)/dist:/app -v /tmp/portainer:/data -v /var/run/docker.sock:/var/run/docker.sock:z --name portainer centurylink/ca-certs /app/portainer-linux-amd64 --no-analytics -a /app' ].join(';') - }, - cleanImages: { - command: 'docker rmi $(docker images -q -f dangling=true)' - } - }, - 'if': { - linuxAmd64BinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildLinuxAmd64Binary'] - }, - linux386BinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildLinux386Binary'] - }, - linuxArmBinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildLinuxArmBinary'] - }, - linuxArm64BinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildLinuxArm64Binary'] - }, - linuxPpc64leBinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildLinuxPpc64leBinary'] - }, - darwinAmd64BinaryNotExist: { - options: { - executable: 'dist/portainer' - }, - ifFalse: ['shell:buildDarwinAmd64Binary'] - }, - windowsAmd64BinaryNotExist: { - options: { - executable: 'dist/portainer.exe' - }, - ifFalse: ['shell:buildWindowsAmd64Binary'] } }, replace: { diff --git a/package.json b/package.json index 345e5f4a8..b346a6f45 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "grunt-contrib-watch": "~0.3.1", "grunt-filerev": "^2.3.1", "grunt-html2js": "~0.1.0", - "grunt-if": "^0.1.5", "grunt-karma": "~0.4.4", "grunt-postcss": "^0.8.0", "grunt-replace": "^1.0.1",