checksummer 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,23 @@
1
+ if Gem.available?("autotest-fsevent")
2
+ require 'autotest/fsevent'
3
+ end
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.add_exception(%r{^\./\.git})
7
+ at.add_exception(%r{^\./db})
8
+ at.add_exception(%r{^\./log})
9
+ at.add_exception(%r{^\./tmp})
10
+ at.add_exception(%r{^\./spec/tmp})
11
+ at.add_exception(%r{^\./rerun.txt})
12
+ at.add_exception(%r{^\./Gemfile.lock})
13
+ at.add_exception(%r{^\./Gemfile.lock})
14
+ at.add_exception(%r{^\./spec/.*?\.txt})
15
+ at.add_exception(%r{^\./spec/.*?\.html})
16
+
17
+ at.add_mapping(%r%^spec/(.*?)/.*rb$%) { |filename, _|
18
+ filename
19
+ }
20
+ at.add_mapping(%r%^lib/(.*?)\/([^\/]*?)\.rb$%) { |_, m|
21
+ ["spec/#{m[1]}/#{m[2]}_spec.rb"]
22
+ }
23
+ end
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,16 @@
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 'autotest'
10
+ gem 'autotest-growl'
11
+ gem 'ruby-debug19'
12
+ gem "rspec", "~> 2.3.0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.5.2"
15
+ gem "rcov", ">= 0"
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,49 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ ZenTest (4.4.2)
5
+ archive-tar-minitar (0.5.2)
6
+ autotest (4.4.6)
7
+ ZenTest (>= 4.4.1)
8
+ autotest-growl (0.2.9)
9
+ columnize (0.3.2)
10
+ diff-lcs (1.1.2)
11
+ git (1.2.5)
12
+ jeweler (1.5.2)
13
+ bundler (~> 1.0.0)
14
+ git (>= 1.2.5)
15
+ rake
16
+ linecache19 (0.5.11)
17
+ ruby_core_source (>= 0.1.4)
18
+ rake (0.8.7)
19
+ rcov (0.9.9)
20
+ rspec (2.3.0)
21
+ rspec-core (~> 2.3.0)
22
+ rspec-expectations (~> 2.3.0)
23
+ rspec-mocks (~> 2.3.0)
24
+ rspec-core (2.3.1)
25
+ rspec-expectations (2.3.0)
26
+ diff-lcs (~> 1.1.2)
27
+ rspec-mocks (2.3.0)
28
+ ruby-debug-base19 (0.11.24)
29
+ columnize (>= 0.3.1)
30
+ linecache19 (>= 0.5.11)
31
+ ruby_core_source (>= 0.1.4)
32
+ ruby-debug19 (0.11.6)
33
+ columnize (>= 0.3.1)
34
+ linecache19 (>= 0.5.11)
35
+ ruby-debug-base19 (>= 0.11.19)
36
+ ruby_core_source (0.1.4)
37
+ archive-tar-minitar (>= 0.5.2)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ autotest
44
+ autotest-growl
45
+ bundler (~> 1.0.0)
46
+ jeweler (~> 1.5.2)
47
+ rcov
48
+ rspec (~> 2.3.0)
49
+ ruby-debug19
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Tobias Schwab
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
+ = checksummer
2
+
3
+ Description goes here.
4
+
5
+ == Contributing to checksummer
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 Tobias Schwab. See LICENSE.txt for
18
+ further details.
19
+
data/Rakefile ADDED
@@ -0,0 +1,50 @@
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 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "checksummer"
16
+ gem.homepage = "http://github.com/tobstarr/checksummer"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Replace files with links to md5 files}
19
+ gem.description = %Q{Replace files with links to md5 files}
20
+ gem.email = "tobias.schwab@dynport.de"
21
+ gem.authors = ["Tobias Schwab"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
36
+ spec.pattern = 'spec/**/*_spec.rb'
37
+ spec.rcov = true
38
+ end
39
+
40
+ task :default => :spec
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "checksummer #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/bin/checksummer ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env
2
+ require "checksummer"
3
+
4
+ Checksummer.run_for_args(ARGV)
@@ -0,0 +1,82 @@
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{checksummer}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Tobias Schwab"]
12
+ s.date = %q{2011-01-26}
13
+ s.default_executable = %q{checksummer}
14
+ s.description = %q{Replace files with links to md5 files}
15
+ s.email = %q{tobias.schwab@dynport.de}
16
+ s.executables = ["checksummer"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".autotest",
23
+ ".document",
24
+ ".rspec",
25
+ "Gemfile",
26
+ "Gemfile.lock",
27
+ "LICENSE.txt",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "autotest/discover.rb",
32
+ "bin/checksummer",
33
+ "checksummer.gemspec",
34
+ "lib/checksummer.rb",
35
+ "lib/checksummer_file.rb",
36
+ "spec/checksummer_file_spec.rb",
37
+ "spec/checksummer_spec.rb",
38
+ "spec/spec_helper.rb"
39
+ ]
40
+ s.homepage = %q{http://github.com/tobstarr/checksummer}
41
+ s.licenses = ["MIT"]
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{Replace files with links to md5 files}
45
+ s.test_files = [
46
+ "spec/checksummer_file_spec.rb",
47
+ "spec/checksummer_spec.rb",
48
+ "spec/spec_helper.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_development_dependency(%q<autotest>, [">= 0"])
57
+ s.add_development_dependency(%q<autotest-growl>, [">= 0"])
58
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
59
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
62
+ s.add_development_dependency(%q<rcov>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<autotest>, [">= 0"])
65
+ s.add_dependency(%q<autotest-growl>, [">= 0"])
66
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
67
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<autotest>, [">= 0"])
74
+ s.add_dependency(%q<autotest-growl>, [">= 0"])
75
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
76
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ end
81
+ end
82
+
@@ -0,0 +1,43 @@
1
+ $:<< File.expand_path(File.dirname(__FILE__))
2
+
3
+ require "checksummer_file"
4
+ class Checksummer
5
+ attr_accessor :checksum_to, :paths
6
+
7
+ def initialize(checksum_to)
8
+ self.checksum_to = File.expand_path(checksum_to)
9
+ end
10
+
11
+ def checksum_directory(directory)
12
+ files = find(directory)
13
+ total = files.length
14
+ files.each_with_index do |file, i|
15
+ status = file.checksum_to!(checksum_to)
16
+ yield(status, file, i, total) if block_given?
17
+ end
18
+ end
19
+
20
+ def find(directory)
21
+ Kernel.send(:`, %(find #{directory} -type f -printf "%T+\t%s\t%Y\t%p\t%l\n")).split("\n").map do |line|
22
+ ChecksummerFile.from_line(line)
23
+ end
24
+ end
25
+
26
+ def self.run_for_args(args)
27
+ directory, checksum_to = args
28
+ sleep = args.index("--sleep") ? args[args.index("--sleep") + 1].to_i / 1000.0 : 0.1
29
+ if !directory || !File.directory?(directory) || !checksum_to || !File.directory?(checksum_to)
30
+ puts usage
31
+ else
32
+ self.new(checksum_to).checksum_directory(directory) do |status, file, index, total|
33
+ puts "%s\t%0#{total.to_s.length}d/%d\t%s\t%s" % [Time.now.strftime("%Y-%m-%d %H:%M:%S"), index, total, status, file.path]
34
+ $stdout.flush
35
+ sleep sleep if !Range.new(0,7).include?(Time.now.hour)
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.usage
41
+ "checksummer <directory_to_checksum> <directory_to_store_checksummed_files>"
42
+ end
43
+ end
@@ -0,0 +1,59 @@
1
+ require "time"
2
+ require "fileutils"
3
+
4
+ class ChecksummerFile
5
+ attr_accessor :modified_at, :size, :type, :path, :original_path
6
+
7
+ def initialize(attributes = {})
8
+ attributes.each do |key, value|
9
+ self.send :"#{key}=", value if self.respond_to?(:"#{key}=")
10
+ end
11
+ end
12
+
13
+ def path=(new_path)
14
+ @path = new_path
15
+ @md5 = nil
16
+ end
17
+
18
+ def md5
19
+ @md5 ||= md5_module.file(path).to_s
20
+ end
21
+
22
+ def md5_module
23
+ if RUBY_VERSION.match(/^1\.9/)
24
+ require "digest/md5"
25
+ Digest::MD5
26
+ else
27
+ require "md5"
28
+ MD5
29
+ end
30
+ end
31
+
32
+ def self.from_line(line)
33
+ modified_at, size, type, path, original_path = line.chomp.split("\t")
34
+ ChecksummerFile.new(:modified_at => Time.parse(modified_at), :size => size.to_i, :type => type, :path => File.expand_path(path),
35
+ :original_path => original_path ? File.expand_path(original_path) : nil
36
+ )
37
+ end
38
+
39
+ def checksum_to!(checksum_dir)
40
+ if !File.symlink?(path)
41
+ new_path = md5_path(checksum_dir)
42
+ status = if !File.exists?(new_path)
43
+ FileUtils.mkdir_p(File.dirname(new_path))
44
+ FileUtils.cp(path, new_path)
45
+ :copied
46
+ else
47
+ :symlinked
48
+ end
49
+ FileUtils.ln_sf(new_path, path)
50
+ status
51
+ else
52
+ :was_symlink
53
+ end
54
+ end
55
+
56
+ def md5_path(checksum_dir)
57
+ "#{checksum_dir}/#{md5.split("")[0,4].join("/")}/#{md5}"
58
+ end
59
+ end
@@ -0,0 +1,186 @@
1
+ require 'spec_helper'
2
+
3
+ describe ChecksummerFile do
4
+ let(:line) { "2010-09-14+10:16:26.4888617110 66 d /v1/incoming/ " }
5
+ let(:line_with_original_path) { "2010-09-14+10:16:26.4888617110 66 d /v1/incoming/ /tmp" }
6
+
7
+ describe "#from_line" do
8
+ before(:each) do
9
+ @file = ChecksummerFile.from_line(line)
10
+ end
11
+
12
+ it "returns a ChecksummerFile" do
13
+ @file.should be_an_instance_of(ChecksummerFile)
14
+ end
15
+
16
+ { :modified_at => Time.local(2010, 9, 14, 10, 16, 26), :type => "d", :path => "/v1/incoming" }.each do |key, value|
17
+ it "sets #{key.inspect} to #{value.inspect}" do
18
+ @file.send(key).to_s.should == value.to_s
19
+ end
20
+ end
21
+
22
+ it "sets original_path to nil when not in response" do
23
+ @file.original_path.should be_nil
24
+ end
25
+
26
+ it "sets original_path to the path when found in response" do
27
+ ChecksummerFile.from_line(line_with_original_path).original_path.should == "/tmp"
28
+ end
29
+
30
+ it "calls expans_path on all found paths" do
31
+ File.should_receive(:expand_path).with("/v1/incoming/", )
32
+ File.should_receive(:expand_path).with("/tmp")
33
+ ChecksummerFile.from_line(line_with_original_path)
34
+ end
35
+ end
36
+
37
+ describe "#checksum_to!" do
38
+ let(:file) { ChecksummerFile.new(:path => "/some/text.csv") }
39
+ let(:md5) { "fde8dad8ea43640b00cdd1e92e532ca9" }
40
+
41
+ before(:each) do
42
+ FileUtils.stub!(:cp).and_return true
43
+ FileUtils.stub!(:mkdir_p)
44
+ FileUtils.stub(:ln_sf).and_return true
45
+ File.stub!(:exists?).and_return false
46
+ File.stub(:symlink?).and_return false
47
+ file.stub!(:md5).and_return md5
48
+ end
49
+
50
+ it "calls exists with correct parameters" do
51
+ File.should_receive(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9")
52
+ file.checksum_to!("/tmp/data")
53
+ end
54
+
55
+ it "calls File.symlink? with the correct parameters" do
56
+ File.should_receive(:symlink?).with("/some/text.csv").and_return false
57
+ file.checksum_to!("/tmp/data")
58
+ end
59
+
60
+ it "calls md5_path with correct directory" do
61
+ file.should_receive(:md5_path).with("/tmp/data").at_least(1).times.and_return md5
62
+ file.checksum_to!("/tmp/data")
63
+ end
64
+
65
+ describe "with the file not being checksummed" do
66
+ it "copys the file to it's md5" do
67
+ File.stub!(:exists?).and_return false
68
+ FileUtils.should_receive(:cp).with("/some/text.csv", "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9")
69
+ file.checksum_to!("/tmp/data")
70
+ end
71
+
72
+ it "calls FileUtils::mkdir_p with correct path" do
73
+ FileUtils.should_receive(:mkdir_p).with("/tmp/data/f/d/e/8")
74
+ file.checksum_to!("/tmp/data")
75
+ end
76
+
77
+ it "creates a symlink for the copied file" do
78
+ FileUtils.should_receive(:ln_sf).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9", "/some/text.csv")
79
+ file.checksum_to!("/tmp/data")
80
+ end
81
+
82
+ it "returns :copied when copied" do
83
+ file.checksum_to!("/tmp/data").should == :copied
84
+ end
85
+ end
86
+
87
+ describe "with the file being checksummed already" do
88
+ before(:each) do
89
+ File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return true
90
+ end
91
+
92
+ it "does not copy the file when already exists" do
93
+ FileUtils.should_not_receive(:cp)
94
+ file.checksum_to!("/tmp/data")
95
+ end
96
+
97
+ it "does not call FileUtils::mkdir_p" do
98
+ FileUtils.should_not_receive(:mkdir_p)
99
+ file.checksum_to!("/tmp/data")
100
+ end
101
+
102
+ it "does symlink the file" do
103
+ FileUtils.should_receive(:ln_sf).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9", "/some/text.csv")
104
+ file.checksum_to!("/tmp/data")
105
+ end
106
+
107
+ it "returns :symlinked" do
108
+ file.checksum_to!("/tmp/data").should == :symlinked
109
+ end
110
+ end
111
+
112
+ describe "with the file being a symlink" do
113
+ before(:each) do
114
+ File.stub(:symlink?).with("/some/text.csv").and_return true
115
+ end
116
+
117
+ it "does not copy the file when already exists" do
118
+ FileUtils.should_not_receive(:cp)
119
+ file.checksum_to!("/tmp/data")
120
+ end
121
+
122
+ it "does not call FileUtils::mkdir_p" do
123
+ FileUtils.should_not_receive(:mkdir_p)
124
+ file.checksum_to!("/tmp/data")
125
+ end
126
+
127
+ it "does not symlink the file" do
128
+ FileUtils.should_not_receive(:ln_sf)
129
+ file.checksum_to!("/tmp/data")
130
+ end
131
+
132
+ it "returns :exists" do
133
+ file.checksum_to!("/tmp/data").should == :was_symlink
134
+ end
135
+ end
136
+ end
137
+
138
+ describe "#md5" do
139
+ let(:md5_module) { double("md5 module", :file => "sometest") }
140
+ let(:file) do
141
+ file = ChecksummerFile.new(:path => "/some/path")
142
+ file.stub!(:md5_module).and_return md5_module
143
+ file
144
+ end
145
+
146
+
147
+ it "calls md5_module with correct file_path when no md5 set" do
148
+ md5_module.should_receive(:file).with("/some/path")
149
+ file.md5
150
+ end
151
+
152
+ it "saves the md5 in instance variable" do
153
+ checksum = double("checksum", :to_s => "the checksum")
154
+ md5_module.stub(:file).and_return checksum
155
+ file.md5
156
+ file.instance_variable_get(:@md5).should == "the checksum"
157
+ end
158
+
159
+ it "returns the instance variable when set" do
160
+ checksum = double("checksum")
161
+ file.instance_variable_set(:@md5, checksum)
162
+ file.md5.should == checksum
163
+ end
164
+ end
165
+
166
+ describe "#md5_module" do
167
+ it "returns Digest::MD5 for Ruby 1.9" do
168
+ ChecksummerFile.new.md5_module.should == Digest::MD5
169
+ end
170
+ end
171
+
172
+ describe "#path=" do
173
+ it "sets the correct path" do
174
+ file = ChecksummerFile.new
175
+ file.path = "/some/path"
176
+ file.path.should == "/some/path"
177
+ end
178
+
179
+ it "resets an existing md5" do
180
+ file = ChecksummerFile.new
181
+ file.instance_variable_set(:@md5, "somemd5")
182
+ file.path = "/some/path"
183
+ file.instance_variable_get(:@md5).should be_nil
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,181 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Checksummer" do
4
+ class ChecksummerFile
5
+ end
6
+
7
+ let(:checksum_to) { "/data" }
8
+ let(:cs) { cs = Checksummer.new(checksum_to) }
9
+
10
+ describe "#intiailize" do
11
+ it "sets the correct chcksum_to" do
12
+ cs = Checksummer.new("/data")
13
+ cs.checksum_to.should == "/data"
14
+ end
15
+
16
+ it "calls expans path on checksum_to" do
17
+ dir_double = double("some double")
18
+ File.should_receive(:expand_path).with(dir_double).and_return "some path"
19
+ cs = Checksummer.new(dir_double)
20
+ end
21
+ end
22
+
23
+ describe "#checksum_directory" do
24
+ let(:file1) { double("checksummer file 1", :checksum_to! => :copied, :path => "/path1") }
25
+ let(:file2) { double("checksummer file 2", :checksum_to! => :symlinked, :path => "/path2") }
26
+
27
+ it "it calls find with correct parameters" do
28
+ cs.should_receive(:find).with("path1").and_return []
29
+ cs.checksum_directory("path1")
30
+ end
31
+
32
+ it "calls checksum on all ChecksummerFiles" do
33
+ file1.should_receive(:checksum_to!).with("/data").and_return true
34
+ file2.should_receive(:checksum_to!).with("/data").and_return true
35
+ cs.stub!(:find).and_return [file1, file2]
36
+ cs.checksum_directory("path1")
37
+ end
38
+
39
+ it "yields all checksum status messages and files" do
40
+ yielder = double("yielder")
41
+ yielder.should_receive(:got_file).with(:copied, file1, 0, 2)
42
+ yielder.should_receive(:got_file).with(:symlinked, file2, 1, 2)
43
+ cs.stub!(:find).and_return [file1, file2]
44
+ cs.checksum_directory("path1") do |status, file, index, total|
45
+ yielder.got_file(status, file, index, total)
46
+ end
47
+ end
48
+ end
49
+
50
+ describe "#find" do
51
+ let(:files) do
52
+ [
53
+ "2010-09-14+10:16:26.4888617110 66 d /v1/incoming/ ",
54
+ "2010-07-08+17:52:08.6168163060 76 d /v1/incoming/rsync_from_delivery_host ",
55
+ "2010-12-06+18:12:13.0000000000 737280 d /v1/incoming/rsync_from_delivery_host/finetunes ",
56
+ "2010-07-24+19:46:38.0000000000 30 d /v1/incoming/rsync_from_delivery_host/finetunes/1069604473114 ",
57
+ "2009-10-31+16:29:51.0000000000 12032 f /v1/incoming/rsync_from_delivery_host/finetunes/1069604473114/1069604473114.xml ",
58
+ "2010-07-24+19:46:38.0000000000 30 d /v1/incoming/rsync_from_delivery_host/finetunes/1069604681256 "
59
+ ].join("\n")
60
+ end
61
+
62
+ before(:each) do
63
+ Kernel.stub(:`).and_return(files)
64
+ end
65
+
66
+ it "calls system command with correct arguments" do
67
+ Kernel.should_receive(:`).with(%(find path1 -type f -printf "%T+\t%s\t%Y\t%p\t%l\n"))
68
+ cs.find("path1")
69
+ end
70
+
71
+ it "returns the correct amount of files" do
72
+ cs.find("path1").length.should == 6
73
+ end
74
+
75
+ it "returns objects of type ChecksummerFile" do
76
+ cs.find("path1").first.should be_an_instance_of(ChecksummerFile)
77
+ end
78
+
79
+ it "sets the correct atributes" do
80
+ cs.find("path1").first.path.should == "/v1/incoming"
81
+ end
82
+ end
83
+
84
+ describe "#run_for_args" do
85
+ before(:each) do
86
+ Checksummer.stub!(:puts)
87
+ end
88
+
89
+ it "prints usage when no checksum_to found" do
90
+ Checksummer.should_receive(:puts).with Checksummer.usage
91
+ Checksummer.run_for_args([])
92
+ end
93
+
94
+ it "prints usage when checksum dir is not a directory" do
95
+ Checksummer.should_receive(:puts).with Checksummer.usage
96
+ Checksummer.run_for_args(["/path/to/something"])
97
+ end
98
+
99
+ it "prints usage when checksum_to is no directory" do
100
+ Checksummer.should_receive(:puts).with Checksummer.usage
101
+ Checksummer.run_for_args(["/tmp", "/some/path"])
102
+ end
103
+
104
+ it "initializes checksummer with correct checksum_to dir" do
105
+ Checksummer.should_receive(:new).with("/tmp").and_return(double("checksummer", :checksum_directory => true))
106
+ Checksummer.run_for_args(["/tmp", "/tmp"])
107
+ end
108
+
109
+ describe "with a cs double" do
110
+ before(:each) do
111
+ @cs_double = double("cs")
112
+ Checksummer.stub(:new).with("/tmp").and_return @cs_double
113
+ def @cs_double.checksum_directory(path)
114
+ file1 = ChecksummerFile.new(:path => "/path1.txt")
115
+ file2 = ChecksummerFile.new(:path => "/path2.txt")
116
+ yield(:copied, file1, 0, 20)
117
+ yield(:symlinked, file2, 1, 20)
118
+ end
119
+ end
120
+
121
+ it "calls puts with a correct string" do
122
+ Time.stub(:now).and_return Time.local(2010, 9, 10, 11, 12)
123
+ Checksummer.should_receive(:puts).with("2010-09-10 11:12:00\t00/20\tcopied\t/path1.txt")
124
+ Checksummer.should_receive(:puts).with("2010-09-10 11:12:00\t01/20\tsymlinked\t/path2.txt")
125
+ Checksummer.run_for_args(["/tmp", "/tmp"])
126
+ end
127
+
128
+ it "calls sleep with 0.1 when between 8 and 23:59" do
129
+ now = double("now", :hour => 8, :strftime => "some time")
130
+ Time.stub!(:now).and_return(now)
131
+ Checksummer.should_receive(:sleep).with(0.1).at_least(1).times
132
+ Checksummer.run_for_args(["/tmp", "/tmp"])
133
+ end
134
+
135
+ it "calls sleep with 0.5 when between 8 and 23:59 and custom sleep given" do
136
+ now = double("now", :hour => 8, :strftime => "some time")
137
+ Time.stub!(:now).and_return(now)
138
+ Checksummer.should_receive(:sleep).with(0.5).at_least(1).times
139
+ Checksummer.run_for_args(["/tmp", "/tmp", "--sleep", "500"])
140
+ end
141
+
142
+ it "does not call sleep with 0.1 when between 00:00 and 07:59" do
143
+ now = double("now", :hour => 7, :strftime => "some time")
144
+ Time.stub!(:now).and_return(now)
145
+ Checksummer.should_not_receive(:sleep)
146
+ Checksummer.run_for_args(["/tmp", "/tmp"])
147
+ end
148
+ end
149
+ end
150
+
151
+ describe "#integration" do
152
+ let(:root) { File.expand_path("tmp", File.dirname(__FILE__)) }
153
+
154
+ before(:each) do
155
+ FileUtils.rm_rf(root)
156
+ FileUtils.mkdir_p("#{root}/source")
157
+ FileUtils.mkdir_p("#{root}/data")
158
+ FileUtils.mkdir_p("#{root}/data/a/b/c/d/abcdefg")
159
+ 1.upto(3).each do |i|
160
+ File.open("#{root}/source/file#{i}.txt", "w") { |f| f.puts "file #{i}" }
161
+ end
162
+ FileUtils.ln_sf("#{root}/data/a/b/c/d/abcdefg", "#{root}/source/file4.txt")
163
+ end
164
+
165
+ it "checksums all files" do
166
+ cs = Checksummer.new("#{root}/data")
167
+ 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|
171
+ original = Pathname.new("#{root}/source/#{original_file}")
172
+ data = Pathname.new("#{root}/data/#{data_file}")
173
+ File.should be_exists(original.to_s)
174
+ File.should be_exists(data.to_s)
175
+ original.realpath.to_s.should match(/\//)
176
+ original.realpath.should == data
177
+ end
178
+ end
179
+ end
180
+
181
+ end
@@ -0,0 +1,13 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'checksummer'
5
+ require "ruby-debug"
6
+
7
+ # Requires supporting files with custom matchers and macros, etc,
8
+ # in ./support/ and its subdirectories.
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
10
+
11
+ RSpec.configure do |config|
12
+
13
+ end
metadata ADDED
@@ -0,0 +1,180 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: checksummer
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - Tobias Schwab
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-26 00:00:00 +01:00
18
+ default_executable: checksummer
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: autotest
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: autotest-growl
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :development
44
+ prerelease: false
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: ruby-debug19
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ version: "0"
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: rspec
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ segments:
67
+ - 2
68
+ - 3
69
+ - 0
70
+ version: 2.3.0
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: *id004
74
+ - !ruby/object:Gem::Dependency
75
+ name: bundler
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 1
83
+ - 0
84
+ - 0
85
+ version: 1.0.0
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: *id005
89
+ - !ruby/object:Gem::Dependency
90
+ name: jeweler
91
+ requirement: &id006 !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ~>
95
+ - !ruby/object:Gem::Version
96
+ segments:
97
+ - 1
98
+ - 5
99
+ - 2
100
+ version: 1.5.2
101
+ type: :development
102
+ prerelease: false
103
+ version_requirements: *id006
104
+ - !ruby/object:Gem::Dependency
105
+ name: rcov
106
+ requirement: &id007 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ type: :development
115
+ prerelease: false
116
+ version_requirements: *id007
117
+ description: Replace files with links to md5 files
118
+ email: tobias.schwab@dynport.de
119
+ executables:
120
+ - checksummer
121
+ extensions: []
122
+
123
+ extra_rdoc_files:
124
+ - LICENSE.txt
125
+ - README.rdoc
126
+ files:
127
+ - .autotest
128
+ - .document
129
+ - .rspec
130
+ - Gemfile
131
+ - Gemfile.lock
132
+ - LICENSE.txt
133
+ - README.rdoc
134
+ - Rakefile
135
+ - VERSION
136
+ - autotest/discover.rb
137
+ - bin/checksummer
138
+ - checksummer.gemspec
139
+ - lib/checksummer.rb
140
+ - lib/checksummer_file.rb
141
+ - spec/checksummer_file_spec.rb
142
+ - spec/checksummer_spec.rb
143
+ - spec/spec_helper.rb
144
+ has_rdoc: true
145
+ homepage: http://github.com/tobstarr/checksummer
146
+ licenses:
147
+ - MIT
148
+ post_install_message:
149
+ rdoc_options: []
150
+
151
+ require_paths:
152
+ - lib
153
+ required_ruby_version: !ruby/object:Gem::Requirement
154
+ none: false
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ hash: -3983138821397024121
159
+ segments:
160
+ - 0
161
+ version: "0"
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ none: false
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ segments:
168
+ - 0
169
+ version: "0"
170
+ requirements: []
171
+
172
+ rubyforge_project:
173
+ rubygems_version: 1.3.7
174
+ signing_key:
175
+ specification_version: 3
176
+ summary: Replace files with links to md5 files
177
+ test_files:
178
+ - spec/checksummer_file_spec.rb
179
+ - spec/checksummer_spec.rb
180
+ - spec/spec_helper.rb