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 CHANGED
@@ -9,8 +9,10 @@ group :development do
9
9
  gem 'autotest'
10
10
  gem 'autotest-growl'
11
11
  gem 'ruby-debug19'
12
+ gem "cucumber", ">= 0"
12
13
  gem "rspec", "~> 2.3.0"
13
14
  gem "bundler", "~> 1.0.0"
14
15
  gem "jeweler", "~> 1.5.2"
15
16
  gem "rcov", ">= 0"
17
+ gem "timecop"
16
18
  end
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.8
1
+ 0.2.0
data/bin/checksummer CHANGED
@@ -1,4 +1,5 @@
1
- #!/usr/bin/env
1
+ #!/usr/bin/env ruby
2
+ $:<<File.expand_path("../lib", File.dirname(__FILE__))
2
3
  require "checksummer"
3
4
 
4
5
  Checksummer.run_for_args(ARGV)
data/checksummer.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{checksummer}
8
- s.version = "0.1.8"
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-18}
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
@@ -0,0 +1,3 @@
1
+ After do
2
+ Timecop.return
3
+ 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
- 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, 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 !directory || !File.directory?(directory) || !checksum_to || !File.directory?(checksum_to)
34
- puts usage
35
- else
36
- self.new(checksum_to).checksum_directory(directory, args[2..-1].join(" ")) do |status, file, index, total|
37
- 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]
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
@@ -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
- 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
- )
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
- if !File.symlink?(path)
41
- new_path = md5_path(checksum_dir)
42
- status = if !File.exists?(new_path)
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 /v1/incoming/ " }
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
- { :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
15
+ it "sets path to the first chunk" do
16
+ @file.path.should == "/v1/incoming"
20
17
  end
21
18
 
22
- it "sets original_path to nil when not in response" do
23
- @file.original_path.should be_nil
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 "sets original_path to the path when found in response" do
27
- ChecksummerFile.from_line(line_with_original_path).original_path.should == "/tmp"
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 "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)
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
@@ -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 /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 "
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%p\t%l\n"))
68
- cs.find("path1")
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%p\t%l\n"))
73
- cs.find("path1", "-mtime +1")
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
- cs.find("path1").length.should == 6
33
+ Checksummer.find("path1").length.should == 6
78
34
  end
79
35
 
80
36
  it "returns objects of type ChecksummerFile" do
81
- cs.find("path1").first.should be_an_instance_of(ChecksummerFile)
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
- cs.find("path1").first.path.should == "/v1/incoming"
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 "initializes checksummer with correct checksum_to dir" do
110
- Checksummer.should_receive(:new).with("/tmp").and_return(double("checksummer", :checksum_directory => true))
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 "does not call checksum_directory with sleep parameter" do
122
- checksummer = double("checksummer")
123
- Checksummer.stub!(:new).and_return checksummer
124
- checksummer.should_receive(:checksum_directory).with("/tmp", %(-mtime +1))
125
- Checksummer.run_for_args(["/tmp", "/tmp", "-mtime", "+1", "--sleep", "10"])
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
- @cs_double = double("cs")
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
- now = double("now", :hour => 8, :strftime => "some time")
149
- Time.stub!(:now).and_return(now)
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
- now = double("now", :hour => 8, :strftime => "some time")
156
- Time.stub!(:now).and_return(now)
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
- now = double("now", :hour => 7, :strftime => "some time")
163
- Time.stub!(:now).and_return(now)
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
- - 1
8
- - 8
9
- version: 0.1.8
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-18 00:00:00 +01:00
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: rspec
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: *id004
86
+ version_requirements: *id005
74
87
  - !ruby/object:Gem::Dependency
75
88
  name: bundler
76
- requirement: &id005 !ruby/object:Gem::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: *id005
101
+ version_requirements: *id006
89
102
  - !ruby/object:Gem::Dependency
90
103
  name: jeweler
91
- requirement: &id006 !ruby/object:Gem::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: *id006
116
+ version_requirements: *id007
104
117
  - !ruby/object:Gem::Dependency
105
118
  name: rcov
106
- requirement: &id007 !ruby/object:Gem::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: *id007
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: -2013251382581930018
187
+ hash: 555043968334052607
159
188
  segments:
160
189
  - 0
161
190
  version: "0"