sombrero 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Rakefile +1 -2
  4. data/app/.gitignore +6 -0
  5. data/app/.pryrc +1 -0
  6. data/app/Gemfile +6 -0
  7. data/app/Rakefile +1 -0
  8. data/app/base/base_controller.rb +3 -0
  9. data/app/base/boot.rb +2 -0
  10. data/app/base/helpers/application_helpers.rb +1 -0
  11. data/app/base/load_controllers.rb +2 -0
  12. data/app/base/rtcp_controller.rb +22 -0
  13. data/app/config/config.rb +11 -0
  14. data/app/config/config.yml +11 -0
  15. data/app/config/env/development.yml +0 -0
  16. data/app/config/env/production.yml +0 -0
  17. data/app/config/env/stage.yml +0 -0
  18. data/app/config/env/test.yml +0 -0
  19. data/app/config.ru +3 -0
  20. data/app/core/Gemfile +5 -0
  21. data/app/core/boot.rb +17 -0
  22. data/app/core/client/activity_observer.coffee +37 -0
  23. data/app/core/client/api.coffee +248 -0
  24. data/app/core/client/channels.coffee +37 -0
  25. data/app/core/client/load.coffee +20 -0
  26. data/app/core/client/page.coffee +68 -0
  27. data/app/core/client/polyfills/array.compact.coffee +4 -0
  28. data/app/core/client/polyfills/array.compact_join.coffee +4 -0
  29. data/app/core/client/polyfills/number.to_money.coffee +3 -0
  30. data/app/core/client/polyfills/string.capitalize.coffee +4 -0
  31. data/app/core/client/polyfills/string.strip.coffee +5 -0
  32. data/app/core/client/polyfills.coffee +6 -0
  33. data/app/core/client/render.coffee +57 -0
  34. data/app/core/client/util/alert.coffee +50 -0
  35. data/app/core/client/util/datetime.coffee +47 -0
  36. data/app/core/client/util.coffee +38 -0
  37. data/app/core/generate_controllers_map.rb +4 -0
  38. data/app/core/generate_webpack_setup.rb +4 -0
  39. data/app/core/load.rb +5 -0
  40. data/app/core/load_controllers.rb +16 -0
  41. data/app/package.json +5 -0
  42. data/app/webpack.config.js +51 -0
  43. data/bin/sombrero +5 -0
  44. data/docker/Dockerfile +5 -0
  45. data/docker/base/Dockerfile +3 -0
  46. data/docker/base/build +10 -0
  47. data/docker/base/build.sh +25 -0
  48. data/docker/cleanup +7 -0
  49. data/docker/run +68 -0
  50. data/docker/skel/build.sh +1 -0
  51. data/docker/skel/config.yml +24 -0
  52. data/docker/skel/prepare_build.sh +5 -0
  53. data/docker/skel/start.sh +1 -0
  54. data/docker/start +7 -0
  55. data/lib/sombrero/{version.rb → app.rb} +3 -1
  56. data/lib/sombrero/base_controller.rb +5 -0
  57. data/lib/sombrero/cli/app/install.rb +38 -0
  58. data/lib/sombrero/cli/app/update.rb +20 -0
  59. data/lib/sombrero/cli/app.rb +10 -0
  60. data/lib/sombrero/cli/docker/build.rb +170 -0
  61. data/lib/sombrero/cli/docker/install.rb +23 -0
  62. data/lib/sombrero/cli/docker.rb +14 -0
  63. data/lib/sombrero/cli.rb +128 -0
  64. data/lib/sombrero/rtcp_controller.rb +93 -0
  65. data/lib/sombrero.rb +110 -2
  66. data/sombrero.gemspec +6 -1
  67. metadata +91 -4
