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 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
- Description goes here.
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/tobstarr/checksummer"
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.2
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.2"
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-26}
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/tobstarr/checksummer}
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}
@@ -46,7 +46,9 @@ class ChecksummerFile
46
46
  else
47
47
  :symlinked
48
48
  end
49
+ mtime = File.mtime(path)
49
50
  FileUtils.ln_sf(new_path, path)
51
+ FileUtils.touch(path, :mtime => mtime)
50
52
  status
51
53
  else
52
54
  :was_symlink
@@ -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
 
@@ -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
- File.open("#{root}/source/file#{i}.txt", "w") { |f| f.puts "file #{i}" }
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", "9/c/3/8/9c38e8324dbf031557c89d53a39f0b26" => "file3.txt",
169
- "e/2/4/3/e243bb39c844b3543a7726576c869caf" => "file1.txt", "a/b/c/d/abcdefg" => "file4.txt"
170
- }.each do |data_file, original_file|
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
- - 2
9
- version: 0.1.2
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-26 00:00:00 +01:00
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/tobstarr/checksummer
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: -3983138821397024121
158
+ hash: 3104515524890018189
159
159
  segments:
160
160
  - 0
161
161
  version: "0"