inimit 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/Gemfile +1 -0
  2. data/VERSION +1 -1
  3. data/bin/inimit +1 -1
  4. data/inimit.gemspec +79 -0
  5. data/lib/inimit.rb +128 -40
  6. metadata +3 -2
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ source "http://rubygems.org"
4
4
  # gem "activesupport", ">= 2.3.5"
5
5
 
6
6
  gem 'paint', '~> 0.8.5'
7
+ #gem 'iopts', '~> 0.1.0'
7
8
 
8
9
  # Add dependencies to develop your gem here.
9
10
  # Include everything needed to run rake, tests, features, etc.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.1
1
+ 0.0.2
data/bin/inimit CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.join(File.dirname(__FILE__), '..', 'lib', 'inimit')
3
3
 
4
- Inimit::compare *ARGV
4
+ Inimit::run *ARGV
@@ -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
+
@@ -1,83 +1,171 @@
1
1
  require 'find'
2
- require 'digest/sha1'
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.1'
9
+ VERSION = '0.0.2'
7
10
 
8
- def self.compare *args
11
+ class Opts < OptionParser
12
+ def to_s
13
+ "#{banner}\nOptions:\n#{summarize ''}"
14
+ end
15
+ end
9
16
 
10
- self.abort "A source and target directory are required (got #{args.length} arguments)" unless args.length == 2
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
- source, target = args.shift, args.shift
13
- self.abort "Source #{source} is not a directory" unless File.directory? source
14
- self.abort "Target #{target} is not a directory" unless File.directory? target
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 << file
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
- puts Paint[" #{source_sha1[0,7]} == #{target_sha1[0,7]}", :green]
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
- puts Paint[" #{source_sha1[0,7]} != #{target_sha1[0,7]}", :red]
49
- different << { :file => file, :source => source_sha1, :target => target_sha1 }
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
- if different.empty? and unknown.empty?
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
- puts Paint["All files in #{source} are the same in #{target}.", :green, :bold]
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
- return
142
+ exit 1
58
143
  end
144
+ end
59
145
 
60
- if unknown.any?
61
- puts
62
- puts Paint["The following files in #{source} were not found in #{target}:", :yellow, :bold]
63
- unknown.each do |file|
64
- puts "- #{file}"
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
- end
67
-
68
- if different.any?
69
- puts
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 = Digest::SHA1.new
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 1
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.1
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-11 00:00:00.000000000 Z
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