di 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/History.txt +3 -0
  2. data/README.txt +67 -0
  3. data/bin/di +545 -0
  4. metadata +55 -0
data/History.txt ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.1 2008-10-06
2
+
3
+ * Initial release
data/README.txt ADDED
@@ -0,0 +1,67 @@
1
+ = di
2
+
3
+ * http://www.idaemons.org/projects/di/
4
+
5
+ == DESCRIPTION:
6
+
7
+ di - a wrapper around GNU diff(1)
8
+
9
+ == FEATURES:
10
+
11
+ The di(1) command wraps around GNU diff(1) to provide reasonable
12
+ default settings and some original features:
13
+
14
+ - Ignore non-significant files, such as backup files, object files,
15
+ VCS administration files, etc. a la rsync(1)'s --cvs-ignore
16
+ option.
17
+
18
+ - Ignore difference of lines containing RCS tags.
19
+
20
+ - Output in unified format.
21
+
22
+ - Perform recursive comparison.
23
+
24
+ - Turn on some other useful options: -N -p -d.
25
+
26
+ - Provide the way to negate any of the above options.
27
+
28
+ == SYNOPSIS:
29
+
30
+ Run di --help for help.
31
+
32
+ == REQUIREMENTS:
33
+
34
+ - Ruby 1.8.6 or later
35
+
36
+ - GNU diff(1)
37
+
38
+ == INSTALL:
39
+
40
+ gem install di
41
+
42
+ == LICENSE:
43
+
44
+ Copyright (c) 2008 Akinori MUSHA
45
+
46
+ All rights reserved.
47
+
48
+ Redistribution and use in source and binary forms, with or without
49
+ modification, are permitted provided that the following conditions
50
+ are met:
51
+ 1. Redistributions of source code must retain the above copyright
52
+ notice, this list of conditions and the following disclaimer.
53
+ 2. Redistributions in binary form must reproduce the above copyright
54
+ notice, this list of conditions and the following disclaimer in the
55
+ documentation and/or other materials provided with the distribution.
56
+
57
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
58
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
61
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67
+ SUCH DAMAGE.
data/bin/di ADDED
@@ -0,0 +1,545 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ #
4
+ # di - a wrapper around GNU diff(1)
5
+ #
6
+ # Copyright (c) 2008 Akinori MUSHA
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions
12
+ # are met:
13
+ # 1. Redistributions of source code must retain the above copyright
14
+ # notice, this list of conditions and the following disclaimer.
15
+ # 2. Redistributions in binary form must reproduce the above copyright
16
+ # notice, this list of conditions and the following disclaimer in the
17
+ # documentation and/or other materials provided with the distribution.
18
+ #
19
+ # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
+ # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
+ # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
+ # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
+ # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
+ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
+ # SUCH DAMAGE.
30
+ #
31
+ # $Id: di 69 2008-10-06 03:58:09Z knu $
32
+
33
+ MYVERSION = "0.1.1"
34
+ MYREVISION = %w$Rev: 69 $[1]
35
+ MYDATE = %w$Date: 2008-10-06 12:58:09 +0900 (Mon, 06 Oct 2008) $[1]
36
+ MYNAME = File.basename($0)
37
+
38
+ DIFF_CMD = ENV.fetch('DIFF', 'diff')
39
+ EMPTYFILE = '/dev/null'
40
+
41
+ RSYNC_EXCLUDE_GLOBS = %w(
42
+ RCS SCCS CVS CVS.adm
43
+ RCSLOG cvslog.* tags TAGS
44
+ .make.state .nse_depinfo *~
45
+ \#* .\#* ,* _$*
46
+ *$ *.old *.bak *.BAK
47
+ *.orig *.rej *.del-* *.a
48
+ *.olb *.o *.obj *.so
49
+ *.exe *.Z *.elc *.ln
50
+ core .svn .git .bzr .hg
51
+ )
52
+
53
+ FIGNORE_GLOBS = ENV.fetch('FIGNORE', '').split(':').map { |pat|
54
+ '*' + pat
55
+ }
56
+
57
+ def main(args)
58
+ setup
59
+
60
+ parse_args!(args)
61
+
62
+ diff_main
63
+
64
+ exit $status
65
+ end
66
+
67
+ def warn(*lines)
68
+ lines.each { |line|
69
+ STDERR.puts "#{MYNAME}: #{line}"
70
+ }
71
+ end
72
+
73
+ def setup
74
+ require 'ostruct'
75
+ $diff = OpenStruct.new
76
+ $diff.exclude = []
77
+ $diff.include = []
78
+ $diff.flags = []
79
+ end
80
+
81
+ def parse_args!(args)
82
+ require 'optparse'
83
+
84
+ banner = <<-"EOF"
85
+ #{MYNAME} - a wrapper around GNU diff(1)
86
+ version #{MYVERSION} [revision #{MYREVISION}] (#{MYDATE})
87
+
88
+ usage: #{MYNAME} [flags] [files]
89
+ EOF
90
+
91
+ opts = OptionParser.new(banner) { |opts|
92
+ miniTrueClass = Class.new
93
+ hash = OptionParser::CompletingHash.new
94
+ hash['-'] = false
95
+ opts.accept(miniTrueClass, hash) {|arg, val| val == nil or val}
96
+
97
+ opts.on('--[no-]rsync-exclude', '--[no-]cvs-exclude',
98
+ 'Exclude some kinds of files and directories a la rsync(1). [!][*]') { |val|
99
+ $diff.rsync_exclude = val
100
+ }
101
+ opts.on('--[no-]ignore-cvs-lines',
102
+ 'Ignore CVS keyword lines. [!][*]') { |val|
103
+ $diff.ignore_cvs_lines = val
104
+ }
105
+ opts.on('--[no-]fignore-exclude',
106
+ 'Ignore files having suffixes specified in FIGNORE. [!][*]') { |val|
107
+ $diff.fignore_exclude = val
108
+ }
109
+ opts.on('-R', '--relative[=-]', miniTrueClass,
110
+ 'Use relative path names. [*]') { |val|
111
+ $diff.relative = val
112
+ }
113
+ opts.on('-i', '--ignore-case[=-]', miniTrueClass,
114
+ 'Ignore case differences in file contents.') { |val|
115
+ set_flag('-i', val)
116
+ }
117
+ # not supported (yet)
118
+ #opts.on("--[no-]ignore-file-name-case",
119
+ # "Ignore case when comparing file names.") { |val|
120
+ # set_flag("--ignore-file-name-case", val)
121
+ #}
122
+ opts.on('-E', '--ignore-tab-expansion[=-]', miniTrueClass,
123
+ 'Ignore changes due to tab expansion.') { |val|
124
+ set_flag('-E', val)
125
+ }
126
+ opts.on('-b', '--ignore-space-change[=-]', miniTrueClass,
127
+ 'Ignore changes in the amount of white space.') { |val|
128
+ set_flag('-b', val)
129
+ }
130
+ opts.on('-w', '--ignore-all-space[=-]', miniTrueClass,
131
+ 'Ignore all white space.') { |val|
132
+ set_flag('-w', val)
133
+ }
134
+ opts.on('-B', '--ignore-blank-lines[=-]', miniTrueClass,
135
+ 'Ignore changes whose lines are all blank.') { |val|
136
+ set_flag('-B', val)
137
+ }
138
+ opts.on('-I RE', '--ignore-matching-lines=RE',
139
+ 'Ignore changes whose lines all match RE.') { |val|
140
+ set_flag('-I', val)
141
+ }
142
+ opts.on('--[no-]strip-trailing-cr',
143
+ 'Strip trailing carriage return on input.') { |val|
144
+ set_flag('--strip-trailing-cr', val)
145
+ }
146
+ opts.on('-a', '--text[=-]', miniTrueClass,
147
+ 'Treat all files as text.') { |val|
148
+ set_flag('-a', val)
149
+ }
150
+ opts.on('-c[NUM]', '--context[=NUM]', Integer,
151
+ 'Output NUM (default 3) lines of copied context.') { |val|
152
+ $diff.format = ['-C', val ? val.to_s : '3']
153
+ }
154
+ opts.on('-C NUM', Integer,
155
+ 'Output NUM lines of copied context.') { |val|
156
+ $diff.format = ['-C', val.to_s]
157
+ }
158
+ opts.on('-u[NUM]', '--unified[=NUM]', Integer,
159
+ 'Output NUM (default 3) lines of unified context. [!]') { |val|
160
+ $diff.format = ['-U', val ? val.to_s : '3']
161
+ }
162
+ opts.on('-U NUM', Integer,
163
+ 'Output NUM lines of unified context.') { |val|
164
+ $diff.format = ['-U', val.to_s]
165
+ }
166
+ opts.on('-L LABEL', '--label=LABEL',
167
+ 'Use LABEL instead of file name.') { |val|
168
+ set_flag('-L', val)
169
+ }
170
+ opts.on('-p', '--show-c-function[=-]', miniTrueClass,
171
+ 'Show which C function each change is in. [!]') { |val|
172
+ set_flag('-p', val)
173
+ }
174
+ opts.on('-F RE', '--show-function-line=RE',
175
+ 'Show the most recent line matching RE.') { |val|
176
+ set_flag('-F', val)
177
+ }
178
+ opts.on('-q', '--brief[=-]', miniTrueClass,
179
+ 'Output only whether files differ.') { |val|
180
+ set_flag('-q', val)
181
+ }
182
+ opts.on('-e', '--ed[=-]', miniTrueClass,
183
+ 'Output an ed script.') { |val|
184
+ if val
185
+ $diff.format = ['-e', val]
186
+ end
187
+ }
188
+ opts.on('--normal[=-]', miniTrueClass,
189
+ 'Output a normal diff.') { |val|
190
+ if val
191
+ $diff.format = ['--normal', val]
192
+ end
193
+ }
194
+ opts.on('-n', '--rcs[=-]', miniTrueClass,
195
+ 'Output an RCS format diff.') { |val|
196
+ if val
197
+ $diff.format = ['-n', val]
198
+ end
199
+ }
200
+ opts.on('-y', '--side-by-side[=-]', miniTrueClass,
201
+ 'Output in two columns.') { |val|
202
+ if val
203
+ $diff.format = ['-y', val]
204
+ end
205
+ }
206
+ opts.on('-W NUM', '--width=NUM', Integer,
207
+ 'Output at most NUM (default 130) print columns.') { |val|
208
+ set_flag('-W', val.to_s)
209
+ }
210
+ opts.on('--left-column[=-]', miniTrueClass,
211
+ 'Output only the left column of common lines.') { |val|
212
+ set_flag('--left-column', val)
213
+ }
214
+ opts.on('--suppress-common-lines[=-]', miniTrueClass,
215
+ 'Do not output common lines.') { |val|
216
+ set_flag('--suppress-common-lines', val)
217
+ }
218
+ opts.on('-D NAME', '--ifdef=NAME',
219
+ 'Output merged file to show `#ifdef NAME\' diffs.') { |val|
220
+ set_flag('-D', val)
221
+ }
222
+ opts.on('--old-group-format=GFMT',
223
+ 'Format old input groups with GFMT.') { |val|
224
+ set_flag('--old-group-format', val)
225
+ }
226
+ opts.on('--new-group-format=GFMT',
227
+ 'Format new input groups with GFMT.') { |val|
228
+ set_flag('--new-group-format', val)
229
+ }
230
+ opts.on('--unchanged-group-format=GFMT',
231
+ 'Format unchanged input groups with GFMT.') { |val|
232
+ set_flag('--unchanged-group-format', val)
233
+ }
234
+ opts.on('--line-format=LFMT',
235
+ 'Format all input lines with LFMT.') { |val|
236
+ set_flag('--line-format', val)
237
+ }
238
+ opts.on('--old-line-format=LFMT',
239
+ 'Format old input lines with LFMT.') { |val|
240
+ set_flag('--old-line-format', val)
241
+ }
242
+ opts.on('--new-line-format=LFMT',
243
+ 'Format new input lines with LFMT.') { |val|
244
+ set_flag('--new-line-format', val)
245
+ }
246
+ opts.on('--unchanged-line-format=LFMT',
247
+ 'Format unchanged input lines with LFMT.') { |val|
248
+ set_flag('--unchanged-line-format', val)
249
+ }
250
+ opts.on('-l', '--paginate[=-]', miniTrueClass,
251
+ 'Pass the output through `pr\' to paginate it.') { |val|
252
+ set_flag('-l', val)
253
+ }
254
+ opts.on('-t', '--expand-tabs[=-]', miniTrueClass,
255
+ 'Expand tabs to spaces in output.') { |val|
256
+ set_flag('-t', val)
257
+ }
258
+ opts.on('-T', '--initial-tab[=-]', miniTrueClass,
259
+ 'Make tabs line up by prepending a tab.') { |val|
260
+ set_flag('-T', '--initial-tab', val)
261
+ }
262
+ opts.on('--tabsize=NUM', Integer,
263
+ 'Tab stops are every NUM (default 8) print columns.') { |val|
264
+ set_flag('--tabsize', val.to_s)
265
+ }
266
+ opts.on('-r', '--recursive[=-]', miniTrueClass,
267
+ 'Recursively compare any subdirectories found. [!]') { |val|
268
+ set_flag('-r', val)
269
+ $diff.recursive = val
270
+ }
271
+ opts.on('-N', '--[no-]new-file[=-]', miniTrueClass,
272
+ 'Treat absent files as empty. [!]') { |val|
273
+ set_flag('-N', val)
274
+ $diff.new_file = val
275
+ }
276
+ opts.on('--unidirectional-new-file[=-]', miniTrueClass,
277
+ 'Treat absent first files as empty.') { |val|
278
+ set_flag('--unidirectional-new-file', val)
279
+ }
280
+ opts.on('-s', '--report-identical-files[=-]', miniTrueClass,
281
+ 'Report when two files are the same.') { |val|
282
+ set_flag('-s', val)
283
+ }
284
+ opts.on('-x PAT', '--exclude=PAT',
285
+ 'Exclude files that match PAT.') { |val|
286
+ $diff.exclude << val
287
+ }
288
+ opts.on('-X FILE', '--exclude-from=FILE',
289
+ 'Exclude files that match any pattern in FILE.') { |val|
290
+ if val == '-'
291
+ $diff.exclude.concat(STDIN.read.split(/\n/))
292
+ else
293
+ $diff.exclude.concat(File.read(val).split(/\n/))
294
+ end
295
+ }
296
+ opts.on('--include=PAT',
297
+ 'Do not exclude files that match PAT.') { |val|
298
+ $diff.include << val
299
+ }
300
+ opts.on('-S FILE', '--starting-file=FILE',
301
+ 'Start with FILE when comparing directories.') { |val|
302
+ set_flag('-S', val)
303
+ }
304
+ opts.on('--from-file=FILE1',
305
+ 'Compare FILE1 to all operands. FILE1 can be a directory.') { |val|
306
+ $diff.from_files = [val]
307
+ }
308
+ opts.on('--to-file=FILE2',
309
+ 'Compare all operands to FILE2. FILE2 can be a directory.') { |val|
310
+ $diff.to_files = [val]
311
+ }
312
+ opts.on('--horizon-lines=NUM', Integer,
313
+ 'Keep NUM lines of the common prefix and suffix.') { |val|
314
+ set_flag('--horizon-lines', val.to_s)
315
+ }
316
+ opts.on('-d', '--minimal[=-]', miniTrueClass,
317
+ 'Try hard to find a smaller set of changes. [!]') { |val|
318
+ set_flag('-d', val)
319
+ }
320
+ opts.on('--speed-large-files[=-]', miniTrueClass,
321
+ 'Assume large files and many scattered small changes.') { |val|
322
+ set_flag('--speed-large-files', val)
323
+ }
324
+ opts.on('-v', '--version',
325
+ 'Output version info.') { |val|
326
+ set_flag('-v', val)
327
+ }
328
+ opts.on('--help',
329
+ 'Output this help.') { |val|
330
+ print opts,
331
+ "\n",
332
+ "Options without the [*] sign will be passed through to diff(1).\n",
333
+ "Options marked as [!] sign are turned on by default. To turn them off,\n",
334
+ "specify -?- for short options and --no-??? for long options, respectively.\n"
335
+ exit 0
336
+ }
337
+ }
338
+
339
+ begin
340
+ opts.parse('--rsync-exclude', '--fignore-exclude', '--ignore-cvs-lines',
341
+ '-N', '-r', '-p', '-d')
342
+ opts.parse!(args)
343
+
344
+ $diff.format ||= ['-U', '3']
345
+ set_flag(*$diff.format)
346
+
347
+ if $diff.ignore_cvs_lines
348
+ opts.parse('--ignore-matching-lines=\$[A-Z][A-Za-z0-9][A-Za-z0-9]*\(:.*\)\{0,1\}\$')
349
+ end
350
+ rescue OptionParser::ParseError => e
351
+ warn e, "Try `#{MYNAME} --help' for more information."
352
+ exit 64
353
+ rescue => e
354
+ warn e
355
+ exit 1
356
+ end
357
+
358
+ begin
359
+ if $diff.from_files
360
+ $diff.to_files ||= args.dup
361
+
362
+ if $diff.to_files.empty?
363
+ raise "missing operand"
364
+ end
365
+ elsif $diff.to_files
366
+ $diff.from_files = args.dup
367
+
368
+ if $diff.from_files.empty?
369
+ raise "missing operand"
370
+ end
371
+ else
372
+ if args.size < 2
373
+ raise "missing operand"
374
+ end
375
+
376
+ if File.directory?(args[0])
377
+ $diff.to_files = args.dup
378
+ $diff.from_files = [$diff.to_files.shift]
379
+ else
380
+ $diff.from_files = args.dup
381
+ $diff.to_files = [$diff.from_files.pop]
382
+ end
383
+ end
384
+
385
+ if $diff.from_files.size != 1 && $diff.to_files.size != 1
386
+ raise "wrong number of files given"
387
+ end
388
+ rescue => e
389
+ warn e, "Try `#{MYNAME} --help' for more information."
390
+ exit 64
391
+ end
392
+ end
393
+
394
+ def set_flag(flag, val)
395
+ case val
396
+ when false
397
+ $diff.flags.reject! { |f,| f == flag }
398
+ when true
399
+ $diff.flags.reject! { |f,| f == flag }
400
+ $diff.flags << [flag]
401
+ else
402
+ $diff.flags << [flag, val]
403
+ end
404
+ end
405
+
406
+ def diff_main
407
+ $status = 0
408
+
409
+ $diff.from_files.each { |from_file|
410
+ if File.directory?(from_file)
411
+ $diff.to_files.each { |to_file|
412
+ if File.directory?(to_file)
413
+ if $diff.relative
414
+ to_file = File.expand_path(from_file, to_file)
415
+ end
416
+
417
+ diff_dirs(from_file, to_file)
418
+ else
419
+ if $diff.relative
420
+ from_file = File.expand_path(to_file, from_file)
421
+ else
422
+ from_file = File.expand_path(File.basename(to_file), from_file)
423
+ end
424
+
425
+ diff_files(from_file, to_file)
426
+ end
427
+ }
428
+ else
429
+ $diff.to_files.each { |to_file|
430
+ if File.directory?(to_file)
431
+ if $diff.relative
432
+ to_file = File.expand_path(from_file, to_file)
433
+ else
434
+ to_file = File.expand_path(File.basename(from_file), to_file)
435
+ end
436
+ end
437
+
438
+ diff_files(from_file, to_file)
439
+ }
440
+ end
441
+ }
442
+ end
443
+
444
+ def diff_files(file1, file2)
445
+ if file1.is_a?(Array)
446
+ file2.is_a?(Array) and raise "cannot compare two sets of multiple files"
447
+ file1.empty? and return 0
448
+
449
+ call_diff('--to-file', file2, file1)
450
+ elsif file2.is_a?(Array)
451
+ file1.empty? and return 0
452
+
453
+ call_diff('--from-file', file1, file2)
454
+ else
455
+ call_diff(file1, file2)
456
+ end
457
+ end
458
+
459
+ def call_diff(*args)
460
+ system(*[DIFF_CMD, $diff.flags, args].flatten)
461
+ status = $? >> 8
462
+ $status = status if $status < status
463
+ return status
464
+ end
465
+
466
+ def diff_dirs(dir1, dir2)
467
+ entries1 = diff_entries(dir1)
468
+ entries2 = diff_entries(dir2)
469
+
470
+ common = entries1 & entries2
471
+ missing1 = entries2 - entries1
472
+ missing2 = entries1 - entries2
473
+
474
+ files = []
475
+ common.each { |file|
476
+ file1 = File.join(dir1, file)
477
+ file2 = File.join(dir2, file)
478
+ file1_is_dir = File.directory?(file1)
479
+ file2_is_dir = File.directory?(file2)
480
+ if file1_is_dir && file2_is_dir
481
+ diff_dirs(file1, file2) if $diff.recursive
482
+ elsif !file1_is_dir && !file2_is_dir
483
+ files << file1
484
+ else
485
+ missing1 << file
486
+ missing2 << file
487
+ end
488
+ }
489
+ diff_files(files, dir2)
490
+
491
+ [[dir1, missing2], [dir2, missing1]].each { |dir, missing|
492
+ new_files = []
493
+ missing.each { |entry|
494
+ file = File.join(dir, entry)
495
+
496
+ if $diff.new_file
497
+ if File.directory?(file)
498
+ if dir.equal?(dir1)
499
+ diff_dirs(file, nil)
500
+ else
501
+ diff_dirs(nil, file)
502
+ end
503
+ else
504
+ new_files << file
505
+ end
506
+ else
507
+ printf "Only in %s: %s (%s)\n",
508
+ dir, entry, File.directory?(file) ? 'directory' : 'file'
509
+ $status = 1 if $status < 1
510
+ end
511
+ }
512
+ if dir.equal?(dir1)
513
+ diff_files(new_files, EMPTYFILE)
514
+ else
515
+ diff_files(EMPTYFILE, new_files)
516
+ end
517
+ }
518
+ end
519
+
520
+ def diff_entries(dir)
521
+ return [] if dir.nil?
522
+ return Dir.entries(dir).reject { |file| diff_exclude?(file) }
523
+ rescue => e
524
+ warn "#{dir}: #{e}"
525
+ return []
526
+ end
527
+
528
+ def diff_exclude?(basename)
529
+ return true if basename == '.' || basename == '..'
530
+ return false if $diff.include.any? { |pat|
531
+ File.fnmatch(pat, basename, File::FNM_DOTMATCH)
532
+ }
533
+ return true if $diff.exclude.any? { |pat|
534
+ File.fnmatch(pat, basename, File::FNM_DOTMATCH)
535
+ }
536
+ return true if $diff.rsync_exclude && RSYNC_EXCLUDE_GLOBS.any? { |pat|
537
+ File.fnmatch(pat, basename, File::FNM_DOTMATCH)
538
+ }
539
+ return true if $diff.fignore_exclude && FIGNORE_GLOBS.any? { |pat|
540
+ File.fnmatch(pat, basename, File::FNM_DOTMATCH)
541
+ }
542
+ return false
543
+ end
544
+
545
+ main(ARGV)
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: di
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Akinori MUSHA
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-10-06 00:00:00 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: knu@idaemons.org
18
+ executables:
19
+ - di
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - bin/di
26
+ - README.txt
27
+ - History.txt
28
+ has_rdoc: false
29
+ homepage: http://www.idaemons.org/projects/di/
30
+ post_install_message:
31
+ rdoc_options: []
32
+
33
+ require_paths:
34
+ - lib
35
+ required_ruby_version: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: "0"
40
+ version:
41
+ required_rubygems_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ requirements: []
48
+
49
+ rubyforge_project: unixutils
50
+ rubygems_version: 1.0.1
51
+ signing_key:
52
+ specification_version: 2
53
+ summary: A wrapper around GNU diff(1)
54
+ test_files: []
55
+