checksummer 0.1.8 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +14 -0
- data/VERSION +1 -1
- data/bin/checksummer +2 -1
- data/checksummer.gemspec +11 -2
- data/features/checksum.feature +80 -0
- data/features/step_definitions/checksum_steps.rb +70 -0
- data/features/support/env.rb +3 -0
- data/lib/checksummer.rb +12 -24
- data/lib/checksummer_file.rb +20 -10
- data/spec/checksummer_file_spec.rb +78 -19
- data/spec/checksummer_spec.rb +60 -92
- metadata +42 -13
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -6,13 +6,23 @@ GEM
|
|
6
6
|
autotest (4.4.6)
|
7
7
|
ZenTest (>= 4.4.1)
|
8
8
|
autotest-growl (0.2.9)
|
9
|
+
builder (3.0.0)
|
9
10
|
columnize (0.3.2)
|
11
|
+
cucumber (0.10.2)
|
12
|
+
builder (>= 2.1.2)
|
13
|
+
diff-lcs (>= 1.1.2)
|
14
|
+
gherkin (>= 2.3.5)
|
15
|
+
json (>= 1.4.6)
|
16
|
+
term-ansicolor (>= 1.0.5)
|
10
17
|
diff-lcs (1.1.2)
|
18
|
+
gherkin (2.3.5)
|
19
|
+
json (>= 1.4.6)
|
11
20
|
git (1.2.5)
|
12
21
|
jeweler (1.5.2)
|
13
22
|
bundler (~> 1.0.0)
|
14
23
|
git (>= 1.2.5)
|
15
24
|
rake
|
25
|
+
json (1.5.1)
|
16
26
|
linecache19 (0.5.11)
|
17
27
|
ruby_core_source (>= 0.1.4)
|
18
28
|
rake (0.8.7)
|
@@ -35,6 +45,8 @@ GEM
|
|
35
45
|
ruby-debug-base19 (>= 0.11.19)
|
36
46
|
ruby_core_source (0.1.4)
|
37
47
|
archive-tar-minitar (>= 0.5.2)
|
48
|
+
term-ansicolor (1.0.5)
|
49
|
+
timecop (0.3.5)
|
38
50
|
|
39
51
|
PLATFORMS
|
40
52
|
ruby
|
@@ -43,7 +55,9 @@ DEPENDENCIES
|
|
43
55
|
autotest
|
44
56
|
autotest-growl
|
45
57
|
bundler (~> 1.0.0)
|
58
|
+
cucumber
|
46
59
|
jeweler (~> 1.5.2)
|
47
60
|
rcov
|
48
61
|
rspec (~> 2.3.0)
|
49
62
|
ruby-debug19
|
63
|
+
timecop
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/bin/checksummer
CHANGED
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.
|
8
|
+
s.version = "0.2.0"
|
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-03-
|
12
|
+
s.date = %q{2011-03-21}
|
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}
|
@@ -31,6 +31,9 @@ Gem::Specification.new do |s|
|
|
31
31
|
"autotest/discover.rb",
|
32
32
|
"bin/checksummer",
|
33
33
|
"checksummer.gemspec",
|
34
|
+
"features/checksum.feature",
|
35
|
+
"features/step_definitions/checksum_steps.rb",
|
36
|
+
"features/support/env.rb",
|
34
37
|
"lib/checksummer.rb",
|
35
38
|
"lib/checksummer_file.rb",
|
36
39
|
"spec/checksummer_file_spec.rb",
|
@@ -56,27 +59,33 @@ Gem::Specification.new do |s|
|
|
56
59
|
s.add_development_dependency(%q<autotest>, [">= 0"])
|
57
60
|
s.add_development_dependency(%q<autotest-growl>, [">= 0"])
|
58
61
|
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<cucumber>, [">= 0"])
|
59
63
|
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
60
64
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
61
65
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
62
66
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
67
|
+
s.add_development_dependency(%q<timecop>, [">= 0"])
|
63
68
|
else
|
64
69
|
s.add_dependency(%q<autotest>, [">= 0"])
|
65
70
|
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
66
71
|
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
72
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
67
73
|
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
68
74
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
69
75
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
70
76
|
s.add_dependency(%q<rcov>, [">= 0"])
|
77
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
71
78
|
end
|
72
79
|
else
|
73
80
|
s.add_dependency(%q<autotest>, [">= 0"])
|
74
81
|
s.add_dependency(%q<autotest-growl>, [">= 0"])
|
75
82
|
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
83
|
+
s.add_dependency(%q<cucumber>, [">= 0"])
|
76
84
|
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
77
85
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
78
86
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
79
87
|
s.add_dependency(%q<rcov>, [">= 0"])
|
88
|
+
s.add_dependency(%q<timecop>, [">= 0"])
|
80
89
|
end
|
81
90
|
end
|
82
91
|
|
@@ -0,0 +1,80 @@
|
|
1
|
+
Feature: Checksum
|
2
|
+
Scenario: Checksum classic
|
3
|
+
Given I clear tmp
|
4
|
+
And the following files exists:
|
5
|
+
| path | content |
|
6
|
+
| src/file1.txt | file 1 |
|
7
|
+
| src/file2.txt | file 2 |
|
8
|
+
| src/file3.txt | file 3 |
|
9
|
+
| src/file4.txt | file 4 |
|
10
|
+
| dst/4/3/4/9/4349cfeff8e2eb74dffc369bb5fd084e | old content |
|
11
|
+
And the directory "dst" exists
|
12
|
+
When I call "checksummer tmp/src tmp/dst"
|
13
|
+
Then I should see 4 files in "tmp/dst"
|
14
|
+
Then I should see the following files
|
15
|
+
| symlink | path | content |
|
16
|
+
| src/file1.txt | dst/e/2/4/3/e243bb39c844b3543a7726576c869caf | file 1 |
|
17
|
+
| src/file2.txt | dst/4/3/4/9/4349cfeff8e2eb74dffc369bb5fd084e | old content |
|
18
|
+
| src/file3.txt | dst/9/c/3/8/9c38e8324dbf031557c89d53a39f0b26 | file 3 |
|
19
|
+
| src/file4.txt | dst/f/b/8/b/fb8b37442ead70d36d54d241a0c7e069 | file 4 |
|
20
|
+
|
21
|
+
Scenario: Checksum classic with find options
|
22
|
+
Given I clear tmp
|
23
|
+
And the following files exists:
|
24
|
+
| path | content |
|
25
|
+
| src/file10.txt | file 10 |
|
26
|
+
| src/file11.txt | file 11 |
|
27
|
+
| src/file20.txt | file 20 |
|
28
|
+
| src/file21.txt | file 21 |
|
29
|
+
And the directory "dst" exists
|
30
|
+
When I call "checksummer tmp/src tmp/dst -name 'file1*'"
|
31
|
+
Then I should see 2 files in "tmp/dst"
|
32
|
+
Then I should see the following files
|
33
|
+
| symlink | path | content |
|
34
|
+
| src/file10.txt | dst/a/9/e/3/a9e3737bb4cf960ff521c4ad4c8275e7 | file 10 |
|
35
|
+
| src/file11.txt | dst/7/1/5/0/715081268e5e053a7e89daf6c155244a | file 11 |
|
36
|
+
And the output should look like this
|
37
|
+
| index | total | checksummed_path |
|
38
|
+
| 1 | 2 | tmp/dst/a/9/e/3/a9e3737bb4cf960ff521c4ad4c8275e7 |
|
39
|
+
| 2 | 2 | tmp/dst/7/1/5/0/715081268e5e053a7e89daf6c155244a |
|
40
|
+
|
41
|
+
Scenario: Checksum from stdin
|
42
|
+
Given I clear tmp
|
43
|
+
And the following files exists:
|
44
|
+
| path | content |
|
45
|
+
| src/file10.txt | file 10 |
|
46
|
+
| src/file11.txt | file 11 |
|
47
|
+
| src/file20.txt | file 20 |
|
48
|
+
| src/file21.txt | file 21 |
|
49
|
+
And the directory "dst" exists
|
50
|
+
When I call "checksummer --stdin tmp/dst" piped through "find tmp/src -name 'file1*.txt' -printf '%p\t%s\n'"
|
51
|
+
Then I should see 2 files in "tmp/dst"
|
52
|
+
Then I should see the following files
|
53
|
+
| symlink | path | content |
|
54
|
+
| src/file10.txt | dst/a/9/e/3/a9e3737bb4cf960ff521c4ad4c8275e7 | file 10 |
|
55
|
+
| src/file11.txt | dst/7/1/5/0/715081268e5e053a7e89daf6c155244a | file 11 |
|
56
|
+
And the output should look like this
|
57
|
+
| index | total | checksummed_path |
|
58
|
+
| 1 | 2 | tmp/dst/a/9/e/3/a9e3737bb4cf960ff521c4ad4c8275e7 |
|
59
|
+
| 2 | 2 | tmp/dst/7/1/5/0/715081268e5e053a7e89daf6c155244a |
|
60
|
+
|
61
|
+
Scenario: Checksum from plain text
|
62
|
+
Given I clear tmp
|
63
|
+
And the following files exists:
|
64
|
+
| path | content |
|
65
|
+
| src/file10.txt | file 10 |
|
66
|
+
| src/file11.txt | file 11 |
|
67
|
+
| src/file20.txt | file 20 |
|
68
|
+
| src/file21.txt | file 21 |
|
69
|
+
And the following file list exists in "src/files.txt"
|
70
|
+
| path |
|
71
|
+
| src/file10.txt |
|
72
|
+
| src/file20.txt |
|
73
|
+
| src/file30.txt |
|
74
|
+
And the directory "dst" exists
|
75
|
+
When I call "checksummer --stdin tmp/dst" piped through "cat tmp/src/files.txt"
|
76
|
+
Then I should see 2 files in "tmp/dst"
|
77
|
+
Then I should see the following files
|
78
|
+
| symlink | path | content |
|
79
|
+
| src/file10.txt | dst/a/9/e/3/a9e3737bb4cf960ff521c4ad4c8275e7 | file 10 |
|
80
|
+
| src/file20.txt | dst/0/6/7/f/067f81212cf0fb2e982bd628a8606f97 | file 20 |
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "pathname"
|
2
|
+
require "timecop"
|
3
|
+
require "time"
|
4
|
+
|
5
|
+
def root
|
6
|
+
Pathname.new(File.expand_path("../../", File.dirname(__FILE__)))
|
7
|
+
end
|
8
|
+
|
9
|
+
Given /^cucumber working$/ do
|
10
|
+
end
|
11
|
+
|
12
|
+
Given /^the following files exists:$/ do |table|
|
13
|
+
table.hashes.each do |hash|
|
14
|
+
full_path = root.join("tmp/#{hash["path"]}")
|
15
|
+
FileUtils.mkdir_p(File.dirname(full_path))
|
16
|
+
File.open(full_path, "w") do |f|
|
17
|
+
f.puts(hash["content"])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
Given /^the directory "([^"]*)" exists$/ do |path|
|
23
|
+
FileUtils.mkdir_p(root.join("tmp/#{path}"))
|
24
|
+
end
|
25
|
+
|
26
|
+
When /^I call "([^"]*)"$/ do |cmd|
|
27
|
+
@out = `ruby #{root}/bin/#{cmd}`
|
28
|
+
end
|
29
|
+
|
30
|
+
When /^I call "([^"]*)" piped through "([^"]*)"$/ do |cmd, pipe|
|
31
|
+
@out = `#{pipe} | ruby #{root}/bin/#{cmd}`
|
32
|
+
end
|
33
|
+
|
34
|
+
Given /^I clear tmp$/ do
|
35
|
+
FileUtils.rm_rf(root.join("tmp"))
|
36
|
+
end
|
37
|
+
|
38
|
+
Then /^I should see the following files$/ do |table|
|
39
|
+
table.hashes.each do |hash|
|
40
|
+
path = root.join("tmp/#{hash["path"]}").to_s
|
41
|
+
Pathname.new(root.join("tmp/#{hash["symlink"]}")).realpath.to_s.should == path
|
42
|
+
File.should be_exists(path)
|
43
|
+
File.read(path).strip.should == hash["content"]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
Then /^I should see (\d+) files in "([^"]*)"$/ do |count, path|
|
48
|
+
Dir.glob("#{root.join("#{path}/**/*")}").select { |file_path| File.file?(file_path) }.count.should == count.to_i
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
Given /^the following file list exists in "([^"]*)"$/ do |path, table|
|
53
|
+
File.open(root.join("tmp/#{path}"), "w") do |f|
|
54
|
+
table.hashes.each do |hash|
|
55
|
+
f.puts root.join("tmp/#{hash["path"]}")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Then /^the output should look like this$/ do |table|
|
61
|
+
results = [%w(index total checksummed_path)] + @out.split("\n").map do |line|
|
62
|
+
hash = JSON.parse(line)
|
63
|
+
[hash["index"], hash["total"], hash["checksummed_path"].gsub("#{root}/", "")].map(&:to_s)
|
64
|
+
end
|
65
|
+
table.diff!(results)
|
66
|
+
end
|
67
|
+
|
68
|
+
Given /^I freeze time to "([^"]*)"$/ do |time|
|
69
|
+
Timecop.freeze(Time.parse(time))
|
70
|
+
end
|
data/lib/checksummer.rb
CHANGED
@@ -1,26 +1,10 @@
|
|
1
1
|
$:<< File.expand_path(File.dirname(__FILE__))
|
2
2
|
|
3
3
|
require "checksummer_file"
|
4
|
+
require "json"
|
4
5
|
class Checksummer
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(checksum_to)
|
8
|
-
self.checksum_to = File.expand_path(checksum_to)
|
9
|
-
end
|
10
|
-
|
11
|
-
def checksum_directory(directory, find_options = nil)
|
12
|
-
files = find(directory, find_options)
|
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, options = nil)
|
21
|
-
Kernel.send(:`, %(find #{directory} #{options ? "#{options} " : ""}-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
|
6
|
+
def self.find(directory, options = nil)
|
7
|
+
Kernel.send(:`, %(find #{directory} #{options ? "#{options} " : ""}-type f -printf "%p\t%T+\t%s\t%Y\t%l\n")).split("\n")
|
24
8
|
end
|
25
9
|
|
26
10
|
def self.run_for_args(args)
|
@@ -30,15 +14,19 @@ class Checksummer
|
|
30
14
|
args.delete_at(idx)
|
31
15
|
sleep = args.delete_at(idx).to_i / 1000.0
|
32
16
|
end
|
33
|
-
if
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
17
|
+
if directory && checksum_to && File.directory?(checksum_to)
|
18
|
+
started_at = Time.now
|
19
|
+
lines = directory == "--stdin" ? $stdin.readlines : find(directory, args[2..-1].join(" "))
|
20
|
+
total = lines.count
|
21
|
+
lines.each_with_index do |line, index|
|
22
|
+
extra = { :index => index + 1, :total => lines.count, :started_at => started_at.iso8601 }
|
23
|
+
puts ChecksummerFile.from_line(line).checksum_to!(checksum_to).merge(extra).to_json
|
38
24
|
$stdout.flush
|
39
25
|
sleep sleep if !Range.new(0,7).include?(Time.now.hour)
|
40
26
|
end
|
27
|
+
return true
|
41
28
|
end
|
29
|
+
puts usage
|
42
30
|
end
|
43
31
|
|
44
32
|
def self.usage
|
data/lib/checksummer_file.rb
CHANGED
@@ -2,7 +2,7 @@ require "time"
|
|
2
2
|
require "fileutils"
|
3
3
|
|
4
4
|
class ChecksummerFile
|
5
|
-
attr_accessor :modified_at, :size, :type, :path, :original_path
|
5
|
+
attr_accessor :modified_at, :size, :type, :path, :original_path, :original_line
|
6
6
|
|
7
7
|
def initialize(attributes = {})
|
8
8
|
attributes.each do |key, value|
|
@@ -30,16 +30,24 @@ class ChecksummerFile
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def self.from_line(line)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
if path = line.chomp.split("\t").first
|
34
|
+
ChecksummerFile.new(:original_line => line.chomp, :path => File.expand_path(path))
|
35
|
+
else
|
36
|
+
ChecksummerFile.new
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.from_paths(stream)
|
41
|
+
stream.map { |path| self.new(:path => path.chomp.split("\t").first) }
|
37
42
|
end
|
38
43
|
|
39
44
|
def checksum_to!(checksum_dir)
|
40
|
-
|
41
|
-
|
42
|
-
status =
|
45
|
+
status = { :original_line => original_line, :original_path => path }
|
46
|
+
if path.to_s.strip.length == 0 || !File.exists?(path)
|
47
|
+
status[:status] = :not_found
|
48
|
+
elsif !File.symlink?(path)
|
49
|
+
new_path = File.expand_path(md5_path(checksum_dir))
|
50
|
+
status[:status] = if !File.exists?(new_path)
|
43
51
|
FileUtils.mkdir_p(File.dirname(new_path))
|
44
52
|
FileUtils.cp(path, "#{new_path}.tmp")
|
45
53
|
FileUtils.mv("#{new_path}.tmp", new_path)
|
@@ -47,13 +55,15 @@ class ChecksummerFile
|
|
47
55
|
else
|
48
56
|
:symlinked
|
49
57
|
end
|
58
|
+
status[:checksummed_path] = new_path
|
59
|
+
status[:checksum] = File.basename(new_path)
|
50
60
|
mtime = File.mtime(path)
|
51
61
|
FileUtils.ln_sf(new_path, path)
|
52
62
|
FileUtils.touch(path, :mtime => mtime)
|
53
|
-
status
|
54
63
|
else
|
55
|
-
:was_symlink
|
64
|
+
status[:status] = :was_symlink
|
56
65
|
end
|
66
|
+
status
|
57
67
|
end
|
58
68
|
|
59
69
|
def md5_path(checksum_dir)
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe ChecksummerFile do
|
4
|
-
let(:line) { "2010-09-14+10:16:26.4888617110 66 d /
|
5
|
-
let(:line_with_original_path) { "2010-09-14+10:16:26.4888617110 66 d /v1/incoming/ /tmp" }
|
4
|
+
let(:line) { "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d /tmp\n" }
|
6
5
|
|
7
6
|
describe "#from_line" do
|
8
7
|
before(:each) do
|
@@ -13,24 +12,21 @@ describe ChecksummerFile do
|
|
13
12
|
@file.should be_an_instance_of(ChecksummerFile)
|
14
13
|
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
@file.send(key).to_s.should == value.to_s
|
19
|
-
end
|
15
|
+
it "sets path to the first chunk" do
|
16
|
+
@file.path.should == "/v1/incoming"
|
20
17
|
end
|
21
18
|
|
22
|
-
it "sets
|
23
|
-
@file.
|
19
|
+
it "sets the original_line to the chomped line" do
|
20
|
+
@file.original_line.should == "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d /tmp"
|
24
21
|
end
|
25
22
|
|
26
|
-
it "
|
27
|
-
|
23
|
+
it "calls expans_path on all found paths" do
|
24
|
+
File.should_receive(:expand_path).with("/v1/incoming/").and_return "/some/path"
|
25
|
+
ChecksummerFile.from_line(line).path.should == "/some/path"
|
28
26
|
end
|
29
27
|
|
30
|
-
it "
|
31
|
-
|
32
|
-
File.should_receive(:expand_path).with("/tmp")
|
33
|
-
ChecksummerFile.from_line(line_with_original_path)
|
28
|
+
it "does not break when line is nil" do
|
29
|
+
ChecksummerFile.from_line("\n").path.should == nil
|
34
30
|
end
|
35
31
|
end
|
36
32
|
|
@@ -49,6 +45,7 @@ describe ChecksummerFile do
|
|
49
45
|
File.stub(:symlink?).and_return false
|
50
46
|
File.stub!(:mtime).and_return time
|
51
47
|
file.stub!(:md5).and_return md5
|
48
|
+
File.stub(:exists?).with("/some/text.csv").and_return true
|
52
49
|
end
|
53
50
|
|
54
51
|
it "calls exists with correct parameters" do
|
@@ -66,15 +63,38 @@ describe ChecksummerFile do
|
|
66
63
|
file.checksum_to!("/tmp/data")
|
67
64
|
end
|
68
65
|
|
66
|
+
it "returns a hash" do
|
67
|
+
file.checksum_to!("/tmp/data").should be_an_instance_of(Hash)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "includes the original line" do
|
71
|
+
file.original_line = "some line"
|
72
|
+
file.checksum_to!("/tmp/data")[:original_line].should == "some line"
|
73
|
+
end
|
74
|
+
|
75
|
+
it "includes the path" do
|
76
|
+
file.checksum_to!("/tmp/data")[:original_path].should == "/some/text.csv"
|
77
|
+
end
|
78
|
+
|
79
|
+
it "includes status :not_found when path is blank" do
|
80
|
+
file.path = " "
|
81
|
+
file.checksum_to!("/tmp/data")[:status].should == :not_found
|
82
|
+
end
|
83
|
+
|
84
|
+
it "includes status :no_exusts when path is nil" do
|
85
|
+
file.path = nil
|
86
|
+
file.checksum_to!("/tmp/data")[:status].should == :not_found
|
87
|
+
end
|
88
|
+
|
69
89
|
describe "with the file not being checksummed" do
|
70
90
|
it "copys the file to it's md5" do
|
71
|
-
File.stub!(:exists?).and_return false
|
91
|
+
File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return false
|
72
92
|
FileUtils.should_receive(:cp).with("/some/text.csv", "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9.tmp")
|
73
93
|
file.checksum_to!("/tmp/data")
|
74
94
|
end
|
75
95
|
|
76
96
|
it "renames the tmp file to the final name" do
|
77
|
-
File.stub!(:exists?).and_return false
|
97
|
+
File.stub!(:exists?).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9").and_return false
|
78
98
|
FileUtils.should_receive(:mv).with("/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9.tmp", "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9")
|
79
99
|
file.checksum_to!("/tmp/data")
|
80
100
|
end
|
@@ -90,7 +110,11 @@ describe ChecksummerFile do
|
|
90
110
|
end
|
91
111
|
|
92
112
|
it "returns :copied when copied" do
|
93
|
-
file.checksum_to!("/tmp/data").should == :copied
|
113
|
+
file.checksum_to!("/tmp/data")[:status].should == :copied
|
114
|
+
end
|
115
|
+
|
116
|
+
it "includes the checksummed_path" do
|
117
|
+
file.checksum_to!("/tmp/data")[:checksummed_path].should == "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9"
|
94
118
|
end
|
95
119
|
|
96
120
|
it "changes the mtime of the symlink to the mtime of the original file" do
|
@@ -120,7 +144,15 @@ describe ChecksummerFile do
|
|
120
144
|
end
|
121
145
|
|
122
146
|
it "returns :symlinked" do
|
123
|
-
file.checksum_to!("/tmp/data").should == :symlinked
|
147
|
+
file.checksum_to!("/tmp/data")[:status].should == :symlinked
|
148
|
+
end
|
149
|
+
|
150
|
+
it "includes the checksummed_path" do
|
151
|
+
file.checksum_to!("/tmp/data")[:checksummed_path].should == "/tmp/data/f/d/e/8/fde8dad8ea43640b00cdd1e92e532ca9"
|
152
|
+
end
|
153
|
+
|
154
|
+
it "includes the checksum" do
|
155
|
+
file.checksum_to!("/tmp/data")[:checksum].should == "fde8dad8ea43640b00cdd1e92e532ca9"
|
124
156
|
end
|
125
157
|
|
126
158
|
it "changes the mtime of the symlink to the mtime of the original file" do
|
@@ -150,7 +182,7 @@ describe ChecksummerFile do
|
|
150
182
|
end
|
151
183
|
|
152
184
|
it "returns :exists" do
|
153
|
-
file.checksum_to!("/tmp/data").should == :was_symlink
|
185
|
+
file.checksum_to!("/tmp/data")[:status].should == :was_symlink
|
154
186
|
end
|
155
187
|
|
156
188
|
it "changes the mtime of the symlink to the mtime of the original file" do
|
@@ -158,6 +190,12 @@ describe ChecksummerFile do
|
|
158
190
|
file.checksum_to!("/tmp/data")
|
159
191
|
end
|
160
192
|
end
|
193
|
+
|
194
|
+
describe "with the file not existing" do
|
195
|
+
it "returns status :not_exists" do
|
196
|
+
ChecksummerFile.new(:path => "/some/broken/path").checksum_to!("/tmp")[:status].should == :not_found
|
197
|
+
end
|
198
|
+
end
|
161
199
|
end
|
162
200
|
|
163
201
|
describe "#md5" do
|
@@ -208,4 +246,25 @@ describe ChecksummerFile do
|
|
208
246
|
file.instance_variable_get(:@md5).should be_nil
|
209
247
|
end
|
210
248
|
end
|
249
|
+
|
250
|
+
describe "#from_paths" do
|
251
|
+
let(:stream) { ["/file/1.txt", "/file/2.txt\n"] }
|
252
|
+
|
253
|
+
it "returns the correct amount of files" do
|
254
|
+
ChecksummerFile.from_paths(stream).length.should == 2
|
255
|
+
end
|
256
|
+
|
257
|
+
it "sets the correct paths" do
|
258
|
+
ChecksummerFile.from_paths(stream).first.path.should == "/file/1.txt"
|
259
|
+
end
|
260
|
+
|
261
|
+
it "strips the paths" do
|
262
|
+
ChecksummerFile.from_paths(stream).at(1).path.should == "/file/2.txt"
|
263
|
+
end
|
264
|
+
|
265
|
+
it "splits the lines by \t" do
|
266
|
+
stream_with_tabs = ["/file/1.txt\t10", "/file/2.txt\t30\n"]
|
267
|
+
ChecksummerFile.from_paths(stream_with_tabs).first.path.should == "/file/1.txt"
|
268
|
+
end
|
269
|
+
end
|
211
270
|
end
|
data/spec/checksummer_spec.rb
CHANGED
@@ -1,61 +1,17 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "Checksummer" do
|
4
|
-
class ChecksummerFile
|
5
|
-
end
|
6
|
-
|
7
4
|
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 "calls find with correct parameters" do
|
28
|
-
cs.should_receive(:find).with("path1", "-mtime +1").and_return []
|
29
|
-
cs.checksum_directory("path1", "-mtime +1")
|
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
5
|
|
50
6
|
describe "#find" do
|
51
7
|
let(:files) do
|
52
8
|
[
|
53
|
-
"2010-09-14+10:16:26.4888617110 66 d
|
54
|
-
"2010-07-08+17:52:08.6168163060 76 d
|
55
|
-
"2010-12-06+18:12:13.0000000000 737280
|
56
|
-
"2010-07-24+19:46:38.0000000000 30 d
|
57
|
-
"2009-10-31+16:29:51.0000000000 12032 f
|
58
|
-
"2010-07-24+19:46:38.0000000000 30 d
|
9
|
+
"/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d ",
|
10
|
+
"/v1/incoming/rsync_from_delivery_host 2010-07-08+17:52:08.6168163060 76 d ",
|
11
|
+
"d /v1/incoming/rsync_from_delivery_host/finetunes 2010-12-06+18:12:13.0000000000 737280 ",
|
12
|
+
"/v1/incoming/rsync_from_delivery_host/finetunes/1069604473114 2010-07-24+19:46:38.0000000000 30 d ",
|
13
|
+
"/v1/incoming/rsync_from_delivery_host/finetunes/1069604473114/1069604473114.xml 2009-10-31+16:29:51.0000000000 12032 f ",
|
14
|
+
"/v1/incoming/rsync_from_delivery_host/finetunes/1069604681256 2010-07-24+19:46:38.0000000000 30 d "
|
59
15
|
].join("\n")
|
60
16
|
end
|
61
17
|
|
@@ -64,25 +20,25 @@ describe "Checksummer" do
|
|
64
20
|
end
|
65
21
|
|
66
22
|
it "calls system command with correct arguments" do
|
67
|
-
Kernel.should_receive(:`).with(%(find path1 -type f -printf "%T+\t%s\t%Y\t%
|
68
|
-
|
23
|
+
Kernel.should_receive(:`).with(%(find path1 -type f -printf "%p\t%T+\t%s\t%Y\t%l\n"))
|
24
|
+
Checksummer.find("path1")
|
69
25
|
end
|
70
26
|
|
71
27
|
it "uses find options" do
|
72
|
-
Kernel.should_receive(:`).with(%(find path1 -mtime +1 -type f -printf "%T+\t%s\t%Y\t%
|
73
|
-
|
28
|
+
Kernel.should_receive(:`).with(%(find path1 -mtime +1 -type f -printf "%p\t%T+\t%s\t%Y\t%l\n"))
|
29
|
+
Checksummer.find("path1", "-mtime +1")
|
74
30
|
end
|
75
31
|
|
76
32
|
it "returns the correct amount of files" do
|
77
|
-
|
33
|
+
Checksummer.find("path1").length.should == 6
|
78
34
|
end
|
79
35
|
|
80
36
|
it "returns objects of type ChecksummerFile" do
|
81
|
-
|
37
|
+
Checksummer.find("path1").first.should be_an_instance_of(String)
|
82
38
|
end
|
83
39
|
|
84
40
|
it "sets the correct atributes" do
|
85
|
-
|
41
|
+
Checksummer.find("path1").first.should == "/v1/incoming/ 2010-09-14+10:16:26.4888617110 66 d "
|
86
42
|
end
|
87
43
|
end
|
88
44
|
|
@@ -106,61 +62,73 @@ describe "Checksummer" do
|
|
106
62
|
Checksummer.run_for_args(["/tmp", "/some/path"])
|
107
63
|
end
|
108
64
|
|
109
|
-
it "
|
110
|
-
Checksummer.should_receive(:
|
111
|
-
Checksummer.run_for_args(["/tmp", "/tmp"])
|
112
|
-
end
|
113
|
-
|
114
|
-
it "calls checksum_directory wirh correct find options" do
|
115
|
-
checksummer = double("checksummer")
|
116
|
-
Checksummer.stub!(:new).and_return checksummer
|
117
|
-
checksummer.should_receive(:checksum_directory).with("/tmp", %(-name "*.mp3"))
|
65
|
+
it "calls find with the correct attributes" do
|
66
|
+
Checksummer.should_receive(:find).with("/tmp", %(-name "*.mp3")).and_return([])
|
118
67
|
Checksummer.run_for_args(["/tmp", "/tmp", "-name", %("*.mp3")])
|
119
68
|
end
|
120
69
|
|
121
|
-
it "
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
70
|
+
# it "initializes checksummer with correct checksum_to dir" do
|
71
|
+
# Checksummer.should_receive(:new).with("/tmp").and_return(double("checksummer", :checksum_directory => true))
|
72
|
+
# Checksummer.run_for_args(["/tmp", "/tmp"])
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# it "calls checksum_directory with correct find options" do
|
76
|
+
# checksummer = double("checksummer")
|
77
|
+
# Checksummer.stub!(:new).and_return checksummer
|
78
|
+
# checksummer.should_receive(:checksum_directory).with("/tmp", %(-name "*.mp3"))
|
79
|
+
# Checksummer.run_for_args(["/tmp", "/tmp", "-name", %("*.mp3")])
|
80
|
+
# end
|
81
|
+
#
|
82
|
+
# it "does not call checksum_directory with sleep parameter" do
|
83
|
+
# checksummer = double("checksummer")
|
84
|
+
# Checksummer.stub!(:new).and_return checksummer
|
85
|
+
# checksummer.should_receive(:checksum_directory).with("/tmp", %(-mtime +1))
|
86
|
+
# Checksummer.run_for_args(["/tmp", "/tmp", "-mtime", "+1", "--sleep", "10"])
|
87
|
+
# end
|
88
|
+
|
89
|
+
describe "with files given from stdin" do
|
90
|
+
it "calls from_line with all files from stdin" do
|
91
|
+
$stdin = StringIO.new("/path/1.txt\n/path/2.txt")
|
92
|
+
file_double = double("file", :checksum_to! => {})
|
93
|
+
ChecksummerFile.should_receive(:from_line).with("/path/1.txt\n").and_return file_double
|
94
|
+
ChecksummerFile.should_receive(:from_line).with("/path/2.txt").and_return file_double
|
95
|
+
Checksummer.run_for_args(["--stdin", "/tmp"])
|
96
|
+
end
|
97
|
+
|
98
|
+
it "calls checksum_files with files_from_stream when --stdin given" do
|
99
|
+
$stdin = StringIO.new("/path/1.txt\n/path/2.txt")
|
100
|
+
double1 = double("double 1")
|
101
|
+
double2 = double("double 2")
|
102
|
+
ChecksummerFile.stub(:from_line).with("/path/1.txt\n").and_return double1
|
103
|
+
ChecksummerFile.stub(:from_line).with("/path/2.txt").and_return double2
|
104
|
+
double1.should_receive(:checksum_to!).with("/tmp").and_return({})
|
105
|
+
double2.should_receive(:checksum_to!).with("/tmp").and_return({})
|
106
|
+
Checksummer.run_for_args(["--stdin", "/tmp"])
|
107
|
+
end
|
126
108
|
end
|
127
109
|
|
128
110
|
describe "with a cs double" do
|
129
111
|
before(:each) do
|
130
|
-
|
131
|
-
Checksummer.stub(:new).with("/tmp").and_return @cs_double
|
132
|
-
def @cs_double.checksum_directory(path, find_options)
|
133
|
-
file1 = ChecksummerFile.new(:path => "/path1.txt")
|
134
|
-
file2 = ChecksummerFile.new(:path => "/path2.txt")
|
135
|
-
yield(:copied, file1, 0, 20)
|
136
|
-
yield(:symlinked, file2, 1, 20)
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
it "calls puts with a correct string" do
|
141
|
-
Time.stub(:now).and_return Time.local(2010, 9, 10, 11, 12)
|
142
|
-
Checksummer.should_receive(:puts).with("2010-09-10 11:12:00\t00/20\tcopied\t/path1.txt")
|
143
|
-
Checksummer.should_receive(:puts).with("2010-09-10 11:12:00\t01/20\tsymlinked\t/path2.txt")
|
144
|
-
Checksummer.run_for_args(["/tmp", "/tmp"])
|
112
|
+
Checksummer.stub!(:find).and_return(%w(/path1.txt /path2.txt))
|
145
113
|
end
|
146
114
|
|
147
115
|
it "calls sleep with 0.1 when between 8 and 23:59" do
|
148
|
-
|
149
|
-
Time.stub!(:now).and_return(
|
116
|
+
time = Time.local(2011, 1, 2, 8, 0, 0)
|
117
|
+
Time.stub!(:now).and_return(time)
|
150
118
|
Checksummer.should_receive(:sleep).with(0.1).at_least(1).times
|
151
119
|
Checksummer.run_for_args(["/tmp", "/tmp"])
|
152
120
|
end
|
153
121
|
|
154
122
|
it "calls sleep with 0.5 when between 8 and 23:59 and custom sleep given" do
|
155
|
-
|
156
|
-
Time.stub!(:now).and_return(
|
123
|
+
time = Time.local(2011, 1, 2, 8, 0, 0)
|
124
|
+
Time.stub!(:now).and_return(time)
|
157
125
|
Checksummer.should_receive(:sleep).with(0.5).at_least(1).times
|
158
126
|
Checksummer.run_for_args(["/tmp", "/tmp", "--sleep", "500"])
|
159
127
|
end
|
160
128
|
|
161
129
|
it "does not call sleep with 0.1 when between 00:00 and 07:59" do
|
162
|
-
|
163
|
-
Time.stub!(:now).and_return(
|
130
|
+
time = Time.local(2011, 1, 2, 7, 59, 59)
|
131
|
+
Time.stub!(:now).and_return(time)
|
164
132
|
Checksummer.should_not_receive(:sleep)
|
165
133
|
Checksummer.run_for_args(["/tmp", "/tmp"])
|
166
134
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
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-03-
|
17
|
+
date: 2011-03-21 00:00:00 +01:00
|
18
18
|
default_executable: checksummer
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -57,8 +57,21 @@ dependencies:
|
|
57
57
|
prerelease: false
|
58
58
|
version_requirements: *id003
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
|
-
name:
|
60
|
+
name: cucumber
|
61
61
|
requirement: &id004 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
segments:
|
67
|
+
- 0
|
68
|
+
version: "0"
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: *id004
|
72
|
+
- !ruby/object:Gem::Dependency
|
73
|
+
name: rspec
|
74
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
62
75
|
none: false
|
63
76
|
requirements:
|
64
77
|
- - ~>
|
@@ -70,10 +83,10 @@ dependencies:
|
|
70
83
|
version: 2.3.0
|
71
84
|
type: :development
|
72
85
|
prerelease: false
|
73
|
-
version_requirements: *
|
86
|
+
version_requirements: *id005
|
74
87
|
- !ruby/object:Gem::Dependency
|
75
88
|
name: bundler
|
76
|
-
requirement: &
|
89
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
77
90
|
none: false
|
78
91
|
requirements:
|
79
92
|
- - ~>
|
@@ -85,10 +98,10 @@ dependencies:
|
|
85
98
|
version: 1.0.0
|
86
99
|
type: :development
|
87
100
|
prerelease: false
|
88
|
-
version_requirements: *
|
101
|
+
version_requirements: *id006
|
89
102
|
- !ruby/object:Gem::Dependency
|
90
103
|
name: jeweler
|
91
|
-
requirement: &
|
104
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
92
105
|
none: false
|
93
106
|
requirements:
|
94
107
|
- - ~>
|
@@ -100,10 +113,10 @@ dependencies:
|
|
100
113
|
version: 1.5.2
|
101
114
|
type: :development
|
102
115
|
prerelease: false
|
103
|
-
version_requirements: *
|
116
|
+
version_requirements: *id007
|
104
117
|
- !ruby/object:Gem::Dependency
|
105
118
|
name: rcov
|
106
|
-
requirement: &
|
119
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
107
120
|
none: false
|
108
121
|
requirements:
|
109
122
|
- - ">="
|
@@ -113,7 +126,20 @@ dependencies:
|
|
113
126
|
version: "0"
|
114
127
|
type: :development
|
115
128
|
prerelease: false
|
116
|
-
version_requirements: *
|
129
|
+
version_requirements: *id008
|
130
|
+
- !ruby/object:Gem::Dependency
|
131
|
+
name: timecop
|
132
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
133
|
+
none: false
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
segments:
|
138
|
+
- 0
|
139
|
+
version: "0"
|
140
|
+
type: :development
|
141
|
+
prerelease: false
|
142
|
+
version_requirements: *id009
|
117
143
|
description: Replace files with links to md5 files
|
118
144
|
email: tobias.schwab@dynport.de
|
119
145
|
executables:
|
@@ -136,6 +162,9 @@ files:
|
|
136
162
|
- autotest/discover.rb
|
137
163
|
- bin/checksummer
|
138
164
|
- checksummer.gemspec
|
165
|
+
- features/checksum.feature
|
166
|
+
- features/step_definitions/checksum_steps.rb
|
167
|
+
- features/support/env.rb
|
139
168
|
- lib/checksummer.rb
|
140
169
|
- lib/checksummer_file.rb
|
141
170
|
- spec/checksummer_file_spec.rb
|
@@ -155,7 +184,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
155
184
|
requirements:
|
156
185
|
- - ">="
|
157
186
|
- !ruby/object:Gem::Version
|
158
|
-
hash:
|
187
|
+
hash: 555043968334052607
|
159
188
|
segments:
|
160
189
|
- 0
|
161
190
|
version: "0"
|