rbfs 0.0.10 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +4 -22
- data/Rakefile +3 -1
- data/lib/rbfs/args.rb +6 -0
- data/lib/rbfs/command.rb +26 -18
- data/lib/rbfs/rsync.rb +18 -5
- data/lib/rbfs/version.rb +1 -1
- data/rbfs.gemspec +2 -0
- data/spec/rbfs/command_spec.rb +92 -0
- data/spec/rbfs/rsync_spec.rb +1 -1
- metadata +32 -14
- data/lib/rbfs/host.rb +0 -23
- data/lib/rbfs/host_parser.rb +0 -20
- data/spec/rbfs/host_parser_spec.rb +0 -30
- data/spec/rbfs/host_spec.rb +0 -38
data/README.md
CHANGED
@@ -1,29 +1,11 @@
|
|
1
1
|
# Rbfs
|
2
2
|
|
3
|
-
|
3
|
+
[![Build Status](https://travis-ci.org/jbussdieker/ruby-rbfs.png?branch=master)](https://travis-ci.org/jbussdieker/ruby-rbfs)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/jbussdieker/ruby-rbfs.png)](https://codeclimate.com/github/jbussdieker/ruby-rbfs)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/rbfs.png)](http://badge.fury.io/rb/rbfs)
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
Add this line to your application's Gemfile:
|
8
|
-
|
9
|
-
gem 'rbfs'
|
10
|
-
|
11
|
-
And then execute:
|
12
|
-
|
13
|
-
$ bundle
|
14
|
-
|
15
|
-
Or install it yourself as:
|
16
|
-
|
17
|
-
$ gem install rbfs
|
7
|
+
Ruby File Sync
|
18
8
|
|
19
9
|
## Usage
|
20
10
|
|
21
11
|
TODO: Write usage instructions here
|
22
|
-
|
23
|
-
## Contributing
|
24
|
-
|
25
|
-
1. Fork it
|
26
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
-
5. Create new Pull Request
|
data/Rakefile
CHANGED
data/lib/rbfs/args.rb
CHANGED
@@ -16,6 +16,12 @@ 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("-e", "--remote-root ROOT", "Remote root path to sync") do |v|
|
20
|
+
options[:remote_root] = v
|
21
|
+
end
|
22
|
+
opts.on("--shell SHELL", "Remote shell to use") do |v|
|
23
|
+
options[:shell] = v
|
24
|
+
end
|
19
25
|
opts.on("-s", "--subpath PATH", "Subpath of root to sync") do |v|
|
20
26
|
options[:subpath] = v
|
21
27
|
end
|
data/lib/rbfs/command.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
+
require 'hosts_file'
|
1
2
|
require 'rbfs/args'
|
2
3
|
require 'rbfs/config'
|
3
|
-
require "rbfs/host_parser"
|
4
4
|
require "rbfs/rsync"
|
5
5
|
require "rbfs/futures"
|
6
6
|
require "rbfs/logger"
|
@@ -9,10 +9,15 @@ module Rbfs
|
|
9
9
|
class Command
|
10
10
|
attr_accessor :config
|
11
11
|
|
12
|
-
def initialize
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def initialize(config = nil)
|
13
|
+
if config
|
14
|
+
@config = config
|
15
|
+
else
|
16
|
+
@config = parse_config unless config
|
17
|
+
end
|
18
|
+
@config[:logger] = Logger.new(@config)
|
19
|
+
logger.critical "No hosts file specified" unless @config[:hosts]
|
20
|
+
logger.critical "Root path not specified" unless @config[:root]
|
16
21
|
end
|
17
22
|
|
18
23
|
def parse_config
|
@@ -24,7 +29,9 @@ module Rbfs
|
|
24
29
|
else
|
25
30
|
config = cmdline_args
|
26
31
|
end
|
27
|
-
config[:
|
32
|
+
unless config[:remote_root]
|
33
|
+
config[:remote_root] = config[:root]
|
34
|
+
end
|
28
35
|
config
|
29
36
|
end
|
30
37
|
|
@@ -34,25 +41,26 @@ module Rbfs
|
|
34
41
|
|
35
42
|
def sync
|
36
43
|
success = true
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
logger.info "#{host}: #{result[:exitcode].to_i}"
|
43
|
-
end
|
44
|
-
result[:output].split("\n").each do |line|
|
45
|
-
logger.puts " | #{line}"
|
44
|
+
|
45
|
+
sync_hosts.each do |host, result|
|
46
|
+
logger.info "#{host.name}: #{result.error}"
|
47
|
+
result.changes.each do |change|
|
48
|
+
logger.puts " | #{change.filename} (#{change.summary})"
|
46
49
|
end
|
47
|
-
success = false
|
50
|
+
success = false unless result.success?
|
48
51
|
end
|
52
|
+
|
49
53
|
success
|
50
54
|
end
|
51
55
|
|
52
56
|
def sync_hosts
|
53
|
-
|
57
|
+
if config[:subpath]
|
58
|
+
config[:root] = File.join(config[:root], config[:subpath])
|
59
|
+
config[:remote_root] = File.join(config[:remote_root], config[:subpath])
|
60
|
+
end
|
61
|
+
|
54
62
|
logger.info "Syncing #{config[:root]}..."
|
55
|
-
hosts =
|
63
|
+
hosts = HostsFile.load(config[:hosts])
|
56
64
|
hosts.collect do |host|
|
57
65
|
[host, sync_host(host)]
|
58
66
|
end
|
data/lib/rbfs/rsync.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'rsync'
|
2
|
+
|
1
3
|
module Rbfs
|
2
4
|
class Rsync
|
3
5
|
def initialize(config = {}, host = nil)
|
@@ -10,24 +12,35 @@ module Rbfs
|
|
10
12
|
end
|
11
13
|
|
12
14
|
def remote_url
|
13
|
-
"#{@host.ip}:#{@config[:
|
15
|
+
"#{@host.ip}:#{@config[:remote_root]}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def local_root
|
19
|
+
if File.directory?(@config[:root])
|
20
|
+
@config[:root] + "/"
|
21
|
+
else
|
22
|
+
@config[:root]
|
23
|
+
end
|
14
24
|
end
|
15
25
|
|
16
26
|
def mkdir
|
17
|
-
args = [@host.ip, "mkdir", "-p", @config[:
|
27
|
+
args = [@host.ip, "mkdir", "-p", @config[:remote_root]]
|
18
28
|
command("ssh", args)
|
19
29
|
end
|
20
30
|
|
21
31
|
def rsync
|
22
|
-
args = ["-
|
32
|
+
args = ["-a", "--delete"]
|
33
|
+
args << "-e #{@config[:shell]}" if @config[:shell]
|
23
34
|
args << "-v" if @config[:verbose]
|
24
35
|
args << "-n" if @config[:dry]
|
25
36
|
args << "--timeout=#{@config[:timeout]}" if @config[:timeout]
|
26
|
-
|
37
|
+
::Rsync.run(local_root, remote_url, args)
|
27
38
|
end
|
28
39
|
|
29
40
|
def sync
|
30
|
-
|
41
|
+
if File.directory?(@config[:root])
|
42
|
+
mkdir
|
43
|
+
end
|
31
44
|
rsync
|
32
45
|
end
|
33
46
|
|
data/lib/rbfs/version.rb
CHANGED
data/rbfs.gemspec
CHANGED
@@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
+
spec.add_dependency "rsync", "~> 0.0"
|
21
|
+
spec.add_dependency "hosts_file", "~> 0.0"
|
20
22
|
spec.add_development_dependency "bundler", "~> 1.3"
|
21
23
|
spec.add_development_dependency "rake"
|
22
24
|
spec.add_development_dependency "rspec"
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rbfs/command'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
describe Rbfs::Command do
|
5
|
+
def make_test_dir(&block)
|
6
|
+
Dir.mktmpdir do |dir|
|
7
|
+
@tmpdir = dir
|
8
|
+
File.open(File.join(@tmpdir, "hosts"), 'w') {|f| f.write("127.0.0.1 testhost")}
|
9
|
+
Dir.mkdir(File.join(@tmpdir, "local"))
|
10
|
+
Dir.mkdir(File.join(@tmpdir, "remote"))
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_simple_test_dir
|
16
|
+
File.open(File.join(@tmpdir, "local", "sample.txt"), 'w') do |f|
|
17
|
+
f.write("hello world!")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def build_multipath_test_dir
|
22
|
+
Dir.mkdir(File.join(@tmpdir, "local", "somepath"))
|
23
|
+
File.open(File.join(@tmpdir, "local", "somepath", "sample.txt"), 'w') do |f|
|
24
|
+
f.write("hello world!")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def build_deeppath_test_dir
|
29
|
+
Dir.mkdir(File.join(@tmpdir, "local", "somepath"))
|
30
|
+
Dir.mkdir(File.join(@tmpdir, "local", "somepath", "someotherpath"))
|
31
|
+
File.open(File.join(@tmpdir, "local", "somepath", "someotherpath", "sample.txt"), 'w') do |f|
|
32
|
+
f.write("hello world!")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_tree(subpath)
|
37
|
+
`cd #{@tmpdir}/#{subpath}; tree`
|
38
|
+
end
|
39
|
+
|
40
|
+
context "simple", :local => true do
|
41
|
+
around(:each) do |example|
|
42
|
+
make_test_dir do
|
43
|
+
example.run
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should do simple file sync" do
|
48
|
+
build_simple_test_dir
|
49
|
+
Rbfs::Command.new(
|
50
|
+
:hosts => File.join(@tmpdir, "hosts"),
|
51
|
+
:root => File.join(@tmpdir, "local") + "/sample.txt",
|
52
|
+
:shell => '"ssh -o StrictHostKeyChecking=no"',
|
53
|
+
:remote_root => File.join(@tmpdir, "remote") + "/sample.txt"
|
54
|
+
).sync
|
55
|
+
get_tree("local").should eql(get_tree("remote"))
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should do simple path sync" do
|
59
|
+
build_simple_test_dir
|
60
|
+
Rbfs::Command.new(
|
61
|
+
:hosts => File.join(@tmpdir, "hosts"),
|
62
|
+
:root => File.join(@tmpdir, "local"),
|
63
|
+
:shell => '"ssh -o StrictHostKeyChecking=no"',
|
64
|
+
:remote_root => File.join(@tmpdir, "remote")
|
65
|
+
).sync
|
66
|
+
get_tree("local").should eql(get_tree("remote"))
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should do multi path sync" do
|
70
|
+
build_multipath_test_dir
|
71
|
+
Rbfs::Command.new(
|
72
|
+
:hosts => File.join(@tmpdir, "hosts"),
|
73
|
+
:root => File.join(@tmpdir, "local"),
|
74
|
+
:shell => '"ssh -o StrictHostKeyChecking=no"',
|
75
|
+
:remote_root => File.join(@tmpdir, "remote")
|
76
|
+
).sync
|
77
|
+
get_tree("local").should eql(get_tree("remote"))
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should do sub path sync" do
|
81
|
+
build_deeppath_test_dir
|
82
|
+
Rbfs::Command.new(
|
83
|
+
:hosts => File.join(@tmpdir, "hosts"),
|
84
|
+
:root => File.join(@tmpdir, "local"),
|
85
|
+
:subpath => "somepath/someotherpath/",
|
86
|
+
:shell => '"ssh -o StrictHostKeyChecking=no"',
|
87
|
+
:remote_root => File.join(@tmpdir, "remote")
|
88
|
+
).sync
|
89
|
+
get_tree("local").should eql(get_tree("remote"))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/rbfs/rsync_spec.rb
CHANGED
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.14
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-07-
|
12
|
+
date: 2013-07-24 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rsync
|
16
|
+
requirement: &10282820 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *10282820
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: hosts_file
|
27
|
+
requirement: &10281820 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0.0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *10281820
|
14
36
|
- !ruby/object:Gem::Dependency
|
15
37
|
name: bundler
|
16
|
-
requirement: &
|
38
|
+
requirement: &10280700 !ruby/object:Gem::Requirement
|
17
39
|
none: false
|
18
40
|
requirements:
|
19
41
|
- - ~>
|
@@ -21,10 +43,10 @@ dependencies:
|
|
21
43
|
version: '1.3'
|
22
44
|
type: :development
|
23
45
|
prerelease: false
|
24
|
-
version_requirements: *
|
46
|
+
version_requirements: *10280700
|
25
47
|
- !ruby/object:Gem::Dependency
|
26
48
|
name: rake
|
27
|
-
requirement: &
|
49
|
+
requirement: &10279760 !ruby/object:Gem::Requirement
|
28
50
|
none: false
|
29
51
|
requirements:
|
30
52
|
- - ! '>='
|
@@ -32,10 +54,10 @@ dependencies:
|
|
32
54
|
version: '0'
|
33
55
|
type: :development
|
34
56
|
prerelease: false
|
35
|
-
version_requirements: *
|
57
|
+
version_requirements: *10279760
|
36
58
|
- !ruby/object:Gem::Dependency
|
37
59
|
name: rspec
|
38
|
-
requirement: &
|
60
|
+
requirement: &10278940 !ruby/object:Gem::Requirement
|
39
61
|
none: false
|
40
62
|
requirements:
|
41
63
|
- - ! '>='
|
@@ -43,7 +65,7 @@ dependencies:
|
|
43
65
|
version: '0'
|
44
66
|
type: :development
|
45
67
|
prerelease: false
|
46
|
-
version_requirements: *
|
68
|
+
version_requirements: *10278940
|
47
69
|
description: Ruby File Sync
|
48
70
|
email:
|
49
71
|
- jbussdieker@gmail.com
|
@@ -63,15 +85,12 @@ files:
|
|
63
85
|
- lib/rbfs/command.rb
|
64
86
|
- lib/rbfs/config.rb
|
65
87
|
- lib/rbfs/futures.rb
|
66
|
-
- lib/rbfs/host.rb
|
67
|
-
- lib/rbfs/host_parser.rb
|
68
88
|
- lib/rbfs/logger.rb
|
69
89
|
- lib/rbfs/rsync.rb
|
70
90
|
- lib/rbfs/version.rb
|
71
91
|
- rbfs.gemspec
|
92
|
+
- spec/rbfs/command_spec.rb
|
72
93
|
- spec/rbfs/futures_spec.rb
|
73
|
-
- spec/rbfs/host_parser_spec.rb
|
74
|
-
- spec/rbfs/host_spec.rb
|
75
94
|
- spec/rbfs/rsync_spec.rb
|
76
95
|
homepage: ''
|
77
96
|
licenses: []
|
@@ -98,8 +117,7 @@ signing_key:
|
|
98
117
|
specification_version: 3
|
99
118
|
summary: Ruby File Sync
|
100
119
|
test_files:
|
120
|
+
- spec/rbfs/command_spec.rb
|
101
121
|
- spec/rbfs/futures_spec.rb
|
102
|
-
- spec/rbfs/host_parser_spec.rb
|
103
|
-
- spec/rbfs/host_spec.rb
|
104
122
|
- spec/rbfs/rsync_spec.rb
|
105
123
|
has_rdoc:
|
data/lib/rbfs/host.rb
DELETED
data/lib/rbfs/host_parser.rb
DELETED
@@ -1,20 +0,0 @@
|
|
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
|
@@ -1,30 +0,0 @@
|
|
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
|
data/spec/rbfs/host_spec.rb
DELETED
@@ -1,38 +0,0 @@
|
|
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
|