rbsync 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/rbsync.rb +268 -0
- data/new/test.txt +10 -0
- data/old/test.txt +10 -0
- data/rbsync.gemspec +61 -0
- data/test/helper.rb +18 -0
- data/test/test_rbsync.rb +113 -0
- metadata +139 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.0"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.0)
|
6
|
+
bundler (~> 1.0.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.8.7)
|
10
|
+
rcov (0.9.9)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.6.0)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 takuya
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= rbsync
|
2
|
+
|
3
|
+
rbsync is sync files utility
|
4
|
+
|
5
|
+
== Contributing to rbsync
|
6
|
+
|
7
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
8
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
9
|
+
* Fork the project
|
10
|
+
* Start a feature/bugfix branch
|
11
|
+
* Commit and push until you are happy with your contribution
|
12
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
13
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
14
|
+
|
15
|
+
== Copyright
|
16
|
+
|
17
|
+
Copyright (c) 2011 takuya. See LICENSE.txt for
|
18
|
+
further details.
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "rbsync"
|
18
|
+
gem.homepage = "http://github.com/takuya/rbsync"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{rbsync is sync file utility}
|
21
|
+
gem.description = %Q{rbsync is sync file utility.this can sync directory even if filename differed.checking content insted.}
|
22
|
+
gem.email = "takuya.1st@gmail"
|
23
|
+
gem.authors = ["takuya"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "rbsync #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/rbsync.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
#rbsyncの改良版。
|
2
|
+
# ファイル名でなくハッシュ値を計算してファイルを同期する。
|
3
|
+
#ファイルの同期
|
4
|
+
|
5
|
+
require 'fileutils'
|
6
|
+
$KCODE='u'
|
7
|
+
|
8
|
+
# Synchronize files src to dest .
|
9
|
+
# this class can sync files and recuresively
|
10
|
+
# options are
|
11
|
+
# +sync update file only
|
12
|
+
# +no overwrite when dist files are newer than src
|
13
|
+
# +sync by file digest hash , not useing filename
|
14
|
+
#
|
15
|
+
# == usage
|
16
|
+
# === mirror files
|
17
|
+
# 同期元と同期先を同じにする
|
18
|
+
# require 'rbsync'
|
19
|
+
# rsync =RbSync.new
|
20
|
+
# rsync.sync( "src", "dest" )
|
21
|
+
# === mirror updated only files
|
22
|
+
# 同期先に、同期元と同名のファイルがあったら、更新日時を調べる。新しいモノだけをコピーする.
|
23
|
+
# require 'rbsync'
|
24
|
+
# rsync =RbSync.new
|
25
|
+
# rsync.sync( "src", "dest",{:update=>true} )
|
26
|
+
# === using exclude pattern
|
27
|
+
# 同期先と同期元を同じにする,但し、*.rb / *.log の拡張子は除外する.
|
28
|
+
# require 'rbsync'
|
29
|
+
# rsync =RbSync.new
|
30
|
+
# rsync.sync( "src", "dest",{:excludes=>["*.log","*.bak"]} )
|
31
|
+
# ==special usage , sync by file cotetets
|
32
|
+
# if directory has a same file with different file name. insted of filename , sync file by file hash
|
33
|
+
# ディレクトリ内のファイル名をうっかり変えてしまったときに使う.ファイル名でなく、ファイルの中身を比較して同期する.
|
34
|
+
# require 'rbsync'
|
35
|
+
# rsync =RbSync.new
|
36
|
+
# rsync.sync( "src", "dest",{:check_hash=>true} )
|
37
|
+
# === directory has very large file ,such as mpeg video
|
38
|
+
# checking only head of 1024*1024 bytes to distinguish src / dest files for speed up.
|
39
|
+
# FileUtils::cmp is reading whole file. This will be so slow for large file
|
40
|
+
# 巨大なファイルだと,全部読み込むのに時間が掛かるので、先頭1024*1024 バイトを比較してOKとする
|
41
|
+
# require 'rbsync'
|
42
|
+
# rsync =RbSync.new
|
43
|
+
# rsync.sync( "src", "dest",{:check_hash=>true,:hash_limit_size=1024*1024} )
|
44
|
+
#
|
45
|
+
# === sync both updated files
|
46
|
+
# 双方向に同期させたい場合は2回起動する.
|
47
|
+
# require 'rbsync'
|
48
|
+
# rsync =RbSync.new
|
49
|
+
# rsync.update = true
|
50
|
+
# rsync.sync( "src", "dest" )
|
51
|
+
# rsync.sync( "dest", "src" )
|
52
|
+
class RbSync
|
53
|
+
attr_accessor :conf
|
54
|
+
def initialize()
|
55
|
+
@conf ={}
|
56
|
+
@conf[:update] = false
|
57
|
+
@conf[:excludes] = []
|
58
|
+
end
|
59
|
+
# collect file paths. paths are relatetive path.
|
60
|
+
def find_as_relative(dir_name,excludes=[])
|
61
|
+
files =[]
|
62
|
+
excludes = [] unless excludes
|
63
|
+
Dir.chdir(dir_name){
|
64
|
+
files = Dir.glob "./**/*", File::FNM_DOTMATCH
|
65
|
+
exclude_files =[]
|
66
|
+
exclude_files = excludes.map{|g| Dir.glob "./**/#{g}",File::FNM_DOTMATCH }
|
67
|
+
files = files - exclude_files.flatten
|
68
|
+
}
|
69
|
+
files.reject{|e| [".",".."].any?{|s| s== File::basename(e) }}
|
70
|
+
end
|
71
|
+
# compare two directory by name and FileUtis,cmp
|
72
|
+
def find_files(src,dest,options)
|
73
|
+
src_files = self.find_as_relative( src, options[:excludes] )
|
74
|
+
dest_files = self.find_as_relative( dest, options[:excludes] )
|
75
|
+
|
76
|
+
# output target files
|
77
|
+
puts " 元フォルダ:" + src_files.size.to_s + "件" if self.debug?
|
78
|
+
puts "同期先フォルダ:" + dest_files.size.to_s + "件" if self.debug?
|
79
|
+
#pp src_files if self.debug?
|
80
|
+
sleep 1 if self.debug?
|
81
|
+
|
82
|
+
#両方にあるファイル名で中身が違うもので src の方が古いもの
|
83
|
+
same_name_files = (dest_files & src_files)
|
84
|
+
same_name_files.reject!{|e|
|
85
|
+
#ファイルが同じモノは省く
|
86
|
+
FileUtils.cmp( File.expand_path(e,src) , File.expand_path(e,dest) )
|
87
|
+
}
|
88
|
+
if options[:update] then
|
89
|
+
same_name_files= same_name_files.select{|e|
|
90
|
+
(File.mtime(File.expand_path(e,src)) > File.mtime( File.expand_path(e,dest)))
|
91
|
+
}
|
92
|
+
end
|
93
|
+
files_not_in_dest = (src_files - dest_files)
|
94
|
+
#files
|
95
|
+
files =[]
|
96
|
+
files = (files_not_in_dest + same_name_files ).flatten
|
97
|
+
end
|
98
|
+
def sync_by_hash(src,dest,options={})
|
99
|
+
src_files = collet_hash(find_as_relative(src, options), src, options)
|
100
|
+
dest_files = collet_hash(find_as_relative(dest,options),dest, options)
|
101
|
+
target = src_files.keys - dest_files.keys
|
102
|
+
target = target.reject{|key|
|
103
|
+
e = src_files[key].first
|
104
|
+
options[:update] &&
|
105
|
+
File.exists?( File.expand_path(e,dest)) &&
|
106
|
+
(File.mtime(File.expand_path(e,src)) < File.mtime( File.expand_path(e,dest)))
|
107
|
+
}
|
108
|
+
puts "同期対象ファイル" if self.debug?
|
109
|
+
puts target.each{|key|puts src_files[key].first} if self.debug?
|
110
|
+
puts "同期対象はありません" if self.debug? and target.size==0
|
111
|
+
ret = target.map{|key|
|
112
|
+
e = src_files[key].first
|
113
|
+
FileUtils.copy( File.expand_path(e,src) , File.expand_path(e,dest),
|
114
|
+
{:preserve=>self.preserve?,:verbose=>self.verbose? })
|
115
|
+
FileTest.exist?(File.expand_path(e,dest))
|
116
|
+
}
|
117
|
+
puts "同期が終りました" if ret.select{|e|!e}.size == 0 && self.debug?
|
118
|
+
puts "同期に失敗したみたい" if ret.select{|e|!e}.size != 0 && self.debug?
|
119
|
+
end
|
120
|
+
def collet_hash(file_names,basedir,options={})
|
121
|
+
#prepare
|
122
|
+
require 'thread'
|
123
|
+
threads =[]
|
124
|
+
output = Hash.new{|s,key| s[key]=[] }
|
125
|
+
q = Queue.new
|
126
|
+
limitsize = options[:hash_limit_size]
|
127
|
+
# compute digests
|
128
|
+
file_names.each{|e| q.push e }
|
129
|
+
5.times{
|
130
|
+
threads.push(
|
131
|
+
Thread.start{
|
132
|
+
while(!q.empty?)
|
133
|
+
name = q.pop
|
134
|
+
hash = compute_digest_file(File.expand_path(name,basedir),limitsize)
|
135
|
+
output[hash].push name
|
136
|
+
end
|
137
|
+
}
|
138
|
+
)
|
139
|
+
}
|
140
|
+
threads.each{|t|t.join}
|
141
|
+
return output
|
142
|
+
end
|
143
|
+
# compute digest md5
|
144
|
+
# ==limitsize
|
145
|
+
# If file size is very large.
|
146
|
+
# And a few byte head of file is enough to compare.
|
147
|
+
# for speedup, setting limit size enable to skipp reading file.
|
148
|
+
# もしファイルがとても巨大で、かつ、先頭の数キロバイトで十分であれば、limitsize 以降をスキップする
|
149
|
+
def compute_digest_file(filename, limitsize=nil)
|
150
|
+
require 'digest/md5'
|
151
|
+
s = %{
|
152
|
+
class Digest::Base
|
153
|
+
def self.open(path,limitsize=nil)
|
154
|
+
obj = new
|
155
|
+
File.open(path, 'rb') do |f|
|
156
|
+
buf = ""
|
157
|
+
while f.read(256, buf)
|
158
|
+
obj << buf
|
159
|
+
break if f.pos > (limitsize or f.pos+1)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
return obj
|
163
|
+
end
|
164
|
+
end
|
165
|
+
}
|
166
|
+
eval s
|
167
|
+
Digest::MD5.open(filename,limitsize).hexdigest
|
168
|
+
end
|
169
|
+
|
170
|
+
# ロジックが長すぎるので短くするか別に分ける.
|
171
|
+
# ロジックのパターン毎に共通化する
|
172
|
+
# ・ディレクトリ内のファイル一覧を作る
|
173
|
+
# ・ファイル一覧を比較する
|
174
|
+
# ・同期するファイル一覧を作って転送する
|
175
|
+
def sync_nornally(src,dest,options={})
|
176
|
+
files = self.find_files(src,dest,options)
|
177
|
+
puts "同期対象のファイルはありません" if self.debug? && files.size==0
|
178
|
+
return true if files.size == 0
|
179
|
+
puts "次のファイルを同期します" if self.debug?
|
180
|
+
pp files if self.debug?
|
181
|
+
|
182
|
+
#srcファイルをdestに上書き
|
183
|
+
#todo options を取り出す
|
184
|
+
files.each{|e|
|
185
|
+
FileUtils.copy( File.expand_path(e,src) , File.expand_path(e,dest),
|
186
|
+
{:preserve=>self.preserve?,:verbose=>self.verbose? } )
|
187
|
+
}
|
188
|
+
files =[]
|
189
|
+
|
190
|
+
#checking sync result
|
191
|
+
files = self.find_files(src,dest,options)
|
192
|
+
|
193
|
+
puts "同期が終りました" if files.size == 0 && self.debug?
|
194
|
+
puts "同期に失敗がありました" if files.size != 0 && self.debug?
|
195
|
+
pp files if files.size != 0 && self.debug?
|
196
|
+
return files.size == 0
|
197
|
+
end
|
198
|
+
def sync(src,dest,options={})
|
199
|
+
options[:excludes] = (self.excludes + [options[:excludes]]).flatten.uniq if options[:excludes]
|
200
|
+
options[:update] = @conf[:update] if options[:update] == nil
|
201
|
+
options[:check_hash] = options[:check_hash] and @conf[:check_hash]
|
202
|
+
options[:hash_limit_size] = @conf[:hash_limit_size] if options[:hash_limit_size] == nil
|
203
|
+
if options[:check_hash]
|
204
|
+
return self.sync_by_hash(src,dest,options)
|
205
|
+
else
|
206
|
+
return self.sync_nornally(src,dest,options)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
#for setting
|
210
|
+
|
211
|
+
def debug_mode?
|
212
|
+
self.conf[:debug] ==true
|
213
|
+
end
|
214
|
+
def verbose?
|
215
|
+
self.conf[:verbose] == true
|
216
|
+
end
|
217
|
+
def hash_limit_size
|
218
|
+
@conf[:hash_limit_size]
|
219
|
+
end
|
220
|
+
|
221
|
+
# flag true or false
|
222
|
+
def debug_mode=(flag)
|
223
|
+
self.conf[:debug] = flag
|
224
|
+
end
|
225
|
+
# flag true or false
|
226
|
+
def verbose=(flag)
|
227
|
+
self.conf[:verbose] = flag
|
228
|
+
$stdout.sync = flag
|
229
|
+
end
|
230
|
+
#
|
231
|
+
# flag true or false
|
232
|
+
def updated_file_only=(flag)
|
233
|
+
@conf[:update] = flag
|
234
|
+
end
|
235
|
+
#
|
236
|
+
# flag true or false
|
237
|
+
def check_hash=(flag)
|
238
|
+
@conf[:use_md5_digest] = flag
|
239
|
+
end
|
240
|
+
def hash_limit_size=(int_byte_size)
|
241
|
+
@conf[:hash_limit_size] = int_byte_size
|
242
|
+
end
|
243
|
+
|
244
|
+
def excludes=(glob_pattern)
|
245
|
+
@conf[:excludes].push glob_pattern
|
246
|
+
end
|
247
|
+
def excludes
|
248
|
+
@conf[:excludes]
|
249
|
+
end
|
250
|
+
def preserve=(flag)
|
251
|
+
@conf[:preserve] = false
|
252
|
+
end
|
253
|
+
def preserve?
|
254
|
+
@conf[:preserve]
|
255
|
+
end
|
256
|
+
|
257
|
+
#aliases
|
258
|
+
|
259
|
+
alias debug? debug_mode?
|
260
|
+
alias debug= debug_mode=
|
261
|
+
alias update= updated_file_only=
|
262
|
+
alias newer= updated_file_only=
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
require 'tmpdir'
|
267
|
+
require 'find'
|
268
|
+
require 'pp'
|
data/new/test.txt
ADDED
data/old/test.txt
ADDED
data/rbsync.gemspec
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rbsync}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["takuya"]
|
12
|
+
s.date = %q{2011-06-12}
|
13
|
+
s.description = %q{rbsync is sync file utility.this can sync directory even if filename differed.checking content insted.}
|
14
|
+
s.email = %q{takuya.1st@gmail}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/rbsync.rb",
|
28
|
+
"new/test.txt",
|
29
|
+
"old/test.txt",
|
30
|
+
"rbsync.gemspec",
|
31
|
+
"test/helper.rb",
|
32
|
+
"test/test_rbsync.rb"
|
33
|
+
]
|
34
|
+
s.homepage = %q{http://github.com/takuya/rbsync}
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = %q{1.5.0}
|
38
|
+
s.summary = %q{rbsync is sync file utility}
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
45
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
46
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
|
47
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
48
|
+
else
|
49
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
50
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
52
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
56
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
|
58
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'rbsync'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
data/test/test_rbsync.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
require 'tmpdir'
|
4
|
+
require 'find'
|
5
|
+
require 'pp'
|
6
|
+
class TestRbsync < Test::Unit::TestCase
|
7
|
+
def test_sync_old_to_new
|
8
|
+
Dir.mktmpdir('foo') do |dir|
|
9
|
+
Dir.chdir dir do
|
10
|
+
Dir.mkdir("old")
|
11
|
+
Dir.mkdir("new")
|
12
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
13
|
+
rsync = RbSync.new
|
14
|
+
rsync.sync("old","new")
|
15
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
def test_sync_old_to_new_and_overwrite
|
20
|
+
Dir.mktmpdir('goo') do |dir|
|
21
|
+
Dir.chdir dir do
|
22
|
+
Dir.mkdir("old")
|
23
|
+
Dir.mkdir("new")
|
24
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
25
|
+
open("./new/test.txt", "w+"){|f| 10.times{f.puts("tests")}}
|
26
|
+
rsync = RbSync.new
|
27
|
+
rsync.sync("old","new")
|
28
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
def test_sync_but_newdir_is_already_updated
|
33
|
+
Dir.mktmpdir('goo') do |dir|
|
34
|
+
Dir.chdir dir do
|
35
|
+
Dir.mkdir("old")
|
36
|
+
Dir.mkdir("new")
|
37
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
38
|
+
open("./new/test.txt", "w+"){|f| 10.times{f.puts("different")}}
|
39
|
+
File::utime( Time.local(2038, 1, 1, 1, 1, 1), Time.local(2038, 1, 1, 1, 1, 1), "./new/test.txt")
|
40
|
+
rsync = RbSync.new
|
41
|
+
rsync.sync("old","new",{:update=>true})
|
42
|
+
assert (FileUtils.cmp("old/test.txt","new/test.txt") == false )
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
def test_sync_old_to_new_by_hash
|
47
|
+
Dir.mktmpdir('foo') do |dir|
|
48
|
+
Dir.chdir dir do
|
49
|
+
Dir.mkdir("old")
|
50
|
+
Dir.mkdir("new")
|
51
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
52
|
+
open("./new/test.txt", "w+"){|f| 10.times{f.puts("tests")}}
|
53
|
+
rsync = RbSync.new
|
54
|
+
rsync.sync("old","new",{:check_hash=>true})
|
55
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def test_sync_old_to_new_by_hash_no_file
|
60
|
+
Dir.mktmpdir('foo') do |dir|
|
61
|
+
Dir.chdir dir do
|
62
|
+
Dir.mkdir("old")
|
63
|
+
Dir.mkdir("new")
|
64
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
65
|
+
open("./new/test.txt", "w+"){|f| 10.times{f.puts("different")}}
|
66
|
+
File::utime( Time.local(2038, 1, 1, 1, 1, 1), Time.local(2038, 1, 1, 1, 1, 1), "./new/test.txt")
|
67
|
+
rsync = RbSync.new
|
68
|
+
rsync.sync("old","new",{:check_hash=>true,:update=>true})
|
69
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt") == false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
def test_sync_old_to_new_by_hash_and_limit
|
74
|
+
Dir.mktmpdir('foo') do |dir|
|
75
|
+
Dir.chdir dir do
|
76
|
+
Dir.mkdir("old")
|
77
|
+
Dir.mkdir("new")
|
78
|
+
open("./old/test.txt", "w+"){|f| 1000.times{f.puts("test")}}
|
79
|
+
open("./new/test.txt", "w+"){|f| 1000.times{f.puts("test")}}
|
80
|
+
rsync = RbSync.new
|
81
|
+
rsync.sync("old","new",{:check_hash=>true,:hash_limit_size=>1024})
|
82
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
def test_sync_failed_hash_limit_size_is_too_small
|
87
|
+
Dir.mktmpdir('foo') do |dir|
|
88
|
+
Dir.chdir dir do
|
89
|
+
Dir.mkdir("old")
|
90
|
+
Dir.mkdir("new")
|
91
|
+
open("./old/test.txt", "w+"){|f| 3072.times{f.write("a")}}
|
92
|
+
open("./new/test.txt", "w+"){|f| 2048.times{f.write("a")}}
|
93
|
+
rsync = RbSync.new
|
94
|
+
rsync.sync("old","new",{:check_hash=>true,:hash_limit_size=>1024})
|
95
|
+
assert FileUtils.cmp("old/test.txt","new/test.txt") == false
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
def test_sync_with_exclude_pattern
|
100
|
+
Dir.mktmpdir('foo') do |dir|
|
101
|
+
Dir.chdir dir do
|
102
|
+
Dir.mkdir("old")
|
103
|
+
Dir.mkdir("new")
|
104
|
+
open("./old/test.txt", "w+"){|f| 10.times{f.puts("test")}}
|
105
|
+
open("./old/test.rb", "w+"){|f| 10.times{f.puts("test")}}
|
106
|
+
rsync = RbSync.new
|
107
|
+
rsync.sync("old","new",{:excludes=>["*.txt","*.rb"]})
|
108
|
+
assert (File.exists? "new/test.txt" ) == false
|
109
|
+
assert (File.exists? "new/test.rb" ) == false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
metadata
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rbsync
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- takuya
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-06-12 00:00:00 +09:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
prerelease: false
|
23
|
+
type: :development
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
name: shoulda
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
prerelease: false
|
37
|
+
type: :development
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 23
|
44
|
+
segments:
|
45
|
+
- 1
|
46
|
+
- 0
|
47
|
+
- 0
|
48
|
+
version: 1.0.0
|
49
|
+
name: bundler
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
prerelease: false
|
53
|
+
type: :development
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ~>
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 15
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 6
|
63
|
+
- 0
|
64
|
+
version: 1.6.0
|
65
|
+
name: jeweler
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
prerelease: false
|
69
|
+
type: :development
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 3
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
version: "0"
|
79
|
+
name: rcov
|
80
|
+
version_requirements: *id004
|
81
|
+
description: rbsync is sync file utility.this can sync directory even if filename differed.checking content insted.
|
82
|
+
email: takuya.1st@gmail
|
83
|
+
executables: []
|
84
|
+
|
85
|
+
extensions: []
|
86
|
+
|
87
|
+
extra_rdoc_files:
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.rdoc
|
90
|
+
files:
|
91
|
+
- .document
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- LICENSE.txt
|
95
|
+
- README.rdoc
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- lib/rbsync.rb
|
99
|
+
- new/test.txt
|
100
|
+
- old/test.txt
|
101
|
+
- rbsync.gemspec
|
102
|
+
- test/helper.rb
|
103
|
+
- test/test_rbsync.rb
|
104
|
+
has_rdoc: true
|
105
|
+
homepage: http://github.com/takuya/rbsync
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options: []
|
110
|
+
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
121
|
+
version: "0"
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
124
|
+
requirements:
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
131
|
+
requirements: []
|
132
|
+
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 1.5.0
|
135
|
+
signing_key:
|
136
|
+
specification_version: 3
|
137
|
+
summary: rbsync is sync file utility
|
138
|
+
test_files: []
|
139
|
+
|