From: Ara.T.Howard@... Date: 2005-08-05T01:41:07+09:00 Subject: Re: Comparing directory contents On Fri, 5 Aug 2005, Jacob Fugal wrote: > On 8/3/05, Lothar Scholz wrote: >> JF> Though Brian Schr=F6der gave an interesting irb implementation, what = > you >> JF> really need is diff[1]. And don't despair, there is diff for >> JF> Windows[2] (via the command line). >> =20 >> JF> The GNU developers have put a *lot* >> JF> of work and refinement into this heavily used tool -- don't reinvent >> JF> the wheel. >> =20 >> >> And they still got nothing what even comes close to "AraxisMerge" on >> Windows, neither from the GUI nor from the quality of the diff algorithm. >> > > Ok, to qualify my statement: Don't reinvent this particular wheel for > a once-off solution. I won't say that someone else can make a better > wheel when that's their primary goal. I don't think Dave Davidson's > goal is to develop a new diff utility. Regarding AraxisMerge, I've > never heard of it. It may be better than GNU DiffUtils. I can't make > any judgement there. > >> But back to the question from the original poster, i think diff is a >> complete wrong idea as he said he only needs the file names and the conte= > nt >> does not matter for an installer as he puts the complete file into the >> setup.exe. > > diff -qr | grep '^Only' > > Know the tool before dismissing it. the way i read the OP's post the original contents should be stored and alterable. the diff approach would require both directories to exist and be stored and i think the OP wanted to store only the __inventory__ of the dir - not the actual dir. so not only would the storage/database requirements skyrocket, but you'd be using a sledgehammer to pound in a mini-tack. this problem is quite easily solved in only a few lines of ruby - including database code, command line parsing, etc: here's the code: harp:~ > cat ./dirlist #! /usr/bin/env ruby require 'pstore' require 'yaml' require 'getoptlong' class DirDb < ::PStore def [] dir transaction{ super(exp(dir)) rescue nil} end def []= dir, filelist transaction{ super(exp(dir), filelist) } end def exp dir File::expand_path dir end end class FileList < ::Array def initialize dir @dir = File::expand_path dir @glob = File::join @dir, '**', '*' replace Dir[@glob].map{|f| File::expand_path f} end def basenames map{|f| f.gsub(%r|^#{ Regexp::escape @dir }/*|,'')} end def add filename self << File::expand_path(File::join(@dir, filename)) end def delete filename super(File::expand_path(File::join(@dir, filename))) end def to_yaml to_a.to_yaml end end class Main def self::main(*a, &b) new(*a, &b).run end def initialize gl = GetoptLong::new ['--db', '-d', GetoptLong::REQUIRED_ARGUMENT] gl.each do |opt, arg| case opt when /db/ @db_path = arg end end @db_path ||= File::expand_path(File::join('~', '.dirdb')) @mode, @mode_args = ARGV.shift, ARGV @mode ||= 'help' @db = DirDb::new @db_path end def run send(@mode, *@mode_args) end def scan dir @db[dir] = FileList::new dir show dir end def show dir y @db[dir] end def report old_dir, new_dir previous = @db[old_dir] current = FileList::new new_dir report = {} report['identical'] = previous.basenames & current.basenames report['extra'] = current.basenames - previous.basenames report['removed'] = previous.basenames - current.basenames y report end def add dir, filename filelist = @db[dir] filelist.add filename @db[dir] = filelist end def delete dir, filename filelist = @db[dir] filelist.delete filename @db[dir] = filelist end def help puts "#{ $0 } scan dir | show dir | report new_dir old_dir | add dir filename | delete dir filename" end end $0 == __FILE__ and Main::main and here's how you use it: harp:~ > mkdir version-1.0.0 && touch version-1.0.0/a version-1.0.0/b version-1.0.0/c harp:~ > ./dirlist ./dirlist scan dir | show dir | report new_dir old_dir | add dir filename | delete dir filename harp:~ > ./dirlist scan version-1.0.0/ --- - /home/ahoward/version-1.0.0/a - /home/ahoward/version-1.0.0/b - /home/ahoward/version-1.0.0/c harp:~ > rm -rf version-1.0.0/ harp:~ > mkdir version-2.0.0 && touch version-2.0.0/a version-2.0.0/b harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: - c extra: [] identical: - a - b harp:~ > touch version-2.0.0/c harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: [] extra: [] identical: - a - b - c harp:~ > touch version-2.0.0/d harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: [] extra: - d identical: - a - b - c harp:~ > ./dirlist add version-1.0.0 d harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: [] extra: [] identical: - a - b - c - d harp:~ > rm version-2.0.0/a harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: - a extra: [] identical: - b - c - d harp:~ > ./dirlist delete version-1.0.0 a harp:~ > ./dirlist report version-1.0.0 version-2.0.0 --- removed: [] extra: [] identical: - b - c - d in any case, i'm all for using built-in tools to accomplish tasks - but this task is so basic it seem silly not to just write it in pure ruby... kind regards. -a -- =============================================================================== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso ===============================================================================