kompar 0.0.4
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.
- checksums.yaml +7 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +20 -0
- data/README.md +12 -0
- data/VERSION +1 -0
- data/bin/kompar +4 -0
- data/lib/kompar.rb +180 -0
- metadata +164 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 84b274ffb0f559f438e704ea26a12bc555bd4bba
|
4
|
+
data.tar.gz: 0e2217c84f930fc633ba7582df3930c0dbd94f69
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3483b909c680e8b2d7885cfcdd7bc84a8938ee4760c048a59c9e0451042e3abd39b968b387c231f2dbb1807020d01ba1e632f20be68d62d7d0479ef80d34ebb5
|
7
|
+
data.tar.gz: ea600c0b49c36ec6702a297d9ee3045c57bf679fe50f5c250375bec3d3657a2544ba734aa1fa2d428fc4635d5ec112c5107b519232263da6b0c7abf4aa11a6bf
|
data/Gemfile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
gem 'paint', '~> 0.8'
|
7
|
+
|
8
|
+
# Add dependencies to develop your gem here.
|
9
|
+
# Include everything needed to run rake, tests, features, etc.
|
10
|
+
group :development do
|
11
|
+
gem 'bundler', '~> 1.5'
|
12
|
+
gem 'rake', '~> 10.1'
|
13
|
+
gem 'rspec', '~> 2.14'
|
14
|
+
gem 'jeweler', '~> 2.0'
|
15
|
+
gem 'rake-version', '~> 0.4'
|
16
|
+
gem 'simplecov', '~> 0.8'
|
17
|
+
gem 'coveralls', '~> 0.7', require: false
|
18
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011-2014 Simon Oulevay (Alpha Hydrae)
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# kompar
|
2
|
+
|
3
|
+
**Recursive file comparison utility.**
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/kompar)
|
6
|
+
[](https://gemnasium.com/AlphaHydrae/kompar)
|
7
|
+
[](http://travis-ci.org/AlphaHydrae/kompar)
|
8
|
+
|
9
|
+
## Meta
|
10
|
+
|
11
|
+
* **Author:** Simon Oulevay (Alpha Hydrae)
|
12
|
+
* **License:** MIT (see [LICENSE.txt](https://github.com/AlphaHydrae/kompar/blob/master/LICENSE.txt))
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
data/bin/kompar
ADDED
data/lib/kompar.rb
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'digest'
|
3
|
+
require 'paint'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
# TODO: lenient option to only fail on mismatch
|
7
|
+
|
8
|
+
module Kompar
|
9
|
+
VERSION = '0.0.4'
|
10
|
+
|
11
|
+
class Opts < OptionParser
|
12
|
+
def to_s
|
13
|
+
"#{banner}\nOptions:\n#{summarize ''}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
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 kompar [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
|
49
|
+
|
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 = {}
|
68
|
+
|
69
|
+
source, target = File.expand_path(source), File.expand_path(target)
|
70
|
+
|
71
|
+
puts
|
72
|
+
puts "Comparing files in #{source} to #{target}."
|
73
|
+
puts unless options[:mismatch_only]
|
74
|
+
|
75
|
+
Dir.chdir source
|
76
|
+
total, match, unknown, mismatch = 0, 0, 0, 0
|
77
|
+
|
78
|
+
Find.find '.' do |file|
|
79
|
+
|
80
|
+
# skip directories
|
81
|
+
next unless File.file? file
|
82
|
+
human_file = file.sub /^\.\//, ''
|
83
|
+
total += 1
|
84
|
+
|
85
|
+
source_file = File.join source, file
|
86
|
+
target_file = File.join target, file
|
87
|
+
|
88
|
+
if !File.file? target_file
|
89
|
+
unknown += 1
|
90
|
+
puts %/#{Paint["not found", :yellow]} #{human_file}/
|
91
|
+
next
|
92
|
+
end
|
93
|
+
|
94
|
+
source_sha1 = self.hash source_file, options
|
95
|
+
target_sha1 = self.hash target_file, options
|
96
|
+
|
97
|
+
if source_sha1 == target_sha1
|
98
|
+
match += 1
|
99
|
+
unless options[:mismatch_only]
|
100
|
+
print Paint[self.hash_notice(source_sha1, target_sha1, options), :green]
|
101
|
+
puts " #{human_file}..."
|
102
|
+
end
|
103
|
+
else
|
104
|
+
mismatch += 1
|
105
|
+
print Paint[self.hash_notice(source_sha1, target_sha1, options), :red]
|
106
|
+
puts " #{human_file}..."
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
puts
|
111
|
+
|
112
|
+
notice = "Checked #{total} files: "
|
113
|
+
notice << Paint["#{match} identical", :green]
|
114
|
+
notice << ", "
|
115
|
+
notice << Paint["#{unknown} not found", :yellow]
|
116
|
+
notice << ", "
|
117
|
+
notice << Paint["#{mismatch} different", :red]
|
118
|
+
|
119
|
+
puts notice
|
120
|
+
puts
|
121
|
+
|
122
|
+
exit 1 if unknown >= 1 or mismatch >= 1
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.compare_files source, target, options = {}
|
126
|
+
|
127
|
+
source_sha1, target_sha1 = self.hash(source, options), self.hash(target, options)
|
128
|
+
|
129
|
+
puts
|
130
|
+
|
131
|
+
if source_sha1 == target_sha1
|
132
|
+
msg = "Files are identical"
|
133
|
+
msg << " (#{self.hash_notice source_sha1, target_sha1, options})" if options[:verbose] >= 1
|
134
|
+
msg << "."
|
135
|
+
puts Paint[msg, :green]
|
136
|
+
puts
|
137
|
+
else
|
138
|
+
msg = "The contents of the files do not match"
|
139
|
+
msg << " (#{self.hash_notice source_sha1, target_sha1, options})" if options[:verbose] >= 1
|
140
|
+
msg << "."
|
141
|
+
puts Paint[msg, :red]
|
142
|
+
puts
|
143
|
+
exit 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.hash_notice h1, h2, options = {}
|
148
|
+
if h1 == h2
|
149
|
+
case options[:verbose]
|
150
|
+
when 1; "#{h1[0,7]} == #{h2[0,7]}"
|
151
|
+
when 2; "#{h1} == #{h2}"
|
152
|
+
else; "identical"
|
153
|
+
end
|
154
|
+
else
|
155
|
+
case options[:verbose]
|
156
|
+
when 1..2; "#{h1} != #{h2}"
|
157
|
+
else; "different"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.hash file, options = {}
|
163
|
+
dig = case options[:digest]
|
164
|
+
when 'md5'; Digest::MD5.new
|
165
|
+
when 'sha256'; Digest::SHA256.new
|
166
|
+
when 'sha384'; Digest::SHA384.new
|
167
|
+
when 'sha512'; Digest::SHA512.new
|
168
|
+
else; Digest::SHA1.new
|
169
|
+
end
|
170
|
+
File.open file, 'rb' do |io|
|
171
|
+
dig.update io.readpartial(4096) while !io.eof
|
172
|
+
end
|
173
|
+
dig.hexdigest
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.abort msg
|
177
|
+
warn Paint[msg, :yellow]
|
178
|
+
exit 2
|
179
|
+
end
|
180
|
+
end
|
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kompar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Simon Oulevay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: paint
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.1'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.14'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.14'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake-version
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.4'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.4'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.8'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: coveralls
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.7'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.7'
|
125
|
+
description: Compares files in two directories using SHA1.
|
126
|
+
email: simon.oulevay@gmail.com
|
127
|
+
executables:
|
128
|
+
- kompar
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files:
|
131
|
+
- LICENSE.txt
|
132
|
+
- README.md
|
133
|
+
files:
|
134
|
+
- Gemfile
|
135
|
+
- LICENSE.txt
|
136
|
+
- README.md
|
137
|
+
- VERSION
|
138
|
+
- bin/kompar
|
139
|
+
- lib/kompar.rb
|
140
|
+
homepage: http://github.com/AlphaHydrae/kompar
|
141
|
+
licenses:
|
142
|
+
- MIT
|
143
|
+
metadata: {}
|
144
|
+
post_install_message:
|
145
|
+
rdoc_options: []
|
146
|
+
require_paths:
|
147
|
+
- lib
|
148
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
requirements: []
|
159
|
+
rubyforge_project:
|
160
|
+
rubygems_version: 2.2.1
|
161
|
+
signing_key:
|
162
|
+
specification_version: 4
|
163
|
+
summary: Recursive file comparison command.
|
164
|
+
test_files: []
|