inimit 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/VERSION +1 -1
- data/bin/inimit +1 -1
- data/inimit.gemspec +79 -0
- data/lib/inimit.rb +128 -40
- metadata +3 -2
data/Gemfile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.2
|
data/bin/inimit
CHANGED
data/inimit.gemspec
ADDED
@@ -0,0 +1,79 @@
|
|
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 = "inimit"
|
8
|
+
s.version = "0.0.2"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["AlphaHydrae"]
|
12
|
+
s.date = "2012-09-12"
|
13
|
+
s.description = "Compares files in two directories using SHA1."
|
14
|
+
s.email = "hydrae.alpha@gmail.com"
|
15
|
+
s.executables = ["inimit"]
|
16
|
+
s.extra_rdoc_files = [
|
17
|
+
"LICENSE.txt",
|
18
|
+
"README.md"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
".screenrc",
|
24
|
+
".travis.yml",
|
25
|
+
"Gemfile",
|
26
|
+
"Gemfile.lock",
|
27
|
+
"LICENSE.txt",
|
28
|
+
"README.md",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"bin/inimit",
|
32
|
+
"inimit.gemspec",
|
33
|
+
"lib/inimit.rb",
|
34
|
+
"spec/helper.rb",
|
35
|
+
"spec/version_spec.rb"
|
36
|
+
]
|
37
|
+
s.homepage = "http://github.com/AlphaHydrae/inimit"
|
38
|
+
s.licenses = ["MIT"]
|
39
|
+
s.require_paths = ["lib"]
|
40
|
+
s.rubygems_version = "1.8.24"
|
41
|
+
s.summary = "Recursive file comparison command."
|
42
|
+
|
43
|
+
if s.respond_to? :specification_version then
|
44
|
+
s.specification_version = 3
|
45
|
+
|
46
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
47
|
+
s.add_runtime_dependency(%q<paint>, ["~> 0.8.5"])
|
48
|
+
s.add_development_dependency(%q<bundler>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
50
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<gemcutter>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<gem-release>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<rake-version>, [">= 0"])
|
55
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
56
|
+
else
|
57
|
+
s.add_dependency(%q<paint>, ["~> 0.8.5"])
|
58
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
59
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
60
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
61
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
62
|
+
s.add_dependency(%q<gemcutter>, [">= 0"])
|
63
|
+
s.add_dependency(%q<gem-release>, [">= 0"])
|
64
|
+
s.add_dependency(%q<rake-version>, [">= 0"])
|
65
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<paint>, ["~> 0.8.5"])
|
69
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
70
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
71
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
72
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
73
|
+
s.add_dependency(%q<gemcutter>, [">= 0"])
|
74
|
+
s.add_dependency(%q<gem-release>, [">= 0"])
|
75
|
+
s.add_dependency(%q<rake-version>, [">= 0"])
|
76
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
data/lib/inimit.rb
CHANGED
@@ -1,83 +1,171 @@
|
|
1
1
|
require 'find'
|
2
|
-
require 'digest
|
2
|
+
require 'digest'
|
3
3
|
require 'paint'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# TODO: lenient option to only fail on mismatch
|
4
7
|
|
5
8
|
module Inimit
|
6
|
-
VERSION = '0.0.
|
9
|
+
VERSION = '0.0.2'
|
7
10
|
|
8
|
-
|
11
|
+
class Opts < OptionParser
|
12
|
+
def to_s
|
13
|
+
"#{banner}\nOptions:\n#{summarize ''}"
|
14
|
+
end
|
15
|
+
end
|
9
16
|
|
10
|
-
|
17
|
+
def self.run *args
|
18
|
+
|
19
|
+
options = {
|
20
|
+
:verbose => 0,
|
21
|
+
:mismatch_only => false
|
22
|
+
}
|
23
|
+
Opts.new do |opts|
|
24
|
+
opts.banner = "#{Paint[opts.program_name, :bold]} recursively compares files.\n\nUsage:\n inimit [OPTION]... [SOURCE] TARGET\n"
|
25
|
+
opts.version = VERSION
|
26
|
+
opts.on('-d', '--digest ALGORITHM', 'Use ALGORITHM to hash file contents (available: md5, sha1, sha256, sha384, sha512)') do |digest|
|
27
|
+
options[:digest] = digest
|
28
|
+
end
|
29
|
+
opts.on('-m', '--mismatch', 'Only show files when missing or the content does not match') do
|
30
|
+
options[:mismatch_only] = true
|
31
|
+
end
|
32
|
+
opts.on('-v', '--verbose', 'Increase verbosity (once: show hash prefixes, twice: show full hashes)') do
|
33
|
+
options[:verbose] += 1
|
34
|
+
end
|
35
|
+
opts.on('-h', '--help', 'Show this help and exit'){ puts opts; exit 0 }
|
36
|
+
opts.on('-u', '--usage', 'Show this help and exit'){ puts opts; exit 0 }
|
37
|
+
end.parse! args
|
38
|
+
|
39
|
+
# check number of args
|
40
|
+
self.abort "A target directory must be given" if args.length < 1
|
41
|
+
self.abort "Only one source and target must be given (got #{args.length} arguments)" if args.length > 2
|
42
|
+
|
43
|
+
source, target = case args.length
|
44
|
+
when 1
|
45
|
+
[ '.', args.shift ]
|
46
|
+
when 2
|
47
|
+
[ args.shift, args.shift ]
|
48
|
+
end
|
11
49
|
|
12
|
-
|
13
|
-
|
14
|
-
|
50
|
+
if !File.exists?(source)
|
51
|
+
self.abort "Unknown file or directory #{source}"
|
52
|
+
elsif !File.file?(source) and !File.directory?(source)
|
53
|
+
self.abort "Source #{source} is neither a file nor a directory"
|
54
|
+
elsif File.file?(source) and !File.file?(target)
|
55
|
+
self.abort "Source #{source} is a file, target #{target} is not"
|
56
|
+
elsif File.directory?(source) and !File.directory?(target)
|
57
|
+
self.abort "Source #{source} is a directory, target #{target} is not"
|
58
|
+
end
|
59
|
+
|
60
|
+
if File.directory? source
|
61
|
+
self.compare source, target, options
|
62
|
+
else
|
63
|
+
self.compare_files source, target, options
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.compare source, target, options = {}
|
15
68
|
|
16
69
|
source, target = File.expand_path(source), File.expand_path(target)
|
17
70
|
|
18
71
|
puts
|
19
|
-
puts "Comparing files in #{source} to #{target}
|
20
|
-
puts
|
72
|
+
puts "Comparing files in #{source} to #{target}."
|
73
|
+
puts unless options[:mismatch_only]
|
21
74
|
|
22
75
|
Dir.chdir source
|
23
|
-
unknown =
|
24
|
-
different = []
|
76
|
+
total, match, unknown, mismatch = 0, 0, 0, 0
|
25
77
|
|
26
78
|
Find.find '.' do |file|
|
27
79
|
|
28
80
|
# skip directories
|
29
81
|
next unless File.file? file
|
30
|
-
|
31
|
-
print "- #{file.sub /^\.\//, ''}..."
|
82
|
+
total += 1
|
32
83
|
|
33
84
|
source_file = File.join source, file
|
34
85
|
target_file = File.join target, file
|
35
86
|
|
36
87
|
if !File.file? target_file
|
37
|
-
unknown
|
88
|
+
unknown += 1
|
38
89
|
puts Paint[" not found", :yellow]
|
39
90
|
next
|
40
91
|
end
|
41
92
|
|
42
|
-
source_sha1 = self.hash source_file
|
43
|
-
target_sha1 = self.hash target_file
|
93
|
+
source_sha1 = self.hash source_file, options
|
94
|
+
target_sha1 = self.hash target_file, options
|
44
95
|
|
45
96
|
if source_sha1 == target_sha1
|
46
|
-
|
97
|
+
match += 1
|
98
|
+
unless options[:mismatch_only]
|
99
|
+
print Paint[self.hash_notice(source_sha1, target_sha1, options), :green]
|
100
|
+
puts " #{file.sub /^\.\//, ''}..."
|
101
|
+
end
|
47
102
|
else
|
48
|
-
|
49
|
-
|
103
|
+
mismatch += 1
|
104
|
+
print Paint[self.hash_notice(source_sha1, target_sha1, options), :red]
|
105
|
+
puts " #{file.sub /^\.\//, ''}..."
|
50
106
|
end
|
51
107
|
end
|
52
108
|
|
53
|
-
|
109
|
+
puts
|
110
|
+
|
111
|
+
notice = "Checked #{total} files: "
|
112
|
+
notice << Paint["#{match} identical", :green]
|
113
|
+
notice << ", "
|
114
|
+
notice << Paint["#{unknown} not found", :yellow]
|
115
|
+
notice << ", "
|
116
|
+
notice << Paint["#{mismatch} different", :red]
|
117
|
+
|
118
|
+
puts notice
|
119
|
+
puts
|
120
|
+
|
121
|
+
exit 1 if unknown >= 1 or mismatch >= 1
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.compare_files source, target, options = {}
|
125
|
+
|
126
|
+
source_sha1, target_sha1 = self.hash(source, options), self.hash(target, options)
|
127
|
+
|
128
|
+
puts
|
129
|
+
|
130
|
+
if source_sha1 == target_sha1
|
131
|
+
msg = "Files are identical"
|
132
|
+
msg << " (#{self.hash_notice source_sha1, target_sha1, options})" if options[:verbose] >= 1
|
133
|
+
msg << "."
|
134
|
+
puts Paint[msg, :green]
|
54
135
|
puts
|
55
|
-
|
136
|
+
else
|
137
|
+
msg = "The contents of the files do not match"
|
138
|
+
msg << " (#{self.hash_notice source_sha1, target_sha1, options})" if options[:verbose] >= 1
|
139
|
+
msg << "."
|
140
|
+
puts Paint[msg, :red]
|
56
141
|
puts
|
57
|
-
|
142
|
+
exit 1
|
58
143
|
end
|
144
|
+
end
|
59
145
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
146
|
+
def self.hash_notice h1, h2, options = {}
|
147
|
+
if h1 == h2
|
148
|
+
case options[:verbose]
|
149
|
+
when 1; "#{h1[0,7]} == #{h2[0,7]}"
|
150
|
+
when 2; "#{h1} == #{h2}"
|
151
|
+
else; "identical"
|
65
152
|
end
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
puts Paint["The following files in #{source} do not have the same content in #{target}:", :red, :bold]
|
71
|
-
different.each do |h|
|
72
|
-
puts "- #{h[:file]}"
|
153
|
+
else
|
154
|
+
case options[:verbose]
|
155
|
+
when 1..2; "#{h1} != #{h2}"
|
156
|
+
else; "different"
|
73
157
|
end
|
74
158
|
end
|
75
|
-
|
76
|
-
puts
|
77
159
|
end
|
78
160
|
|
79
|
-
def self.hash file
|
80
|
-
dig =
|
161
|
+
def self.hash file, options = {}
|
162
|
+
dig = case options[:digest]
|
163
|
+
when 'md5'; Digest::MD5.new
|
164
|
+
when 'sha256'; Digest::SHA256.new
|
165
|
+
when 'sha384'; Digest::SHA384.new
|
166
|
+
when 'sha512'; Digest::SHA512.new
|
167
|
+
else; Digest::SHA1.new
|
168
|
+
end
|
81
169
|
File.open file, 'rb' do |io|
|
82
170
|
dig.update io.readpartial(4096) while !io.eof
|
83
171
|
end
|
@@ -85,7 +173,7 @@ module Inimit
|
|
85
173
|
end
|
86
174
|
|
87
175
|
def self.abort msg
|
88
|
-
warn msg
|
89
|
-
exit
|
176
|
+
warn Paint[msg, :yellow]
|
177
|
+
exit 2
|
90
178
|
end
|
91
179
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inimit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: paint
|
@@ -175,6 +175,7 @@ files:
|
|
175
175
|
- Rakefile
|
176
176
|
- VERSION
|
177
177
|
- bin/inimit
|
178
|
+
- inimit.gemspec
|
178
179
|
- lib/inimit.rb
|
179
180
|
- spec/helper.rb
|
180
181
|
- spec/version_spec.rb
|