checksummer 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +23 -0
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +49 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/autotest/discover.rb +1 -0
- data/bin/checksummer +4 -0
- data/checksummer.gemspec +82 -0
- data/lib/checksummer.rb +43 -0
- data/lib/checksummer_file.rb +59 -0
- data/spec/checksummer_file_spec.rb +186 -0
- data/spec/checksummer_spec.rb +181 -0
- data/spec/spec_helper.rb +13 -0
- metadata +180 -0
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
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
data/checksummer.gemspec
ADDED
@@ -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
|
+
|
data/lib/checksummer.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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
|