rbfs 0.0.2 → 0.0.3
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/.travis.yml +7 -0
- data/Rakefile +3 -0
- data/bin/rbfs +3 -6
- data/lib/rbfs.rb +0 -2
- data/lib/rbfs/args.rb +9 -0
- data/lib/rbfs/command.rb +67 -4
- data/lib/rbfs/futures.rb +27 -0
- data/lib/rbfs/host.rb +4 -4
- data/lib/rbfs/host_parser.rb +20 -0
- data/lib/rbfs/logger.rb +26 -0
- data/lib/rbfs/rsync.rb +28 -6
- data/lib/rbfs/version.rb +1 -1
- data/rbfs.gemspec +1 -0
- data/spec/rbfs/host_parser_spec.rb +30 -0
- data/spec/rbfs/host_spec.rb +38 -0
- data/spec/rbfs/rsync_spec.rb +23 -0
- metadata +27 -7
- data/lib/rbfs/hosts.rb +0 -17
data/.travis.yml
ADDED
data/Rakefile
CHANGED
data/bin/rbfs
CHANGED
@@ -2,9 +2,6 @@
|
|
2
2
|
require 'rbfs'
|
3
3
|
require 'rbfs/command'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
puts "#{host} (#{host.ip})" if config[:verbose]
|
9
|
-
host.sync(config)
|
10
|
-
end
|
5
|
+
command = Rbfs::Command.new
|
6
|
+
success = command.sync
|
7
|
+
exit 1 unless success
|
data/lib/rbfs.rb
CHANGED
data/lib/rbfs/args.rb
CHANGED
@@ -16,12 +16,21 @@ module Rbfs
|
|
16
16
|
opts.on("-r", "--root ROOT", "Root path to sync") do |v|
|
17
17
|
options[:root] = v
|
18
18
|
end
|
19
|
+
opts.on("-s", "--subpath PATH", "Subpath of root to sync") do |v|
|
20
|
+
options[:subpath] = v
|
21
|
+
end
|
19
22
|
opts.on("-v", "--[no-]verbose", "Print extra debugging info") do |v|
|
20
23
|
options[:verbose] = v
|
21
24
|
end
|
22
25
|
opts.on("-d", "--dry", "Test config settings") do |v|
|
23
26
|
options[:dry] = v
|
24
27
|
end
|
28
|
+
opts.on("-t", "--[no-]threaded", "Run all hosts concurrently") do |v|
|
29
|
+
options[:threaded] = v
|
30
|
+
end
|
31
|
+
opts.on("--timeout TIMEOUT", "Set I/O timeout") do |v|
|
32
|
+
options[:timeout] = v
|
33
|
+
end
|
25
34
|
end.parse!
|
26
35
|
|
27
36
|
options
|
data/lib/rbfs/command.rb
CHANGED
@@ -1,12 +1,75 @@
|
|
1
1
|
require 'rbfs/args'
|
2
2
|
require 'rbfs/config'
|
3
|
+
require "rbfs/host_parser"
|
4
|
+
require "rbfs/rsync"
|
5
|
+
require "rbfs/futures"
|
6
|
+
require "rbfs/logger"
|
3
7
|
|
4
8
|
module Rbfs
|
5
9
|
class Command
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
+
attr_accessor :config
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@config = parse_config
|
14
|
+
logger.critical "No hosts file specified" unless config[:hosts]
|
15
|
+
logger.critical "Root path not specified" unless config[:root]
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse_config
|
19
|
+
config = {}
|
20
|
+
cmdline_args = Rbfs::Args.new.parse
|
21
|
+
if cmdline_args[:config]
|
22
|
+
config_args = Rbfs::Config.new(cmdline_args[:config]).parse
|
23
|
+
config = config_args.merge(cmdline_args)
|
24
|
+
else
|
25
|
+
config = cmdline_args
|
26
|
+
end
|
27
|
+
config[:logger] = Logger.new(config)
|
28
|
+
config
|
29
|
+
end
|
30
|
+
|
31
|
+
def logger
|
32
|
+
@config[:logger]
|
33
|
+
end
|
34
|
+
|
35
|
+
def sync
|
36
|
+
success = true
|
37
|
+
results = sync_hosts
|
38
|
+
results.each do |host, result|
|
39
|
+
if result[:exitcode] != 0
|
40
|
+
logger.error "#{host}: #{result[:exitcode].to_i}"
|
41
|
+
else
|
42
|
+
logger.info "#{host}: #{result[:exitcode].to_i}"
|
43
|
+
end
|
44
|
+
result[:output].split("\n").each do |line|
|
45
|
+
if result[:exitcode] != 0
|
46
|
+
logger.error " | #{line}"
|
47
|
+
else
|
48
|
+
logger.info " | #{line}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
success = false if result[:exitcode] != 0
|
52
|
+
end
|
53
|
+
success
|
54
|
+
end
|
55
|
+
|
56
|
+
def sync_hosts
|
57
|
+
config[:root] = File.join(config[:root], config[:subpath]) if config[:subpath]
|
58
|
+
logger.info "Syncing #{config[:root]}..."
|
59
|
+
hosts = Rbfs::HostParser.new(File.open(config[:hosts]))
|
60
|
+
hosts.collect do |host|
|
61
|
+
[host, sync_host(host)]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def sync_host(host)
|
66
|
+
if config[:threaded]
|
67
|
+
Future.new do
|
68
|
+
Rsync.new(config, host).sync
|
69
|
+
end
|
70
|
+
else
|
71
|
+
Rsync.new(config, host).sync
|
72
|
+
end
|
10
73
|
end
|
11
74
|
end
|
12
75
|
end
|
data/lib/rbfs/futures.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Rbfs
|
2
|
+
class Future < BasicObject
|
3
|
+
def initialize(&callable)
|
4
|
+
@thread ||= ::Thread.new { callable.call }
|
5
|
+
end
|
6
|
+
|
7
|
+
def value
|
8
|
+
@thread.value
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
if @thread.alive?
|
13
|
+
"#<Future running>"
|
14
|
+
else
|
15
|
+
value.inspect
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method, *args)
|
20
|
+
value.send(method, *args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to_missing?(method, include_private = false)
|
24
|
+
value.respond_to?(method, include_private)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/rbfs/host.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rbfs/host"
|
2
|
+
|
3
|
+
module Rbfs
|
4
|
+
class HostParser
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize(file)
|
8
|
+
@file = file
|
9
|
+
end
|
10
|
+
|
11
|
+
def each(&block)
|
12
|
+
lines = @file.read.split("\n")
|
13
|
+
lines.reject! {|line| line.strip.start_with? "#" }
|
14
|
+
lines.reject! {|line| line.strip.empty? }
|
15
|
+
lines.each do |line|
|
16
|
+
yield(Host.new(line))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rbfs/logger.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rbfs
|
2
|
+
class Logger
|
3
|
+
attr_reader :config
|
4
|
+
|
5
|
+
def initialize(config)
|
6
|
+
@config = config
|
7
|
+
end
|
8
|
+
|
9
|
+
def info(msg)
|
10
|
+
puts "\033[0;32m#{msg}" if config[:verbose]
|
11
|
+
end
|
12
|
+
|
13
|
+
def error(msg)
|
14
|
+
puts "\033[0;31m#{msg}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def critical(msg)
|
18
|
+
puts "\033[0;31m#{msg}"
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def notice(msg)
|
23
|
+
puts "\033[0;33m#{msg}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rbfs/rsync.rb
CHANGED
@@ -1,10 +1,32 @@
|
|
1
1
|
module Rbfs
|
2
|
-
|
3
|
-
def
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
class Rsync
|
3
|
+
def initialize(config = {}, host = nil)
|
4
|
+
@config = config
|
5
|
+
@host = host
|
6
|
+
end
|
7
|
+
|
8
|
+
def sync
|
9
|
+
args = ["-ae", "ssh", "--delete", @config[:root], "#{@host.ip}:#{@config[:root]}"]
|
10
|
+
args << "-v" if @config[:verbose]
|
11
|
+
args << "-n" if @config[:dry]
|
12
|
+
args << "--timeout=#{@config[:timeout]}" if @config[:timeout]
|
13
|
+
output = command("rsync", args)
|
14
|
+
exitcode = $?
|
15
|
+
{:output => output, :exitcode => exitcode}
|
16
|
+
end
|
17
|
+
|
18
|
+
def command(cmd, options = [], &block)
|
19
|
+
cmd_line = "#{cmd} "
|
20
|
+
cmd_line += options.join(' ')
|
21
|
+
run_command(cmd_line, &block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_command(cmd, &block)
|
25
|
+
if block_given?
|
26
|
+
IO.popen("#{cmd} 2>&1", &block)
|
27
|
+
else
|
28
|
+
`#{cmd} 2>&1`
|
29
|
+
end
|
8
30
|
end
|
9
31
|
end
|
10
32
|
end
|
data/lib/rbfs/version.rb
CHANGED
data/rbfs.gemspec
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rbfs/host_parser'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
describe Rbfs::HostParser do
|
5
|
+
def test_case(string, size)
|
6
|
+
io = StringIO.new(string)
|
7
|
+
hp = Rbfs::HostParser.new(io)
|
8
|
+
hp.collect {|v|v}.length.should eql(size)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should handle a file with only comments" do
|
12
|
+
test_case("# TEST", 0)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should handle a file with one host" do
|
16
|
+
test_case("1.1.1.1 HOSTNAME", 1)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should handle a basic file" do
|
20
|
+
test_case("# TEST\n1.1.1.1 HOSTNAME", 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should handle empty lines" do
|
24
|
+
test_case("\n\n# TEST\n1.1.1.1 HOSTNAME\n\n", 1)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should handle multiple lines" do
|
28
|
+
test_case("1.1.1.1 HOSTNAME\n1.1.1.1 HOSTNAME\n1.1.1.1 HOSTNAME", 3)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'rbfs/host'
|
2
|
+
|
3
|
+
describe Rbfs::Host do
|
4
|
+
def test_example(line, ip, name=nil, alias_name=nil)
|
5
|
+
host = Rbfs::Host.new(line)
|
6
|
+
host.ip.should eql(ip)
|
7
|
+
host.name.should eql(name)
|
8
|
+
host.alias.should eql(alias_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should handle minimal syntax" do
|
12
|
+
test_example("1.1.1.1", "1.1.1.1")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should handle basic syntax" do
|
16
|
+
test_example("1.1.1.1 HOSTNAME", "1.1.1.1", "HOSTNAME")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should handle advanced syntax" do
|
20
|
+
test_example("1.1.1.1 HOSTNAME HOST", "1.1.1.1", "HOSTNAME", "HOST")
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should support tab separation" do
|
24
|
+
test_example("1.1.1.1\tHOSTNAME", "1.1.1.1", "HOSTNAME")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should tolerate lots of tab separation" do
|
28
|
+
test_example("1.1.1.1\t\t\t\t\t\t\tHOSTNAME", "1.1.1.1", "HOSTNAME")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should tolerate lots of spaces" do
|
32
|
+
test_example("1.1.1.1 HOSTNAME", "1.1.1.1", "HOSTNAME")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should tolerate lots of aliases" do
|
36
|
+
test_example("1.1.1.1 HOSTNAME HOSTA HOSTB HOSTC HOSTD", "1.1.1.1", "HOSTNAME", "HOSTA")
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rbfs/rsync'
|
2
|
+
|
3
|
+
describe Rbfs::Rsync do
|
4
|
+
it "should run_command" do
|
5
|
+
Rbfs::Rsync.new.run_command("echo test").should eql("test\n")
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should run_command block" do
|
9
|
+
Rbfs::Rsync.new.run_command("echo test") do |io|
|
10
|
+
io.read.should eql("test\n")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should command" do
|
15
|
+
Rbfs::Rsync.new.command("echo", ["test"]).should eql("test\n")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should command block" do
|
19
|
+
Rbfs::Rsync.new.command("echo", ["test"]) do |io|
|
20
|
+
io.read.should eql("test\n")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbfs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-07-18 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
|
-
requirement: &
|
16
|
+
requirement: &15800280 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '1.3'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *15800280
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &15799780 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,18 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *15799780
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &15799280 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *15799280
|
36
47
|
description: Ruby File Sync
|
37
48
|
email:
|
38
49
|
- jbussdieker@gmail.com
|
@@ -42,6 +53,7 @@ extensions: []
|
|
42
53
|
extra_rdoc_files: []
|
43
54
|
files:
|
44
55
|
- .gitignore
|
56
|
+
- .travis.yml
|
45
57
|
- Gemfile
|
46
58
|
- README.md
|
47
59
|
- Rakefile
|
@@ -50,11 +62,16 @@ files:
|
|
50
62
|
- lib/rbfs/args.rb
|
51
63
|
- lib/rbfs/command.rb
|
52
64
|
- lib/rbfs/config.rb
|
65
|
+
- lib/rbfs/futures.rb
|
53
66
|
- lib/rbfs/host.rb
|
54
|
-
- lib/rbfs/
|
67
|
+
- lib/rbfs/host_parser.rb
|
68
|
+
- lib/rbfs/logger.rb
|
55
69
|
- lib/rbfs/rsync.rb
|
56
70
|
- lib/rbfs/version.rb
|
57
71
|
- rbfs.gemspec
|
72
|
+
- spec/rbfs/host_parser_spec.rb
|
73
|
+
- spec/rbfs/host_spec.rb
|
74
|
+
- spec/rbfs/rsync_spec.rb
|
58
75
|
homepage: ''
|
59
76
|
licenses: []
|
60
77
|
post_install_message:
|
@@ -79,5 +96,8 @@ rubygems_version: 1.8.17
|
|
79
96
|
signing_key:
|
80
97
|
specification_version: 3
|
81
98
|
summary: Ruby File Sync
|
82
|
-
test_files:
|
99
|
+
test_files:
|
100
|
+
- spec/rbfs/host_parser_spec.rb
|
101
|
+
- spec/rbfs/host_spec.rb
|
102
|
+
- spec/rbfs/rsync_spec.rb
|
83
103
|
has_rdoc:
|
data/lib/rbfs/hosts.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require "rbfs/host"
|
2
|
-
|
3
|
-
module Rbfs
|
4
|
-
class Hosts
|
5
|
-
def initialize(file_name)
|
6
|
-
@file_name = file_name
|
7
|
-
end
|
8
|
-
|
9
|
-
def each(&block)
|
10
|
-
lines = File.read(@file_name).split("\n")
|
11
|
-
lines.reject! {|line| line.strip.start_with? "#"}
|
12
|
-
lines.each do |line|
|
13
|
-
yield(Host.new(line))
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|