syc-backup 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/README.rdoc +48 -0
  2. data/Rakefile +7 -0
  3. data/bin/sycbackup +6 -0
  4. data/doc/Backup.html +186 -0
  5. data/doc/Backup/CronEdit.html +381 -0
  6. data/doc/Backup/Environment.html +231 -0
  7. data/doc/Backup/FileBackup.html +363 -0
  8. data/doc/Backup/MySQLBackup.html +305 -0
  9. data/doc/Backup/Options.html +328 -0
  10. data/doc/Backup/Process.html +261 -0
  11. data/doc/Backup/Runner.html +244 -0
  12. data/doc/README_rdoc.html +202 -0
  13. data/doc/Rakefile.html +118 -0
  14. data/doc/TestCronEdit.html +211 -0
  15. data/doc/TestEnvironment.html +156 -0
  16. data/doc/TestFileBackup.html +237 -0
  17. data/doc/TestMySQLBackup.html +167 -0
  18. data/doc/TestOptions.html +156 -0
  19. data/doc/TestProcess.html +236 -0
  20. data/doc/created.rid +18 -0
  21. data/doc/images/add.png +0 -0
  22. data/doc/images/brick.png +0 -0
  23. data/doc/images/brick_link.png +0 -0
  24. data/doc/images/bug.png +0 -0
  25. data/doc/images/bullet_black.png +0 -0
  26. data/doc/images/bullet_toggle_minus.png +0 -0
  27. data/doc/images/bullet_toggle_plus.png +0 -0
  28. data/doc/images/date.png +0 -0
  29. data/doc/images/delete.png +0 -0
  30. data/doc/images/find.png +0 -0
  31. data/doc/images/loadingAnimation.gif +0 -0
  32. data/doc/images/macFFBgHack.png +0 -0
  33. data/doc/images/package.png +0 -0
  34. data/doc/images/page_green.png +0 -0
  35. data/doc/images/page_white_text.png +0 -0
  36. data/doc/images/page_white_width.png +0 -0
  37. data/doc/images/plugin.png +0 -0
  38. data/doc/images/ruby.png +0 -0
  39. data/doc/images/tag_blue.png +0 -0
  40. data/doc/images/tag_green.png +0 -0
  41. data/doc/images/transparent.png +0 -0
  42. data/doc/images/wrench.png +0 -0
  43. data/doc/images/wrench_orange.png +0 -0
  44. data/doc/images/zoom.png +0 -0
  45. data/doc/index.html +106 -0
  46. data/doc/js/darkfish.js +153 -0
  47. data/doc/js/jquery.js +18 -0
  48. data/doc/js/navigation.js +142 -0
  49. data/doc/js/search.js +94 -0
  50. data/doc/js/search_index.js +1 -0
  51. data/doc/js/searcher.js +228 -0
  52. data/doc/rdoc.css +543 -0
  53. data/doc/table_of_contents.html +148 -0
  54. data/lib/backup/cron_edit.rb +127 -0
  55. data/lib/backup/environment.rb +44 -0
  56. data/lib/backup/file_backup.rb +94 -0
  57. data/lib/backup/mysql_backup.rb +58 -0
  58. data/lib/backup/options.rb +199 -0
  59. data/lib/backup/process.rb +99 -0
  60. data/lib/backup/runner.rb +79 -0
  61. data/lib/backup_version.rb +9 -0
  62. data/syc-backup-0.0.1.gem +0 -0
  63. data/syc-backup-0.0.3.gem +0 -0
  64. data/sycbackup.gemspec +20 -0
  65. data/test/test_cron_edit.rb +49 -0
  66. data/test/test_environment.rb +22 -0
  67. data/test/test_file_backup.rb +70 -0
  68. data/test/test_mysql_backup.rb +71 -0
  69. data/test/test_options.rb +189 -0
  70. data/test/test_process.rb +40 -0
  71. metadata +123 -0
