redmine-installer 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +25 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +273 -0
- data/Rakefile +7 -0
- data/bin/redmine +8 -0
- data/lib/redmine-installer.rb +72 -0
- data/lib/redmine-installer/backup.rb +48 -0
- data/lib/redmine-installer/cli.rb +90 -0
- data/lib/redmine-installer/command.rb +142 -0
- data/lib/redmine-installer/config_param.rb +90 -0
- data/lib/redmine-installer/error.rb +5 -0
- data/lib/redmine-installer/exec.rb +158 -0
- data/lib/redmine-installer/ext/module.rb +7 -0
- data/lib/redmine-installer/ext/string.rb +15 -0
- data/lib/redmine-installer/git.rb +51 -0
- data/lib/redmine-installer/helper.rb +5 -0
- data/lib/redmine-installer/helpers/generate_config.rb +29 -0
- data/lib/redmine-installer/install.rb +56 -0
- data/lib/redmine-installer/locales/cs.yml +145 -0
- data/lib/redmine-installer/locales/en.yml +146 -0
- data/lib/redmine-installer/plugin.rb +9 -0
- data/lib/redmine-installer/plugins/base.rb +28 -0
- data/lib/redmine-installer/plugins/database.rb +168 -0
- data/lib/redmine-installer/plugins/email_sending.rb +82 -0
- data/lib/redmine-installer/plugins/redmine_plugin.rb +30 -0
- data/lib/redmine-installer/plugins/web_server.rb +26 -0
- data/lib/redmine-installer/profile.rb +74 -0
- data/lib/redmine-installer/step.rb +15 -0
- data/lib/redmine-installer/steps/backup.rb +120 -0
- data/lib/redmine-installer/steps/base.rb +60 -0
- data/lib/redmine-installer/steps/database_config.rb +15 -0
- data/lib/redmine-installer/steps/email_config.rb +11 -0
- data/lib/redmine-installer/steps/install.rb +21 -0
- data/lib/redmine-installer/steps/load_package.rb +180 -0
- data/lib/redmine-installer/steps/move_redmine.rb +22 -0
- data/lib/redmine-installer/steps/redmine_root.rb +29 -0
- data/lib/redmine-installer/steps/upgrade.rb +55 -0
- data/lib/redmine-installer/steps/validation.rb +38 -0
- data/lib/redmine-installer/steps/webserver_config.rb +22 -0
- data/lib/redmine-installer/task.rb +85 -0
- data/lib/redmine-installer/upgrade.rb +68 -0
- data/lib/redmine-installer/utils.rb +233 -0
- data/lib/redmine-installer/version.rb +5 -0
- data/redmine-installer.gemspec +25 -0
- data/spec/lib/install_spec.rb +46 -0
- data/spec/lib/upgrade_spec.rb +62 -0
- data/spec/load_redmine.rb +24 -0
- data/spec/spec_helper.rb +30 -0
- metadata +130 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'gli'
|
2
|
+
|
3
|
+
module Redmine::Installer
|
4
|
+
class CLI
|
5
|
+
extend GLI::App
|
6
|
+
|
7
|
+
def self.spec
|
8
|
+
@spec ||= Gem::Specification::load('redmine-installer.gemspec')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.start(argv)
|
12
|
+
# Program settings
|
13
|
+
program_desc I18n.translate(:redmine_installer_summary)
|
14
|
+
version Redmine::Installer::VERSION
|
15
|
+
|
16
|
+
# Global options
|
17
|
+
|
18
|
+
# Verbose
|
19
|
+
desc I18n.translate(:cli_show_verbose_output)
|
20
|
+
default_value false
|
21
|
+
switch [:d, :v, :debug, :verbose], negatable: false
|
22
|
+
|
23
|
+
# Locale
|
24
|
+
default_value 'en'
|
25
|
+
flag [:l, :locale]
|
26
|
+
|
27
|
+
# Before all action
|
28
|
+
pre do |global_options, command, options, args|
|
29
|
+
$verbose = global_options[:debug]
|
30
|
+
I18n.locale = global_options[:locale]
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# Install command
|
35
|
+
desc I18n.translate(:cli_install_desc)
|
36
|
+
arg :package
|
37
|
+
command [:i, :install] do |c|
|
38
|
+
c.flag [:s, :source], default_value: 'file',
|
39
|
+
must_match: ['file', 'git'],
|
40
|
+
desc: I18n.translate(:cli_flag_source)
|
41
|
+
|
42
|
+
c.flag [:b, :branch], default_value: 'master',
|
43
|
+
desc: I18n.translate(:cli_flag_branch)
|
44
|
+
|
45
|
+
c.flag [:e, :env, :environment], default_value: ['production'],
|
46
|
+
desc: I18n.translate(:cli_flag_environment),
|
47
|
+
type: Array
|
48
|
+
|
49
|
+
c.action do |global_options, options, args|
|
50
|
+
run_action('install', args.first, options)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Upgrade command
|
55
|
+
desc I18n.translate(:cli_upgrade_desc)
|
56
|
+
arg :package
|
57
|
+
command [:u, :upgrade] do |c|
|
58
|
+
c.flag [:p, :profile]
|
59
|
+
c.flag [:s, :source], default_value: 'file',
|
60
|
+
must_match: ['file', 'git'],
|
61
|
+
desc: I18n.translate(:cli_flag_source)
|
62
|
+
|
63
|
+
c.flag [:e, :env, :environment], default_value: ['production'],
|
64
|
+
desc: I18n.translate(:cli_flag_environment),
|
65
|
+
type: Array
|
66
|
+
|
67
|
+
c.action do |global_options, options, args|
|
68
|
+
run_action('upgrade', args.first, options)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Backup command
|
73
|
+
desc I18n.translate(:cli_backup_desc)
|
74
|
+
arg :redmine_root
|
75
|
+
command [:b, :backup] do |c|
|
76
|
+
c.flag [:p, :profile]
|
77
|
+
c.action do |global_options, options, args|
|
78
|
+
run_action('backup', args.first, options)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
run(argv)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.run_action(action, *args)
|
86
|
+
Redmine::Installer.const_get(action.capitalize).new(*args).run
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module Redmine::Installer
|
4
|
+
class Command
|
5
|
+
include Singleton
|
6
|
+
include Redmine::Installer::Utils
|
7
|
+
|
8
|
+
RAKE = 'bundle exec rake'
|
9
|
+
|
10
|
+
def bundle_install(env)
|
11
|
+
run('bundle install', get_bundle_env(env), :'command.bundle_install')
|
12
|
+
end
|
13
|
+
|
14
|
+
def rake_db_create(env)
|
15
|
+
run(RAKE, 'db:create', get_rails_env(env), :'command.rake_db_create')
|
16
|
+
end
|
17
|
+
|
18
|
+
def rake_db_migrate(env)
|
19
|
+
run(RAKE, 'db:migrate', get_rails_env(env), :'command.rake_db_migrate')
|
20
|
+
end
|
21
|
+
|
22
|
+
def rake_redmine_plugin_migrate(env)
|
23
|
+
run(RAKE, 'redmine:plugins:migrate', get_rails_env(env), :'command.rake_redmine_plugin_migrate')
|
24
|
+
end
|
25
|
+
|
26
|
+
def rake_generate_secret_token(env)
|
27
|
+
run(RAKE, 'generate_secret_token', get_rails_env(env), :'command.rake_generate_secret_token')
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def run(*args)
|
33
|
+
_args = args.dup
|
34
|
+
|
35
|
+
# Last element is title
|
36
|
+
title = args.pop
|
37
|
+
title = translate(title) if title.is_a?(Symbol)
|
38
|
+
title = "--> <yellow>#{title}</yellow>"
|
39
|
+
colorize(title)
|
40
|
+
|
41
|
+
command = args.join(' ')
|
42
|
+
|
43
|
+
puts '-->'
|
44
|
+
puts title
|
45
|
+
puts '-->'
|
46
|
+
success = Kernel.system(command)
|
47
|
+
|
48
|
+
unless success
|
49
|
+
if confirm(:do_you_want_repeat_command, false)
|
50
|
+
return run(*_args)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
return success
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_rails_env(env)
|
58
|
+
if env.include?('production'); 'RAILS_ENV=production'
|
59
|
+
elsif env.include?('development'); 'RAILS_ENV=development'
|
60
|
+
elsif env.include?('test'); 'RAILS_ENV=test'
|
61
|
+
else
|
62
|
+
''
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_bundle_env(env)
|
67
|
+
if env.include?('production')
|
68
|
+
'--without development test'
|
69
|
+
else
|
70
|
+
''
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Class for easier create complex command
|
79
|
+
#
|
80
|
+
# == Examples:
|
81
|
+
#
|
82
|
+
# Instead of this:
|
83
|
+
# exec('rake redmine:plugins:migrate RAILS_ENV=production')
|
84
|
+
#
|
85
|
+
# you can write:
|
86
|
+
# rake.plugin_migrate.production.run
|
87
|
+
#
|
88
|
+
# module Redmine::Installer
|
89
|
+
# module Command
|
90
|
+
# class Base
|
91
|
+
# # Register main command only for child class
|
92
|
+
# def self.command(cmd)
|
93
|
+
# self.class_variable_set('@@command', cmd)
|
94
|
+
# end
|
95
|
+
|
96
|
+
# # Register new argument and method name
|
97
|
+
# def self.add(name, cmd)
|
98
|
+
# self.class_eval <<-EVAL
|
99
|
+
# def #{name}
|
100
|
+
# arguments << '#{cmd}'
|
101
|
+
# self
|
102
|
+
# end
|
103
|
+
# EVAL
|
104
|
+
# end
|
105
|
+
|
106
|
+
# def initialize(command=nil)
|
107
|
+
# @command = self.class.class_variable_get('@@command')
|
108
|
+
# end
|
109
|
+
|
110
|
+
# def arguments
|
111
|
+
# @arguments ||= []
|
112
|
+
# end
|
113
|
+
|
114
|
+
# def command
|
115
|
+
# %{#{@command} #{arguments.join(' ')}}
|
116
|
+
# end
|
117
|
+
|
118
|
+
# def run(title=nil, with_timer=false)
|
119
|
+
# Redmine::Installer::Exec.new(command, title, with_timer).run
|
120
|
+
# end
|
121
|
+
|
122
|
+
# def repeatable_run(title=nil, with_timer=false)
|
123
|
+
# Redmine::Installer::Exec.new(command, title, with_timer).repeatable_run
|
124
|
+
# end
|
125
|
+
# end
|
126
|
+
|
127
|
+
# class Rake < Base
|
128
|
+
# command 'bundle exec rake'
|
129
|
+
# add 'db_create', 'db:create'
|
130
|
+
# add 'db_migrate', 'db:migrate'
|
131
|
+
# add 'generate_secret_token', 'generate_secret_token'
|
132
|
+
# add 'redmine_plugin_migrate', 'redmine:plugins:migrate'
|
133
|
+
# add 'production', 'RAILS_ENV=production'
|
134
|
+
# end
|
135
|
+
|
136
|
+
# class Bundle < Base
|
137
|
+
# command 'bundle'
|
138
|
+
# add 'install', 'install'
|
139
|
+
# add 'production', '--without development test'
|
140
|
+
# end
|
141
|
+
# end
|
142
|
+
# end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
##
|
2
|
+
# Class for easyier handle configuration parameters
|
3
|
+
#
|
4
|
+
# == Examples:
|
5
|
+
#
|
6
|
+
# params = Redmine::Installer::ConfigParams.new
|
7
|
+
# params.add('database')
|
8
|
+
# params.add('host').note('this is a host').default('localhost')
|
9
|
+
#
|
10
|
+
module Redmine::Installer
|
11
|
+
class ConfigParams
|
12
|
+
def initialize
|
13
|
+
@params = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
@params.detect{|p| p.name == key}
|
18
|
+
end
|
19
|
+
|
20
|
+
def for_asking
|
21
|
+
@for_asking ||= @params.select{|p| p.ask}
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(name)
|
25
|
+
param = ConfigParam.new(name)
|
26
|
+
@params << param
|
27
|
+
param
|
28
|
+
end
|
29
|
+
|
30
|
+
def each(&block)
|
31
|
+
@params.each(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def map(&block)
|
35
|
+
@params.map(&block)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class ConfigParam
|
40
|
+
|
41
|
+
@@attributes = []
|
42
|
+
|
43
|
+
def self.attribute(name, default=nil)
|
44
|
+
eval <<-EVAL
|
45
|
+
def #{name}(value=nil)
|
46
|
+
return @#{name} if value.nil?
|
47
|
+
self.#{name} = value
|
48
|
+
end
|
49
|
+
|
50
|
+
def #{name}=(value)
|
51
|
+
@#{name} = value
|
52
|
+
end
|
53
|
+
EVAL
|
54
|
+
|
55
|
+
@@attributes << [name, default]
|
56
|
+
end
|
57
|
+
|
58
|
+
attribute :name
|
59
|
+
attribute :note
|
60
|
+
attribute :default
|
61
|
+
attribute :value
|
62
|
+
attribute :ask, true
|
63
|
+
|
64
|
+
def initialize(name)
|
65
|
+
# Default
|
66
|
+
@@attributes.each{|(k,v)| set(k,v)}
|
67
|
+
|
68
|
+
set(:name, name)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return string for print
|
72
|
+
def title
|
73
|
+
out = name.capitalize
|
74
|
+
out << " (#{note})" if note
|
75
|
+
out
|
76
|
+
end
|
77
|
+
|
78
|
+
def set(key, value)
|
79
|
+
self.send("#{key}=", value)
|
80
|
+
end
|
81
|
+
|
82
|
+
def default(value=nil)
|
83
|
+
return @default if value.nil?
|
84
|
+
|
85
|
+
self.default = value
|
86
|
+
self.value = value if self.value.nil?
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
##
|
4
|
+
# Executions commands with timer and error handling
|
5
|
+
#
|
6
|
+
module Redmine::Installer
|
7
|
+
class Exec
|
8
|
+
|
9
|
+
include Redmine::Installer::Utils
|
10
|
+
|
11
|
+
REFRESH_TIMER = 1 # in s
|
12
|
+
|
13
|
+
attr_reader :stdout, :stderr
|
14
|
+
|
15
|
+
def initialize(command, title=nil, timer=true)
|
16
|
+
@command = command
|
17
|
+
|
18
|
+
with_title(title)
|
19
|
+
with_timer(timer)
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_title(title)
|
23
|
+
if title.is_a?(Symbol)
|
24
|
+
title = I18n.translate(title)
|
25
|
+
end
|
26
|
+
|
27
|
+
@title = title
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
def with_timer(yes_no)
|
32
|
+
if $stdout.tty?
|
33
|
+
@with_timer = yes_no
|
34
|
+
else
|
35
|
+
@with_timer = false
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def run(repeatable=false)
|
41
|
+
show_title
|
42
|
+
|
43
|
+
Open3.popen3(@command) do |stdin, stdout, stderr, wait_thr|
|
44
|
+
# log = StringIO.new
|
45
|
+
# redirect_stream(stdout, log)
|
46
|
+
# redirect_stream(stderr, log)
|
47
|
+
|
48
|
+
# For example: rake db:create can ask for root login
|
49
|
+
# if current setting does not work
|
50
|
+
# stdin.closes
|
51
|
+
|
52
|
+
exit_status = wait_thr.value
|
53
|
+
@stdout = stdout.read
|
54
|
+
@stderr = stderr.read
|
55
|
+
|
56
|
+
stop_timer
|
57
|
+
if exit_status.success?
|
58
|
+
print_result(true)
|
59
|
+
@return_value = true
|
60
|
+
else
|
61
|
+
print_result(false)
|
62
|
+
@return_value = false
|
63
|
+
# raise Redmine::Installer::Error, stderr.read
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
unless success
|
68
|
+
# print_error
|
69
|
+
if repeatable && repeat?
|
70
|
+
return run(repeatable)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
return success
|
75
|
+
ensure
|
76
|
+
# stop_timer
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def print_error
|
82
|
+
message = '<red>'
|
83
|
+
message << '--------------------------------------------------------------'
|
84
|
+
message << "\n"
|
85
|
+
message << stderr
|
86
|
+
message << '--------------------------------------------------------------'
|
87
|
+
message << '</red>'
|
88
|
+
colorize(message)
|
89
|
+
|
90
|
+
$stderr.puts(message)
|
91
|
+
$stderr.flush
|
92
|
+
end
|
93
|
+
|
94
|
+
def repeat?
|
95
|
+
confirm(:do_you_want_repeat_command, false)
|
96
|
+
end
|
97
|
+
|
98
|
+
def show_title
|
99
|
+
if @with_timer
|
100
|
+
@timer = start_timer
|
101
|
+
else
|
102
|
+
$stdout.print(@title)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def start_timer
|
107
|
+
Thread.new do
|
108
|
+
counter = 0
|
109
|
+
|
110
|
+
loop {
|
111
|
+
hours, seconds = counter.divmod(3600)
|
112
|
+
minutes, seconds = seconds.divmod(60)
|
113
|
+
|
114
|
+
printf "[%02d:%02d:%02d] %s\r", hours, minutes, seconds, @title
|
115
|
+
counter += REFRESH_TIMER
|
116
|
+
sleep(REFRESH_TIMER)
|
117
|
+
}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def stop_timer
|
122
|
+
if @timer
|
123
|
+
@timer.kill
|
124
|
+
|
125
|
+
# Clean line
|
126
|
+
print ' ' * 100
|
127
|
+
print "\r"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def print_result(ok=true)
|
132
|
+
if ok
|
133
|
+
out = $stdout
|
134
|
+
message = '... OK'
|
135
|
+
else
|
136
|
+
out = $stderr
|
137
|
+
message = '... FAIL'
|
138
|
+
end
|
139
|
+
|
140
|
+
if @with_timer
|
141
|
+
out.puts("#{@title} #{message}")
|
142
|
+
else
|
143
|
+
out.print(message)
|
144
|
+
end
|
145
|
+
|
146
|
+
out.flush
|
147
|
+
end
|
148
|
+
|
149
|
+
def redirect_stream(stream, out)
|
150
|
+
Thread.new do
|
151
|
+
while (line = stream.gets)
|
152
|
+
out.puts(line)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|