jmstacey-cfbackup 0.5.0

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.
@@ -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