From: Robert Klemme Date: 2008-03-25T17:19:28+09:00 Subject: Re: Find.find sorting: files before directories 2008/3/24, Adam Boyle : > > Why do you need that? I mean, if a folder is excluded then you want to > > exclude all files and subfolders, don't you? > > > Yes, an excluded folder would also exclude its children files and > folders. > > I'm thinking that I haven't exactly made it clear what my goal is... > > Using Find.find, I want to traverse through a directory structure and > make an NSIS-style list of files and their paths for use in an NSIS > installer script. A list of this sort would be best organized if a > directory's file children are listed before the directory children. > > Example: > > SetOutPath "jruby-1.0.3/docs" > File "jruby-1.0.3/docs/README.rails" > File "jruby-1.0.3/docs/README.coverage" > File "jruby-1.0.3/docs/Readline-HOWTO.txt" > File "jruby-1.0.3/docs/LICENSE.bouncycastle" > File "jruby-1.0.3/docs/LICENSE.ant" > File "jruby-1.0.3/docs/LICENCE.bsf" > File "jruby-1.0.3/docs/Glossary.txt" > File "jruby-1.0.3/docs/getting_involved.html" > > SetOutPath "jruby-1.0.3/docs/rbyaml" > File "jruby-1.0.3/docs/rbyaml/README" > File "jruby-1.0.3/docs/rbyaml/LICENSE" > > SetOutPath "jruby-1.0.3/docs/jvyaml" > File "jruby-1.0.3/docs/jvyaml/README" > File "jruby-1.0.3/docs/jvyaml/LICENSE" > File "jruby-1.0.3/docs/jvyaml/CREDITS" > > ... > > > The "SetOutPath" lines are the directories, the "File" lines are the > files. > > The code you gave will gave results like this (once I used Ruby > instead of JRuby :)...): > > SetOutPath jruby-1.0.3 > > SetOutPath jruby-1.0.3/samples > File jruby-1.0.3/samples/xslt.rb > File jruby-1.0.3/samples/thread.rb > File jruby-1.0.3/samples/swing2.rb > File jruby-1.0.3/samples/scripting.rb > File jruby-1.0.3/samples/javascript.rb > File jruby-1.0.3/samples/java2.rb > File jruby-1.0.3/samples/error.rb > File jruby-1.0.3/samples/dom-applet.html > File jruby-1.0.3/samples/applet.html > File jruby-1.0.3/README > SetOutPath jruby-1.0.3/lib > SetOutPath jruby-1.0.3/lib/ruby > SetOutPath jruby-1.0.3/lib/ruby/site_ruby > SetOutPath jruby-1.0.3/lib/ruby/site_ruby/1.8 > File jruby-1.0.3/lib/ruby/site_ruby/1.8/ubygems.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/securerandom.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems.rb > SetOutPath jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/version.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/validator.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > user_interaction.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/timer.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > specification.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > source_info_cache_entry.rb > ... > > > The issue is that it is very important that the SetOutPath call for > any particular file comes directly before it in the list (ie, > SetOutPath jruby-1.0.3 for the line File jruby-1.0.3/README). That > way the output path is set correctly when the file is extracted from > the installer executable. > > The selected lines from the previous example would ideally be listed > this way: > > SetOutPath jruby-1.0.3 > > File jruby-1.0.3/README > SetOutPath jruby-1.0.3/samples > File jruby-1.0.3/samples/xslt.rb > File jruby-1.0.3/samples/thread.rb > File jruby-1.0.3/samples/swing2.rb > File jruby-1.0.3/samples/scripting.rb > File jruby-1.0.3/samples/javascript.rb > File jruby-1.0.3/samples/java2.rb > File jruby-1.0.3/samples/error.rb > File jruby-1.0.3/samples/dom-applet.html > File jruby-1.0.3/samples/applet.html > SetOutPath jruby-1.0.3/lib/ruby/site_ruby/1.8 > File jruby-1.0.3/lib/ruby/site_ruby/1.8/ubygems.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/securerandom.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems.rb > SetOutPath jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/version.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/validator.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > user_interaction.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/timer.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > specification.rb > File jruby-1.0.3/lib/ruby/site_ruby/1.8/rubygems/ > source_info_cache_entry.rb > ... > > > It's beginning to seem to me that Find.find just doesn't have an easy > way of sorting the elements being traversed. Any additional help is > greatly appreciated. Thanks for clarifying. You could do something like this: require 'find' base='.' excludes = [] dirs = Hash.new {|h,p| h[p]=[]} Find.find base do |path| if File.directory? path Find.prune if excludes.include? path else dirs[File.dirname(path)] << path end end dirs.sort.each do |dir,files| puts "SetOutPath #{dir}" files.each {|f| puts "File #{f}"} end If you want to do printing while traversing then the code becomes more complicated (either using Find or manual traversal via Dir[]). Kind regards robert -- use.inject do |as, often| as.you_can - without end