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,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