checksummer 0.1.2 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +53 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/checksummer.gemspec +3 -3
- data/lib/checksummer_file.rb +2 -0
- data/spec/checksummer_file_spec.rb +18 -0
- data/spec/checksummer_spec.rb +14 -4
- metadata +5 -5
data/README.rdoc
CHANGED
@@ -1,6 +1,58 @@
|
|
1
1
|
= checksummer
|
2
|
+
checksummer replaces all files in a given directory with symlinks to files named and hashed by MD5 checksum of each file.
|
2
3
|
|
3
|
-
|
4
|
+
= Usage
|
5
|
+
|
6
|
+
checksummer <directory_to_checksum> <directory_to_write_data> [OPTIONS]
|
7
|
+
|
8
|
+
Options:
|
9
|
+
--sleep TIME Sleep for TIME milliseconds after each symlink operation (for fair IO)
|
10
|
+
|
11
|
+
= Example
|
12
|
+
|
13
|
+
checksummer /music /data
|
14
|
+
|
15
|
+
== Jay-Z - The Blueprint 3
|
16
|
+
source destination
|
17
|
+
/music/jay-z/the_blueprint_3/01-what_we_talkin_about.mp3 => /data/3/6/a/5/36a5642b1613bf5589cb479332bddca6
|
18
|
+
/music/jay-z/the_blueprint_3/02-thank_you.mp3 => /data/5/1/e/8/51e896f5544b9372edbdf7ec853892a1
|
19
|
+
/music/jay-z/the_blueprint_3/03-doa.mp3 => /data/1/e/7/a/1e7aa593020b60e6b45d0178e49d0413 (duplicate)
|
20
|
+
/music/jay-z/the_blueprint_3/04-run_this_town.mp3 => /data/1/f/4/5/1f454817ee460e28ede71b5e5ee902bd (duplicate)
|
21
|
+
/music/jay-z/the_blueprint_3/05-empire_state_of_mind.mp3 => /data/4/9/d/3/49d39143e0c42e4c2b852f604938c0d0 (duplicate)
|
22
|
+
/music/jay-z/the_blueprint_3/06-real_as_it_gets.mp3 => /data/9/8/8/d/988d10054f0eceb5def18bbb2c453557
|
23
|
+
/music/jay-z/the_blueprint_3/07-on_to_the_next_one.mp3 => /data/e/f/8/0/ef80c8b3560b5e1c15c919f354d226f8
|
24
|
+
/music/jay-z/the_blueprint_3/08-off_that.mp3 => /data/3/6/a/8/36a8152e0d98ccd6a375a8ab489cd4a1
|
25
|
+
/music/jay-z/the_blueprint_3/09-a_star_is_born.mp3 => /data/4/f/0/f/4f0f8253196a98fb54bed89a3768fb8b
|
26
|
+
/music/jay-z/the_blueprint_3/10-venus_vs_mars.mp3 => /data/3/6/1/c/361cba2aaa0d42bc376187a49448fa45
|
27
|
+
/music/jay-z/the_blueprint_3/11-already_home.mp3 => /data/d/4/a/7/d4a7756791dbd6df6514c84262b9bb18
|
28
|
+
/music/jay-z/the_blueprint_3/12-hate.mp3 => /data/4/a/6/d/4a6d2a9d04778ead9b04d7f45be1e6bd
|
29
|
+
/music/jay-z/the_blueprint_3/13-reminder.mp3 => /data/c/e/7/4/ce74f6184af8acc3af232df9b9335a76
|
30
|
+
/music/jay-z/the_blueprint_3/14-so_ambitious.mp3 => /data/0/d/6/1/0d6140d1a1c681b1f9f5eba7dee523e9
|
31
|
+
/music/jay-z/the_blueprint_3/15-young_forever.mp3 => /data/f/0/2/1/f0212f638eea55b9d5815515d40e9787
|
32
|
+
|
33
|
+
== Jay-Z - The Hits Collection Volume One
|
34
|
+
source destination
|
35
|
+
/music/jay-z/the_hits_collection_volume_one/01-public_service_announcement_(interlude).mp3 => /data/a/c/1/a/ac1a8c0df8971e732f034a2c6efa6fc1
|
36
|
+
/music/jay-z/the_hits_collection_volume_one/02-run_this_town.mp3 => /data/1/f/4/5/1f454817ee460e28ede71b5e5ee902bd (duplicate)
|
37
|
+
/music/jay-z/the_hits_collection_volume_one/03-03_bonnie_&_clyde.mp3 => /data/d/9/6/5/d9659ed413e0be456c35521639953724
|
38
|
+
/music/jay-z/the_hits_collection_volume_one/04-encore.mp3 => /data/c/7/c/e/c7ce40508cb1cacf56cbd671bd1adfb8
|
39
|
+
/music/jay-z/the_hits_collection_volume_one/05-i_just_wanna_love_u_(give_it_2_me).mp3 => /data/e/1/9/f/e19fa1483b208e75792b30d8562aaed0
|
40
|
+
/music/jay-z/the_hits_collection_volume_one/06-izzo_(hova).mp3 => /data/1/a/a/a/1aaabf78c9d8e30745b3fc8b2e87e285
|
41
|
+
/music/jay-z/the_hits_collection_volume_one/07-doa_(death_of_auto-tune).mp3 => /data/1/e/7/a/1e7aa593020b60e6b45d0178e49d0413 (duplicate)
|
42
|
+
/music/jay-z/the_hits_collection_volume_one/08-99_problems.mp3 => /data/7/6/b/6/76b689ae2f65bc44340a4bc2831cd559
|
43
|
+
/music/jay-z/the_hits_collection_volume_one/09-empire_state_of_mind.mp3 => /data/4/9/d/3/49d39143e0c42e4c2b852f604938c0d0 (duplicate)
|
44
|
+
/music/jay-z/the_hits_collection_volume_one/10-dirt_off_your_shoulder.mp3 => /data/3/2/c/5/32c5218d1a460a6257ab6b7aad23add9
|
45
|
+
/music/jay-z/the_hits_collection_volume_one/11-hard_knock_life_(ghetto_anthem).mp3 => /data/3/5/9/9/3599648c6dfba16787a0f27b2593c624
|
46
|
+
/music/jay-z/the_hits_collection_volume_one/12-show_me_what_you_got.mp3 => /data/1/a/3/8/1a38f265b1e40d5fc7e1c1814eecc887
|
47
|
+
/music/jay-z/the_hits_collection_volume_one/13-roc_boys_(and_the_winner_is).mp3 => /data/f/8/7/5/f875b6de8e2f7fd5366a209a1ec225c2
|
48
|
+
/music/jay-z/the_hits_collection_volume_one/14-big_pimpin.mp3 => /data/e/9/e/b/e9ebaa49726d7ac990c4eb57fc8eee59
|
49
|
+
|
50
|
+
= Advantages
|
51
|
+
|
52
|
+
* Save space: dulicate files are replaced with symlinks to one file
|
53
|
+
* Partition data uniformly on multiple disks:
|
54
|
+
/data/[0-8] could be symlinked to e.g. /dev/disk1
|
55
|
+
/data/[9-f] could be symlinked to e.g. /dev/disk2
|
4
56
|
|
5
57
|
== Contributing to checksummer
|
6
58
|
|
data/Rakefile
CHANGED
@@ -13,7 +13,7 @@ require 'jeweler'
|
|
13
13
|
Jeweler::Tasks.new do |gem|
|
14
14
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
15
|
gem.name = "checksummer"
|
16
|
-
gem.homepage = "http://github.com/
|
16
|
+
gem.homepage = "http://github.com/dynport/checksummer"
|
17
17
|
gem.license = "MIT"
|
18
18
|
gem.summary = %Q{Replace files with links to md5 files}
|
19
19
|
gem.description = %Q{Replace files with links to md5 files}
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.4
|
data/checksummer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{checksummer}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.4"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tobias Schwab"]
|
12
|
-
s.date = %q{2011-01-
|
12
|
+
s.date = %q{2011-01-29}
|
13
13
|
s.default_executable = %q{checksummer}
|
14
14
|
s.description = %q{Replace files with links to md5 files}
|
15
15
|
s.email = %q{tobias.schwab@dynport.de}
|
@@ -37,7 +37,7 @@ Gem::Specification.new do |s|
|
|
37
37
|
"spec/checksummer_spec.rb",
|
38
38
|
"spec/spec_helper.rb"
|
39
39
|
]
|
40
|
-
s.homepage = %q{http://github.com/
|
40
|
+
s.homepage = %q{http://github.com/dynport/checksummer}
|
41
41
|
s.licenses = ["MIT"]
|
42
42
|
s.require_paths = ["lib"]
|
43
43
|
s.rubygems_version = %q{1.3.7}
|
data/lib/checksummer_file.rb
CHANGED
@@ -36,14 +36,17 @@ describe ChecksummerFile do
|
|
36
36
|
|
37
37
|
describe "#checksum_to!" do
|
38
38
|
let(:file) { ChecksummerFile.new(:path => "/some/text.csv") }
|
39
|
+
let(:time) { Time.local(2010, 9, 10, 11, 12, 13) }
|
39
40
|
let(:md5) { "fde8dad8ea43640b00cdd1e92e532ca9" }
|
40
41
|
|
41
42
|
before(:each) do
|
42
43
|
FileUtils.stub!(:cp).and_return true
|
43
44
|
FileUtils.stub!(:mkdir_p)
|
45
|
+
FileUtils.stub!(:touch)
|
44
46
|
FileUtils.stub(:ln_sf).and_return true
|
45
47
|
File.stub!(:exists?).and_return false
|
46
48
|
File.stub(:symlink?).and_return false
|
49
|
+
File.stub!(:mtime).and_return time
|
47
50
|
file.stub!(:md5).and_return md5
|
48
51
|
end
|
49
52
|
|
@@ -82,6 +85,11 @@ describe ChecksummerFile do
|
|
82
85
|
it "returns :copied when copied" do
|
83
86
|
file.checksum_to!("/tmp/data").should == :copied
|
84
87
|
end
|
88
|
+
|
89
|
+
it "changes the mtime of the symlink to the mtime of the original file" do
|
90
|
+
FileUtils.should_receive(:touch).with("/some/text.csv", :mtime => time)
|
91
|
+
file.checksum_to!("/tmp/data")
|
92
|
+
end
|
85
93
|
end
|
86
94
|
|
87
95
|
describe "with the file being checksummed already" do
|
@@ -107,6 +115,11 @@ describe ChecksummerFile do
|
|
107
115
|
it "returns :symlinked" do
|
108
116
|
file.checksum_to!("/tmp/data").should == :symlinked
|
109
117
|
end
|
118
|
+
|
119
|
+
it "changes the mtime of the symlink to the mtime of the original file" do
|
120
|
+
FileUtils.should_receive(:touch).with("/some/text.csv", :mtime => time)
|
121
|
+
file.checksum_to!("/tmp/data")
|
122
|
+
end
|
110
123
|
end
|
111
124
|
|
112
125
|
describe "with the file being a symlink" do
|
@@ -132,6 +145,11 @@ describe ChecksummerFile do
|
|
132
145
|
it "returns :exists" do
|
133
146
|
file.checksum_to!("/tmp/data").should == :was_symlink
|
134
147
|
end
|
148
|
+
|
149
|
+
it "changes the mtime of the symlink to the mtime of the original file" do
|
150
|
+
FileUtils.should_not_receive(:touch)
|
151
|
+
file.checksum_to!("/tmp/data")
|
152
|
+
end
|
135
153
|
end
|
136
154
|
end
|
137
155
|
|
data/spec/checksummer_spec.rb
CHANGED
@@ -151,29 +151,39 @@ describe "Checksummer" do
|
|
151
151
|
describe "#integration" do
|
152
152
|
let(:root) { File.expand_path("tmp", File.dirname(__FILE__)) }
|
153
153
|
|
154
|
+
def time_for_index(index)
|
155
|
+
Time.local(2010, 11, 12, 13, 14, index)
|
156
|
+
end
|
157
|
+
|
154
158
|
before(:each) do
|
155
159
|
FileUtils.rm_rf(root)
|
156
160
|
FileUtils.mkdir_p("#{root}/source")
|
157
161
|
FileUtils.mkdir_p("#{root}/data")
|
158
162
|
FileUtils.mkdir_p("#{root}/data/a/b/c/d/abcdefg")
|
159
163
|
1.upto(3).each do |i|
|
160
|
-
|
164
|
+
path = "#{root}/source/file#{i}.txt"
|
165
|
+
File.open(path, "w") { |f| f.puts "file #{i}" }
|
166
|
+
FileUtils.touch("#{root}/source/file#{i}.txt", :mtime => time_for_index(i))
|
161
167
|
end
|
162
168
|
FileUtils.ln_sf("#{root}/data/a/b/c/d/abcdefg", "#{root}/source/file4.txt")
|
169
|
+
FileUtils.touch("#{root}/data/a/b/c/d/abcdefg", :mtime => time_for_index(4))
|
163
170
|
end
|
164
171
|
|
165
172
|
it "checksums all files" do
|
166
173
|
cs = Checksummer.new("#{root}/data")
|
167
174
|
cs.checksum_directory("#{root}/source")
|
168
|
-
{ "4/3/4/9/4349cfeff8e2eb74dffc369bb5fd084e" => "file2.txt",
|
169
|
-
"
|
170
|
-
|
175
|
+
{ "4/3/4/9/4349cfeff8e2eb74dffc369bb5fd084e" => ["file2.txt", time_for_index(2)],
|
176
|
+
"9/c/3/8/9c38e8324dbf031557c89d53a39f0b26" => ["file3.txt", time_for_index(3)],
|
177
|
+
"e/2/4/3/e243bb39c844b3543a7726576c869caf" => ["file1.txt", time_for_index(1)],
|
178
|
+
"a/b/c/d/abcdefg" => ["file4.txt", time_for_index(4)]
|
179
|
+
}.each do |data_file, (original_file, mtime)|
|
171
180
|
original = Pathname.new("#{root}/source/#{original_file}")
|
172
181
|
data = Pathname.new("#{root}/data/#{data_file}")
|
173
182
|
File.should be_exists(original.to_s)
|
174
183
|
File.should be_exists(data.to_s)
|
175
184
|
original.realpath.to_s.should match(/\//)
|
176
185
|
original.realpath.should == data
|
186
|
+
File.mtime(original).should == mtime
|
177
187
|
end
|
178
188
|
end
|
179
189
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 4
|
9
|
+
version: 0.1.4
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Tobias Schwab
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-01-
|
17
|
+
date: 2011-01-29 00:00:00 +01:00
|
18
18
|
default_executable: checksummer
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -142,7 +142,7 @@ files:
|
|
142
142
|
- spec/checksummer_spec.rb
|
143
143
|
- spec/spec_helper.rb
|
144
144
|
has_rdoc: true
|
145
|
-
homepage: http://github.com/
|
145
|
+
homepage: http://github.com/dynport/checksummer
|
146
146
|
licenses:
|
147
147
|
- MIT
|
148
148
|
post_install_message:
|
@@ -155,7 +155,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
155
|
requirements:
|
156
156
|
- - ">="
|
157
157
|
- !ruby/object:Gem::Version
|
158
|
-
hash:
|
158
|
+
hash: 3104515524890018189
|
159
159
|
segments:
|
160
160
|
- 0
|
161
161
|
version: "0"
|