@@ -0,0 +1,148 @@
1
+ <!DOCTYPE html>
2
+
3
+ <html>
4
+ <head>
5
+ <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
6
+
7
+ <title>Table of Contents - RDoc Documentation</title>
8
+
9
+ <link type="text/css" media="screen" href="./rdoc.css" rel="stylesheet">
10
+
11
+ <script type="text/javascript">
12
+ var rdoc_rel_prefix = "./";
13
+ </script>
14
+
15
+ <script type="text/javascript" charset="utf-8" src="./js/jquery.js"></script>
16
+ <script type="text/javascript" charset="utf-8" src="./js/navigation.js"></script>
17
+ <script type="text/javascript" charset="utf-8" src="./js/search_index.js"></script>
18
+ <script type="text/javascript" charset="utf-8" src="./js/search.js"></script>
19
+ <script type="text/javascript" charset="utf-8" src="./js/searcher.js"></script>
20
+ <script type="text/javascript" charset="utf-8" src="./js/darkfish.js"></script>
21
+
22
+
23
+ <body class="indexpage">
24
+ <h1>Table of Contents - RDoc Documentation</h1>
25
+
26
+ <h2>Pages</h2>
27
+ <ul>
28
+ <li class="file">
29
+ <a href="README_rdoc.html">README</a>
30
+
31
+ <img class="toc-toggle" src="images/transparent.png" alt="" title="toggle headings">
32
+ <ul class="initially-hidden">
33
+ <li><a href="README_rdoc.html#label-Backup+utility+for+database%2C+folders+and+files">Backup utility for database, folders and files</a>
34
+ <li><a href="README_rdoc.html#label-Install">Install</a>
35
+ <li><a href="README_rdoc.html#label-Usage">Usage</a>
36
+ <li><a href="README_rdoc.html#label-Supported+Platform">Supported Platform</a>
37
+ <li><a href="README_rdoc.html#label-Notes">Notes</a>
38
+ <li><a href="README_rdoc.html#label-Tests">Tests</a>
39
+ <li><a href="README_rdoc.html#label-Links">Links</a>
40
+ </ul>
41
+ </li>
42
+ <li class="file">
43
+ <a href="Rakefile.html">Rakefile</a>
44
+ </li>
45
+
46
+ </ul>
47
+
48
+ <h2 id="classes">Classes/Modules</h2>
49
+ <ul>
50
+ <li class="module">
51
+ <a href="Backup.html">Backup</a>
52
+ </li>
53
+ <li class="class">
54
+ <a href="Backup/CronEdit.html">Backup::CronEdit</a>
55
+ </li>
56
+ <li class="class">
57
+ <a href="Backup/Environment.html">Backup::Environment</a>
58
+ </li>
59
+ <li class="class">
60
+ <a href="Backup/FileBackup.html">Backup::FileBackup</a>
61
+ </li>
62
+ <li class="class">
63
+ <a href="Backup/MySQLBackup.html">Backup::MySQLBackup</a>
64
+ </li>
65
+ <li class="class">
66
+ <a href="Backup/Options.html">Backup::Options</a>
67
+ </li>
68
+ <li class="class">
69
+ <a href="Backup/Process.html">Backup::Process</a>
70
+ </li>
71
+ <li class="class">
72
+ <a href="Backup/Runner.html">Backup::Runner</a>
73
+ </li>
74
+ <li class="class">
75
+ <a href="TestCronEdit.html">TestCronEdit</a>
76
+ </li>
77
+ <li class="class">
78
+ <a href="TestEnvironment.html">TestEnvironment</a>
79
+ </li>
80
+ <li class="class">
81
+ <a href="TestFileBackup.html">TestFileBackup</a>
82
+ </li>
83
+ <li class="class">
84
+ <a href="TestMySQLBackup.html">TestMySQLBackup</a>
85
+ </li>
86
+ <li class="class">
87
+ <a href="TestOptions.html">TestOptions</a>
88
+ </li>
89
+ <li class="class">
90
+ <a href="TestProcess.html">TestProcess</a>
91
+ </li>
92
+
93
+ </ul>
94
+
95
+ <h2 id="methods">Methods</h2>
96
+ <ul>
97
+
98
+ <li class="method"><a href="Backup/Process.html#method-c-new">::new &mdash; Backup::Process</a>
99
+
100
+ <li class="method"><a href="Backup/Runner.html#method-c-new">::new &mdash; Backup::Runner</a>
101
+
102
+ <li class="method"><a href="Backup/Options.html#method-c-new">::new &mdash; Backup::Options</a>
103
+
104
+ <li class="method"><a href="Backup/MySQLBackup.html#method-c-new">::new &mdash; Backup::MySQLBackup</a>
105
+
106
+ <li class="method"><a href="Backup/FileBackup.html#method-c-new">::new &mdash; Backup::FileBackup</a>
107
+
108
+ <li class="method"><a href="Backup/Environment.html#method-c-ruby">::ruby &mdash; Backup::Environment</a>
109
+
110
+ <li class="method"><a href="Backup/CronEdit.html#method-i-add_command">#add_command &mdash; Backup::CronEdit</a>
111
+
112
+ <li class="method"><a href="Backup/FileBackup.html#method-i-backup">#backup &mdash; Backup::FileBackup</a>
113
+
114
+ <li class="method"><a href="Backup/MySQLBackup.html#method-i-backup">#backup &mdash; Backup::MySQLBackup</a>
115
+
116
+ <li class="method"><a href="Backup/Process.html#method-i-backup">#backup &mdash; Backup::Process</a>
117
+
118
+ <li class="method"><a href="Backup/FileBackup.html#method-i-check_for_inexistent">#check_for_inexistent &mdash; Backup::FileBackup</a>
119
+
120
+ <li class="method"><a href="Backup/CronEdit.html#method-i-cleanup">#cleanup &mdash; Backup::CronEdit</a>
121
+
122
+ <li class="method"><a href="Backup/MySQLBackup.html#method-i-compress">#compress &mdash; Backup::MySQLBackup</a>
123
+
124
+ <li class="method"><a href="Backup/FileBackup.html#method-i-compress">#compress &mdash; Backup::FileBackup</a>
125
+
126
+ <li class="method"><a href="TestCronEdit.html#method-i-crontab_count">#crontab_count &mdash; TestCronEdit</a>
127
+
128
+ <li class="method"><a href="Backup/CronEdit.html#method-i-remove_command">#remove_command &mdash; Backup::CronEdit</a>
129
+
130
+ <li class="method"><a href="Backup/Runner.html#method-i-run">#run &mdash; Backup::Runner</a>
131
+
132
+ <li class="method"><a href="TestProcess.html#method-i-setup">#setup &mdash; TestProcess</a>
133
+
134
+ <li class="method"><a href="TestFileBackup.html#method-i-setup">#setup &mdash; TestFileBackup</a>
135
+
136
+ <li class="method"><a href="TestProcess.html#method-i-teardown">#teardown &mdash; TestProcess</a>
137
+
138
+ <li class="method"><a href="TestFileBackup.html#method-i-teardown">#teardown &mdash; TestFileBackup</a>
139
+
140
+ </ul>
141
+
142
+
143
+ <footer id="validator-badges">
144
+ <p><a href="http://validator.w3.org/check/referer">[Validate]</a>
145
+ <p>Generated by <a href="https://github.com/rdoc/rdoc">RDoc</a> 3.12.
146
+ <p>Generated with the <a href="http://deveiate.org/projects/Darkfish-Rdoc/">Darkfish Rdoc Generator</a> 3.
147
+ </footer>
148
+
@@ -0,0 +1,127 @@
1
+ require 'open3'
2
+
3
+ module Backup
4
+
5
+ # Adds or removes a command to the user's crontab. To make sure that the
6
+ # Ruby application is invoked as a cron job it needs the environment
7
+ # variables that are available when run from command line. To meet these
8
+ # requirements the environment variables are read and added to the crontab. If
9
+ # variables already exist in the crontab they are overridden.
10
+ class CronEdit
11
+
12
+ # Temporary file that holds the entries to be written to the crontab
13
+ CRON_ENTRIES_FILE = ".cron_entries"
14
+
15
+ # Adds a command to the user's crontab. If the provided command is empty
16
+ # add_command will exit the application with exit status -1.
17
+ # The method uses the <tt>crontab -l</tt> and <tt>crontab file</tt> command.
18
+ # If the crontab call fails the error message and exit status of
19
+ # <tt>crontab</tt> will be returned and the application exits
20
+ def add_command(command, environment=[])
21
+ command = command.strip.squeeze(" ")
22
+
23
+ if command.empty?
24
+ STDERR.puts "Cannot add empty command to cron"
25
+ exit -1
26
+ end
27
+
28
+ read_crontab_command = 'crontab -l'
29
+
30
+ stdout, stderr, status = Open3.capture3(read_crontab_command)
31
+
32
+ entries = [] + environment
33
+
34
+ stdout.split(/\n/).each do |entry|
35
+ entry = entry.strip.squeeze(" ")
36
+ variable = entry.match(/\A\w+(?=\=)/).to_s
37
+ unless variable.empty?
38
+ entries << entry unless environment.grep(/\A#{variable}/)
39
+ else
40
+ entries << entry
41
+ end
42
+ end
43
+
44
+ unless entries.include? command
45
+ entries << command
46
+
47
+ cron_entries_file = CRON_ENTRIES_FILE
48
+ File.open(cron_entries_file, 'w') do |f|
49
+ entries.each {|entry| f.puts entry}
50
+ end
51
+
52
+ write_crontab_command = "crontab #{cron_entries_file}"
53
+
54
+ stdout, stderr, status = Open3.capture3(write_crontab_command)
55
+
56
+ cleanup
57
+
58
+ unless status.exitstatus == 0
59
+ STDERR.puts "There is a problem executing command"
60
+ STDERR.puts write_crontab_command
61
+ STDERR.puts stderr
62
+ exit status.exitstatus
63
+ end
64
+ end
65
+
66
+ command
67
+
68
+ end
69
+
70
+ # Removes a command from the user's crontab. If the provided command is
71
+ # empty remove_command will exit the application with exit status -1.
72
+ # The method uses the <tt>crontab -l</tt> and <tt>crontab file</tt> command.
73
+ # If the crontab call fails the error message and exit status of
74
+ # <tt>crontab</tt> will be returned and the application exits
75
+ def remove_command(command)
76
+ command = command.strip.squeeze(" ")
77
+
78
+ if command.empty?
79
+ STDERR.puts "Cannot delete empty command from crontab"
80
+ exit -1
81
+ end
82
+
83
+ read_crontab_command = "crontab -l"
84
+
85
+ stdout, stderr, status = Open3.capture3(read_crontab_command)
86
+
87
+ unless status.exitstatus == 0
88
+ STDERR.puts "There is a problem executing command"
89
+ STDERR.puts read_crontab_command
90
+ STDERR.puts stderr
91
+ exit status.existatus
92
+ end
93
+
94
+ entries = stdout.split(/\n/).each {|entry| entry.strip.squeeze(" ")}
95
+
96
+ entries.delete(command)
97
+
98
+ cron_entries_file = CRON_ENTRIES_FILE #".cron_entries"
99
+
100
+ File.open(cron_entries_file, 'w') do |file|
101
+ entries.each {|entry| file.puts entry}
102
+ end
103
+
104
+ write_crontab_command = "crontab #{cron_entries_file}"
105
+
106
+ stdout, stderr, status = Open3.capture3(write_crontab_command)
107
+
108
+ cleanup
109
+
110
+ unless status.exitstatus == 0
111
+ STDERR.puts "There is a problem executing command"
112
+ STDERR.puts write_crontab_command
113
+ STDERR.puts stderr
114
+ exit status.exitstatus
115
+ end
116
+
117
+ command
118
+
119
+ end
120
+
121
+ # Removes the CRON_ENTRIES_FILE after the values have been written to
122
+ # crontab
123
+ def cleanup
124
+ File.delete CRON_ENTRIES_FILE if File.exists? CRON_ENTRIES_FILE
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,44 @@
1
+ module Backup
2
+
3
+ # Reads and filters the user's environment variables to meet Ruby and Gem
4
+ # requirements to run the application as a cron job
5
+ class Environment
6
+
7
+ # Contains the environment variable names that are required to run a Ruby
8
+ # application from as a cron job
9
+ VARIABLES = ["RVM_BIN_PATH",
10
+ "GEM_HOME",
11
+ "SHELL",
12
+ "MY_RUBY_HOME",
13
+ "USER",
14
+ "RVM_PATH",
15
+ "RVM_PREFIX",
16
+ "PATH",
17
+ "RVM_VERSION",
18
+ "HOME",
19
+ "LOGNAME",
20
+ "GEM_PATH",
21
+ "RUBY_VERSION"]
22
+
23
+ # Retrieves the environment variables that are required running a Ruby
24
+ # application as a cron job. The variable are returned in an Array
25
+ def self.ruby
26
+ file = ".current_environment.tmp"
27
+ system ("env > #{file}")
28
+
29
+ lines = []
30
+
31
+ File.open(file, 'r') do |f|
32
+ while line = f.gets
33
+ variable = line.chomp.match(/\A\w+(?=\=)/).to_s
34
+ lines << line.chomp if VARIABLES.find_index variable.upcase
35
+ end
36
+ end
37
+
38
+ File.delete file
39
+
40
+ lines
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,94 @@
1
+ require 'fileutils'
2
+ require 'open3'
3
+
4
+ # Backup contains functions to backup a MySQL database and files and directories
5
+ # to a default or specified backup directory. Instead of instant backup the
6
+ # invoked command can be added to a crontab and invoked based on the provided
7
+ # schedule that is a parameter of the --cron option. The backed up files are
8
+ # per default compressed but this can be ommitted
9
+ module Backup
10
+
11
+ # Backup directories and files to a backup directory
12
+ class FileBackup
13
+
14
+ # Initializes the files to be backed up. If no file is provided an error
15
+ # is returned
16
+ def initialize(files=[])
17
+ @files = files
18
+ end
19
+
20
+ # Compress the files to the backup directory
21
+ def compress(files, backup_folder)
22
+ inexistent_files = check_for_inexistent files
23
+ unless inexistent_files.empty?
24
+ STDERR.puts "Cannot compress inexistent files"
25
+ STDERR.puts "Following #{inexistent_files.size} file(s) do not exist"
26
+ STDERR.puts inexistent_files.join(" ")
27
+ exit 2
28
+ end
29
+
30
+ timestamp = Time.now.strftime("%Y%m%d-%H%M%S")
31
+ backup_folder += '/' unless backup_folder.match(/.*\/\Z/)
32
+ compress_file = backup_folder + timestamp + "_" + "files.tar.gz"
33
+
34
+ tar_command = "tar cfz #{compress_file} " + files.join(" ")
35
+
36
+ stdout_str, stderr_str, status = Open3.capture3(tar_command)
37
+
38
+ unless status.exitstatus == 0
39
+ STDERR.puts "There was a problem running tar command"
40
+ STDERR.puts "--> #{tar_command}"
41
+ STDERR.puts stderr_str
42
+ exit(2)
43
+ end
44
+
45
+ status.exitstatus
46
+
47
+ end
48
+
49
+ # The files to be backed up are initilized when creating an instance of
50
+ # FileBackup. These files are then backed up to the backup directory
51
+ def backup(backup_folder)
52
+
53
+ inexistent_files = []
54
+
55
+ @files.each do |file|
56
+ inexistent_files << file unless File.exists? file
57
+ end
58
+
59
+ unless inexistent_files.empty?
60
+ STDERR.puts "Cannot backup inexistent files"
61
+ STDERR.puts "Following #{inexistent_files.size} file(s) do not exist"
62
+ STDERR.puts "#{inexistent_files.join(', ')}"
63
+ exit 1
64
+ end
65
+
66
+ backup_folder += '/' unless backup_folder.match(/.*\/\Z/)
67
+
68
+ Dir.mkdir backup_folder unless File.exists? backup_folder
69
+
70
+ backup_files = []
71
+
72
+ @files.each.with_index do |file, index|
73
+ backup_files << backup_file = backup_folder+File.basename(file)
74
+ FileUtils.cp file, backup_file
75
+ end
76
+
77
+ backup_files
78
+
79
+ end
80
+
81
+ # Checks if the files all exist. Files that do not exist are returned in
82
+ # an Array
83
+ def check_for_inexistent (files)
84
+ inexistent_files = []
85
+ files.each do |f|
86
+ inexistent_files << f unless File.exists? f
87
+ end
88
+
89
+ inexistent_files
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,58 @@
1
+ require 'open3'
2
+
3
+ module Backup
4
+
5
+ # MySQLBackup creates a dump file of a MySQL database with _mysqldump_ and
6
+ # returns the dump file.
7
+ class MySQLBackup
8
+
9
+ # database is the database to be backed up with the user that has the
10
+ # credentials to access the database with the provided password
11
+ def initialize(database, user, password)
12
+ @database = database
13
+ @user = user
14
+ @password = password
15
+ end
16
+
17
+ # Compresses the MySQL dump file. If an error occurs when compressing the
18
+ # file an error message is printed and the application terminates
19
+ def compress(backup_file)
20
+ tar_file = backup_file + '.tar.gz'
21
+ tar_command = "tar cfz #{tar_file} #{backup_file}"
22
+ stdout_str, stderr_str, status = Open3.capture3(tar_command)
23
+ unless status.exitstatus == 0
24
+ File.delete tar_file if File.exists? tar_file
25
+ STDERR.puts "There was a problem compressing the backup file"
26
+ STDERR.puts "-->#{tar_command}"
27
+ STDERR.puts stderr_str
28
+ exit(2)
29
+ end
30
+
31
+ status.exitstatus
32
+
33
+ end
34
+
35
+ # Creates a MySQL dump file and returns the file
36
+ def backup(backup_folder="./")
37
+ Dir.mkdir backup_folder unless File.exists? backup_folder
38
+
39
+ timestamp = Time.now.strftime('%Y%m%d-%H%M%S')
40
+ backup_file = backup_folder + @database + '_' + timestamp + '.sql'
41
+ mysqldump = "mysqldump -u#{@user} -p#{@password} #{@database}"
42
+
43
+ backup_command = "#{mysqldump} > #{backup_file}"
44
+ stdout_str, stderr_str, status = Open3.capture3(backup_command)
45
+ unless status.exitstatus == 0
46
+ File.delete backup_file if File.exists? backup_file
47
+ STDERR.puts "There was a problem running mysqldump"
48
+ STDERR.puts "--> #{backup_command}"
49
+ STDERR.puts stderr_str
50
+ exit(1)
51
+ end
52
+
53
+ backup_file
54
+
55
+ end
56
+
57
+ end
58
+ end