kaiser 0.0.0 → 0.4.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +281 -0
- data/exe/kaiser +87 -0
- data/lib/kaiser/after_dotter.rb +23 -0
- data/lib/kaiser/cli.rb +579 -0
- data/lib/kaiser/cli_options.rb +14 -0
- data/lib/kaiser/cmds/attach.rb +23 -0
- data/lib/kaiser/cmds/db_load.rb +29 -0
- data/lib/kaiser/cmds/db_reset.rb +22 -0
- data/lib/kaiser/cmds/db_reset_hard.rb +21 -0
- data/lib/kaiser/cmds/db_save.rb +26 -0
- data/lib/kaiser/cmds/deinit.rb +22 -0
- data/lib/kaiser/cmds/down.rb +19 -0
- data/lib/kaiser/cmds/init.rb +39 -0
- data/lib/kaiser/cmds/login.rb +21 -0
- data/lib/kaiser/cmds/logs.rb +19 -0
- data/lib/kaiser/cmds/root.rb +21 -0
- data/lib/kaiser/cmds/set.rb +70 -0
- data/lib/kaiser/cmds/show.rb +39 -0
- data/lib/kaiser/cmds/shutdown.rb +26 -0
- data/lib/kaiser/cmds/up.rb +42 -0
- data/lib/kaiser/command_runner.rb +50 -0
- data/lib/kaiser/config.rb +66 -0
- data/lib/kaiser/docker_control.rb +10 -0
- data/lib/kaiser/dotter.rb +18 -0
- data/lib/kaiser/error.rb +14 -0
- data/lib/kaiser/kaiserfile.rb +80 -0
- data/lib/kaiser/plugin.rb +58 -0
- data/lib/kaiser/plugins/git_submodule.rb +20 -0
- data/lib/kaiser/version.rb +5 -0
- data/lib/kaiser.rb +51 -5
- metadata +142 -13
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class DbSave < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down the database docker container, backs up the database and brings the container back up.
|
9
|
+
|
10
|
+
The database will be saved as a tarball to \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/<DB_BACKUP_FILENAME>.tar.bz\`
|
11
|
+
|
12
|
+
Alternatively you can also save it to your current directory.
|
13
|
+
|
14
|
+
USAGE: kaiser db_save DB_BACKUP_FILENAME
|
15
|
+
kaiser db_save ./my_database.tar.bz
|
16
|
+
EOS
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute(_opts)
|
20
|
+
ensure_setup
|
21
|
+
name = ARGV.shift || '.default'
|
22
|
+
save_db(name)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Deinit < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Removes the Kaiser environment from \`~/.kaiser/.config.yml\`. This however does not delete the \`~/.kaiser/databases/<ENV_NAME>\` directory.
|
9
|
+
|
10
|
+
USAGE: kaiser init ENV_NAME
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
down
|
16
|
+
Config.config[:envs].delete(envname)
|
17
|
+
Config.config[:envnames].delete(Config.work_dir)
|
18
|
+
save_config
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Down < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Shuts down and *deletes* the containers that were started using \`kaiser up\`.
|
9
|
+
|
10
|
+
USAGE: kaiser down
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
down
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Init < Cli
|
6
|
+
# TODO: Add explanation for the Already initialized error.
|
7
|
+
def usage
|
8
|
+
<<~EOS
|
9
|
+
Initializes a Kaiser environment and assigns ports for it in \`~/.kaiser/.config.yml\`. When running \`kaiser up\` later the directory \`~/.kaiser/databases/<ENV_NAME>\` will get created.
|
10
|
+
|
11
|
+
USAGE: kaiser init ENV_NAME
|
12
|
+
EOS
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(_opts)
|
16
|
+
return Optimist.die "Already initialized as #{envname}" if envname
|
17
|
+
|
18
|
+
name = ARGV.shift
|
19
|
+
return Optimist.die 'Needs environment name' if name.nil?
|
20
|
+
|
21
|
+
init_config_for_env(name)
|
22
|
+
save_config
|
23
|
+
end
|
24
|
+
|
25
|
+
def init_config_for_env(name)
|
26
|
+
Config.config[:envnames][Config.work_dir] = name
|
27
|
+
Config.config[:envs][name] = {
|
28
|
+
app_port: (largest_port + 1).to_s,
|
29
|
+
db_port: (largest_port + 2).to_s
|
30
|
+
}
|
31
|
+
Config.config[:largest_port] = Config.config[:largest_port] + 2
|
32
|
+
end
|
33
|
+
|
34
|
+
def largest_port
|
35
|
+
Config.config[:largest_port]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Login < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Executes a command on the application docker container. By executing the command \`sh\` you can get a login shell.
|
9
|
+
|
10
|
+
USAGE: kaiser login COMMAND
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
ensure_setup
|
16
|
+
cmd = (ARGV || []).join(' ')
|
17
|
+
exec "docker exec -ti #{app_container_name} #{cmd}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Logs < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Continuously monitors the application container's logs.
|
9
|
+
|
10
|
+
USAGE: kaiser logs
|
11
|
+
EOS
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
exec "docker logs -f #{app_container_name}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Root < Cli
|
6
|
+
def usage
|
7
|
+
<<~USAGE
|
8
|
+
Executes a command on the application docker container as a root user.
|
9
|
+
|
10
|
+
USAGE: kaiser root COMMAND
|
11
|
+
USAGE
|
12
|
+
end
|
13
|
+
|
14
|
+
def execute(_opts)
|
15
|
+
ensure_setup
|
16
|
+
cmd = (ARGV || []).join(' ')
|
17
|
+
exec "docker exec -ti --user root #{app_container_name} #{cmd}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Set < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
This command lets you set up special variables that configure kaiser's behavior for you.
|
9
|
+
|
10
|
+
Available subcommands:
|
11
|
+
|
12
|
+
http-suffix - Sets the domain suffix for the reverse proxy to use (defaults to lvh.me)
|
13
|
+
cert-url - Sets up a URL from which HTTPS certificates can be downloaded.
|
14
|
+
cert-folder - Sets up a folder from which HTTPS certificates can be copied.
|
15
|
+
help-https - Shows the HTTPS notes.
|
16
|
+
|
17
|
+
USAGE: kaiser set cert-url
|
18
|
+
kaiser set cert-folder
|
19
|
+
kaiser set http-suffix
|
20
|
+
kaiser set help-https
|
21
|
+
EOS
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute(_opts)
|
25
|
+
cmd = ARGV.shift
|
26
|
+
if cmd == 'cert-url'
|
27
|
+
Config.config[:cert_source] = {
|
28
|
+
url: ARGV.shift
|
29
|
+
}
|
30
|
+
elsif cmd == 'cert-folder'
|
31
|
+
Config.config[:cert_source] = {
|
32
|
+
folder: ARGV.shift
|
33
|
+
}
|
34
|
+
elsif cmd == 'http-suffix'
|
35
|
+
Config.config[:http_suffix] = ARGV.shift
|
36
|
+
elsif cmd == 'help-https'
|
37
|
+
puts <<~SET_HELP
|
38
|
+
Notes on HTTPS:
|
39
|
+
|
40
|
+
You need to set suffix and either cert-url or cert-folder to enable HTTPS.
|
41
|
+
|
42
|
+
cert-url and cert-folder are mutually exclusive. If you set one of them the other will be erased.
|
43
|
+
|
44
|
+
The cert-url and cert-folder must satisfy the following requirements to work:
|
45
|
+
|
46
|
+
The strings must be the root of certificates named after the suffix. For example,
|
47
|
+
|
48
|
+
if cert-url is https://mydomain.com/certs and your suffix is local.mydomain.com, the following
|
49
|
+
url need to be the certificate files:
|
50
|
+
|
51
|
+
https://mydomain.com/certs/local.mydomain.com.chain.pem
|
52
|
+
https://mydomain.com/certs/local.mydomain.com.crt
|
53
|
+
https://mydomain.com/certs/local.mydomain.com.key
|
54
|
+
|
55
|
+
Another example:
|
56
|
+
|
57
|
+
If you use suffix of localme.com and cert-folder is /home/me/https, The following files need to exist:
|
58
|
+
|
59
|
+
/home/me/https/localme.com.chain.pem
|
60
|
+
/home/me/https/localme.com.crt
|
61
|
+
/home/me/https/localme.com.key
|
62
|
+
SET_HELP
|
63
|
+
else
|
64
|
+
Optimist.die "Unknown subcommand: '#{cmd}'"
|
65
|
+
end
|
66
|
+
save_config
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Show < Cli
|
6
|
+
def usage
|
7
|
+
<<~EOS
|
8
|
+
Subcommand that shows information about the environment such as the TCP ports or the certificate used for HTTPS.
|
9
|
+
|
10
|
+
USAGE: kaiser show ports
|
11
|
+
kaiser show cert-source
|
12
|
+
kaiser show http-suffix
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(_opts)
|
17
|
+
ensure_setup
|
18
|
+
cmd = ARGV.shift
|
19
|
+
valid_cmds = 'ports cert-source http-suffix'
|
20
|
+
return Optimist.die "Available things to show: #{valid_cmds}" unless cmd
|
21
|
+
|
22
|
+
if cmd == 'ports'
|
23
|
+
Config.info_out.puts "app: #{app_port}"
|
24
|
+
Config.info_out.puts "db: #{db_port}"
|
25
|
+
elsif cmd == 'cert-source'
|
26
|
+
unless Config.config[:cert_source]
|
27
|
+
Optimist.die 'No certificate source set.
|
28
|
+
see kaiser set help'
|
29
|
+
end
|
30
|
+
|
31
|
+
source = Config.config[:cert_source][:url] || Config.config[:cert_source][:folder]
|
32
|
+
Config.info_out.puts source
|
33
|
+
elsif cmd == 'http-suffix'
|
34
|
+
Config.info_out.puts http_suffix
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Shutdown < Cli
|
6
|
+
def usage
|
7
|
+
# TODO: Explain a bit more about what these containers do and what shutting
|
8
|
+
# them down really means for an end user.
|
9
|
+
<<~EOS
|
10
|
+
Shuts down all the containers used internally by Kaiser.
|
11
|
+
|
12
|
+
USAGE: kaiser shutdown
|
13
|
+
EOS
|
14
|
+
end
|
15
|
+
|
16
|
+
def execute(_opts)
|
17
|
+
Config.config[:shared_names].each do |_, container_name|
|
18
|
+
killrm container_name
|
19
|
+
end
|
20
|
+
|
21
|
+
CommandRunner.run Config.out, "docker network rm #{Config.config[:networkname]}"
|
22
|
+
CommandRunner.run Config.out, "docker volume rm #{Config.config[:shared_names][:certs]}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
module Cmds
|
5
|
+
class Up < Cli
|
6
|
+
option :attach, "Bind mount the current source code directory in the app container (as the \`kaiser attach\` command would)", short: '-a'
|
7
|
+
|
8
|
+
def usage
|
9
|
+
<<~EOS
|
10
|
+
Boots up the application in docker as defined in the \`Kaiserfile\` in its source code. Usually this will create two docker containers \`<ENV_NAME>-db\` and \`<ENV_NAME>-app\` running your database and application respectively.
|
11
|
+
|
12
|
+
A backup of the default database is created and saved to \`~/.kaiser/<ENV_NAME>/<current_github_branch_name>/.default.tar.bz\`. This can be restored at any time using the \`db_reset\` command.
|
13
|
+
|
14
|
+
USAGE: kaiser up
|
15
|
+
EOS
|
16
|
+
end
|
17
|
+
|
18
|
+
def execute(opts)
|
19
|
+
ensure_setup
|
20
|
+
setup_app
|
21
|
+
setup_db
|
22
|
+
|
23
|
+
if opts[:attach]
|
24
|
+
attach_app
|
25
|
+
else
|
26
|
+
start_app
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def setup_app
|
31
|
+
Config.info_out.puts 'Setting up application'
|
32
|
+
File.write(tmp_dockerfile_name, docker_file_contents)
|
33
|
+
build_args = docker_build_args.map { |k, v| "--build-arg #{k}=#{v}" }
|
34
|
+
CommandRunner.run! Config.out, "docker build
|
35
|
+
-t kaiser:#{envname}-#{current_branch}
|
36
|
+
-f #{tmp_dockerfile_name} #{Config.work_dir}
|
37
|
+
#{build_args.join(' ')}"
|
38
|
+
FileUtils.rm(tmp_dockerfile_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'English'
|
4
|
+
|
5
|
+
# This is the command runner
|
6
|
+
module Kaiser
|
7
|
+
# Make running easy
|
8
|
+
class CommandRunner
|
9
|
+
def self.run(out, cmd, &block)
|
10
|
+
out.puts "> #{cmd}"
|
11
|
+
CommandRunner.new(out, cmd).run_command(&block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.run!(out, cmd, &block)
|
15
|
+
status = run(out, cmd, &block)
|
16
|
+
raise Kaiser::CmdError.new(cmd, status) if status.to_s != '0'
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(out, cmd)
|
20
|
+
@out = out
|
21
|
+
@cmd = cmd.tr "\n", ' '
|
22
|
+
end
|
23
|
+
|
24
|
+
def print_and_return_status(status = 0)
|
25
|
+
@out.puts "$? = #{status}"
|
26
|
+
@out.flush
|
27
|
+
status
|
28
|
+
end
|
29
|
+
|
30
|
+
def print_lines(lines)
|
31
|
+
lines.each do |line|
|
32
|
+
@out.print line
|
33
|
+
@out.flush
|
34
|
+
yield line.chomp if block_given?
|
35
|
+
end
|
36
|
+
rescue Errno::EIO
|
37
|
+
# Happens when `lines` stream is closed
|
38
|
+
end
|
39
|
+
|
40
|
+
def run_command(&block)
|
41
|
+
PTY.spawn("#{@cmd} 2>&1") do |stdout, _stdin, pid|
|
42
|
+
print_lines(stdout, &block)
|
43
|
+
Process.wait(pid)
|
44
|
+
end
|
45
|
+
print_and_return_status $CHILD_STATUS.exitstatus
|
46
|
+
rescue PTY::ChildExited => e
|
47
|
+
print_and_return_status(e.status)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
class Config
|
5
|
+
class << self
|
6
|
+
attr_reader :work_dir,
|
7
|
+
:config_dir,
|
8
|
+
:config_file,
|
9
|
+
:kaiserfile,
|
10
|
+
:config,
|
11
|
+
:out,
|
12
|
+
:info_out
|
13
|
+
|
14
|
+
attr_writer :out,
|
15
|
+
:info_out
|
16
|
+
|
17
|
+
def load(work_dir)
|
18
|
+
@work_dir = work_dir
|
19
|
+
@config_dir = "#{ENV['HOME']}/.kaiser"
|
20
|
+
|
21
|
+
FileUtils.mkdir_p @config_dir
|
22
|
+
@config_file = "#{@config_dir}/.config.yml"
|
23
|
+
@kaiserfile = Kaiserfile.new("#{@work_dir}/Kaiserfile")
|
24
|
+
|
25
|
+
@config = {
|
26
|
+
envnames: {},
|
27
|
+
envs: {},
|
28
|
+
networkname: 'kaiser_net',
|
29
|
+
shared_names: {
|
30
|
+
redis: 'kaiser-redis',
|
31
|
+
nginx: 'kaiser-nginx',
|
32
|
+
chrome: 'kaiser-chrome',
|
33
|
+
dns: 'kaiser-dns',
|
34
|
+
certs: 'kaiser-certs'
|
35
|
+
},
|
36
|
+
largest_port: 9000,
|
37
|
+
always_verbose: false
|
38
|
+
}
|
39
|
+
|
40
|
+
load_config
|
41
|
+
|
42
|
+
alt_kaiserfile = "#{ENV['HOME']}/kaiserfiles/Kaiserfile.#{@config[:envnames][work_dir]}"
|
43
|
+
@kaiserfile = Kaiserfile.new(alt_kaiserfile) if File.exist?(alt_kaiserfile)
|
44
|
+
|
45
|
+
@config
|
46
|
+
end
|
47
|
+
|
48
|
+
def always_verbose?
|
49
|
+
@config[:always_verbose]
|
50
|
+
end
|
51
|
+
|
52
|
+
def load_config
|
53
|
+
loaded = YAML.load_file(@config_file) if File.exist?(@config_file)
|
54
|
+
|
55
|
+
config_shared_names = @config[:shared_names] if @config
|
56
|
+
loaded_shared_names = loaded[:shared_names] if loaded
|
57
|
+
|
58
|
+
@config = {
|
59
|
+
**(@config || {}),
|
60
|
+
**(loaded || {}),
|
61
|
+
shared_names: { **(config_shared_names || {}), **(loaded_shared_names || {}) }
|
62
|
+
}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
# Prints dots for every line printed
|
5
|
+
class Dotter
|
6
|
+
attr_accessor :dotted
|
7
|
+
|
8
|
+
def method_missing(name, *value)
|
9
|
+
$stderr.print '.'
|
10
|
+
@dotted = true
|
11
|
+
super unless @dotted
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to_missing?(name)
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/kaiser/error.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
# Base class for Kaiser-related errors.
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Raised when a command exits with non-zero exit status.
|
9
|
+
class CmdError < Error
|
10
|
+
def initialize(cmd, status)
|
11
|
+
super "ERROR\n#{cmd}\n- exited with code #{status}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
# This class is responsible for parsing the Kaiserfile
|
5
|
+
class Kaiserfile
|
6
|
+
attr_accessor :docker_file_contents,
|
7
|
+
:docker_build_args,
|
8
|
+
:database,
|
9
|
+
:port,
|
10
|
+
:database_reset_command,
|
11
|
+
:attach_mounts,
|
12
|
+
:server_type
|
13
|
+
|
14
|
+
def initialize(filename)
|
15
|
+
Optimist.die 'No Kaiserfile in current directory' unless File.exist? filename
|
16
|
+
|
17
|
+
@databases = {}
|
18
|
+
@attach_mounts = []
|
19
|
+
@params_array = []
|
20
|
+
@server_type = :unknown
|
21
|
+
|
22
|
+
instance_eval File.read(filename), filename
|
23
|
+
end
|
24
|
+
|
25
|
+
def plugin(name)
|
26
|
+
raise "Plugin #{name} is not loaded." unless Plugin.loaded?(name)
|
27
|
+
|
28
|
+
Plugin.all_plugins[name].new(self).on_init
|
29
|
+
end
|
30
|
+
|
31
|
+
def dockerfile(name, options = {})
|
32
|
+
@docker_file_contents = File.read(name)
|
33
|
+
@docker_build_args = options[:args] || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def attach_mount(from, to)
|
37
|
+
attach_mounts << [from, to]
|
38
|
+
end
|
39
|
+
|
40
|
+
def db(image,
|
41
|
+
data_dir:,
|
42
|
+
port:,
|
43
|
+
params: '',
|
44
|
+
commands: '',
|
45
|
+
waitscript: nil,
|
46
|
+
waitscript_params: '')
|
47
|
+
@database = {
|
48
|
+
image: image,
|
49
|
+
port: port,
|
50
|
+
data_dir: data_dir,
|
51
|
+
params: params,
|
52
|
+
commands: commands,
|
53
|
+
waitscript: waitscript,
|
54
|
+
waitscript_params: waitscript_params
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def expose(port)
|
59
|
+
@port = port
|
60
|
+
end
|
61
|
+
|
62
|
+
def app_params(value)
|
63
|
+
@params_array << value
|
64
|
+
end
|
65
|
+
|
66
|
+
def params
|
67
|
+
@params_array.join(' ')
|
68
|
+
end
|
69
|
+
|
70
|
+
def db_reset_command(value)
|
71
|
+
@database_reset_command = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def type(value)
|
75
|
+
raise 'Valid server types are: [:http]' if value != :http
|
76
|
+
|
77
|
+
@server_type = value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
# To implement a Kaiser plugin you must inherit from this class.
|
5
|
+
# For example,
|
6
|
+
#
|
7
|
+
# class MyPlugin < Plugin
|
8
|
+
# def on_init
|
9
|
+
# puts 'My plugin is loaded!'
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# Then in your Kasierfile
|
14
|
+
#
|
15
|
+
# plugin :my_plugin
|
16
|
+
#
|
17
|
+
# Plugins has access the Kaiserfile DSL. For example,
|
18
|
+
#
|
19
|
+
# class Ruby < Plugin
|
20
|
+
# def on_init
|
21
|
+
# attach_mount 'Gemfile', '/usr/app/Gemfile'
|
22
|
+
# attach_mount 'Gemfile.lock', '/usr/app/Gemfile.lock'
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
class Plugin
|
27
|
+
def initialize(kaiserfile)
|
28
|
+
@kaiserfile = kaiserfile
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.loaded?(name)
|
32
|
+
Plugin.all_plugins.key?(name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.inherited(plugin)
|
36
|
+
# underscore class name
|
37
|
+
name = plugin.to_s.split('::').last
|
38
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
39
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
40
|
+
.gsub(/([a-z])(\d)/, '\1_\2')
|
41
|
+
.tr('-', '_').downcase
|
42
|
+
|
43
|
+
Plugin.all_plugins[name.to_sym] = plugin
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.all_plugins
|
47
|
+
@all_plugins ||= {}
|
48
|
+
end
|
49
|
+
|
50
|
+
def on_init
|
51
|
+
raise 'Please implement #on_init'
|
52
|
+
end
|
53
|
+
|
54
|
+
def method_missing(method_sym, *arguments, &block) # rubocop:disable all
|
55
|
+
@kaiserfile.send(method_sym, *arguments, &block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kaiser
|
4
|
+
class GitSubmodule < Plugin
|
5
|
+
def on_init
|
6
|
+
`git submodule status`.lines.each do |line|
|
7
|
+
# The git-submodule man page says uninitialized submodules are prefixed with a -
|
8
|
+
# but I found this unreliable. While testing I pressed Control-C in the middle of
|
9
|
+
# the update command so some submodule would be initialized and others wouldn't.
|
10
|
+
# After that, the status command had removed the - for every submodule.
|
11
|
+
# Therefore we just check if there's files in the directory instead.
|
12
|
+
dir = line.strip.split(' ')[1]
|
13
|
+
if !Dir.exist?(dir) || Dir.empty?(dir) # rubocop:disable Style/Next
|
14
|
+
puts "Found uninitialized git submodule '#{dir}'"
|
15
|
+
system 'git submodule update --init --recursive'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|