siba 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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