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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +273 -0
  6. data/Rakefile +7 -0
  7. data/bin/redmine +8 -0
  8. data/lib/redmine-installer.rb +72 -0
  9. data/lib/redmine-installer/backup.rb +48 -0
  10. data/lib/redmine-installer/cli.rb +90 -0
  11. data/lib/redmine-installer/command.rb +142 -0
  12. data/lib/redmine-installer/config_param.rb +90 -0
  13. data/lib/redmine-installer/error.rb +5 -0
  14. data/lib/redmine-installer/exec.rb +158 -0
  15. data/lib/redmine-installer/ext/module.rb +7 -0
  16. data/lib/redmine-installer/ext/string.rb +15 -0
  17. data/lib/redmine-installer/git.rb +51 -0
  18. data/lib/redmine-installer/helper.rb +5 -0
  19. data/lib/redmine-installer/helpers/generate_config.rb +29 -0
  20. data/lib/redmine-installer/install.rb +56 -0
  21. data/lib/redmine-installer/locales/cs.yml +145 -0
  22. data/lib/redmine-installer/locales/en.yml +146 -0
  23. data/lib/redmine-installer/plugin.rb +9 -0
  24. data/lib/redmine-installer/plugins/base.rb +28 -0
  25. data/lib/redmine-installer/plugins/database.rb +168 -0
  26. data/lib/redmine-installer/plugins/email_sending.rb +82 -0
  27. data/lib/redmine-installer/plugins/redmine_plugin.rb +30 -0
  28. data/lib/redmine-installer/plugins/web_server.rb +26 -0
  29. data/lib/redmine-installer/profile.rb +74 -0
  30. data/lib/redmine-installer/step.rb +15 -0
  31. data/lib/redmine-installer/steps/backup.rb +120 -0
  32. data/lib/redmine-installer/steps/base.rb +60 -0
  33. data/lib/redmine-installer/steps/database_config.rb +15 -0
  34. data/lib/redmine-installer/steps/email_config.rb +11 -0
  35. data/lib/redmine-installer/steps/install.rb +21 -0
  36. data/lib/redmine-installer/steps/load_package.rb +180 -0
  37. data/lib/redmine-installer/steps/move_redmine.rb +22 -0
  38. data/lib/redmine-installer/steps/redmine_root.rb +29 -0
  39. data/lib/redmine-installer/steps/upgrade.rb +55 -0
  40. data/lib/redmine-installer/steps/validation.rb +38 -0
  41. data/lib/redmine-installer/steps/webserver_config.rb +22 -0
  42. data/lib/redmine-installer/task.rb +85 -0
  43. data/lib/redmine-installer/upgrade.rb +68 -0
  44. data/lib/redmine-installer/utils.rb +233 -0
  45. data/lib/redmine-installer/version.rb +5 -0
  46. data/redmine-installer.gemspec +25 -0
  47. data/spec/lib/install_spec.rb +46 -0
  48. data/spec/lib/upgrade_spec.rb +62 -0
  49. data/spec/load_redmine.rb +24 -0
  50. data/spec/spec_helper.rb +30 -0
  51. 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,5 @@
1
+ module Redmine::Installer
2
+ # Package does not exist
3
+ class Error < StandardError
4
+ end
5
+ 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