understudy 0.0.8 → 0.0.9
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.
- data/Gemfile +0 -12
- data/bin/understudy +5 -116
- data/lib/understudy/cli.rb +103 -0
- data/lib/understudy/version.rb +1 -1
- data/lib/understudy.rb +2 -1
- data/understudy.gemspec +7 -0
- metadata +122 -17
- checksums.yaml +0 -7
- data/spec/lib/stage_spec.rb +0 -18
- data/spec/understudy_spec.rb +0 -8
data/Gemfile
CHANGED
@@ -2,15 +2,3 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in understudy.gemspec
|
4
4
|
gemspec
|
5
|
-
|
6
|
-
group :development, :test do
|
7
|
-
gem "rspec", "~> 2"
|
8
|
-
gem "rake"
|
9
|
-
gem "coveralls"
|
10
|
-
gem "fakefs"
|
11
|
-
end
|
12
|
-
|
13
|
-
group :development do
|
14
|
-
gem "bundler", "~> 1.3"
|
15
|
-
gem 'guard-rspec', :require => false
|
16
|
-
end
|
data/bin/understudy
CHANGED
@@ -1,119 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require 'fileutils'
|
7
|
-
require 'rdiff_simple'
|
3
|
+
# Trap interrupts to quit cleanly.
|
4
|
+
# See https://twitter.com/mitchellh/status/283014103189053442
|
5
|
+
Signal.trap("INT") { exit 1 }
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
usage = "Usage: understudy [options] job-name"
|
13
|
-
|
14
|
-
OptionParser.new do |opts|
|
15
|
-
opts.banner = usage
|
16
|
-
opts.on '-v', '--verbose', 'Output extra information' do |v|
|
17
|
-
@verbose = v
|
18
|
-
end
|
19
|
-
opts.on '-f', '--first-time', 'Force first-time run' do |f|
|
20
|
-
options.first = f
|
21
|
-
end
|
22
|
-
end.parse!
|
23
|
-
|
24
|
-
def error msg
|
25
|
-
STDERR.puts "ERROR: #{msg}"
|
26
|
-
exit 255
|
27
|
-
end
|
28
|
-
|
29
|
-
error usage if ARGV.length != 1
|
30
|
-
|
31
|
-
job_name = ARGV.shift
|
32
|
-
|
33
|
-
config_file = "/etc/understudy/#{job_name}.conf"
|
34
|
-
|
35
|
-
error "Cannot find '#{config_file}'" unless File.exist? config_file
|
36
|
-
|
37
|
-
DATA_DIR = "/var/lib/understudy/#{job_name}"
|
38
|
-
|
39
|
-
FileUtils.mkdir_p DATA_DIR
|
40
|
-
|
41
|
-
lockfile = File.open( "#{DATA_DIR}/LOCK", File::RDWR|File::CREAT, 0644 )
|
42
|
-
unless lockfile.flock File::LOCK_EX|File::LOCK_NB
|
43
|
-
error "Job #{job_name} is already running"
|
44
|
-
end
|
45
|
-
lockfile.puts $$
|
46
|
-
lockfile.flush
|
47
|
-
|
48
|
-
config = OpenStruct.new
|
49
|
-
|
50
|
-
# Any options that aren't our options go to rdiff-backup
|
51
|
-
OUR_OPTIONS = %w{source dest command}
|
52
|
-
|
53
|
-
rdiff_args = []
|
54
|
-
|
55
|
-
File.read( config_file ).split( /\n/ ).each do |line|
|
56
|
-
line.sub! /#.*$/, ''
|
57
|
-
line.sub! /^\s+/, ''
|
58
|
-
line.sub! /\s+$/, ''
|
59
|
-
next if line.empty?
|
60
|
-
|
61
|
-
line =~ /^([-\w]+)(\s+=\s+(.*))?$/ or raise "Strange line in config: #{line}"
|
62
|
-
key = $1
|
63
|
-
val = $3
|
64
|
-
if OUR_OPTIONS.member? key
|
65
|
-
config.send "#{key}=".to_sym, val
|
66
|
-
else
|
67
|
-
rdiff_args.push "--#{key}" + ( val ? "=#{val}" : "" )
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
error "Missing 'dest' config option" unless config.dest
|
72
|
-
error "Missing 'source' config option" unless config.source
|
73
|
-
|
74
|
-
rdiff_data = "#{config.dest}/rdiff-backup-data"
|
75
|
-
exists = File.directory? rdiff_data
|
76
|
-
if exists && options.first
|
77
|
-
error "Cannot force first time, destination '#{config.dest}' already exists"
|
78
|
-
elsif !exists && !options.first
|
79
|
-
error "Destination '#{config.dest}' does not appear to exist, try again with --first-time"
|
80
|
-
end
|
81
|
-
|
82
|
-
def info message
|
83
|
-
return unless @verbose
|
84
|
-
end
|
85
|
-
|
86
|
-
def run command
|
87
|
-
friendly = nil
|
88
|
-
if command.is_a? Array
|
89
|
-
friendly = command.map { |i| i =~ /[^-=\/\.\w]/ ? "#{i}" : i }.join ' '
|
90
|
-
info "Running: #{friendly}"
|
91
|
-
RdiffSimple.execute( friendly ) or error "Could not run #{friendly}"
|
92
|
-
else
|
93
|
-
friendly = command
|
94
|
-
info "Running: #{friendly}"
|
95
|
-
RdiffSimple.execute( friendly ) or error "Could not run #{friendly}"
|
96
|
-
end
|
97
|
-
if $? != 0
|
98
|
-
error "Could not run #{friendly}"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
ENV['PATH'] += ":/etc/understudy"
|
103
|
-
run config.command if config.command
|
104
|
-
|
105
|
-
command = []
|
106
|
-
|
107
|
-
command << "--terminal-verbosity=5" if @verbose
|
108
|
-
command << "--print-statistics"
|
109
|
-
|
110
|
-
command += rdiff_args
|
111
|
-
|
112
|
-
command << config.source
|
113
|
-
command << config.dest
|
114
|
-
|
115
|
-
run command
|
116
|
-
|
117
|
-
info "Backup successful"
|
118
|
-
|
119
|
-
exit 0
|
7
|
+
require 'understudy'
|
8
|
+
Understudy::CLI.start
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Understudy
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
desc "perform [job]", "Perform backup [job]"
|
8
|
+
method_option :verbose, type: :boolean, banner: "Enable verbose output mode", aliases: "-v", default: false
|
9
|
+
method_option "first-time", type: :boolean, banner: "Force first-time run", aliases: "-f", default: false
|
10
|
+
def perform(job)
|
11
|
+
ENV['PATH'] += ":/etc/understudy"
|
12
|
+
ENV['TMPDIR']='/tmp/understudy/'
|
13
|
+
|
14
|
+
log = Logger.new(STDOUT)
|
15
|
+
log.level = Logger::INFO if options[:verbose]
|
16
|
+
|
17
|
+
job_name = job
|
18
|
+
|
19
|
+
config_file = "/etc/understudy/#{job_name}.conf"
|
20
|
+
|
21
|
+
log.error "Cannot find '#{config_file}'" unless File.exist? config_file
|
22
|
+
|
23
|
+
data_dir = "/tmp/understudy-#{job_name}"
|
24
|
+
|
25
|
+
FileUtils.mkdir_p data_dir
|
26
|
+
|
27
|
+
lockfile = File.open( "#{data_dir}/LOCK", File::RDWR|File::CREAT, 0644 )
|
28
|
+
unless lockfile.flock File::LOCK_EX|File::LOCK_NB
|
29
|
+
log.error "Job #{job_name} is already running"
|
30
|
+
end
|
31
|
+
lockfile.puts $$
|
32
|
+
lockfile.flush
|
33
|
+
|
34
|
+
config = OpenStruct.new
|
35
|
+
|
36
|
+
# Any options that aren't our options go to rdiff-backup
|
37
|
+
our_options = %w{source dest command}
|
38
|
+
|
39
|
+
rdiff_args = []
|
40
|
+
|
41
|
+
File.read( config_file ).split( /\n/ ).each do |line|
|
42
|
+
line.sub! /#.*$/, ''
|
43
|
+
line.sub! /^\s+/, ''
|
44
|
+
line.sub! /\s+$/, ''
|
45
|
+
next if line.empty?
|
46
|
+
|
47
|
+
line =~ /^([-\w]+)(\s+=\s+(.*))?$/ or raise "Strange line in config: #{line}"
|
48
|
+
key = $1
|
49
|
+
val = $3
|
50
|
+
if our_options.member? key
|
51
|
+
config.send "#{key}=".to_sym, val
|
52
|
+
else
|
53
|
+
rdiff_args.push "--#{key}" + ( val ? "=#{val}" : "" )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
log.error "Missing 'dest' config option" unless config.dest
|
58
|
+
log.error "Missing 'source' config option" unless config.source
|
59
|
+
|
60
|
+
rdiff_data = "#{config.dest}/rdiff-backup-data"
|
61
|
+
exists = File.directory? rdiff_data
|
62
|
+
|
63
|
+
if exists && options["first-time"]
|
64
|
+
log.error "Cannot force first time, destination '#{config.dest}' already exists"
|
65
|
+
elsif !exists && !options["first-time"]
|
66
|
+
log.error "Destination '#{config.dest}' does not appear to exist, try again with --first-time"
|
67
|
+
end
|
68
|
+
|
69
|
+
run config.command if config.command
|
70
|
+
|
71
|
+
command = []
|
72
|
+
|
73
|
+
command << "--terminal-verbosity=5" if options[:verbose]
|
74
|
+
command << "--print-statistics"
|
75
|
+
|
76
|
+
command += rdiff_args
|
77
|
+
|
78
|
+
command << config.source
|
79
|
+
command << config.dest
|
80
|
+
|
81
|
+
run command, log
|
82
|
+
|
83
|
+
log.info "Backup successful"
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
def run(command, log)
|
88
|
+
friendly = nil
|
89
|
+
if command.is_a? Array
|
90
|
+
friendly = command.map { |i| i =~ /[^-=\/\.\w]/ ? "#{i}" : i }.join ' '
|
91
|
+
log.info "Running: #{friendly}"
|
92
|
+
RdiffSimple.execute( friendly ) or log.error "Could not run #{friendly}"
|
93
|
+
else
|
94
|
+
friendly = command
|
95
|
+
log.info "Running: #{friendly}"
|
96
|
+
RdiffSimple.execute( friendly ) or log.error "Could not run #{friendly}"
|
97
|
+
end
|
98
|
+
if $? != 0
|
99
|
+
log.error "Could not run #{friendly}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/understudy/version.rb
CHANGED
data/lib/understudy.rb
CHANGED
data/understudy.gemspec
CHANGED
@@ -23,4 +23,11 @@ Gem::Specification.new do |spec|
|
|
23
23
|
|
24
24
|
spec.add_dependency "thor"
|
25
25
|
spec.add_dependency "rdiff-simple"
|
26
|
+
|
27
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
28
|
+
spec.add_development_dependency "rake"
|
29
|
+
spec.add_development_dependency "rspec", "~> 2"
|
30
|
+
spec.add_development_dependency "coveralls"
|
31
|
+
spec.add_development_dependency "fakefs"
|
32
|
+
spec.add_development_dependency "guard-rspec"
|
26
33
|
end
|
metadata
CHANGED
@@ -1,43 +1,144 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: understudy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.9
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Ryan Hansen
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
+
date: 2013-08-09 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ! '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
none: false
|
21
|
+
prerelease: false
|
14
22
|
name: thor
|
23
|
+
type: :runtime
|
15
24
|
requirement: !ruby/object:Gem::Requirement
|
16
25
|
requirements:
|
17
|
-
- - '>='
|
26
|
+
- - ! '>='
|
18
27
|
- !ruby/object:Gem::Version
|
19
28
|
version: '0'
|
29
|
+
none: false
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
version_requirements: !ruby/object:Gem::Requirement
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
none: false
|
37
|
+
prerelease: false
|
38
|
+
name: rdiff-simple
|
20
39
|
type: :runtime
|
40
|
+
requirement: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
none: false
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ~>
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '1.3'
|
52
|
+
none: false
|
21
53
|
prerelease: false
|
54
|
+
name: bundler
|
55
|
+
type: :development
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.3'
|
61
|
+
none: false
|
62
|
+
- !ruby/object:Gem::Dependency
|
22
63
|
version_requirements: !ruby/object:Gem::Requirement
|
23
64
|
requirements:
|
24
|
-
- - '>='
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
none: false
|
69
|
+
prerelease: false
|
70
|
+
name: rake
|
71
|
+
type: :development
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
25
75
|
- !ruby/object:Gem::Version
|
26
76
|
version: '0'
|
77
|
+
none: false
|
27
78
|
- !ruby/object:Gem::Dependency
|
28
|
-
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '2'
|
84
|
+
none: false
|
85
|
+
prerelease: false
|
86
|
+
name: rspec
|
87
|
+
type: :development
|
29
88
|
requirement: !ruby/object:Gem::Requirement
|
30
89
|
requirements:
|
31
|
-
- -
|
90
|
+
- - ~>
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '2'
|
93
|
+
none: false
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
version_requirements: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
32
98
|
- !ruby/object:Gem::Version
|
33
99
|
version: '0'
|
34
|
-
|
100
|
+
none: false
|
101
|
+
prerelease: false
|
102
|
+
name: coveralls
|
103
|
+
type: :development
|
104
|
+
requirement: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
none: false
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
none: false
|
35
117
|
prerelease: false
|
118
|
+
name: fakefs
|
119
|
+
type: :development
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ! '>='
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
none: false
|
126
|
+
- !ruby/object:Gem::Dependency
|
36
127
|
version_requirements: !ruby/object:Gem::Requirement
|
37
128
|
requirements:
|
38
|
-
- - '>='
|
129
|
+
- - ! '>='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
none: false
|
133
|
+
prerelease: false
|
134
|
+
name: guard-rspec
|
135
|
+
type: :development
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ! '>='
|
39
139
|
- !ruby/object:Gem::Version
|
40
140
|
version: '0'
|
141
|
+
none: false
|
41
142
|
description: Automated system backups via rdiff-backup
|
42
143
|
email:
|
43
144
|
- ketiko@gmail.com
|
@@ -58,16 +159,14 @@ files:
|
|
58
159
|
- Rakefile
|
59
160
|
- bin/understudy
|
60
161
|
- lib/understudy.rb
|
162
|
+
- lib/understudy/cli.rb
|
61
163
|
- lib/understudy/stage.rb
|
62
164
|
- lib/understudy/version.rb
|
63
|
-
- spec/lib/stage_spec.rb
|
64
165
|
- spec/spec_helper.rb
|
65
|
-
- spec/understudy_spec.rb
|
66
166
|
- understudy.gemspec
|
67
167
|
homepage: http://github.com/ketiko/understudy
|
68
168
|
licenses:
|
69
169
|
- MIT
|
70
|
-
metadata: {}
|
71
170
|
post_install_message:
|
72
171
|
rdoc_options:
|
73
172
|
- --charset=UTF-8
|
@@ -75,21 +174,27 @@ require_paths:
|
|
75
174
|
- lib
|
76
175
|
required_ruby_version: !ruby/object:Gem::Requirement
|
77
176
|
requirements:
|
78
|
-
- - '>='
|
177
|
+
- - ! '>='
|
79
178
|
- !ruby/object:Gem::Version
|
179
|
+
segments:
|
180
|
+
- 0
|
181
|
+
hash: 3610360581697942929
|
80
182
|
version: '0'
|
183
|
+
none: false
|
81
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
185
|
requirements:
|
83
|
-
- - '>='
|
186
|
+
- - ! '>='
|
84
187
|
- !ruby/object:Gem::Version
|
188
|
+
segments:
|
189
|
+
- 0
|
190
|
+
hash: 3610360581697942929
|
85
191
|
version: '0'
|
192
|
+
none: false
|
86
193
|
requirements: []
|
87
194
|
rubyforge_project:
|
88
|
-
rubygems_version:
|
195
|
+
rubygems_version: 1.8.23
|
89
196
|
signing_key:
|
90
|
-
specification_version:
|
197
|
+
specification_version: 3
|
91
198
|
summary: Automated system backups via rdiff-backup
|
92
199
|
test_files:
|
93
|
-
- spec/lib/stage_spec.rb
|
94
200
|
- spec/spec_helper.rb
|
95
|
-
- spec/understudy_spec.rb
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: a0878c926cb6750c7670444a59b2eb790a634232
|
4
|
-
data.tar.gz: 5936917e05495ad5dcc334e98c1f64a1cf7370fe
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: 10082a9e57c61cb860c460553164d6207a9f81e8d252a4091107e75bd66b685acfd196d5ac8ed90fd02825d32f9b2813ebee564e95c0cc07c10c13595f9405b9
|
7
|
-
data.tar.gz: 98849071bb5e28420693abca8a9a6ba561d2388037bd97f016b07072b676ae8bbea71f2c91edc6d1873a583bb28897f4ca3e3d2afe142e26bc2df9cfa815f243
|
data/spec/lib/stage_spec.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Understudy::Stage do
|
4
|
-
describe "#setup" do
|
5
|
-
before(:each) do
|
6
|
-
Understudy::Stage.setup
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should create the default configuration directory" do
|
10
|
-
File.exists?(Understudy::Stage::DEFAULT_DIRECTORY).should be_true
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should a configuration file for the machine" do
|
14
|
-
File.exists?(File.join(Understudy::Stage::DEFAULT_DIRECTORY, "#{`hostname`.chomp}.config")).should be_true
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|