siba 0.4.3

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 (159) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +4 -0
  3. data/Guardfile +18 -0
  4. data/LICENSE +22 -0
  5. data/README.md +47 -0
  6. data/Rakefile +27 -0
  7. data/bin/siba +5 -0
  8. data/lib/siba.rb +27 -0
  9. data/lib/siba/backup.rb +31 -0
  10. data/lib/siba/console.rb +196 -0
  11. data/lib/siba/errors.rb +8 -0
  12. data/lib/siba/generator.rb +115 -0
  13. data/lib/siba/globals.rb +19 -0
  14. data/lib/siba/helpers/encoding_helper.rb +38 -0
  15. data/lib/siba/helpers/file_helper.rb +89 -0
  16. data/lib/siba/helpers/gem_helper.rb +22 -0
  17. data/lib/siba/helpers/password_strength.rb +94 -0
  18. data/lib/siba/helpers/security_helper.rb +30 -0
  19. data/lib/siba/helpers/string_helper.rb +32 -0
  20. data/lib/siba/helpers/test/extend_test.rb +114 -0
  21. data/lib/siba/helpers/test/file_mock.rb +38 -0
  22. data/lib/siba/helpers/test/helper.rb +55 -0
  23. data/lib/siba/helpers/test/kernel_mock.rb +44 -0
  24. data/lib/siba/helpers/test/removable_constants.rb +18 -0
  25. data/lib/siba/helpers/test/require.rb +12 -0
  26. data/lib/siba/logger_plug.rb +36 -0
  27. data/lib/siba/options_backup.rb +37 -0
  28. data/lib/siba/options_loader.rb +38 -0
  29. data/lib/siba/plugins/archive/tar/archive.rb +117 -0
  30. data/lib/siba/plugins/archive/tar/init.rb +38 -0
  31. data/lib/siba/plugins/archive/tar/options.yml +1 -0
  32. data/lib/siba/plugins/destination/dir/dest_dir.rb +77 -0
  33. data/lib/siba/plugins/destination/dir/init.rb +31 -0
  34. data/lib/siba/plugins/destination/dir/options.yml +2 -0
  35. data/lib/siba/plugins/encryption/gpg/encryption.rb +140 -0
  36. data/lib/siba/plugins/encryption/gpg/init.rb +45 -0
  37. data/lib/siba/plugins/encryption/gpg/options.yml +2 -0
  38. data/lib/siba/plugins/installed_plugins.rb +77 -0
  39. data/lib/siba/plugins/plugin_loader.rb +100 -0
  40. data/lib/siba/plugins/plugins.rb +57 -0
  41. data/lib/siba/plugins/plugins.yml +9 -0
  42. data/lib/siba/plugins/source/files/files.rb +166 -0
  43. data/lib/siba/plugins/source/files/init.rb +33 -0
  44. data/lib/siba/plugins/source/files/options.yml +11 -0
  45. data/lib/siba/restore.rb +113 -0
  46. data/lib/siba/scaffold.rb +166 -0
  47. data/lib/siba/siba_check.rb +75 -0
  48. data/lib/siba/siba_file.rb +89 -0
  49. data/lib/siba/siba_kernel.rb +37 -0
  50. data/lib/siba/siba_logger.rb +172 -0
  51. data/lib/siba/tasks/siba_task.rb +42 -0
  52. data/lib/siba/tasks/siba_tasks.rb +120 -0
  53. data/lib/siba/test_files.rb +76 -0
  54. data/lib/siba/test_files/a_file +1 -0
  55. data/lib/siba/test_files/files_and_dirs/.hidden +1 -0
  56. data/lib/siba/test_files/files_and_dirs/.hidden_dir/file10 +1 -0
  57. data/lib/siba/test_files/files_and_dirs/File With Spaces +1 -0
  58. data/lib/siba/test_files/files_and_dirs/dir1/file10 +1 -0
  59. data/lib/siba/test_files/files_and_dirs/dir1/sub-dir/file111.txt +1 -0
  60. data/lib/siba/test_files/files_and_dirs/file1 +1 -0
  61. data/lib/siba/test_files/files_and_dirs/file2.txt +1 -0
  62. data/lib/siba/tmp_dir.rb +94 -0
  63. data/lib/siba/version.rb +5 -0
  64. data/scaffolds/archive.rb +26 -0
  65. data/scaffolds/destination.rb +20 -0
  66. data/scaffolds/encryption.rb +26 -0
  67. data/scaffolds/project/.gitignore +5 -0
  68. data/scaffolds/project/Gemfile +4 -0
  69. data/scaffolds/project/Guardfile +9 -0
  70. data/scaffolds/project/LICENSE +22 -0
  71. data/scaffolds/project/README.md +33 -0
  72. data/scaffolds/project/Rakefile +28 -0
  73. data/scaffolds/project/lib/siba-c6y-demo.rb +11 -0
  74. data/scaffolds/project/lib/siba-c6y-demo/options.yml +2 -0
  75. data/scaffolds/project/lib/siba-c6y-demo/version.rb +9 -0
  76. data/scaffolds/project/siba-c6y-demo.gemspec +26 -0
  77. data/scaffolds/project/test/helper/require_integration.rb +5 -0
  78. data/scaffolds/project/test/helper/require_unit.rb +4 -0
  79. data/scaffolds/project/test/integration/i9n_init.rb +35 -0
  80. data/scaffolds/project/test/unit/test_init.rb +43 -0
  81. data/scaffolds/project/test/unit/yml/valid.yml +8 -0
  82. data/scaffolds/shared/examples.rb +47 -0
  83. data/scaffolds/shared/init_example.rb +13 -0
  84. data/scaffolds/source.rb +25 -0
  85. data/siba.gemspec +30 -0
  86. data/test/helper/require_integration.rb +4 -0
  87. data/test/helper/require_unit.rb +4 -0
  88. data/test/integration/helpers/i9n_file_helper.rb +50 -0
  89. data/test/integration/i9n_backup.rb +53 -0
  90. data/test/integration/i9n_console.rb +16 -0
  91. data/test/integration/i9n_generator.rb +29 -0
  92. data/test/integration/i9n_options_backup.rb +22 -0
  93. data/test/integration/i9n_scaffold.rb +27 -0
  94. data/test/integration/i9n_siba_file.rb +30 -0
  95. data/test/integration/i9n_test_unicode_files.rb +40 -0
  96. data/test/integration/i9n_tmp_dir.rb +44 -0
  97. data/test/integration/plugins/archive/tar/i9n_archive.rb +18 -0
  98. data/test/integration/plugins/destination/dir/i9n_dest_dir.rb +52 -0
  99. data/test/integration/plugins/encryption/gpg/i9n_encryption.rb +87 -0
  100. data/test/integration/plugins/i9n_installed_plugins.rb +13 -0
  101. data/test/integration/plugins/source/files/i9n_files.rb +146 -0
  102. data/test/integration/tasks/i9n_siba_tasks.rb +30 -0
  103. data/test/integration/yml/valid.yml +16 -0
  104. data/test/unit/helpers/test_encoding_helper.rb +17 -0
  105. data/test/unit/helpers/test_gem_helper.rb +17 -0
  106. data/test/unit/helpers/test_security_helper.rb +21 -0
  107. data/test/unit/helpers/test_string_helper.rb +35 -0
  108. data/test/unit/plugins/archive/tar/test_archive.rb +41 -0
  109. data/test/unit/plugins/archive/tar/test_init.rb +36 -0
  110. data/test/unit/plugins/archive/tar/yml/archive/check_installed.yml +2 -0
  111. data/test/unit/plugins/archive/tar/yml/init/default_compression.yml +1 -0
  112. data/test/unit/plugins/archive/tar/yml/init/invalid_compression.yml +2 -0
  113. data/test/unit/plugins/archive/tar/yml/init/valid.yml +2 -0
  114. data/test/unit/plugins/destination/dir/test_dest_dir.rb +41 -0
  115. data/test/unit/plugins/destination/dir/test_init.rb +36 -0
  116. data/test/unit/plugins/destination/dir/yml/init/valid.yml +2 -0
  117. data/test/unit/plugins/encryption/gpg/test_encryption.rb +70 -0
  118. data/test/unit/plugins/encryption/gpg/test_init.rb +47 -0
  119. data/test/unit/plugins/source/files/test_files.rb +44 -0
  120. data/test/unit/plugins/source/files/test_init.rb +48 -0
  121. data/test/unit/plugins/source/files/test_path_match.rb +140 -0
  122. data/test/unit/plugins/source/files/yml/ignore_list.yml +8 -0
  123. data/test/unit/plugins/source/files/yml/ignore_not_array.yml +5 -0
  124. data/test/unit/plugins/source/files/yml/include_not_array.yml +3 -0
  125. data/test/unit/plugins/source/files/yml/include_subdirs_false.yml +6 -0
  126. data/test/unit/plugins/source/files/yml/include_subdirs_missing.yml +5 -0
  127. data/test/unit/plugins/source/files/yml/no_ignore.yml +4 -0
  128. data/test/unit/plugins/source/files/yml/no_include.yml +1 -0
  129. data/test/unit/plugins/source/files/yml/valid.yml +9 -0
  130. data/test/unit/plugins/test_installed_plugins.rb +32 -0
  131. data/test/unit/plugins/test_plugin_loader.rb +27 -0
  132. data/test/unit/plugins/test_plugins.rb +44 -0
  133. data/test/unit/tasks/test_siba_task.rb +30 -0
  134. data/test/unit/tasks/test_siba_tasks.rb +84 -0
  135. data/test/unit/tasks/yml/task/invalid.yml +4 -0
  136. data/test/unit/tasks/yml/task/valid.yml +7 -0
  137. data/test/unit/test_backup.rb +18 -0
  138. data/test/unit/test_console.rb +166 -0
  139. data/test/unit/test_generator.rb +21 -0
  140. data/test/unit/test_globals.rb +34 -0
  141. data/test/unit/test_log_message.rb +26 -0
  142. data/test/unit/test_logger_plug.rb +49 -0
  143. data/test/unit/test_options_backup.rb +21 -0
  144. data/test/unit/test_options_loader.rb +72 -0
  145. data/test/unit/test_password_strength.rb +76 -0
  146. data/test/unit/test_restore.rb +18 -0
  147. data/test/unit/test_scaffold.rb +26 -0
  148. data/test/unit/test_siba_check.rb +118 -0
  149. data/test/unit/test_siba_logger.rb +174 -0
  150. data/test/unit/test_tmp_dir.rb +21 -0
  151. data/test/unit/yml/options_loader/array.yml +2 -0
  152. data/test/unit/yml/options_loader/empty.yml +0 -0
  153. data/test/unit/yml/options_loader/invalid.yml +4 -0
  154. data/test/unit/yml/options_loader/string.yml +1 -0
  155. data/test/unit/yml/options_loader/utf8_with_bom.yml +2 -0
  156. data/test/unit/yml/options_loader/valid.yml +12 -0
  157. data/test/unit/yml/siba_options_backup.yml +20 -0
  158. data/test/unit/yml/valid.yml +18 -0
  159. metadata +240 -0
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba::Destination
4
+ module Dir
5
+ class DestDir
6
+ include Siba::FilePlug
7
+ include Siba::LoggerPlug
8
+ attr_accessor :dir
9
+
10
+ def initialize(dir)
11
+ @dir = siba_file.file_expand_path dir
12
+ test_dir_access
13
+ end
14
+
15
+ def copy_backup_to_dest(path_to_backup)
16
+ siba_file.run_this "copy backup to dest" do
17
+ logger.info "Copying backup to destination directory: #{dir}"
18
+ unless siba_file.file_file? path_to_backup
19
+ raise Siba::Error, "Backup file '#{path_to_backup}' does not exist"
20
+ end
21
+ unless siba_file.file_directory? dir
22
+ raise Siba::Error, "Destination directory '#{dir}' does not exist"
23
+ end
24
+ siba_file.file_utils_cp(path_to_backup, dir)
25
+ end
26
+ end
27
+
28
+ def restore_backup_to_dir(backup_name, to_dir)
29
+ siba_file.run_this do
30
+ logger.info "Copying backup from destination directory: #{dir}"
31
+ path_to_backup = File.join dir, backup_name
32
+ unless siba_file.file_file? path_to_backup
33
+ raise Siba::Error, "Can not find backup #{path_to_backup}"
34
+ end
35
+
36
+ siba_file.file_utils_cp path_to_backup, to_dir
37
+ end
38
+ end
39
+
40
+ def test_dir_access
41
+ siba_file.run_this "test dir access" do
42
+ # create dest dir
43
+ begin
44
+ siba_file.file_utils_mkpath dir unless siba_file.file_directory? dir
45
+ rescue Exception
46
+ logger.error "Failed to create destination dir '#{dir}'."
47
+ raise
48
+ end
49
+
50
+ # copy a test file to dest dir
51
+ begin
52
+ test_file = Siba::TestFiles.prepare_test_file "destination_dir", dir
53
+ raise "Can not find the test file." unless siba_file.file_file? test_file
54
+ siba_file.file_utils_remove_entry_secure test_file
55
+ rescue Exception
56
+ logger.error "Could not write to destination dir '#{dir}'"
57
+ raise
58
+ end
59
+
60
+ logger.debug "Access to destination directory is verified"
61
+ end
62
+ end
63
+
64
+ # Returns an array of two-element arrays: [file_name, mtime]
65
+ def get_backups_list(backup_name)
66
+ siba_file.run_this do
67
+ Siba::FileHelper.entries(dir).select do |f|
68
+ f =~ /^#{backup_name}/
69
+ end.map do |f|
70
+ mtime = siba_file.file_mtime File.join dir, f
71
+ [f, mtime]
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'siba/plugins/destination/dir/dest_dir'
4
+
5
+ module Siba::Destination
6
+ module Dir
7
+ class Init
8
+ attr_accessor :dest_dir
9
+
10
+ def initialize(options)
11
+ dir = Siba::SibaCheck.options_string options, "dir"
12
+ @dest_dir = Siba::Destination::Dir::DestDir.new dir
13
+ end
14
+
15
+ def backup(path_to_backup_file)
16
+ @dest_dir.copy_backup_to_dest path_to_backup_file
17
+ end
18
+
19
+ # Put backup file into dir
20
+ def restore(backup_name, dir)
21
+ @dest_dir.restore_backup_to_dir backup_name, dir
22
+ end
23
+
24
+ # Returns an array of two-element arrays:
25
+ # [backup_file_name, modification_time]
26
+ def get_backups_list(backup_name)
27
+ @dest_dir.get_backups_list backup_name
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,2 @@
1
+ dir: destination_dir # relative to this options file
2
+ # or /absolute or ~/relative_to_home
@@ -0,0 +1,140 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba::Encryption
4
+ module Gpg
5
+ class Encryption
6
+ include Siba::LoggerPlug
7
+ include Siba::FilePlug
8
+
9
+ DEFAULT_CIPHER = "AES256"
10
+
11
+ attr_accessor :passphrase, :cipher
12
+
13
+ def initialize(passphrase, cipher=DEFAULT_CIPHER)
14
+ @passphrase = passphrase
15
+ @cipher = Encryption.check_cipher cipher
16
+ check_password_strength
17
+ test_encryption
18
+ end
19
+
20
+ def encrypt(path_to_archive)
21
+ path_to_encrypted_backup = "#{path_to_archive}.gpg"
22
+ siba_file.run_this("encrypt") do
23
+ if siba_file.file_file? path_to_encrypted_backup
24
+ raise Siba::Error, "Encrypted file #{path_to_encrypted_backup} already exists"
25
+ end
26
+ passphare_for_command = passphrase.gsub('"','\\"')
27
+ gpg_homedir = Siba::TestFiles.mkdir_in_tmp_dir "gpg-homedir"
28
+ command_without_password = %(gpg -c -q --batch --homedir="#{gpg_homedir}" --no-options --cipher-algo=#{cipher} --passphrase="****" --no-use-agent "#{path_to_archive}")
29
+ command = command_without_password.gsub "****", passphare_for_command
30
+ siba_file.run_shell command, "failed to encrypt: #{command_without_password}"
31
+ unless siba_file.file_file? path_to_encrypted_backup
32
+ raise siba::error, "failed to find encrypted backup file: #{command_without_password}"
33
+ end
34
+ end
35
+ path_to_encrypted_backup
36
+ end
37
+
38
+ def decrypt(path_to_encrypted_file, path_to_decrypted_file=nil)
39
+ path_to_decrypted_file = path_to_encrypted_file.gsub /\.gpg$/, "" if path_to_decrypted_file.nil?
40
+ siba_file.run_this("decrypt") do
41
+ if siba_file.file_file? path_to_decrypted_file
42
+ raise Siba::Error, "Decrypted file #{path_to_decrypted_file} already exists"
43
+ end
44
+ passphare_for_command = passphrase.gsub('"','\\"')
45
+ gpg_homedir = Siba::TestFiles.mkdir_in_tmp_dir "gpg-homedir"
46
+ command_without_password = %(gpg -d -q --batch --homedir="#{gpg_homedir}" --no-options --passphrase="****" -o "#{path_to_decrypted_file}" --no-use-agent "#{path_to_encrypted_file}")
47
+ command = command_without_password.gsub "****", passphare_for_command
48
+ siba_file.run_shell command, "failed to decrypt: #{command_without_password}"
49
+ unless siba_file.file_file? path_to_decrypted_file
50
+ raise siba::error, "failed to find decrypted backup file: #{command_without_password}"
51
+ end
52
+ end
53
+ path_to_decrypted_file
54
+ end
55
+
56
+ def test_encryption
57
+ begin
58
+ siba_file.run_this("test_encryption") do
59
+ # encrypt
60
+ path_to_source_file = Siba::TestFiles.prepare_test_file "encryption-gpg"
61
+ path_to_encrypted_file = encrypt path_to_source_file
62
+ raise unless path_to_encrypted_file == "#{path_to_source_file}.gpg"
63
+ raise unless siba_file.file_file? path_to_encrypted_file
64
+ raise if siba_file.file_utils_compare_file path_to_source_file, path_to_encrypted_file
65
+
66
+ # decrypt
67
+ path_to_output_file = "#{path_to_source_file}.decrypted"
68
+ path_to_decrypted_file = decrypt path_to_encrypted_file, path_to_output_file
69
+ raise unless path_to_decrypted_file == path_to_output_file
70
+ raise unless siba_file.file_utils_compare_file path_to_source_file, path_to_decrypted_file
71
+
72
+ logger.debug "GPG encryption is verified"
73
+ end
74
+ rescue Exception
75
+ logger.error "'gpg' encryption utility does not work correctly. Try reinstalling it."
76
+ raise
77
+ end
78
+ end
79
+
80
+ class << self
81
+ include Siba::FilePlug
82
+ include Siba::LoggerPlug
83
+
84
+ def check_cipher(cipher)
85
+ siba_file.run_this("check_cipher") do
86
+ supported_ciphers = nil
87
+ begin
88
+ supported_ciphers = Encryption.get_cipher_names
89
+ rescue Exception
90
+ logger.error "'gpg' encryption utility is not found. Please install it."
91
+ raise
92
+ end
93
+
94
+ supported_ciphers_msg = "Please use one of the following: #{supported_ciphers.join(', ')}."
95
+ if cipher.nil?
96
+ cipher = Encryption::DEFAULT_CIPHER
97
+ raise Siba::CheckError, "Default cipher '#{cipher}' is not supported.
98
+ #{supported_ciphers_msg}" unless supported_ciphers.include?(cipher)
99
+ else
100
+ cipher.upcase!
101
+ end
102
+
103
+ raise Siba::CheckError, "'#{cipher}' cipher is not supported.
104
+ #{supported_ciphers_msg}" unless supported_ciphers.include?(cipher)
105
+ end
106
+ cipher
107
+ end
108
+
109
+ def get_cipher_names
110
+ output = siba_file.run_shell "gpg --version"
111
+ cipher_names = parse_cipher_names output
112
+ raise Siba::Error, "Failed to get the list of supported ciphers" if cipher_names.empty?
113
+ cipher_names
114
+ end
115
+
116
+ def parse_cipher_names(version)
117
+ scan = version.scan /Cipher:(.*?)\n\w+:/m
118
+ scan = version.scan /Cipher:(.*)/m if scan.size == 0
119
+ if scan.size == 0 || !scan[0].is_a?(Array) || scan[0].size == 0 || !scan[0][0].is_a?(String)
120
+ raise "Failed to parse gpg version information"
121
+ end
122
+ scan = scan[0][0]
123
+ scan.gsub!(/ |\n/, "")
124
+ scan.split(",").each {|a| a.upcase!}
125
+ end
126
+ end
127
+
128
+ private
129
+
130
+ def check_password_strength
131
+ seconds_to_crack = Siba::PasswordStrength.seconds_to_crack(@passphrase)
132
+ if Siba::PasswordStrength.is_weak? seconds_to_crack
133
+ timespan_to_guess = Siba::PasswordStrength.seconds_to_timespan seconds_to_crack
134
+ guess_estimation_message = "It will take #{timespan_to_guess} to guess it."
135
+ logger.warn "Your encryption password is weak. #{guess_estimation_message}"
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'siba/helpers/password_strength'
4
+ require 'siba/plugins/encryption/gpg/encryption'
5
+
6
+ module Siba::Encryption
7
+ module Gpg
8
+ class Init
9
+ include Siba::LoggerPlug
10
+ include Siba::FilePlug
11
+ attr_accessor :encryption
12
+
13
+ def initialize(options)
14
+ passphrase = Siba::SibaCheck.options_string(options, "passphrase")
15
+ cipher = Siba::SibaCheck.options_string(options, "cipher", true)
16
+ @encryption = Siba::Encryption::Gpg::Encryption.new passphrase, cipher
17
+ end
18
+
19
+ # Encrypt backup archive file (path_to_archive) and put it to dest_dir.
20
+ # Return the name of encrypted file. It must begin with archive name
21
+ # and its ending must always be the same.
22
+ def backup(path_to_archive, dest_dir)
23
+ logger.info "Encrypting backup with 'gpg', cipher: '#{encryption.cipher}'"
24
+ path_to_encrypted_file = encryption.encrypt path_to_archive
25
+
26
+ # move encrypted file to dest_dir
27
+ file_name = File.basename path_to_encrypted_file
28
+ dest_file_path = File.join dest_dir, file_name
29
+ siba_file.file_utils_mv path_to_encrypted_file, dest_file_path
30
+ file_name
31
+ end
32
+
33
+ # Decrypt backup file (path_to_backup) to_dir.
34
+ # Return the name of decrypted file.
35
+ def restore(path_to_backup, to_dir)
36
+ logger.info "Decrypting backup with 'gpg', cipher: '#{encryption.cipher}'"
37
+ decrypted_file_name = File.basename path_to_backup
38
+ decrypted_file_name.gsub! /\.gpg$/, ""
39
+ path_to_decrypted_file = File.join to_dir, decrypted_file_name
40
+ encryption.decrypt path_to_backup, path_to_decrypted_file
41
+ decrypted_file_name
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,2 @@
1
+ passphrase: "<%= Siba::SecurityHelper.generate_password_for_yaml %>"
2
+ cipher: AES256 # or BLOWFISH, TWOFISH, 3DES...
@@ -0,0 +1,77 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba
4
+ class InstalledPlugins
5
+ GEM_PREFIX = "siba-"
6
+
7
+ class << self
8
+ include Siba::FilePlug
9
+
10
+ def installed?(category, type)
11
+ types = all_installed[category]
12
+ return false if types.nil?
13
+ types.include? type
14
+ end
15
+
16
+ def all_installed
17
+ @installed ||= find_installed
18
+ end
19
+
20
+ def plugin_path(category, type)
21
+ unless installed? category, type
22
+ raise Siba::Error, "Plugin #{plugin_category_and_type(category, type)} is not installed"
23
+ end
24
+ siba_file.run_this do
25
+ path = type_dir category, type
26
+ unless siba_file.file_directory? path
27
+ path = Siba::GemHelper.gem_path gem_name(category, type)
28
+ path = File.join path, "lib", gem_name(category, type)
29
+ end
30
+ unless siba_file.file_directory? path
31
+ raise Siba::Error, "Failed to get path to plugin #{plugin_category_and_type(category, type)}"
32
+ end
33
+ path
34
+ end
35
+ end
36
+
37
+ def category_dir(category)
38
+ File.expand_path "../#{category}/", __FILE__
39
+ end
40
+
41
+ def type_dir(category, type)
42
+ File.join category_dir(category), type
43
+ end
44
+
45
+ def gem_name(category, type)
46
+ "#{GEM_PREFIX}#{category}-#{type}"
47
+ end
48
+
49
+ def plugin_category_and_type(category, type)
50
+ "#{category}#{type.nil? ? "" : '-' + type}"
51
+ end
52
+
53
+ private
54
+
55
+ def find_installed
56
+ installed = {}
57
+ Siba::GemHelper.all_local_gems.map{|a| a.name}.each do |item|
58
+ Siba::Plugins::CATEGORIES.each do |category|
59
+ installed[category] ||= []
60
+ gem_prefix_full = /^#{GEM_PREFIX}#{category}-/
61
+ installed[category] << item.gsub(gem_prefix_full, '') if item =~ /#{gem_prefix_full}.*$/
62
+ end
63
+ end
64
+
65
+ Siba::Plugins::CATEGORIES.each do |category|
66
+ installed[category] += Dir.glob(File.join(category_dir(category),"*")).select { |entry|
67
+ File.directory? entry
68
+ }.select{|dir| File.file?(File.join(dir,"init.rb")) }
69
+ .map{|directory| File.basename(directory)}
70
+ end
71
+
72
+ installed
73
+ end
74
+
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba
4
+ class PluginLoader
5
+ include Siba::LoggerPlug
6
+ include Siba::FilePlug
7
+
8
+ InitClassName = "Init"
9
+
10
+ def self.loader
11
+ @loader ||= PluginLoader.new
12
+ end
13
+
14
+ def load(category, type, options)
15
+ unless Siba::Plugins.valid_category? category
16
+ raise PluginLoadError, "Incorrect plugin category '#{category}'. Available plugin categories are: #{Siba::Plugins.categories_str}"
17
+ end
18
+
19
+ raise PluginLoadError, "Options data is incorrect for #{plugin_category_and_type} plugin." unless options.is_a? Hash
20
+
21
+ @category=category
22
+ @type=type
23
+ @options = options
24
+ logger.debug "Loading #{plugin_category_and_type} plugin"
25
+
26
+ require_plugin
27
+ plugin_module = get_plugin_module
28
+ plugin_type_module = get_plugin_type_module plugin_module
29
+ init_class = get_plugin_init_class plugin_type_module
30
+ init_plugin(init_class)
31
+ end
32
+
33
+ private
34
+ attr_accessor :category, :type, :options
35
+
36
+ def require_plugin
37
+ path_to_init_file = File.join(plugin_dir, "init.rb")
38
+ if File.exists?(path_to_init_file)
39
+ require path_to_init_file
40
+ else
41
+ gem_name = Siba::InstalledPlugins.gem_name category, type
42
+ begin
43
+ Gem::Specification.find_by_name(gem_name)
44
+ rescue Gem::LoadError
45
+ raise PluginLoadError, "Unknown type '#{type}' for '#{category}' plugin. #{available_types_msg}"
46
+ end
47
+ require gem_name
48
+ end
49
+ end
50
+
51
+ def get_plugin_module
52
+ plugin_module_name = "#{category.capitalize}"
53
+ Siba.const_get(plugin_module_name)
54
+ rescue Exception
55
+ raise PluginLoadError, "Failed to load #{plugin_category_and_type} plugin: module 'Siba::#{plugin_module_name}' is undefined."
56
+ end
57
+
58
+ def get_plugin_type_module(plugin_module)
59
+ plugin_type_module_name = StringHelper.camelize type
60
+ plugin_module.const_get(plugin_type_module_name)
61
+ rescue
62
+ raise PluginLoadError, "Failed to load #{plugin_category_and_type} plugin: module 'Siba::#{category.capitalize}::#{plugin_type_module_name}' is undefined."
63
+ end
64
+
65
+ def get_plugin_init_class(plugin_type_module)
66
+ plugin_type_module.const_get InitClassName
67
+ rescue Exception => e
68
+ raise PluginLoadError, "#{InitClassName} class is undefined for #{plugin_category_and_type} plugin."
69
+ end
70
+
71
+ def init_plugin(plugin_init_class)
72
+ plugin_init_class.new options
73
+ rescue ArgumentError
74
+ logger.error "Failed to load #{plugin_category_and_type} plugin: 'initialize' method is not defined or has wrong agruments."
75
+ raise
76
+ end
77
+
78
+ def plugin_category_and_type
79
+ Siba::InstalledPlugins.plugin_category_and_type category, type
80
+ end
81
+
82
+ def plugins_root_dir
83
+ Siba::InstalledPlugins.category_dir category
84
+ end
85
+
86
+ def plugin_dir
87
+ Siba::InstalledPlugins.type_dir category, type
88
+ end
89
+
90
+ def available_types_msg
91
+ return "No #{category} plugins are installed." if find_all_installed.empty?
92
+ return "Available types are: #{find_all_installed.join(", ")}." if find_all_installed.size > 1
93
+ "Available type is '#{find_all_installed.join(", ")}'."
94
+ end
95
+
96
+ def find_all_installed
97
+ Siba::InstalledPlugins.all_installed[category]
98
+ end
99
+ end
100
+ end