redmine-installer 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,60 @@
1
+ module Redmine::Installer::Step
2
+ class Base
3
+
4
+ include Redmine::Installer::Utils
5
+
6
+ attr_accessor :index
7
+ attr_accessor :base
8
+ attr_accessor :ran
9
+
10
+ def initialize(index, base)
11
+ self.index = index
12
+ self.base = base
13
+ self.ran = false
14
+ end
15
+
16
+ def print_title
17
+ title = '<bright><on_black><white>'
18
+ title << "#{index}. "
19
+ title << translate("step.#{self.class.class_name.underscore}.title"
20
+ )
21
+ title <<'</white></on_black></bright>'
22
+
23
+ say(title, 1)
24
+ end
25
+
26
+ def print_header
27
+ end
28
+
29
+ def print_footer
30
+ end
31
+
32
+ def final_step
33
+ end
34
+
35
+ def up
36
+ end
37
+
38
+ def down
39
+ end
40
+
41
+ def save(*)
42
+ end
43
+
44
+ def load(*)
45
+ end
46
+
47
+ def redmine_plugins
48
+ @redmine_plugins ||= _redmine_plugins
49
+ end
50
+
51
+ private
52
+
53
+ def _redmine_plugins
54
+ Dir.glob(File.join(base.redmine_root, 'plugins', '*')).select do |entry|
55
+ File.directory?(entry)
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,15 @@
1
+ module Redmine::Installer::Step
2
+ class DatabaseConfig < Base
3
+
4
+ include Redmine::Installer::Helper::GenerateConfig
5
+
6
+ def up
7
+ if create_for(plugin::Database)
8
+ # continue
9
+ else
10
+ base.settings[:skip_migration] = true
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Redmine::Installer::Step
2
+ class EmailConfig < Base
3
+
4
+ include Redmine::Installer::Helper::GenerateConfig
5
+
6
+ def up
7
+ create_for(plugin::EmailSending)
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Redmine::Installer::Step
2
+ class Install < Base
3
+
4
+ def up
5
+ Dir.chdir(base.tmp_redmine_root) do
6
+ command.bundle_install(base.env)
7
+
8
+ return if base.settings[:skip_migration]
9
+
10
+ command.rake_db_create(base.env)
11
+ command.rake_db_migrate(base.env)
12
+ command.rake_redmine_plugin_migrate(base.env) if some_plugins?
13
+ command.rake_generate_secret_token(base.env)
14
+
15
+ # Other plugins can have post-install procedure
16
+ plugin::RedminePlugin.all.each(&:install)
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,180 @@
1
+ require 'rubygems/package'
2
+ require 'ruby-progressbar'
3
+ require 'fileutils'
4
+ require 'zip'
5
+ require 'tmpdir'
6
+ require 'zlib'
7
+
8
+ module Redmine::Installer::Step
9
+ class LoadPackage < Base
10
+
11
+ SUPPORTED_ARCHIVE_FORMATS = ['.zip', '.gz', '.tgz']
12
+ TAR_LONGLINK = '././@LongLink'
13
+ PROGRESSBAR_FORMAT = '%a [%b>%i] %p%% %t'
14
+
15
+ def up
16
+ case base.options[:source]
17
+ when 'file'
18
+ load_file
19
+ when 'git'
20
+ load_git
21
+ else
22
+ error :error_unsupported_source, source: base.options[:source]
23
+ end
24
+ end
25
+
26
+ def final_step
27
+ # Delete tmp_redmine_root
28
+ FileUtils.remove_entry_secure(@tmpdir) if @tmpdir
29
+ end
30
+
31
+ private
32
+
33
+ # =======================================================================
34
+ # General
35
+
36
+ def create_tmp_dir
37
+ @tmpdir = Dir.mktmpdir
38
+ rescue
39
+ FileUtils.remove_entry_secure(@tmpdir)
40
+ end
41
+
42
+ # Move files from temp dir to target. First check
43
+ # if folder contains redmine or contains
44
+ # folder which contains redmine :-)
45
+ #
46
+ # Package can have format:
47
+ # |-- redmine-2
48
+ # |-- app
49
+ # `-- config
50
+ # ...
51
+ #
52
+ def get_tmp_redmine_root
53
+ base.tmp_redmine_root = @tmpdir
54
+
55
+ loop {
56
+ ls = Dir.glob(File.join(base.tmp_redmine_root, '*'))
57
+
58
+ if ls.size == 1
59
+ base.tmp_redmine_root = ls.first
60
+ else
61
+ break
62
+ end
63
+ }
64
+ end
65
+
66
+
67
+ # =======================================================================
68
+ # File
69
+
70
+ def load_file
71
+ unless File.exist?(base.package)
72
+ error :file_not_exist, file: base.package
73
+ end
74
+
75
+ @type = File.extname(base.package)
76
+ unless SUPPORTED_ARCHIVE_FORMATS.include?(@type)
77
+ error :file_must_have_format, file: base.package, formats: SUPPORTED_ARCHIVE_FORMATS.join(', ')
78
+ end
79
+
80
+ # Make temp directory and extract archive + move it to the redmine_folder
81
+ extract_to_tmp
82
+
83
+ # Locate redmine_root in tmpdir
84
+ get_tmp_redmine_root
85
+ end
86
+
87
+ def extract_to_tmp
88
+ create_tmp_dir
89
+
90
+ case @type
91
+ when '.zip'
92
+ extract_zip
93
+ when '.gz', '.tgz'
94
+ extract_tar_gz
95
+ end
96
+ end
97
+
98
+ def extract_zip
99
+ Zip::File.open(base.package) do |zip_file|
100
+ # Progressbar
101
+ progressbar = ProgressBar.create(format: PROGRESSBAR_FORMAT, total: zip_file.size)
102
+
103
+ zip_file.each do |entry|
104
+ dest_file = File.join(@tmpdir, entry.name)
105
+ FileUtils.mkdir_p(File.dirname(dest_file))
106
+
107
+ entry.extract(dest_file)
108
+ progressbar.increment
109
+ end
110
+ end
111
+ end
112
+
113
+ # Extract .tar.gz archive
114
+ # based on http://dracoater.blogspot.cz/2013/10/extracting-files-from-targz-with-ruby.html
115
+ #
116
+ # Originally tar did not support paths longer than 100 chars. GNU tar is better and they
117
+ # implemented support for longer paths, but it was made through a hack called ././@LongLink.
118
+ # Shortly speaking, if you stumble upon an entry in tar archive which path equals to above
119
+ # mentioned ././@LongLink, that means that the following entry path is longer than 100 chars and
120
+ # is truncated. The full path of the following entry is actually the value of the current entry.
121
+ #
122
+ def extract_tar_gz
123
+ Gem::Package::TarReader.new(Zlib::GzipReader.open(base.package)) do |tar|
124
+
125
+ # Progressbar
126
+ progressbar = ProgressBar.create(format: PROGRESSBAR_FORMAT, total: tar.count)
127
+
128
+ # tar.count move position pointer to end
129
+ tar.rewind
130
+
131
+ dest_file = nil
132
+ tar.each do |entry|
133
+ if entry.full_name == TAR_LONGLINK
134
+ dest_file = File.join(@tmpdir, entry.read.strip)
135
+ next
136
+ end
137
+ dest_file ||= File.join(@tmpdir, entry.full_name)
138
+ if entry.directory?
139
+ FileUtils.rm_rf(dest_file) unless File.directory?(dest_file)
140
+ FileUtils.mkdir_p(dest_file, mode: entry.header.mode, verbose: false)
141
+ elsif entry.file?
142
+ FileUtils.rm_rf(dest_file) unless File.file?(dest_file)
143
+ File.open(dest_file, 'wb') do |f|
144
+ f.write(entry.read)
145
+ end
146
+ FileUtils.chmod(entry.header.mode, dest_file, verbose: false)
147
+ elsif entry.header.typeflag == '2' # symlink
148
+ File.symlink(entry.header.linkname, dest_file)
149
+ end
150
+
151
+ dest_file = nil
152
+ progressbar.increment
153
+ end
154
+ end
155
+ end
156
+
157
+
158
+ # =======================================================================
159
+ # Git
160
+
161
+ def load_git
162
+ create_tmp_dir
163
+
164
+ # Package is remote url to git repository
165
+ remote = base.package
166
+
167
+ if remote
168
+ # Clone repository
169
+ Git.clone(remote, @tmpdir, base.options['branch'])
170
+ else
171
+ # Copy current repository to tmp and run pull
172
+ Git.copy_and_fetch(base.redmine_root, @tmpdir)
173
+ end
174
+
175
+ # Locate redmine_root in tmpdir
176
+ get_tmp_redmine_root
177
+ end
178
+
179
+ end
180
+ end
@@ -0,0 +1,22 @@
1
+ require 'fileutils'
2
+
3
+ module Redmine::Installer::Step
4
+ class MoveRedmine < Base
5
+
6
+ def up
7
+ # Move all files from tmp_redmine_root to redmine_root
8
+ Dir.chdir(base.tmp_redmine_root) do
9
+ Dir.glob('{*,.*}') do |entry|
10
+ next if entry.end_with?('.') || entry.end_with?('..')
11
+
12
+ FileUtils.mv(entry, base.redmine_root)
13
+ end
14
+ end
15
+ end
16
+
17
+ def print_footer
18
+ say '<green>... OK</green>', 1
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ module Redmine::Installer::Step
2
+ class RedmineRoot < Base
3
+
4
+ def up
5
+ # Get redmine root
6
+ base.redmine_root ||= ask(:path_for_redmine_root, default: '.')
7
+
8
+ # Make absolute path
9
+ base.redmine_root = File.expand_path(base.redmine_root)
10
+
11
+ unless Dir.exist?(base.redmine_root)
12
+ try_create_dir(base.redmine_root)
13
+ end
14
+
15
+ unless File.writable?(base.redmine_root)
16
+ error t(:dir_is_not_writeable, dir: base.redmine_root)
17
+ end
18
+ end
19
+
20
+ def save(configuration)
21
+ configuration['redmine_root'] = base.redmine_root
22
+ end
23
+
24
+ def load(configuration)
25
+ base.redmine_root = configuration['redmine_root']
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,55 @@
1
+ require 'fileutils'
2
+
3
+ module Redmine::Installer::Step
4
+ class Upgrade < Base
5
+
6
+ def up
7
+ # Copy database.yml
8
+ copy_config_file(plugin::Database::DATABASE_YML_PATH)
9
+
10
+ # Copy configuration.yml
11
+ copy_config_file(plugin::EmailSending::CONFIGURATION_YML_PATH)
12
+
13
+ # Copy files
14
+ FileUtils.cp_r(File.join(base.redmine_root, 'files'), base.tmp_redmine_root)
15
+
16
+ # Copy plugins
17
+ tmp_plugin_dir = File.join(base.tmp_redmine_root, 'plugins')
18
+ redmine_plugins.each do |plugin|
19
+ # Copy only plugins which are not part of package
20
+ # - this is a upgrade so package should contains newer version
21
+ unless Dir.exist?(File.join(tmp_plugin_dir, File.basename(plugin)))
22
+ FileUtils.cp_r(plugin, tmp_plugin_dir)
23
+ end
24
+ end
25
+
26
+ Dir.chdir(base.tmp_redmine_root) do
27
+ command.bundle_install(base.env)
28
+ command.rake_db_migrate(base.env)
29
+ command.rake_redmine_plugin_migrate(base.env) if some_plugins?
30
+ command.rake_generate_secret_token(base.env)
31
+
32
+ # Other plugins can have post-install procedure
33
+ plugin::RedminePlugin.all.each(&:upgrade)
34
+ end
35
+
36
+ # Delete content of redmine_root
37
+ Dir.glob(File.join(base.redmine_root, '{*,.*}')) do |entry|
38
+ next if entry.end_with?('.') || entry.end_with?('..')
39
+
40
+ FileUtils.remove_entry_secure(entry)
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def copy_config_file(relative_path)
47
+ file = File.join(base.redmine_root, relative_path)
48
+
49
+ if File.exist?(file)
50
+ FileUtils.cp(file, File.join(base.tmp_redmine_root, 'config'))
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,38 @@
1
+ ##
2
+ # Validate redmine folder
3
+ #
4
+ module Redmine::Installer::Step
5
+ class Validation < Base
6
+
7
+ REDMINE_SHOULD_CONTAINS = [
8
+ 'app', 'lib', 'config', 'public', 'db',
9
+ 'Gemfile', 'Rakefile', 'config.ru',
10
+ File.join('lib', 'redmine'),
11
+ File.join('lib', 'redmine', 'core_ext'),
12
+ File.join('lib', 'redmine', 'helpers'),
13
+ File.join('lib', 'redmine', 'views'),
14
+ File.join('lib', 'redmine.rb'),
15
+ ].sort
16
+
17
+ def up
18
+ Dir.chdir(base.redmine_root) do
19
+ @records = Dir.glob(File.join('**', '*')).sort
20
+ end
21
+
22
+ # Is this redmine
23
+ unless (@records & REDMINE_SHOULD_CONTAINS) == REDMINE_SHOULD_CONTAINS
24
+ error :error_redmine_not_contains_all, records: REDMINE_SHOULD_CONTAINS.join(', ')
25
+ end
26
+
27
+ # Plugins are in righ dir
28
+ if @records.select{|x| x.start_with?('vendor/plugins')}.size > 1
29
+ error :error_plugins_should_be_on_plugins
30
+ end
31
+ end
32
+
33
+ def print_footer
34
+ say '<green>... OK</green>', 1
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ module Redmine::Installer::Step
2
+ class WebserverConfig < Base
3
+
4
+ def up
5
+ choices = {}
6
+ plugin::WebServer.all.each do |m|
7
+ choices[m] = m.title
8
+ end
9
+ choices[nil] = t(:skip)
10
+
11
+ answer = choose(:"what_web_server_do_you_want", choices, default: nil)
12
+
13
+ # Skip
14
+ return if answer.nil?
15
+
16
+ say("(#{answer.title })", 5)
17
+
18
+ say(answer.generate_config(base.redmine_root))
19
+ end
20
+
21
+ end
22
+ end