boatman 0.1.2 → 0.1.3
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/VERSION +1 -1
- data/boatman.gemspec +88 -0
- data/lib/boatman.rb +20 -3
- data/lib/boatman/copyable.rb +6 -6
- data/lib/boatman/monitored_directory.rb +11 -10
- data/lib/boatman/monitored_file.rb +25 -11
- data/spec/boatman_spec.rb +12 -2
- data/spec/data/invalid_directory.rb +7 -0
- data/spec/data/invalid_directory.yml +5 -0
- metadata +32 -18
- data/.gitignore +0 -21
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.3
|
data/boatman.gemspec
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{boatman}
|
8
|
+
s.version = "0.1.3"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Bruz Marzolf"]
|
12
|
+
s.date = %q{2011-04-19}
|
13
|
+
s.default_executable = %q{boatman}
|
14
|
+
s.description = %q{}
|
15
|
+
s.email = %q{bmarzolf@systemsbiology.org}
|
16
|
+
s.executables = ["boatman"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.rdoc"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"bin/boatman",
|
28
|
+
"lib/boatman.rb",
|
29
|
+
"lib/boatman/copyable.rb",
|
30
|
+
"lib/boatman/ext/class.rb",
|
31
|
+
"lib/boatman/ext/fixnum.rb",
|
32
|
+
"lib/boatman/ext/string.rb",
|
33
|
+
"lib/boatman/monitored_directory.rb",
|
34
|
+
"lib/boatman/monitored_file.rb",
|
35
|
+
"spec/boatman_spec.rb",
|
36
|
+
"spec/data/copy_exception.rb",
|
37
|
+
"spec/data/copy_exception.yml",
|
38
|
+
"spec/data/filename_ending.rb",
|
39
|
+
"spec/data/filename_ending.yml",
|
40
|
+
"spec/data/filename_ending_regexp.rb",
|
41
|
+
"spec/data/filename_ending_regexp.yml",
|
42
|
+
"spec/data/filename_regexp.rb",
|
43
|
+
"spec/data/filename_regexp.yml",
|
44
|
+
"spec/data/folder.rb",
|
45
|
+
"spec/data/folder.yml",
|
46
|
+
"spec/data/invalid_directory.rb",
|
47
|
+
"spec/data/invalid_directory.yml",
|
48
|
+
"spec/data/modify.rb",
|
49
|
+
"spec/data/modify.yml",
|
50
|
+
"spec/data/no_destination_folder.rb",
|
51
|
+
"spec/data/no_destination_folder.yml",
|
52
|
+
"spec/data/rename.rb",
|
53
|
+
"spec/data/rename.yml",
|
54
|
+
"spec/spec.opts",
|
55
|
+
"spec/spec_helper.rb"
|
56
|
+
]
|
57
|
+
s.homepage = %q{http://github.com/bmarzolf/boatman}
|
58
|
+
s.require_paths = ["lib"]
|
59
|
+
s.rubygems_version = %q{1.3.6}
|
60
|
+
s.summary = %q{Ruby DSL for ferrying around and manipulating files}
|
61
|
+
s.test_files = [
|
62
|
+
"spec/boatman_spec.rb",
|
63
|
+
"spec/data/copy_exception.rb",
|
64
|
+
"spec/data/filename_ending.rb",
|
65
|
+
"spec/data/filename_ending_regexp.rb",
|
66
|
+
"spec/data/filename_regexp.rb",
|
67
|
+
"spec/data/folder.rb",
|
68
|
+
"spec/data/invalid_directory.rb",
|
69
|
+
"spec/data/modify.rb",
|
70
|
+
"spec/data/no_destination_folder.rb",
|
71
|
+
"spec/data/rename.rb",
|
72
|
+
"spec/spec_helper.rb"
|
73
|
+
]
|
74
|
+
|
75
|
+
if s.respond_to? :specification_version then
|
76
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
77
|
+
s.specification_version = 3
|
78
|
+
|
79
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
80
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
81
|
+
else
|
82
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
83
|
+
end
|
84
|
+
else
|
85
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/lib/boatman.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
begin
|
2
|
+
require "ftputils"
|
3
|
+
rescue LoadError
|
4
|
+
require "rubygems"
|
5
|
+
require "ftputils"
|
6
|
+
end
|
7
|
+
|
1
8
|
require "yaml"
|
2
9
|
require "digest/md5"
|
3
10
|
|
@@ -68,9 +75,19 @@ class Boatman
|
|
68
75
|
|
69
76
|
tasks.each do |task|
|
70
77
|
if task[:last_run].nil? || Time.now - task[:last_run] > task[:time_interval]
|
71
|
-
|
72
|
-
|
73
|
-
task[:directory].
|
78
|
+
begin
|
79
|
+
# do everything in the context of the working directory
|
80
|
+
puts "Going to check #{task[:directory].path} at #{Time.now}" if $DEBUG
|
81
|
+
Dir.chdir(@working_directory) do
|
82
|
+
task[:directory].instance_eval &task[:block]
|
83
|
+
end
|
84
|
+
puts "Leaving #{task[:directory].path} at #{Time.now}" if $DEBUG
|
85
|
+
rescue Exception => e
|
86
|
+
Boatman.logger.error "Task monitoring #{task[:directory].path} had an error: #{e.message}" rescue nil
|
87
|
+
Boatman.logger.error "Backtrace: #{e.backtrace.join("\n")}" if $DEBUG
|
88
|
+
|
89
|
+
# clear the FTP connection cache for good luck
|
90
|
+
FTPUtils::FTPConnection.clear_connection_cache
|
74
91
|
end
|
75
92
|
|
76
93
|
task[:last_run] = Time.now
|
data/lib/boatman/copyable.rb
CHANGED
@@ -2,20 +2,20 @@ class Boatman
|
|
2
2
|
module Copyable
|
3
3
|
def copy(file, params, remove_original=false, &block)
|
4
4
|
source_path = file.path
|
5
|
-
base_name = params[:rename] ||
|
5
|
+
base_name = params[:rename] || FTPUtils::FTPFile.basename(source_path)
|
6
6
|
|
7
|
-
destination_path =
|
7
|
+
destination_path = FTPUtils::FTPFile.expand_path(params[:to] + "/" + base_name)
|
8
8
|
|
9
|
-
return if
|
9
|
+
return if FTPUtils::FTPFile.exists?(destination_path)
|
10
10
|
|
11
11
|
begin
|
12
12
|
copy_entry(source_path, destination_path, &block)
|
13
|
-
|
13
|
+
FTPUtils.rm_r source_path if remove_original
|
14
14
|
|
15
15
|
Boatman.logger.info "Successfully copied #{source_path} to #{destination_path}"
|
16
16
|
rescue Exception => e
|
17
|
-
# remove the
|
18
|
-
|
17
|
+
# remove the possibly incorrect destination file
|
18
|
+
FTPUtils.rm_r "#{destination_path}" rescue nil
|
19
19
|
Boatman.logger.error "#{e.message} at #{e.backtrace[0]}"
|
20
20
|
end
|
21
21
|
end
|
@@ -25,20 +25,20 @@ class Boatman
|
|
25
25
|
@minimum_age ||= false
|
26
26
|
@maximum_age ||= false
|
27
27
|
|
28
|
-
entry_paths =
|
28
|
+
entry_paths = FTPUtils.ls(@path).grep(/#{entry_pattern}/).collect do |name|
|
29
29
|
"#{@path}/#{name}"
|
30
30
|
end
|
31
31
|
|
32
32
|
Boatman.logger.debug "Found #{entry_paths.size} entries in #{@path}"
|
33
33
|
entry_paths.each do |entry_path|
|
34
|
-
next if type == :file && !
|
35
|
-
next if type == :directory && !
|
34
|
+
next if type == :file && !FTPUtils::FTPFile.file?(entry_path)
|
35
|
+
next if type == :directory && !FTPUtils::FTPFile.directory?(entry_path)
|
36
36
|
|
37
|
-
age = Time.now -
|
37
|
+
age = Time.now - FTPUtils::FTPFile.mtime(entry_path)
|
38
38
|
next if @minimum_age && age < @minimum_age
|
39
39
|
next if @maximum_age && age > @maximum_age
|
40
40
|
|
41
|
-
match_data =
|
41
|
+
match_data = FTPUtils::FTPFile.basename(entry_path).match(entry_pattern) if entry_pattern.is_a?(Regexp)
|
42
42
|
case type
|
43
43
|
when :file
|
44
44
|
entry = MonitoredFile.new(entry_path, match_data)
|
@@ -69,13 +69,14 @@ class Boatman
|
|
69
69
|
private
|
70
70
|
|
71
71
|
def copy_entry(source_path, destination_path, &block)
|
72
|
-
|
73
|
-
FileUtils.cp_r source_path, destination_path
|
72
|
+
FTPUtils.mkdir_p FTPUtils::FTPFile.dirname(destination_path)
|
74
73
|
|
75
74
|
if block_given?
|
76
|
-
yield
|
77
|
-
|
78
|
-
|
75
|
+
yield source_path, "#{destination_path}.tmp"
|
76
|
+
FTPUtils.cp_r "#{destination_path}.tmp", destination_path
|
77
|
+
FTPUtils.rm_r "#{destination_path}.tmp"
|
78
|
+
else
|
79
|
+
FTPUtils.cp_r source_path, destination_path
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
@@ -17,24 +17,38 @@ class Boatman
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def copy_entry(source_path, destination_path, &block)
|
20
|
-
|
21
|
-
FileUtils.cp source_path, destination_path
|
22
|
-
|
23
|
-
unless @checksum_verification_disabled
|
24
|
-
verify_checksum_matches(source_path, destination_path, &block)
|
25
|
-
end
|
20
|
+
FTPUtils.mkdir_p FTPUtils::FTPFile.dirname(destination_path)
|
26
21
|
|
27
22
|
if block_given?
|
28
|
-
yield
|
29
|
-
|
30
|
-
|
23
|
+
yield source_path, "#{destination_path}.tmp"
|
24
|
+
FTPUtils.cp "#{destination_path}.tmp", destination_path
|
25
|
+
FTPUtils.rm "#{destination_path}.tmp"
|
26
|
+
else
|
27
|
+
FTPUtils.cp source_path, destination_path
|
28
|
+
|
29
|
+
unless @checksum_verification_disabled
|
30
|
+
verify_checksum_matches(source_path, destination_path)
|
31
|
+
end
|
31
32
|
end
|
32
33
|
end
|
33
34
|
|
34
35
|
def verify_checksum_matches(file_1, file_2)
|
35
|
-
file_1_digest =
|
36
|
-
file_2_digest =
|
36
|
+
file_1_digest = incremental_digest(file_1)
|
37
|
+
file_2_digest = incremental_digest(file_2)
|
37
38
|
raise "Checksum verification failed when copying #{base_name}" unless file_1_digest == file_2_digest
|
38
39
|
end
|
40
|
+
|
41
|
+
def incremental_digest(file_name)
|
42
|
+
file = open(file_name, "r")
|
43
|
+
|
44
|
+
digester = Digest::MD5.new
|
45
|
+
file.each_line do |line|
|
46
|
+
digester << line
|
47
|
+
end
|
48
|
+
|
49
|
+
file.close
|
50
|
+
|
51
|
+
return digester.hexdigest
|
52
|
+
end
|
39
53
|
end
|
40
54
|
end
|
data/spec/boatman_spec.rb
CHANGED
@@ -9,11 +9,11 @@ describe "Moving new files from one location to another" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def run_boatman
|
12
|
-
thread = Thread.new do
|
12
|
+
@thread = Thread.new do
|
13
13
|
Boatman.run
|
14
14
|
end
|
15
15
|
sleep 2
|
16
|
-
thread.exit
|
16
|
+
@thread.exit
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should move based on filename ending" do
|
@@ -96,6 +96,16 @@ describe "Moving new files from one location to another" do
|
|
96
96
|
File.exist?(@working_directory + '/tmp/destination/datafile.txt').should be_false
|
97
97
|
end
|
98
98
|
|
99
|
+
it "should not raise and exception (and crash boatman) when a task raises and exception" do
|
100
|
+
FileUtils.touch(@working_directory + '/tmp/source/datafile.txt')
|
101
|
+
|
102
|
+
boatman = Boatman.load(["#{@working_directory}/invalid_directory.yml", @working_directory])
|
103
|
+
run_boatman
|
104
|
+
|
105
|
+
# nil status indicates an exception was thrown
|
106
|
+
@thread.status.should_not be_nil
|
107
|
+
end
|
108
|
+
|
99
109
|
after(:each) do
|
100
110
|
FileUtils.rm_rf(@working_directory + '/tmp')
|
101
111
|
end
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: boatman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 3
|
9
|
+
version: 0.1.3
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Bruz Marzolf
|
@@ -9,19 +14,23 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date:
|
17
|
+
date: 2011-04-19 00:00:00 -07:00
|
13
18
|
default_executable: boatman
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: rspec
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
23
31
|
version: 1.2.9
|
24
|
-
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
25
34
|
description: ""
|
26
35
|
email: bmarzolf@systemsbiology.org
|
27
36
|
executables:
|
@@ -33,12 +42,12 @@ extra_rdoc_files:
|
|
33
42
|
- README.rdoc
|
34
43
|
files:
|
35
44
|
- .document
|
36
|
-
- .gitignore
|
37
45
|
- LICENSE
|
38
46
|
- README.rdoc
|
39
47
|
- Rakefile
|
40
48
|
- VERSION
|
41
49
|
- bin/boatman
|
50
|
+
- boatman.gemspec
|
42
51
|
- lib/boatman.rb
|
43
52
|
- lib/boatman/copyable.rb
|
44
53
|
- lib/boatman/ext/class.rb
|
@@ -57,6 +66,8 @@ files:
|
|
57
66
|
- spec/data/filename_regexp.yml
|
58
67
|
- spec/data/folder.rb
|
59
68
|
- spec/data/folder.yml
|
69
|
+
- spec/data/invalid_directory.rb
|
70
|
+
- spec/data/invalid_directory.yml
|
60
71
|
- spec/data/modify.rb
|
61
72
|
- spec/data/modify.yml
|
62
73
|
- spec/data/no_destination_folder.rb
|
@@ -70,37 +81,40 @@ homepage: http://github.com/bmarzolf/boatman
|
|
70
81
|
licenses: []
|
71
82
|
|
72
83
|
post_install_message:
|
73
|
-
rdoc_options:
|
74
|
-
|
84
|
+
rdoc_options: []
|
85
|
+
|
75
86
|
require_paths:
|
76
87
|
- lib
|
77
88
|
required_ruby_version: !ruby/object:Gem::Requirement
|
78
89
|
requirements:
|
79
90
|
- - ">="
|
80
91
|
- !ruby/object:Gem::Version
|
92
|
+
segments:
|
93
|
+
- 0
|
81
94
|
version: "0"
|
82
|
-
version:
|
83
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
96
|
requirements:
|
85
97
|
- - ">="
|
86
98
|
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 0
|
87
101
|
version: "0"
|
88
|
-
version:
|
89
102
|
requirements: []
|
90
103
|
|
91
104
|
rubyforge_project:
|
92
|
-
rubygems_version: 1.3.
|
105
|
+
rubygems_version: 1.3.6
|
93
106
|
signing_key:
|
94
107
|
specification_version: 3
|
95
108
|
summary: Ruby DSL for ferrying around and manipulating files
|
96
109
|
test_files:
|
97
|
-
- spec/spec_helper.rb
|
98
110
|
- spec/boatman_spec.rb
|
99
|
-
- spec/data/
|
111
|
+
- spec/data/copy_exception.rb
|
100
112
|
- spec/data/filename_ending.rb
|
101
|
-
- spec/data/no_destination_folder.rb
|
102
|
-
- spec/data/filename_regexp.rb
|
103
|
-
- spec/data/modify.rb
|
104
113
|
- spec/data/filename_ending_regexp.rb
|
114
|
+
- spec/data/filename_regexp.rb
|
105
115
|
- spec/data/folder.rb
|
106
|
-
- spec/data/
|
116
|
+
- spec/data/invalid_directory.rb
|
117
|
+
- spec/data/modify.rb
|
118
|
+
- spec/data/no_destination_folder.rb
|
119
|
+
- spec/data/rename.rb
|
120
|
+
- spec/spec_helper.rb
|