checksummer 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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"