jmstacey-cfbackup 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ CFBackup ChangeLog
2
+ ==================
3
+
4
+ 0.5.0 2009-04-18
5
+ -----------------
6
+
7
+ * Conversion to a Ruby Gem
8
+ * cfbackup put in bin so that it can be called from anywhere
9
+ * Looks in a few standard locations for the config file
10
+ * Unit test framework prepped
11
+ * Cloud Files API has been moved to a separate repository and made available as a gem
12
+ * Most doc files converted to markdown
13
+
14
+ 0.0.4 2009-04-11
15
+ -----------------
16
+
17
+ * Pipe data straight to container
18
+ * Specify remote path or file name
19
+
20
+ 0.0.3 2009-04-08
21
+ -------------------
22
+
23
+ * Initial release to public
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (C) 2009 Jon Stacey
2
+
3
+ This program is free software: you can redistribute it and/or modify
4
+ it under the terms of the GNU General Public License as published by
5
+ the Free Software Foundation, either version 3 of the License, or
6
+ (at your option) any later version.
7
+
8
+ This program is distributed in the hope that it will be useful,
9
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ GNU General Public License for more details.
12
+
13
+ You should have received a copy of the GNU General Public License
14
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
data/README.markdown ADDED
@@ -0,0 +1,33 @@
1
+ CFBackup
2
+ =========
3
+
4
+ CFBackup is a small ruby program that transfers files or directories from the
5
+ local machine to a Cloud Files container. It is meant to serve as a useful tool
6
+ for automated backups.
7
+
8
+ Features
9
+ -----------
10
+
11
+ * Backup a single file or directory (recursion uses pseudo directories)
12
+ * Pipe data straight to container
13
+ * Free transfers over local Rackspace network for Slicehost/Cloud Server
14
+ customers in DFW1 datacenter
15
+
16
+ Requirements
17
+ --------------
18
+
19
+ TODO: Complete this area
20
+ * ruby-cloudfiles
21
+
22
+ Install
23
+ -----------
24
+
25
+ * gem sources -a http://gems.github.com
26
+ * sudo gem install jmstacey-cfbackup
27
+
28
+ Depending on what Operating System you're using, you may be required to install libs that are outside of the gem world.
29
+
30
+ Copyright
31
+ ------------
32
+
33
+ Copyright (c) 2009 Jon Stacey. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "cfbackup"
8
+ gem.summary = %Q{TODO}
9
+ gem.email = "jon@jonsview.com"
10
+ gem.homepage = "http://github.com/jmstacey/cfbackup"
11
+ gem.authors = ["Jon Stacey"]
12
+
13
+ # dependencies
14
+ gem.add_dependency('jmstacey-ruby-cloudfiles', '>=1.3.3')
15
+
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/*_test.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ if File.exist?('VERSION.yml')
48
+ config = YAML.load(File.read('VERSION.yml'))
49
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
50
+ else
51
+ version = ""
52
+ end
53
+
54
+ rdoc.rdoc_dir = 'rdoc'
55
+ rdoc.title = "cfbackup #{version}"
56
+ rdoc.rdoc_files.include('README*')
57
+ rdoc.rdoc_files.include('lib/**/*.rb')
58
+ end
59
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 5
4
+ :patch: 0
data/bin/cfbackup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'CFBackup'
4
+
5
+ backup = CFBackup.new(ARGV)
6
+ backup::run
@@ -0,0 +1,85 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ class OptCFBackup
5
+
6
+ # Options structure
7
+ attr_reader :options
8
+
9
+ # Ussage message
10
+ attr_reader :banner
11
+
12
+ # Initializes object with command line arguments passed
13
+ def initialize(args)
14
+
15
+ @banner = "Usage: cfbackup.rb [options] --pipe_data|--local_path PATH --container CONTAINER"
16
+
17
+ @options = OpenStruct.new
18
+ self.options.config = ['~/.cfconfig.yml', './cfconfig.yml', '/etc/cfconfig.yml']
19
+ self.options.pipe_data = false
20
+ self.options.show_ver = false
21
+ self.options.recursive = false
22
+ self.options.restore = false
23
+ self.options.local_net = false
24
+ self.options.container = ''
25
+ self.options.local_path = ''
26
+ self.options.remote_path = ''
27
+ self.options.verbose = false;
28
+
29
+ opts = OptionParser.new do |opts|
30
+ opts.banner = self.banner
31
+
32
+ opts.on("--pipe_data", "Pipe data from another application and stream it to Cloud Files") do |pipe|
33
+ self.options.pipe_data = pipe
34
+ end
35
+
36
+ opts.on("-r", "--recursive", "Traverse local path recursivley") do |recursive|
37
+ self.options.recursive = recursive
38
+ end
39
+
40
+ opts.on("-v", "--verbose", "Run verbosely") do |verbose|
41
+ self.options.verbose = verbose
42
+ end
43
+
44
+ opts.on("--local_path LOCAL_PATH", "Local path or file") do |local_path|
45
+ self.options.local_path = local_path
46
+ end
47
+
48
+ opts.on("--container CONTAINER", "Cloud Files container name") do |name|
49
+ self.options.container, self.options.remote_path = name.split(":", 2)
50
+ clean_remote_path unless (self.options.remote_path.nil?)
51
+ end
52
+
53
+ opts.on("--restore", "Restore files to local path") do |restore|
54
+ self.options.restore = restore
55
+ end
56
+
57
+ opts.on("--version", "Show current version") do |version|
58
+ self.options.show_ver = version
59
+ end
60
+
61
+ opts.on("--config_file PATH", "Use specified config file, rather than the default") do |config|
62
+ self.options.config << config
63
+ end
64
+
65
+ opts.on("--local_net", "Use unmetered connection in DFW1 (only applicable to Slicehost or Mosso Cloud Server customers)") do |local_net|
66
+ self.options.local_net = local_net
67
+ end
68
+
69
+ end
70
+
71
+ opts.parse!(args)
72
+
73
+ end # parse()
74
+
75
+ private
76
+
77
+ def clean_remote_path
78
+ if self.options.remote_path[0,1] == "/"
79
+ self.options.remote_path.slice!(0)
80
+ end
81
+ # Won't work for piped data. Might result in "text.txt/"
82
+ # self.options.remote_path = self.options.remote_path + "/" unless (self.options.remote_path[-1,1] == "/")
83
+ end
84
+
85
+ end # class OptCFBackup
data/lib/cfbackup.rb ADDED
@@ -0,0 +1,162 @@
1
+ # CFBackup, a small utility script to backup files to Mosso Cloud Files
2
+ # Copyright (C) 2009 Jon Stacey
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation, either version 3 of the License, or
7
+ # (at your option) any later version.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ require 'rubygems'
18
+ require 'cloudfiles'
19
+ require 'OptCFBackup'
20
+ require 'yaml'
21
+
22
+ class CFBackup
23
+
24
+ def initialize(args)
25
+ @opts = OptCFBackup.new(args)
26
+
27
+ # Special case if the version is requested
28
+ if @opts.options.show_ver
29
+ version_file = File.join(File.dirname(__FILE__), '..', 'VERSION.yml')
30
+ config = YAML::load(File.open(version_file))
31
+ show_error("CFBackup v#{config[:major]}.#{config[:minor]}.#{config[:patch]}")
32
+ end
33
+
34
+ # Locate and load config file
35
+ @opts.options.config.each do |path|
36
+ if (File.exist?(path))
37
+ @conf = YAML::load(File.open(path))
38
+ break
39
+ end
40
+ end
41
+ show_error('Error: Unable to locate config file.') unless (@conf != nil)
42
+
43
+ end # initialize()
44
+
45
+ def run
46
+
47
+ show_error() unless (@opts.options.container != "")
48
+
49
+ if @opts.options.pipe_data
50
+ prep_container
51
+ run_piped_data
52
+ elsif @opts.options.local_path != ""
53
+ prep_container
54
+
55
+ if @opts.options.restore
56
+ run_restore
57
+ else
58
+ run_backup
59
+ end
60
+ else
61
+ show_error()
62
+ end
63
+
64
+ end # run()
65
+
66
+ private
67
+
68
+ def prep_container
69
+
70
+ # Establish connection
71
+ show_verbose "Establishing connection...", false
72
+ @cf = CloudFiles::Connection.new(@conf["username"], @conf["api_key"]);
73
+ show_verbose " done."
74
+
75
+ # Special option for Slicehost customers in DFW datacenter
76
+ if @opts.options.local_net
77
+ @cf.storagehost = 'snet-storage.clouddrive.com'
78
+ end
79
+
80
+ # Check for the container. If it doesn't exist, create it.
81
+ unless @cf.container_exists?(@opts.options.container)
82
+ show_verbose "Conainer '#{@opts.options.container}' does not exist. Creating it...", false
83
+ @cf.create_container(@opts.options.container)
84
+ show_verbose " done."
85
+ end
86
+
87
+ @container = @cf.container(@opts.options.container)
88
+
89
+ end # prepConnection()
90
+
91
+ def run_piped_data
92
+ puts "Warning: 5GB per stream cap"
93
+ object = @container.create_object(@opts.options.remote_path, true)
94
+ object.write("STDIN")
95
+ end
96
+
97
+ def run_backup
98
+
99
+ path = @opts.options.local_path
100
+
101
+ if FileTest::file?(path)
102
+ Dir.chdir(File::dirname(path))
103
+ glob_options = File.join(File::basename(path))
104
+ elsif @opts.options.recursive
105
+ Dir.chdir(path)
106
+ glob_options = File.join("**", "*")
107
+ else
108
+ Dir.chdir(path)
109
+ glob_options = File.join("*")
110
+ end
111
+ files = Dir.glob(glob_options)
112
+
113
+ # Upload file(s)
114
+ files.each do |file|
115
+ file = file.sub(/\.\//, '')
116
+ if file == "" || file[0,1] == "." || FileTest.directory?(file)
117
+ next
118
+ end
119
+
120
+ show_verbose "Uploading #{file}...", false
121
+ object = @container.create_object(file, true)
122
+ object.load_from_filename(file)
123
+ show_verbose " done."
124
+ end # files.each
125
+
126
+ end # run_backup()
127
+
128
+ def run_restore
129
+
130
+ # TODO: Implement run_restore
131
+ # We have to do a bit of fancy footwork to make directories work
132
+ puts "Oops! Restore hasn't been implemented yet. Help me out and submit a patch :-)"
133
+
134
+ end # run_restore()
135
+
136
+ # Shows given message if verbose output is turned on
137
+ def show_verbose(message, line_break = true)
138
+
139
+ unless !@opts.options.verbose
140
+ if line_break
141
+ puts message
142
+ else
143
+ print message
144
+ end
145
+
146
+ $stdout.flush
147
+ end
148
+
149
+ end # show_verbose()
150
+
151
+ # Show error message, banner and exit
152
+ def show_error(message = '')
153
+ puts message
154
+ puts @opts.banner
155
+ exit
156
+ end # show_error()
157
+
158
+ def parse_container_path(container)
159
+ # Split based on :
160
+ end # parse_container_path()
161
+
162
+ end # class CFBackup
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class CfbackupTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
data/test/data.txt ADDED
@@ -0,0 +1,11 @@
1
+ TEST LINE
2
+ And some more
3
+ date
4
+ This file will
5
+ be used in the
6
+ piping test to make
7
+ sure that we can
8
+ pipe date directly
9
+ into a container
10
+ using standard
11
+ input.
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'cfbackup'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jmstacey-cfbackup
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Jon Stacey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-19 00:00:00 -07:00
13
+ default_executable: cfbackup
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: jmstacey-ruby-cloudfiles
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.3
24
+ version:
25
+ description:
26
+ email: jon@jonsview.com
27
+ executables:
28
+ - cfbackup
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - LICENSE
33
+ - README.markdown
34
+ files:
35
+ - CHANGELOG.markdown
36
+ - LICENSE
37
+ - README.markdown
38
+ - Rakefile
39
+ - VERSION.yml
40
+ - bin/cfbackup
41
+ - lib/OptCFBackup.rb
42
+ - lib/cfbackup.rb
43
+ - test/cfbackup_test.rb
44
+ - test/data.txt
45
+ - test/test_helper.rb
46
+ has_rdoc: true
47
+ homepage: http://github.com/jmstacey/cfbackup
48
+ post_install_message:
49
+ rdoc_options:
50
+ - --charset=UTF-8
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.2.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: TODO
72
+ test_files:
73
+ - test/cfbackup_test.rb
74
+ - test/test_helper.rb