rsync 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -0
- data/lib/rsync.rb +5 -1
- data/lib/rsync/change.rb +154 -115
- data/lib/rsync/command.rb +6 -0
- data/lib/rsync/result.rb +18 -1
- data/lib/rsync/version.rb +2 -1
- data/spec/rsync/change_spec.rb +18 -24
- metadata +48 -73
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Rsync
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/jbussdieker/ruby-rsync.png?branch=master)](https://travis-ci.org/jbussdieker/ruby-rsync)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/jbussdieker/ruby-rsync.png)](https://codeclimate.com/github/jbussdieker/ruby-rsync)
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/rsync.png)](http://badge.fury.io/rb/rsync)
|
4
6
|
|
5
7
|
Ruby/Rsync is a Ruby library that can syncronize files between remote hosts by wrapping a call to the rsync binary.
|
6
8
|
|
data/lib/rsync.rb
CHANGED
@@ -2,8 +2,12 @@ require "rsync/version"
|
|
2
2
|
require "rsync/command"
|
3
3
|
require "rsync/result"
|
4
4
|
|
5
|
+
# The main interface to rsync
|
5
6
|
module Rsync
|
6
|
-
|
7
|
+
# Creates and runs an rsync {Command} and return the {Result}
|
8
|
+
# @return {Result}
|
9
|
+
# @yield {Result}
|
10
|
+
def self.command(args, &block)
|
7
11
|
output = Command.new(args).run
|
8
12
|
exitcode = $?
|
9
13
|
result = Result.new(output, exitcode)
|
data/lib/rsync/change.rb
CHANGED
@@ -1,146 +1,185 @@
|
|
1
1
|
module Rsync
|
2
|
+
# Provides details about changes made to a specific file.
|
3
|
+
#
|
4
|
+
# Change Flags:
|
5
|
+
#
|
6
|
+
# :no_change
|
7
|
+
# :identical
|
8
|
+
# :new
|
9
|
+
# :unknown
|
10
|
+
# :changed
|
2
11
|
class Change
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(raw)
|
6
|
-
@raw = raw
|
12
|
+
def initialize(data)
|
13
|
+
@data = data
|
7
14
|
end
|
8
15
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
detail = Detail.new(line)
|
14
|
-
yield(detail) if detail.changed?
|
15
|
-
end
|
16
|
-
end
|
16
|
+
# The filename associated with this change.
|
17
|
+
# @return [String]
|
18
|
+
def filename
|
19
|
+
@data[12..-1]
|
17
20
|
end
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
# Whether the file was changed or not.
|
23
|
+
# @return [Boolean]
|
24
|
+
def changed?
|
25
|
+
if update_type == :message
|
26
|
+
return true
|
27
|
+
elsif update_type == :recv
|
28
|
+
return true
|
26
29
|
end
|
30
|
+
false
|
31
|
+
end
|
27
32
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
+
# Simple description of the change.
|
34
|
+
# @return [String]
|
35
|
+
def summary
|
36
|
+
if update_type == :message
|
37
|
+
message
|
38
|
+
elsif update_type == :recv and @data[2,9] == "+++++++++"
|
39
|
+
"creating"
|
40
|
+
elsif update_type == :recv
|
41
|
+
"updating"
|
42
|
+
else
|
43
|
+
changes = []
|
44
|
+
#[:checksum, :size, :timestamp, :permissions, :owner, :group, :acl].each do |prop|
|
45
|
+
[:checksum, :size, :permissions, :owner, :group, :acl].each do |prop|
|
46
|
+
changes << prop if send(prop) == :changed
|
33
47
|
end
|
34
|
-
|
48
|
+
changes.join(", ")
|
35
49
|
end
|
50
|
+
end
|
36
51
|
|
37
|
-
|
38
|
-
if update_type == :message
|
39
|
-
message
|
40
|
-
elsif update_type == :recv and @raw[2,9] == "+++++++++"
|
41
|
-
"creating"
|
42
|
-
elsif update_type == :recv
|
43
|
-
"updating"
|
44
|
-
else
|
45
|
-
changes = []
|
46
|
-
#[:checksum, :size, :timestamp, :permissions, :owner, :group, :acl].each do |prop|
|
47
|
-
[:checksum, :size, :permissions, :owner, :group, :acl].each do |prop|
|
48
|
-
changes << prop if send(prop) == :changed
|
49
|
-
end
|
50
|
-
changes.join(", ")
|
51
|
-
end
|
52
|
-
end
|
52
|
+
# @!group Change Flags
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
# The change, if any, to the checksum of the file.
|
55
|
+
# @return [Symbol]
|
56
|
+
def checksum
|
57
|
+
attribute_prop(2)
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
-
|
60
|
+
# The change, if any, to the size of the file.
|
61
|
+
# @return [Symbol]
|
62
|
+
def size
|
63
|
+
attribute_prop(3)
|
64
|
+
end
|
61
65
|
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
# The change, if any, to the timestamp of the file.
|
67
|
+
# @return [Symbol]
|
68
|
+
def timestamp
|
69
|
+
attribute_prop(4)
|
70
|
+
end
|
65
71
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
:identical
|
72
|
-
when '+'
|
73
|
-
:new
|
74
|
-
when '?'
|
75
|
-
:unknown
|
76
|
-
else
|
77
|
-
:changed
|
78
|
-
end
|
79
|
-
end
|
72
|
+
# The change, if any, to the file permissions.
|
73
|
+
# @return [Symbol]
|
74
|
+
def permissions
|
75
|
+
attribute_prop(5)
|
76
|
+
end
|
80
77
|
|
81
|
-
|
82
|
-
|
83
|
-
|
78
|
+
# The change, if any, to the owner of the file.
|
79
|
+
# @return [Symbol]
|
80
|
+
def owner
|
81
|
+
attribute_prop(6)
|
82
|
+
end
|
84
83
|
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
# The change, if any, to the group of the file.
|
85
|
+
# @return [Symbol]
|
86
|
+
def group
|
87
|
+
attribute_prop(7)
|
88
|
+
end
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
90
|
+
# The change, if any, to the file ACL.
|
91
|
+
# @return [Symbol]
|
92
|
+
def acl
|
93
|
+
attribute_prop(9)
|
94
|
+
end
|
92
95
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
+
# The change, if any, to the file's extended attributes.
|
97
|
+
# @return [Symbol]
|
98
|
+
def ext_attr
|
99
|
+
attribute_prop(10)
|
100
|
+
end
|
96
101
|
|
97
|
-
|
98
|
-
|
102
|
+
# @!endgroup
|
103
|
+
|
104
|
+
# The type of update made to the file.
|
105
|
+
#
|
106
|
+
# :sent
|
107
|
+
# :recv
|
108
|
+
# :change
|
109
|
+
# :hard_link
|
110
|
+
# :no_update
|
111
|
+
# :message
|
112
|
+
#
|
113
|
+
# @return [Symbol]
|
114
|
+
def update_type
|
115
|
+
case raw_update_type
|
116
|
+
when '<'
|
117
|
+
:sent
|
118
|
+
when '>'
|
119
|
+
:recv
|
120
|
+
when 'c'
|
121
|
+
:change
|
122
|
+
when 'h'
|
123
|
+
:hard_link
|
124
|
+
when '.'
|
125
|
+
:no_update
|
126
|
+
when '*'
|
127
|
+
:message
|
99
128
|
end
|
129
|
+
end
|
100
130
|
|
101
|
-
|
102
|
-
|
131
|
+
# The type of file.
|
132
|
+
#
|
133
|
+
# :file
|
134
|
+
# :directory
|
135
|
+
# :symlink
|
136
|
+
# :device
|
137
|
+
# :special
|
138
|
+
#
|
139
|
+
# @return [Symbol]
|
140
|
+
def file_type
|
141
|
+
case raw_file_type
|
142
|
+
when 'f'
|
143
|
+
:file
|
144
|
+
when 'd'
|
145
|
+
:directory
|
146
|
+
when 'L'
|
147
|
+
:symlink
|
148
|
+
when 'D'
|
149
|
+
:device
|
150
|
+
when 'S'
|
151
|
+
:special
|
103
152
|
end
|
153
|
+
end
|
104
154
|
|
105
|
-
|
106
|
-
attribute_prop(9)
|
107
|
-
end
|
155
|
+
private
|
108
156
|
|
109
|
-
|
110
|
-
|
111
|
-
|
157
|
+
def message
|
158
|
+
@data[1..10].strip
|
159
|
+
end
|
112
160
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
:sent
|
117
|
-
when '>'
|
118
|
-
:recv
|
119
|
-
when 'c'
|
120
|
-
:change
|
121
|
-
when 'h'
|
122
|
-
:hard_link
|
123
|
-
when '.'
|
124
|
-
:no_update
|
125
|
-
when '*'
|
126
|
-
:message
|
127
|
-
end
|
128
|
-
end
|
161
|
+
def raw_update_type
|
162
|
+
@data[0,1]
|
163
|
+
end
|
129
164
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
165
|
+
def raw_file_type
|
166
|
+
@data[1,1]
|
167
|
+
end
|
168
|
+
|
169
|
+
def attribute_prop(index)
|
170
|
+
case @data[index,1]
|
171
|
+
when '.'
|
172
|
+
:no_change
|
173
|
+
when ' '
|
174
|
+
:identical
|
175
|
+
when '+'
|
176
|
+
:new
|
177
|
+
when '?'
|
178
|
+
:unknown
|
179
|
+
else
|
180
|
+
:changed
|
143
181
|
end
|
144
182
|
end
|
183
|
+
|
145
184
|
end
|
146
185
|
end
|
data/lib/rsync/command.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
module Rsync
|
2
|
+
# An rsync command to be run
|
2
3
|
class Command
|
3
4
|
def initialize(args)
|
4
5
|
@args = args.join(" ")
|
5
6
|
end
|
6
7
|
|
8
|
+
# Runs the rsync job and returns the results
|
9
|
+
#
|
10
|
+
# @return {Result}
|
7
11
|
def run
|
8
12
|
run_command("rsync --itemize-changes #{@args}")
|
9
13
|
end
|
10
14
|
|
15
|
+
private
|
16
|
+
|
11
17
|
def run_command(cmd, &block)
|
12
18
|
if block_given?
|
13
19
|
IO.popen("#{cmd} 2>&1", &block)
|
data/lib/rsync/result.rb
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
require 'rsync/change'
|
2
2
|
|
3
3
|
module Rsync
|
4
|
+
# The result of a sync.
|
4
5
|
class Result
|
6
|
+
# @!visibility private
|
5
7
|
def initialize(raw, exitcode)
|
6
8
|
@raw = raw
|
7
9
|
@exitcode = exitcode
|
8
10
|
end
|
9
11
|
|
12
|
+
# Whether the rsync job was run without errors.
|
13
|
+
# @return Boolean
|
10
14
|
def success?
|
11
15
|
@exitcode.to_i == 0
|
12
16
|
end
|
13
17
|
|
18
|
+
# The error message based on exit code.
|
19
|
+
# @return String
|
14
20
|
def error
|
15
21
|
case @exitcode.exitstatus
|
16
22
|
when 0
|
@@ -58,8 +64,19 @@ module Rsync
|
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
67
|
+
# List of changes made during this run.
|
68
|
+
#
|
69
|
+
# @return {Array<Change>}
|
61
70
|
def changes
|
62
|
-
|
71
|
+
list = []
|
72
|
+
@raw.split("\n").each do |line|
|
73
|
+
#if line =~ /^([<>ch.*][fdLDS][ .+\?cstTpoguax]{9}) (.*)$/
|
74
|
+
if line =~ /^([<>ch.\*].{10}) (.*)$/
|
75
|
+
detail = Change.new(line)
|
76
|
+
list << detail if detail.changed?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
list
|
63
80
|
end
|
64
81
|
end
|
65
82
|
end
|
data/lib/rsync/version.rb
CHANGED
data/spec/rsync/change_spec.rb
CHANGED
@@ -1,42 +1,36 @@
|
|
1
1
|
require 'rsync/change'
|
2
2
|
|
3
3
|
describe Rsync::Change do
|
4
|
-
it "should handle example" do
|
5
|
-
Rsync::Change.new(".f blah2.txt")
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
describe Rsync::Change::Detail do
|
10
4
|
it "should handle filename" do
|
11
|
-
Rsync::Change
|
5
|
+
Rsync::Change.new(" filename").filename.should eql("filename")
|
12
6
|
end
|
13
7
|
|
14
8
|
it "should handle message type" do
|
15
|
-
Rsync::Change
|
9
|
+
Rsync::Change.new("*deleting ").summary.should eql("deleting")
|
16
10
|
end
|
17
11
|
|
18
12
|
it "should handle update types" do
|
19
|
-
Rsync::Change
|
20
|
-
Rsync::Change
|
21
|
-
Rsync::Change
|
22
|
-
Rsync::Change
|
23
|
-
Rsync::Change
|
24
|
-
Rsync::Change
|
13
|
+
Rsync::Change.new("< ").update_type.should eql(:sent)
|
14
|
+
Rsync::Change.new("> ").update_type.should eql(:recv)
|
15
|
+
Rsync::Change.new("c ").update_type.should eql(:change)
|
16
|
+
Rsync::Change.new("h ").update_type.should eql(:hard_link)
|
17
|
+
Rsync::Change.new(". ").update_type.should eql(:no_update)
|
18
|
+
Rsync::Change.new("* ").update_type.should eql(:message)
|
25
19
|
end
|
26
20
|
|
27
21
|
it "should handle file types" do
|
28
|
-
Rsync::Change
|
29
|
-
Rsync::Change
|
30
|
-
Rsync::Change
|
31
|
-
Rsync::Change
|
32
|
-
Rsync::Change
|
22
|
+
Rsync::Change.new(" f ").file_type.should eql(:file)
|
23
|
+
Rsync::Change.new(" d ").file_type.should eql(:directory)
|
24
|
+
Rsync::Change.new(" L ").file_type.should eql(:symlink)
|
25
|
+
Rsync::Change.new(" D ").file_type.should eql(:device)
|
26
|
+
Rsync::Change.new(" S ").file_type.should eql(:special)
|
33
27
|
end
|
34
28
|
|
35
29
|
it "should handle checksum info" do
|
36
|
-
Rsync::Change
|
37
|
-
Rsync::Change
|
38
|
-
Rsync::Change
|
39
|
-
Rsync::Change
|
40
|
-
Rsync::Change
|
30
|
+
Rsync::Change.new(" c ").checksum.should eql(:changed)
|
31
|
+
Rsync::Change.new(" . ").checksum.should eql(:no_change)
|
32
|
+
Rsync::Change.new(" ").checksum.should eql(:identical)
|
33
|
+
Rsync::Change.new(" + ").checksum.should eql(:new)
|
34
|
+
Rsync::Change.new(" ? ").checksum.should eql(:unknown)
|
41
35
|
end
|
42
36
|
end
|
metadata
CHANGED
@@ -1,75 +1,56 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsync
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Joshua Bussdieker
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2013-07-24 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: bundler
|
22
|
-
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
16
|
+
requirement: &7909780 !ruby/object:Gem::Requirement
|
24
17
|
none: false
|
25
|
-
requirements:
|
18
|
+
requirements:
|
26
19
|
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
|
29
|
-
segments:
|
30
|
-
- 1
|
31
|
-
- 3
|
32
|
-
version: "1.3"
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
33
22
|
type: :development
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: rake
|
37
23
|
prerelease: false
|
38
|
-
|
24
|
+
version_requirements: *7909780
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &7909000 !ruby/object:Gem::Requirement
|
39
28
|
none: false
|
40
|
-
requirements:
|
41
|
-
- -
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
|
44
|
-
segments:
|
45
|
-
- 0
|
46
|
-
version: "0"
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
47
33
|
type: :development
|
48
|
-
version_requirements: *id002
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: rspec
|
51
34
|
prerelease: false
|
52
|
-
|
35
|
+
version_requirements: *7909000
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &7908040 !ruby/object:Gem::Requirement
|
53
39
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
|
58
|
-
segments:
|
59
|
-
- 0
|
60
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
61
44
|
type: :development
|
62
|
-
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *7908040
|
63
47
|
description:
|
64
|
-
email:
|
48
|
+
email:
|
65
49
|
- jbussdieker@gmail.com
|
66
50
|
executables: []
|
67
|
-
|
68
51
|
extensions: []
|
69
|
-
|
70
52
|
extra_rdoc_files: []
|
71
|
-
|
72
|
-
files:
|
53
|
+
files:
|
73
54
|
- .gitignore
|
74
55
|
- .travis.yml
|
75
56
|
- Gemfile
|
@@ -84,37 +65,31 @@ files:
|
|
84
65
|
- rsync.gemspec
|
85
66
|
- spec/rsync/change_spec.rb
|
86
67
|
homepage: http://github.com/jbussdieker/ruby-rsync
|
87
|
-
licenses:
|
68
|
+
licenses:
|
88
69
|
- MIT
|
89
70
|
post_install_message:
|
90
71
|
rdoc_options: []
|
91
|
-
|
92
|
-
require_paths:
|
72
|
+
require_paths:
|
93
73
|
- lib
|
94
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
75
|
none: false
|
96
|
-
requirements:
|
97
|
-
- -
|
98
|
-
- !ruby/object:Gem::Version
|
99
|
-
|
100
|
-
|
101
|
-
- 0
|
102
|
-
version: "0"
|
103
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
81
|
none: false
|
105
|
-
requirements:
|
106
|
-
- -
|
107
|
-
- !ruby/object:Gem::Version
|
108
|
-
|
109
|
-
segments:
|
110
|
-
- 0
|
111
|
-
version: "0"
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
112
86
|
requirements: []
|
113
|
-
|
114
87
|
rubyforge_project:
|
115
|
-
rubygems_version: 1.8.
|
88
|
+
rubygems_version: 1.8.17
|
116
89
|
signing_key:
|
117
90
|
specification_version: 3
|
118
|
-
summary: Ruby/Rsync is a Ruby library that can syncronize files between remote hosts
|
119
|
-
|
91
|
+
summary: Ruby/Rsync is a Ruby library that can syncronize files between remote hosts
|
92
|
+
by wrapping a call to the rsync binary.
|
93
|
+
test_files:
|
120
94
|
- spec/rsync/change_spec.rb
|
95
|
+
has_rdoc:
|