@@ -0,0 +1,50 @@
1
+ _ =
2
+ isObject: require('lodash/isObject')
3
+ isFunction: require('lodash/isFunction')
4
+ merge: require('lodash/merge')
5
+ #end
6
+
7
+ require 'sweetalert/dist/sweetalert.css'
8
+ Alert = require('sweetalert')
9
+
10
+
11
+ Alert.setDefaults
12
+ allowEscapeKey: false
13
+ allowOutsideClick: false
14
+ #end
15
+
16
+
17
+ module.exports =
18
+ alert: Alert
19
+
20
+ error: (text, opts = {}) ->
21
+ if _.isObject(text)
22
+ [text, opts] = [null, text]
23
+ Alert(_.merge({type: 'error', title: 'Error', text: text}, opts))
24
+ #end
25
+
26
+
27
+ warning: (title, opts = {}) ->
28
+ if _.isObject(title)
29
+ [title, opts] = [null, title]
30
+ Alert(_.merge({type: 'warning', title: title, text: null}, opts))
31
+ #end
32
+
33
+
34
+ success: (title = 'Done!', opts = {}) ->
35
+ if _.isObject(title)
36
+ [title, opts] = [null, title]
37
+ Alert(_.merge({title: title, text: null, showConfirmButton: false, timer: 1000, type: 'success'}, opts))
38
+ #end
39
+
40
+
41
+ confirm: (title, opts, cb) ->
42
+ if _.isFunction(title)
43
+ [title, opts, cb] = [null, {}, title]
44
+ else if _.isFunction(opts)
45
+ [opts, cb] = [null, opts]
46
+ title ||= 'This action is irreversible! Continue?'
47
+ Alert(_.merge({title: title, type: 'warning', showCancelButton: true}, opts), cb)
48
+ #end
49
+
50
+ #end
@@ -0,0 +1,47 @@
1
+ Moment = require('moment')
2
+
3
+ current_year = ->
4
+ new Date().getFullYear()
5
+ #end
6
+
7
+ Api =
8
+
9
+ date_format: (x, skip_current_year = false) ->
10
+ date = Moment(x)
11
+ if skip_current_year && time.year() == current_year()
12
+ date.format('MMM Do')
13
+ else
14
+ date.format('MMM Do YYYY')
15
+ #end
16
+
17
+
18
+ datetime_format: (x, skip_current_year = false) ->
19
+ time = Moment(x)
20
+ if skip_current_year && time.year() == current_year()
21
+ time.format('MMMM D, h:mmA')
22
+ else
23
+ time.format('MMMM D YYYY, h:mmA')
24
+ #end
25
+
26
+
27
+ time_format: (x) ->
28
+ Moment(x).format('HH:mm')
29
+ #end
30
+
31
+
32
+ relative_time_format: (x) ->
33
+ return '' unless x
34
+ now = Moment()
35
+ _then = Moment(x)
36
+ diff = now.diff(_then, 'seconds')
37
+
38
+ if diff < 86400
39
+ _then.fromNow()
40
+ else if diff < 172800
41
+ _then.calendar(now)
42
+ else
43
+ Api.datetime_format(x)
44
+ #end
45
+ #end
46
+
47
+ module.exports = Api
@@ -0,0 +1,38 @@
1
+ module.exports =
2
+
3
+ generate_uuid: ->
4
+ 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace /[xy]/g, (c) ->
5
+ v = r = Math.random() * 16|0
6
+ v = (r&0x3|0x8) if c == 'x'
7
+ v.toString(16)
8
+ #end
9
+
10
+
11
+ shorten: (text, max_length = 50) ->
12
+ return unless text
13
+ text[0 .. max_length] + (if text.length > max_length then '...' else '')
14
+ #end
15
+
16
+
17
+ scroll_top: ->
18
+ window.scrollTo(0, 0)
19
+ #end
20
+
21
+
22
+ reload: ->
23
+ window.location.reload()
24
+ #end
25
+
26
+
27
+ popup: (url, width, height) ->
28
+ width ||= 800
29
+ height ||= 600
30
+ left = (screen.width / 2) - (width / 2)
31
+ top = (screen.height / 2) - (height / 2)
32
+ window.open url, '_blank', 'menubar=no' +
33
+ ',width=' + width +
34
+ ',height=' + height +
35
+ ',left=' + left +
36
+ ',top=' + top
37
+ #end
38
+ #end
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../load', __FILE__)
3
+
4
+ Sombrero.generate_controllers_map(File.expand_path('../..', __FILE__))
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require File.expand_path('../load', __FILE__)
3
+
4
+ Sombrero.generate_webpack_setup(File.expand_path('../..', __FILE__))
data/app/core/load.rb ADDED
@@ -0,0 +1,5 @@
1
+ # DO NOT EDIT THIS FILE, all updates will be lost on next update.
2
+ # edit base/load.rb instead.
3
+
4
+ require File.expand_path('../boot', __FILE__)
5
+ require File.expand_path('../load_controllers', __FILE__)
@@ -0,0 +1,16 @@
1
+ # DO NOT EDIT THIS FILE, all updates will be lost on next update.
2
+ # edit base/load_controllers.rb instead.
3
+
4
+ Dir.chdir File.expand_path('../..', __FILE__) do
5
+
6
+ require './base/base_controller'
7
+ require './base/rtcp_controller'
8
+
9
+ %w[
10
+ **/server.rb
11
+ ].each_with_object([]) {|f,o| o.concat(Dir["./base/api/#{f}"])}.sort {|a,b|
12
+ a.split(/\/+/).size <=> b.split(/\/+/).size
13
+ }.each {|f| require(f)}
14
+
15
+ require './base/load_controllers'
16
+ end
data/app/package.json ADDED
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+
4
+ }
5
+ }
@@ -0,0 +1,51 @@
1
+ var webpack = require('webpack'),
2
+ fs = require('fs'),
3
+ child_process = require('child_process')
4
+ ;
5
+
6
+ if (process.env.APP_ENV == 'development') {
7
+ console.log('Generating controllers map...');
8
+ child_process.execSync('./core/generate_controllers_map.rb');
9
+ console.log('Generating webpack setup...');
10
+ child_process.execSync('./core/generate_webpack_setup.rb');
11
+ }
12
+
13
+ var setup = JSON.parse(fs.readFileSync('./webpack_setup.json'));
14
+ console.log(JSON.stringify(setup, null, 2))
15
+
16
+ module.exports = {
17
+ entry: setup.entries,
18
+ output: {
19
+ path: [setup.path, setup.url].join('/'),
20
+ filename: '[name].js',
21
+ publicPath: setup.url + '/', // trailing slash required
22
+ libraryTarget: 'commonjs2'
23
+ },
24
+ module: {
25
+ loaders: [
26
+ // { test: /\.coffee$/, loader: 'coffee-loader' },
27
+ // { test: /\.css$/, loader: 'style-loader!css-loader' },
28
+ // { test: /\.json$/, loader: 'json-loader' },
29
+ // { test: /\.otf($|\?)/, loader: require.resolve('file-loader') },
30
+ // { test: /\.ttf($|\?)/, loader: require.resolve('file-loader') },
31
+ // { test: /\.eot($|\?)/, loader: require.resolve('file-loader') },
32
+ // { test: /\.svg($|\?)/, loader: require.resolve('file-loader') },
33
+ // { test: /\.png($|\?)/, loader: require.resolve('url-loader') + '?limit=10000&mimetype=image/png' },
34
+ // { test: /\.jpg($|\?)/, loader: require.resolve('file-loader') },
35
+ // { test: /\.gif($|\?)/, loader: require.resolve('file-loader') },
36
+ // { test: /\.woff[2]?($|\?)/, loader: require.resolve('url-loader') + '?limit=10000&mimetype=application/font-woff' },
37
+ ]
38
+ },
39
+ resolve: {
40
+ extensions: ['', '.js', '.css', '.json', '.coffee', '.html'],
41
+ alias: {
42
+ core: __dirname + '/core/client',
43
+ base: __dirname + '/base',
44
+ api: __dirname + '/base/api',
45
+ }
46
+ },
47
+ plugins: [
48
+ new webpack.optimize.DedupePlugin(),
49
+ new webpack.optimize.CommonsChunkPlugin('core', 'core.js'),
50
+ ]
51
+ }
data/bin/sombrero CHANGED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.expand_path('../../lib', __FILE__))
3
+ require 'sombrero'
4
+ require 'sombrero/cli'
5
+ Sombrero::CLI.new($*)
data/docker/Dockerfile ADDED
@@ -0,0 +1,5 @@
1
+ FROM sombrero/base
2
+ COPY start /
3
+ COPY build /build
4
+ RUN sh /build/build && sh /build/cleanup && mkdir /app
5
+ CMD sh /start
@@ -0,0 +1,3 @@
1
+ FROM alpine
2
+ COPY build.sh /
3
+ RUN sh /build.sh && rm -f /build.sh
data/docker/base/build ADDED
@@ -0,0 +1,10 @@
1
+ set -e
2
+
3
+ image="sombrero/base"
4
+
5
+ cd "$(cd $(dirname $0); pwd)"
6
+ docker build -t $image --force-rm --no-cache .
7
+
8
+ if [ "$1" = "-p" ]; then
9
+ docker push $image
10
+ fi
@@ -0,0 +1,25 @@
1
+ #/usr/bin/env sh
2
+
3
+ set -e
4
+
5
+ for e in $(getent passwd | cut -d: -f1); do
6
+ [[ "$e" = "root" || "$e" = "nobody" ]] || ! deluser "$e"
7
+ done
8
+
9
+ for e in $(getent group | cut -d: -f1); do
10
+ [[ "$e" = "root" || "$e" = "nobody" ]] || ! delgroup "$e"
11
+ done
12
+
13
+ echo "http://dl-4.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories
14
+
15
+ apk update
16
+ apk upgrade
17
+
18
+ apk add build-base runit nmap-ncat libxml2 libxml2-dev libxslt libxslt-dev \
19
+ ruby ruby-dev ruby-irb ruby-io-console ruby-bigdecimal \
20
+ nodejs nodejs-dev python git \
21
+ redis libpq postgresql-dev \
22
+ imagemagick imagemagick-dev
23
+
24
+ curl -fsSL curl.haxx.se/ca/cacert.pem -o "$(ruby -ropenssl -e 'puts OpenSSL::X509::DEFAULT_CERT_FILE')"
25
+ echo 'gem: --no-ri --no-rdoc' > /root/.gemrc
data/docker/cleanup ADDED
@@ -0,0 +1,7 @@
1
+ set -e
2
+
3
+ apk del build-base libxml2-dev libxslt-dev \
4
+ ruby-dev postgresql-dev imagemagick-dev \
5
+ nodejs-dev python git
6
+
7
+ rm -rf /var/cache/apk/*
data/docker/run ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env bash
2
+
3
+ run() {
4
+ echo -e "\n$ $@"
5
+ "$@"
6
+ }
7
+
8
+ container_is_built() {
9
+ [[ -n $(docker ps -a | grep -E "\s$CONTAINER_NAME\s") ]]
10
+ }
11
+
12
+ container_is_running() {
13
+ [[ -n $(docker ps | grep -E "\s$CONTAINER_NAME\s") ]]
14
+ }
15
+
16
+ stop_container() {
17
+ run docker stop $CONTAINER_NAME
18
+ }
19
+
20
+ remove_container() {
21
+ run docker rm $CONTAINER_NAME
22
+ }
23
+
24
+ env_prompt() {
25
+ read APP_ENV
26
+ [ "$(echo " {environments} " | grep -E "\s$APP_ENV\s")" = "" ] && env_prompt
27
+ }
28
+
29
+ if [ "$APP_ENV" = "" ]; then
30
+ echo "APP_ENV not set, please use one of"
31
+ echo "{environments}"
32
+ echo -n "> "
33
+ env_prompt
34
+ fi
35
+
36
+ set -e
37
+
38
+ {container_definitions}
39
+
40
+ if [ "$CONTAINER_NAME" = "" ]; then
41
+ echo -e "\n\t::: $APP_ENV environment not supported. Use one of: {environments} :::\n"
42
+ exit 1
43
+ fi
44
+
45
+ APP_UID="$(id -u)"
46
+ APP_GID="$(id -g)"
47
+ APP_DIR="$(cd "$(dirname ${BASH_SOURCE[0]})/{script_path_traversal}"; pwd)"
48
+
49
+ if [ "$APP_UID" = "0" ]; then
50
+ echo -e "\n\t::: No superpowers accepted here! Run this as a regular user :::\n"
51
+ exit 1
52
+ fi
53
+
54
+ run docker pull {image}
55
+ container_is_running && stop_container
56
+ container_is_built && remove_container
57
+
58
+ run docker run \
59
+ --name "$CONTAINER_NAME" \
60
+ -e APP_ENV="$APP_ENV" \
61
+ -e APP_UID="$APP_UID" \
62
+ -e APP_GID="$APP_GID" \
63
+ -e LANG="en_US.UTF-8" \
64
+ -e LC_ALL="en_US.UTF-8" \
65
+ -e LC_TYPE="en_US.UTF-8" \
66
+ -v "$APP_DIR":/app \
67
+ {run_opts} {image}
68
+ echo
@@ -0,0 +1 @@
1
+ # running inside container.
@@ -0,0 +1,24 @@
1
+ # a image with this name will be built (see prepare_build.sh and build.sh)
2
+ IMAGE_NAME:
3
+
4
+ # the name of container to be run on your server(s).
5
+ # name depends on APP_ENV variable.
6
+ # you can add/remove environments but at least one is required.
7
+ CONTAINER_NAME:
8
+ development:
9
+ test:
10
+ stage:
11
+ production:
12
+
13
+ # path to app.
14
+ # should be absolute or relative to this file.
15
+ APP_DIR:
16
+
17
+ # a file with this name will be generated and installed inside APP_DIR.
18
+ RUN_SCRIPT: docker/run
19
+
20
+ # options passed to `docker build`
21
+ BUILD_OPTS: --force-rm --no-cache
22
+
23
+ # options passed to `docker run`
24
+ RUN_OPTS: -d --restart always
@@ -0,0 +1,5 @@
1
+ # running before image building started.
2
+ # will run inside building dir so copy into ./ any files you need for building.
3
+ # APP_DIR variable points to your app directory
4
+ # so use it to copy any files from your app into building dir.
5
+ # running outside container, e.g. on your dev machine.
@@ -0,0 +1 @@
1
+ # start your app
data/docker/start ADDED
@@ -0,0 +1,7 @@
1
+ set -e
2
+
3
+ [ "$(getent group $APP_GID)" = "" ] && addgroup -g $APP_GID app
4
+
5
+ [ "$(getent passwd $APP_UID)" = "" ] && adduser -D -u $APP_UID -G app app
6
+
7
+ {start}
@@ -1,3 +1,5 @@
1
1
  module Sombrero
2
- VERSION = "0.1.0"
2
+ class App
3
+
4
+ end
3
5
  end
@@ -0,0 +1,5 @@
1
+ module Sombrero
2
+ class BaseController < RocketIO::Controller
3
+
4
+ end
5
+ end
@@ -0,0 +1,38 @@
1
+ module Sombrero
2
+ class CLI
3
+ class App
4
+ class Install
5
+ include InstallHelpers
6
+
7
+ def initialize dir, namespace
8
+ ensure_dirname_exists(dir)
9
+ assert_installable_dir(dir)
10
+ install(dir, namespace)
11
+ end
12
+
13
+ def install dir, namespace
14
+ src = dir.to_path == '.' ? BASE_DIR.to_path + '/.' : BASE_DIR
15
+ FileUtils.cp_r(src, dir)
16
+ FileUtils.chmod('+x', dir / 'core/generate_webpack_setup.rb')
17
+ FileUtils.chmod('+x', dir / 'core/generate_controllers_map.rb')
18
+ if namespace
19
+ %w[
20
+ base/base_controller.rb
21
+ base/rtcp_controller.rb
22
+ config/config.rb
23
+ ].each do |file|
24
+ code = File.read(dir / file)
25
+ File.open dir / file, 'w' do |f|
26
+ f.puts "module #{namespace}"
27
+ code.split("\n").each {|l| f.puts " #{l}"}
28
+ f.puts "end"
29
+ end
30
+ end
31
+ end
32
+ puts "Done. All files installed into #{dir}"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ module Sombrero
2
+ class CLI
3
+ class App
4
+ class Update
5
+
6
+ def initialize dir
7
+ assert_is_a_sombrero_dir(dir)
8
+ end
9
+
10
+ def assert_is_a_sombrero_dir dir
11
+
12
+ end
13
+
14
+ def update
15
+
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Sombrero
2
+ class CLI
3
+ class App
4
+ BASE_DIR = (Sombrero::BASE_DIR / 'app').freeze
5
+ end
6
+ end
7
+ end
8
+
9
+ require 'sombrero/cli/app/install'
10
+ require 'sombrero/cli/app/update'
@@ -0,0 +1,170 @@
1
+ module Sombrero
2
+ class CLI
3
+ module Docker
4
+ class Build
5
+
6
+ def initialize dir, args
7
+ check_working_dir(dir)
8
+
9
+ Dir.chdir dir do
10
+ check_config_file
11
+
12
+ config = load_config
13
+ validate_config(config)
14
+
15
+ build_dir = Pathname.new(File.expand_path('__tmpbuildir__'))
16
+
17
+ prepare_build_dir(build_dir)
18
+
19
+ install_files(build_dir)
20
+
21
+ app_dir = Pathname.new(File.expand_path(config['APP_DIR']))
22
+
23
+ unless skip_build?(args)
24
+ prepare_build(build_dir, app_dir)
25
+
26
+ image_built = build_image(build_dir, config['IMAGE_NAME'], config['BUILD_OPTS'])
27
+
28
+ if image_built && push_opted?(args)
29
+ push_image(config['IMAGE_NAME'])
30
+ end
31
+ end
32
+
33
+ install_run_script(app_dir, *config.values_at('IMAGE_NAME', 'CONTAINER_NAME', 'RUN_SCRIPT', 'RUN_OPTS'))
34
+
35
+ FileUtils.rm_rf(build_dir)
36
+ end
37
+ end
38
+
39
+ def push_opted? args
40
+ args.find {|a| a == '-p'}
41
+ end
42
+
43
+ def skip_build? args
44
+ args.find {|a| a == '-u'}
45
+ end
46
+
47
+ def check_working_dir dir
48
+ return if File.directory?(dir)
49
+ puts "#{dir} should be a directory"
50
+ exit 1
51
+ end
52
+
53
+ def check_config_file
54
+ return if File.file?(CONFIG_FILE)
55
+ puts "#{dir}/config.yml file is missing"
56
+ exit 1
57
+ end
58
+
59
+ def load_config
60
+ YAML.load(File.read(CONFIG_FILE))
61
+ end
62
+
63
+ def validate_config config
64
+ {
65
+ 'IMAGE_NAME' => :validate_config__image_name,
66
+ 'CONTAINER_NAME' => :validate_config__container_name,
67
+ 'APP_DIR' => :validate_config__app_dir,
68
+ 'RUN_SCRIPT' => :validate_config__run_script,
69
+ }.each_pair do |key,validator|
70
+ next if send(validator, config[key])
71
+ puts "", "\t::: Please set #{key} in config.yml :::", ""
72
+ exit 1
73
+ end
74
+ end
75
+
76
+ def validate_config__image_name value
77
+ !value.nil? && !value.empty?
78
+ end
79
+
80
+ def validate_config__container_name value
81
+ !value.nil? && !value.empty? && value.values.any?
82
+ end
83
+
84
+ def validate_config__app_dir value
85
+ !value.nil? && !value.empty?
86
+ end
87
+
88
+ def validate_config__run_script value
89
+ !value.nil? && !value.empty?
90
+ end
91
+
92
+ def prepare_build_dir dir
93
+ FileUtils.rm_rf(dir)
94
+ FileUtils.mkdir_p(dir / 'build')
95
+ end
96
+
97
+ def install_files dir
98
+ install_dockerfile(dir)
99
+ install_start_file(dir)
100
+ install_build_files(dir)
101
+ install_cleanup_file(dir)
102
+ end
103
+
104
+ def install_dockerfile dir
105
+ FileUtils.cp(BASE_DIR / 'Dockerfile', dir)
106
+ end
107
+
108
+ def install_start_file dir
109
+ File.open dir / 'start', 'w' do |f|
110
+ f << File.read(BASE_DIR / 'start').sub('{start}', File.read(START_FILE))
111
+ end
112
+ end
113
+
114
+ def install_build_files dir
115
+ FileUtils.cp(PREPARE_BUILD_FILE, dir / 'build')
116
+ FileUtils.cp(BUILD_FILE, dir / 'build/build')
117
+ end
118
+
119
+ def install_cleanup_file dir
120
+ FileUtils.cp(BASE_DIR / 'cleanup', dir / 'build')
121
+ end
122
+
123
+ def prepare_build dir, app_dir
124
+ Dir.chdir dir / 'build' do
125
+ CLI.run "APP_DIR=#{app_dir} #{PREPARE_BUILD_FILE}"
126
+ exit 1 unless $? && $?.success?
127
+ end
128
+ end
129
+
130
+ def build_image dir, image_name, build_opts
131
+ CLI.run "docker build -t #{image_name} #{build_opts} '#{dir}'"
132
+ $? && $?.success?
133
+ end
134
+
135
+ def push_image image_name
136
+ CLI.run "docker push #{image_name}"
137
+ $? && $?.success?
138
+ end
139
+
140
+ def install_run_script app_dir, image_name, container_name, run_script, run_opts
141
+ FileUtils.mkdir_p(app_dir / File.dirname(run_script))
142
+
143
+ script_path = app_dir / run_script
144
+
145
+ File.open script_path, 'w' do |f|
146
+ f << File.read(BASE_DIR / 'run').
147
+ gsub('{image}', image_name).
148
+ gsub('{script_path_traversal}', script_path_traversal(run_script)).
149
+ gsub('{run_opts}', run_opts).
150
+ gsub('{environments}', container_name.keys.join(' ')).
151
+ gsub('{container_definitions}', container_definitions(container_name))
152
+ end
153
+
154
+ FileUtils.chmod('+x', script_path)
155
+ end
156
+
157
+ def container_definitions container_name
158
+ container_name.map do |kv|
159
+ '[ "$APP_ENV" = "%s" ] && CONTAINER_NAME="%s"' % kv
160
+ end.join("\n")
161
+ end
162
+
163
+ def script_path_traversal run_script
164
+ run_script.gsub(/\A\/+|\/+\Z/, '').scan(/\/+/).map {'..'}*'/'
165
+ end
166
+
167
+ end
168
+ end
169
+ end
170
+ end