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,57 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'siba/plugins/plugin_loader.rb'
4
+ require 'siba/plugins/installed_plugins.rb'
5
+
6
+ module Siba
7
+ class Plugins
8
+ PLUGINS_HASH = Siba::OptionsLoader.load_hash_from_yml(File.expand_path "../plugins.yml", __FILE__)
9
+ CATEGORIES = PLUGINS_HASH.keys
10
+
11
+ class << self
12
+ def valid_category?(category)
13
+ Siba::Plugins::CATEGORIES.include? category
14
+ end
15
+
16
+ def categories_str
17
+ Siba::Plugins::CATEGORIES.join(", ")
18
+ end
19
+
20
+ def category_and_type_correct?(category, type)
21
+ PLUGINS_HASH.keys.include?(category) && PLUGINS_HASH[category].keys.include?(type)
22
+ end
23
+
24
+ def plugin_description(category, type)
25
+ unless category_and_type_correct? category, type
26
+ raise Siba::Error, "Incorrect category '#{category}' or type '#{type}'."
27
+ end
28
+ PLUGINS_HASH[category][type]
29
+ end
30
+
31
+ def plugin_type_and_description(category, type, name_column_length)
32
+ desc = plugin_description category, type
33
+ sprintf("%-#{name_column_length}s %s", type, desc)
34
+ end
35
+
36
+ def get_list
37
+ str = ""
38
+ all_names = PLUGINS_HASH.values.map{|a| a.keys}.flatten
39
+ max_name_length = all_names.max do |a,b|
40
+ a.length <=> b.length
41
+ end.length + 5
42
+
43
+ PLUGINS_HASH.each do |category, plugins|
44
+ str << "#{category.capitalize}"
45
+ str << "s" if plugins.size > 1
46
+ str << ":\n"
47
+ plugins.each do |type, desc|
48
+ installed = InstalledPlugins.installed?(category, type) ? "*" : " "
49
+ str << " #{installed} #{plugin_type_and_description(category, type, max_name_length)}\n"
50
+ end
51
+ str << "\n"
52
+ end
53
+ str
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,9 @@
1
+ source:
2
+ files: Backup local files and directories
3
+ archive:
4
+ tar: Archive with optional gzip or bzip2 compression
5
+ encryption:
6
+ gpg: Encrypt with AES256, Blowfish, Twofish, 3DES and other ciphers
7
+ destination:
8
+ dir: Backup to local directory
9
+ aws-s3: Upload backup to Amazon S3 storage
@@ -0,0 +1,166 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba::Source
4
+ module Files
5
+ class Files
6
+ include Siba::LoggerPlug
7
+ include Siba::FilePlug
8
+ attr_accessor :files_to_include, :ignore, :include_subdirs
9
+
10
+ def initialize(files_to_include, ignore, include_subdirs)
11
+ @files_to_include = files_to_include
12
+ @ignore = ignore
13
+ @include_subdirs = include_subdirs
14
+ end
15
+
16
+ def backup(dest_dir)
17
+ siba_file.run_this "backup" do
18
+ size_digits = files_to_include.size.to_s.length
19
+ files_to_include.each_index do |i|
20
+ file = files_to_include[i]
21
+ file = siba_file.file_expand_path file
22
+ next if ignored? file
23
+
24
+ is_file = siba_file.file_file? file
25
+ unless is_file || siba_file.file_directory?(file)
26
+ logger.error "Source file or directory does not exist: #{file}"
27
+ next
28
+ end
29
+
30
+ path_to_subdir = Files.sub_dir_name i+1, size_digits, is_file, file, dest_dir
31
+ siba_file.file_utils_mkpath path_to_subdir
32
+
33
+ logger.debug file
34
+ if is_file
35
+ copy_file file, path_to_subdir
36
+ else
37
+ copy_dir file, path_to_subdir, false
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def restore(from_dir)
44
+ siba_file.run_this do
45
+ backup_dirs = Siba::FileHelper.entries(from_dir).select do |e|
46
+ siba_file.file_directory? File.join(from_dir, e)
47
+ end.sort
48
+
49
+ if backup_dirs.size != files_to_include.size
50
+ raise Siba::Error, "Number of source files does not equal the number of files that are in the backup"
51
+ end
52
+
53
+ backup_dirs.each_index do |i|
54
+ backup_dir = backup_dirs[i]
55
+ splitted = backup_dir.split "-"
56
+ if splitted.size < 3
57
+ logger.error "Failed to parse backup dir #{backup_dir}"
58
+ next
59
+ end
60
+ dir_or_file = splitted[1]
61
+ if dir_or_file != "dir" && dir_or_file != "file"
62
+ logger.error "Failed to parse backup dir #{backup_dir}"
63
+ next
64
+ end
65
+ is_dir = dir_or_file == "dir"
66
+ path_to_backup_dir = File.join from_dir, backup_dir
67
+ entry_name_to_restore = files_to_include[i]
68
+ path_to_source = siba_file.file_expand_path entry_name_to_restore
69
+ if is_dir
70
+ siba_file.file_utils_mkpath path_to_source
71
+ siba_file.file_utils_cp_r File.join(path_to_backup_dir, "."), path_to_source
72
+ logger.info "Dir: #{path_to_source}"
73
+ else
74
+ restore_file path_to_backup_dir, entry_name_to_restore, path_to_source
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def restore_file(path_to_backup_dir, entry_name_to_restore, path_to_source)
81
+ backup_dir_entries = Siba::FileHelper.entries path_to_backup_dir
82
+ if backup_dir_entries.size != 1
83
+ logger.error "Failed to restore file: #{entry_name_to_restore}"
84
+ return
85
+ end
86
+
87
+
88
+ backup_file_name = backup_dir_entries[0]
89
+ path_to_backup_file = File.join path_to_backup_dir, backup_file_name
90
+ unless siba_file.file_file? path_to_backup_file
91
+ logger.error "Failed to restore file: #{path_to_backup_file}"
92
+ return
93
+ end
94
+ source_file_name = File.basename path_to_source
95
+ unless source_file_name == backup_file_name
96
+ logger.error "Failed to restore file, source file name '#{source_file_name}' is not the same as backup file name #{backup_file_name}"
97
+ return
98
+ end
99
+ path_to_source_dir = File.dirname path_to_source
100
+ siba_file.file_utils_mkpath path_to_source_dir
101
+ siba_file.file_utils_cp path_to_backup_file, path_to_source_dir
102
+ logger.info "File: #{path_to_source}"
103
+ end
104
+
105
+ def copy_file(file, dest_dir)
106
+ siba_file.run_this "copy file" do
107
+ return if ignored? file
108
+ siba_file.file_utils_cp(file, dest_dir)
109
+ end
110
+ end
111
+
112
+ def copy_dir(dir, dest_dir, create_subdir=false)
113
+ siba_file.run_this "copy dir" do
114
+ return if ignored? dir
115
+
116
+ if create_subdir
117
+ dest_dir = File.join(dest_dir, File.basename(dir))
118
+ siba_file.file_utils_mkpath dest_dir
119
+ end
120
+
121
+ Siba::FileHelper.entries(dir).each do |entry|
122
+ entry = File.join dir, entry
123
+ if siba_file.file_file? entry
124
+ copy_file entry, dest_dir
125
+ elsif siba_file.file_directory? entry
126
+ copy_dir entry, dest_dir, true if include_subdirs
127
+ else
128
+ logger.error "Failed to backup: #{file}."
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def ignored?(file)
135
+ return false if ignore.nil?
136
+ ignore.each do |pattern|
137
+ if Siba::Source::Files::Files.path_match? pattern, file
138
+ logger.info "Ignoring #{file}"
139
+ return true
140
+ end
141
+ end
142
+ false
143
+ end
144
+
145
+ class << self
146
+ def path_match?(pattern, file)
147
+ file.strip!
148
+ pattern.strip!
149
+ basename = File.basename(file)
150
+
151
+ return File.fnmatch(pattern, basename, File::FNM_CASEFOLD) || # match basename against pattern
152
+ File.fnmatch(pattern, file, File::FNM_CASEFOLD) # match whole path against pattern
153
+ end
154
+
155
+ def sub_dir_name(num, size_digits, is_file, src_file, dest_dir)
156
+ basename = File.basename src_file
157
+ basename = "root" if basename.empty? || basename == "/"
158
+ sub_dir_name = "%0#{size_digits}d" % num
159
+ sub_dir_name += is_file ? "-file" : "-dir"
160
+ sub_dir_name += "-#{basename}"
161
+ File.join dest_dir, sub_dir_name
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'siba/plugins/source/files/files'
4
+
5
+ module Siba::Source
6
+ module Files
7
+ class Init
8
+ include Siba::LoggerPlug
9
+ attr_accessor :files
10
+
11
+ def initialize(options)
12
+ files_to_include = Siba::SibaCheck.options_string_array options, "include"
13
+ ignore = Siba::SibaCheck.options_string_array options, "ignore", true
14
+ include_subdirs = Siba::SibaCheck.options_bool options, "include_subdirs", true, true
15
+ @files = Siba::Source::Files::Files.new files_to_include, ignore, include_subdirs
16
+ end
17
+
18
+ # Collect sources and put them into dest_dir
19
+ # No return value is expected
20
+ def backup(dest_dir)
21
+ logger.info "Collecting files"
22
+ @files.backup dest_dir
23
+ end
24
+
25
+ # Restore source files and dirs from_dir
26
+ # No return value is expected
27
+ def restore(from_dir)
28
+ logger.info "Restoring files"
29
+ @files.restore from_dir
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ include:
2
+ - /dir
3
+ - /dir/file
4
+ - ~/file # relative to home dir
5
+ - file # relative to this options file
6
+ ignore:
7
+ - "*.log"
8
+ - ".*"
9
+ - file_name
10
+ - dir_name
11
+ include_subdirs: Yes
@@ -0,0 +1,113 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba
4
+ class Restore
5
+ include Siba::LoggerPlug
6
+ include Siba::FilePlug
7
+ include Siba::KernelPlug
8
+
9
+ def restore(path_to_options_yml)
10
+ run_restore path_to_options_yml
11
+ ensure
12
+ Siba.cleanup
13
+ end
14
+
15
+ private
16
+
17
+ def run_restore(path_to_options_yml)
18
+ LoggerPlug.create "Restore", nil
19
+ options = Siba::OptionsLoader.load_yml path_to_options_yml
20
+ Siba.current_dir = File.dirname path_to_options_yml
21
+ Siba.settings = options["settings"] || {}
22
+ Siba.backup_name = File.basename path_to_options_yml, ".yml"
23
+ TmpDir.test_access
24
+ tasks = SibaTasks.new options, path_to_options_yml, true
25
+ file_name = get_backup_choice tasks
26
+ unless file_name.nil?
27
+ if user_wants_to_proceed?
28
+ tasks.restore file_name
29
+ else
30
+ logger.show_finish_message = false
31
+ logger.info "Cancelled by user"
32
+ end
33
+ end
34
+ Siba.cleanup_tmp_dir
35
+ rescue Exception => e
36
+ logger.fatal e
37
+ logger.log_exception e, true
38
+ end
39
+
40
+ def get_backup_choice(tasks)
41
+ list = tasks.get_backups_list
42
+
43
+ siba_file.run_this do
44
+ if list.empty?
45
+ logger.show_finish_message = false
46
+ logger.info "No backups named '#{Siba.backup_name}' found"
47
+ return
48
+ end
49
+
50
+ if list.size == 1
51
+ return list[0][0]
52
+ else
53
+ list.sort_by!{|a| a[1]}
54
+ siba_kernel.puts "\nAvailable '#{Siba.backup_name}' backups:\n"
55
+ show_backups list
56
+ file_name = get_backup_user_choice list
57
+
58
+ if file_name.nil?
59
+ logger.show_finish_message = false
60
+ logger.info "Cancelled by user"
61
+ end
62
+ return file_name
63
+ end
64
+ end
65
+ end
66
+
67
+ def show_backups(list)
68
+ list.map! {|a| a << Siba::StringHelper.format_time(a[1])}
69
+ max_date_length = list.max do |a,b|
70
+ a[2].length <=> b[2].length
71
+ end[2].length + 5
72
+
73
+ rows = list.size / 2 + list.size % 2
74
+ 1.upto(rows) do |i|
75
+ num1 = "#{i.to_s.rjust(2)}."
76
+ str1 = list[i-1][2]
77
+ column1 = sprintf("%s %-#{max_date_length}s", num1, str1)
78
+
79
+ if (i+rows) <= list.size
80
+ num2 = "#{(i+rows).to_s.rjust(2)}."
81
+ str2 = list[i+rows-1][2]
82
+ column2 = "#{num2} #{str2}"
83
+ end
84
+ siba_kernel.puts " #{column1}#{column2}"
85
+ end
86
+ end
87
+
88
+ def user_wants_to_proceed?
89
+ siba_kernel.printf "\nWarning: backup will be restored into your original source location.
90
+ Your current source data will be overwritten and WILL BE LOST.
91
+ Type 'yes' if you want to proceed:
92
+ (yes/n) > "
93
+ user_choice = siba_kernel.gets.chomp.strip
94
+ return user_choice.downcase == "yes"
95
+ end
96
+
97
+ def get_backup_user_choice(list)
98
+ msg = "\nChoose a backup to restore.\nEnter backup number from 1 to #{list.size}, or 0 to exit.\n> "
99
+ siba_kernel.printf msg
100
+ while true
101
+ user_choice = siba_kernel.gets.chomp.strip
102
+ number = Integer(user_choice) rescue -1
103
+ if number >= 0 && number <= list.size
104
+ return if number == 0
105
+ return list[number-1][0]
106
+ else
107
+ siba_kernel.printf msg
108
+ end
109
+ end
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,166 @@
1
+ # encoding: UTF-8
2
+
3
+ module Siba
4
+ class Scaffold
5
+ include Siba::FilePlug
6
+ include Siba::LoggerPlug
7
+ attr_accessor :category, :name, :name_camelized
8
+ CATEGORY_REPLACE_TEXT = "c6y"
9
+ NAME_REPLACE_TEXT = "demo"
10
+
11
+ def initialize(category, name)
12
+ @category = category
13
+ unless Siba::Plugins.valid_category? category
14
+ raise Siba::Error, "Invalid category '#{category}'. Available categories are: #{Siba::Plugins.categories_str}"
15
+ end
16
+
17
+ @name = Siba::StringHelper.str_to_alphnumeric name
18
+ raise Siba::Error, "first character of gem name can not be number" if name =~ /^[0-9]/
19
+
20
+ @name_camelized = StringHelper.camelize name
21
+ end
22
+
23
+ def scaffold(dest_dir)
24
+ run_scaffold dest_dir
25
+ ensure
26
+ Siba.cleanup
27
+ end
28
+
29
+ private
30
+
31
+ def run_scaffold(dest_dir)
32
+ siba_file.run_this "scaffold" do
33
+ LoggerPlug.create "Scaffolding", nil, false
34
+ logger.debug "Scaffolding started"
35
+ dest_dir = File.join dest_dir, name
36
+ if siba_file.file_directory?(dest_dir) || siba_file.file_file?(dest_dir)
37
+ raise Siba::Error, "Directory already exists #{dest_dir}."
38
+ end
39
+
40
+ logger.debug "Checking if GIT is installed"
41
+ raise Siba::Error, "Please install GIT first" unless siba_file.shell_ok? "git help"
42
+ scaffolds_dir = siba_file.file_expand_path "../../../scaffolds", __FILE__
43
+
44
+ logger.debug "Creating a tmp dir"
45
+ dest_tmp_dir = Siba::TestFiles.mkdir_in_tmp_dir "scaffold"
46
+
47
+ logger.debug "Copying project files"
48
+ project_dir = File.join scaffolds_dir, "project"
49
+ unless siba_file.file_directory? project_dir
50
+ raise Siba::Error, "Scaffold project dir does not exist '#{project_dir}'"
51
+ end
52
+ siba_file.file_utils_cp_r File.join(project_dir,"."), dest_tmp_dir
53
+
54
+ logger.debug "Copying init file"
55
+ init_file = File.join scaffolds_dir, "#{category}.rb"
56
+ unless siba_file.file_file? init_file
57
+ raise Siba::Error, "Scaffold init file does not exist '#{init_file}'"
58
+ end
59
+ init_dir = File.join dest_tmp_dir, "lib", "siba-#{CATEGORY_REPLACE_TEXT}-demo"
60
+ unless siba_file.file_directory? init_dir
61
+ raise Siba::Error, "Source dir does not exist '#{init_dir}'"
62
+ end
63
+ init_file_dest = File.join init_dir,"init.rb"
64
+ siba_file.file_utils_cp init_file, init_file_dest
65
+ unless siba_file.file_file? init_file_dest
66
+ raise Siba::Error, "Filed to create init file '#{init_file_dest}'"
67
+ end
68
+
69
+ logger.debug "Writing examples to init.rb"
70
+ replace_init_examples scaffolds_dir, init_file_dest
71
+
72
+ logger.debug "Setting siba gem dependency"
73
+ replace_siba_version dest_tmp_dir
74
+
75
+ logger.debug "Setting gem category and name in file names and contents"
76
+ replace_category_and_name dest_tmp_dir
77
+
78
+ gitify dest_tmp_dir
79
+
80
+ logger.debug "Copying the project to destination"
81
+ siba_file.file_utils_mkpath dest_dir
82
+ siba_file.file_utils_cp_r File.join(dest_tmp_dir,"."), dest_dir
83
+
84
+
85
+ logger.info "Project created in #{dest_dir}"
86
+ logger.info "There is a README file with instructions there"
87
+ logger.show_finish_message = false
88
+ end
89
+ rescue Exception => e
90
+ logger.fatal e
91
+ logger.log_exception e, true
92
+ end
93
+
94
+ def replace_category_and_name(dir)
95
+ Siba::FileHelper.entries(dir).each do |entry|
96
+ entry_path = replace_path dir, entry
97
+ if siba_file.file_directory? entry_path
98
+ replace_category_and_name entry_path
99
+ else
100
+ replace_file_contents entry_path
101
+ end
102
+ end
103
+ end
104
+
105
+ def replace_path(dir, entry)
106
+ entry_path = File.join dir, entry
107
+ entry_after = entry.gsub CATEGORY_REPLACE_TEXT, category
108
+ entry_after = entry_after.gsub NAME_REPLACE_TEXT, name
109
+ if entry_after != entry
110
+ entry_path_after = File.join(dir, entry_after)
111
+ siba_file.file_utils_mv entry_path, entry_path_after
112
+ entry_path = entry_path_after
113
+ end
114
+ entry_path
115
+ end
116
+
117
+ def replace_file_contents(path_to_file)
118
+ return unless siba_file.file_file? path_to_file
119
+ Siba::FileHelper.change_file(path_to_file) do |file_text|
120
+ file_text.gsub! CATEGORY_REPLACE_TEXT, category
121
+ file_text.gsub! CATEGORY_REPLACE_TEXT.capitalize, category.capitalize
122
+ file_text.gsub! NAME_REPLACE_TEXT, name
123
+ file_text.gsub! NAME_REPLACE_TEXT.capitalize, name_camelized
124
+ file_text
125
+ end
126
+ end
127
+
128
+ def gitify(path_to_project)
129
+ logger.debug "Initializing GIT repository"
130
+ siba_file.file_utils_cd path_to_project
131
+ siba_file.run_shell "git init", "Failed to init git repository"
132
+ siba_file.run_shell "git add ."
133
+ siba_file.run_shell "git commit -a -m 'Initial commit'"
134
+ end
135
+
136
+ def replace_siba_version(project_dir)
137
+ path_to_gemspec = File.join project_dir, "siba-c6y-demo.gemspec"
138
+ raise Siba::Error, "Can not find gemspec file #{path_to_gemspec}" unless siba_file.file_file? path_to_gemspec
139
+ Siba::FileHelper.change_file(path_to_gemspec) do |file_text|
140
+ version = Siba::VERSION.split('.')[0..-2].join('.')
141
+ file_text.gsub "siba_version", version
142
+ end
143
+ end
144
+
145
+ def replace_init_examples(scaffolds_dir, init_file_dest)
146
+ replace_init_example scaffolds_dir, init_file_dest, "init_example.rb"
147
+ replace_init_example scaffolds_dir, init_file_dest, "examples.rb"
148
+ end
149
+
150
+ def replace_init_example(scaffolds_dir, init_file_dest, example_file_name)
151
+ shared_dir = siba_file.file_expand_path File.join(scaffolds_dir, "shared")
152
+ init_example_file = File.join shared_dir, example_file_name
153
+ unless siba_file.file_file? init_example_file
154
+ raise Siba::Error, "Can not find init example file: '#{init_example_file}'"
155
+ end
156
+ init_example = Siba::FileHelper.read init_example_file
157
+ Siba::FileHelper.change_file(init_file_dest) do |f|
158
+ replace_text = "## #{example_file_name} ##"
159
+ unless f.include? replace_text
160
+ raise Siba::Error, "Can not replacement text: #{replace_text}"
161
+ end
162
+ f.gsub! replace_text, init_example
163
+ end
164
+ end
165
+ end
166
+ end