[26793] users/pipping/merge.rb

source_changes at macosforge.org source_changes at macosforge.org
Sun Jul 8 05:38:57 PDT 2007


Revision: 26793
          http://trac.macosforge.org/projects/macports/changeset/26793
Author:   pipping at macports.org
Date:     2007-07-08 05:38:56 -0700 (Sun, 08 Jul 2007)

Log Message:
-----------
r50: rewrite 'wrapper_target' ( takes another argument now, looks nicer, cares about permissions )
r51: rewrite option parsing

Modified Paths:
--------------
    users/pipping/merge.rb

Modified: users/pipping/merge.rb
===================================================================
--- users/pipping/merge.rb	2007-07-08 07:40:39 UTC (rev 26792)
+++ users/pipping/merge.rb	2007-07-08 12:38:56 UTC (rev 26793)
@@ -23,6 +23,7 @@
 require 'fileutils'
 require 'find'
 require 'optparse'
+require 'ostruct'
 require 'pathname'
 require 'set'
 
@@ -31,153 +32,130 @@
 # able to recognize x86_64 mach-o files
 FILE = '/usr/bin/file'
 
-class MergeArguments < Hash
-  def initialize( args )
-    super( )
+class MergeArguments
+  def self.parse( args )
 
     # set up defaults
-    self[:dry_run] = false
-    self[:force]   = false
-    self[:verbose] = false
+    options = OpenStruct.new
+    options.dryrun  = false
+    options.force   = false
+    options.verbose = false
 
-    self[:exclude] = Set.new << '.svn' << 'CVS'
-    self[:output]  = Pathname.pwd + 'out'
-    self[:input]   = Pathname.pwd
+    options.exclude = %w{.svn CVS}
 
+    options.input   = Pathname.pwd
+    options.output  = Pathname.pwd + 'out'
+
     opts = OptionParser.new {|opts|
-      opts.banner = "Usage: #$0 [options] <arch> <arch> [<arch> ...]"
+      opts.banner = 'Usage: %s [options] arch arch [arch [arch ...]]' % $0
 
-      opts.on(
-        '-i', '--input DIRECTORY',
-        'specify input directory'
-      ) {|input|
-        self[:input] = Pathname.new( input ).expand_path || Pathname.pwd
+      opts.on( '-i', '--input DIRECTORY',
+        'Change input directory', 'Defaults to \'.\'') {|i|
+        options.input = Pathname.new( i ).expand_path || options.input
       }
 
-      opts.on(
-        '-o', '--output DIRECTORY',
-        'specify output directory'
-      ) {|output|
-        self[:output] = Pathname.new( output ).expand_path || Pathname.pwd
+      opts.on( '-o', '--output DIRECTORY',
+        'Change output directory', 'Defaults to \'./out\'') {|o|
+        options.output = Pathname.new( o ).expand_path || options.output
       }
 
-      opts.on(
-        '-e', '--exclude NAMES',
-        'specify names of files/directories to exclude'
-      ) {|exclude|
-        self[:exclude] = Set.new
-        exclude.split.each {|item|
-          self[:exclude] << item
-        }
+      opts.on( '-e', '--exclude PATTERN1,PATTERN2', Array,
+        'Exclude files/directories (glob-style)') {|e|
+        options.exclude = e
       }
 
-      opts.on(
-        '-d', '--dry-run',
-        'perform a dry run'
-      ) {
-        self[:dry_run] = true
+      opts.on( '-d', '--[no-]dry-run', 'Perform a dry run' ) {|d|
+        options.dryrun = d
       }
 
-      opts.on(
-        '-f', '--force',
-        'force writing, ignoring collisions'
-      ) {
-        self[:force] = true
+      opts.on( '-f', '--[no-]force', 'Ignore collisions' ) {|f|
+        options.force = f
       }
 
-      opts.on(
-        '-v', '--verbose',
-        'enable verbose output'
-      ) {
-        self[:verbose] = true
+      opts.on( '-v', '--[no-]verbose', 'Run verbosely' ) {|v|
+        options.verbose = v
       }
 
-      opts.on_tail(
-        '-h', '--help',
-        'display this help and exit'
-      ) {
+      opts.on_tail( '-h', '--help', 'Show this message' ) {
         puts opts
         exit
       }
     }
     opts.parse!( args )
+    options
   end
 end
 
-arguments = MergeArguments.new( ARGV )
+options = MergeArguments.parse( ARGV )
 
 # ignore duplicates and trailing slashes
 ARGS = ARGV.collect {|arg| arg.chomp( '/' )}.uniq
 
-def true_for_all? ( path, args, first_too, &block )
+def true_for_all? ( path, opts, first_too, &block )
 # checks if a predicate is true for all (but the first) architecture
   result = true
   iter_over = first_too ? ARGS : ARGS[1..-1]
   iter_over.each {|arch|
-    result = false unless yield( args[:input] + arch + path, arch )
+    result = false unless yield( opts.input + arch + path, arch )
   }
   return result
 end
 
-def copy ( origin, target, args )
+def copy ( origin, target, opts )
 # copies files
-  unless target.exist? and !args[:force]
+  unless target.exist? and !opts.force
     FileUtils.cp( origin, target,
-      :noop => args[:dry_run],
-      :verbose => args[:verbose]
+      :noop => opts.dryrun,
+      :verbose => opts.verbose
     )
   end
 end
 
-def check_singlearch( my_path, args, regex )
+def check_singlearch( my_path, opts, regex )
 # checks if a file has the correct type and architecture across all trees
-  type_matches = true_for_all?( my_path, args, true ) {|filepath, arch|
+  type_matches = true_for_all?( my_path, opts, true ) {|filepath, arch|
     filecall_out = %x{#{ FILE } -b "#{ filepath }"}.chomp
     filecall_out =~ regex
   }
-  arch_matches = true_for_all?( my_path, args, true ) {|filepath, arch|
+  arch_matches = true_for_all?( my_path, opts, true ) {|filepath, arch|
     lipocall_out = %x{lipo -info "#{ filepath }"}.chomp
     lipocall_out =~ %r{is architecture: #{ arch }$}
   }
   raise 'type or architecture mismatch' unless type_matches and arch_matches
 end
 
-def lipo ( filepath, architectures, args )
+def lipo ( filepath, architectures, opts )
 # glues single-architecture files together using lipo(1)
   lipoargs = Array.new
   architectures.each {|arch|
-    lipoargs << sprintf( '-arch %s %s', arch, args[:input] + arch + filepath )
+    lipoargs << sprintf( '-arch %s %s', arch, opts.input + arch + filepath )
   }
-  lipotarget = args[:output] + filepath
+  lipotarget = opts.output + filepath
   lipocmd = sprintf( 'lipo %s -create -o %s', lipoargs.join( ' ' ), lipotarget )
-  unless lipotarget.exist? and !args[:force]
-    puts lipocmd if args[:verbose]
-    system lipocmd unless args[:dry_run]
+  unless lipotarget.exist? and !opts.force
+    puts lipocmd if opts.verbose
+    system lipocmd unless opts.dryrun
   end
 end
 
-def make_wrapper ( filepath, args )
+def make_wrapper ( filepath, first, opts )
 # creates a wrapper for config scripts that differ across trees
-  unless ( args[:output] + filepath ).exist? and !args[:force]
-    open( args[:output] + filepath, 'w' ) {|my_file|
-      my_file.puts <<EOF
-#! /bin/sh
-
-DIR="#{filepath.dirname}"
-
-args=$@
-
-if [ "${args/-arch/}" != "$args" ]; then
-  arch=`echo "$args" | sed 's!.*-arch  *\\([^ ][^ ]*\\).*!\\1!'`;
-else
-  arch=`uname -p`
-fi
-
-args=`echo $@ | sed "s!-arch  *${arch}!!"`
- 
-exec $DIR/${arch}/#{filepath.basename} ${args}
-EOF
+  wrapper_target = opts.output + filepath
+  unless wrapper_target.exist? and !opts.force
+    wrapper_target.open( 'w' ) {|wrapper|
+      wrapper.puts '#! /bin/sh'
+      wrapper.puts 'DIR="%s"' % filepath.dirname
+      wrapper.puts 'args=$@'
+      wrapper.puts 'if [ "${args/-arch/}" != "$args" ]; then'
+      wrapper.puts '  arch=`echo "$args" | ' +
+                   'sed \'s!.*-arch  *\([^ ][^ ]*\).*!\1!\'`;'
+      wrapper.puts 'else'
+      wrapper.puts '  arch=`uname -p`'
+      wrapper.puts 'fi'
+      wrapper.puts 'args=`echo $@ | sed "s!-arch  *${arch}!!"`'
+      wrapper.puts 'exec $DIR/${arch}/%s ${args}' % filepath.basename
     }
+    wrapper_target.chmod( first.stat.mode )
   end
 end
 
@@ -186,52 +164,52 @@
 processed = Set.new
 
 # make sure we're given a valid root directory
-unless arguments[:input].directory?
-  raise 'invalid input directory: %s' % arguments[:input]
+unless options.input.directory?
+  raise 'invalid input directory: %s' % options.input
 end
 
 # make sure the requested architectures have corresponding subdirectories
 # in the the given input directory
-unless true_for_all?( '.', arguments, true) {|filepath, arch|
+unless true_for_all?( '.', options, true) {|filepath, arch|
   filepath.directory?
 }
   raise 'architecture missing from input directory'
 end
 
 ARGS.each {|architecture|
-  FileUtils.cd arguments[:input] + architecture
+  FileUtils.cd options.input + architecture
   Pathname.new( '.' ).find {|path|
-    arguments[:exclude].each {|exclude_me|
+    options.exclude.each {|exclude_me|
       Find.prune if path.basename.fnmatch? exclude_me
     }
     Find.prune if processed.include? path
 
-    first_path = arguments[:input] + ARGS[0] + path
-    unless true_for_all?( path, arguments, false ) {|filepath, arch|
+    first_path = options.input + ARGS[0] + path
+    unless true_for_all?( path, options, false ) {|filepath, arch|
       begin
         filepath.ftype == first_path.ftype
-      # file does not exist
       rescue Errno::ENOENT
+        # DEBUG: file does not exist
         false
       end
     }
-      printf "DEBUG: skipping %s\n", path
+      puts 'DEBUG: skipping %s' % path
       Find.prune
     end
 
     case first_path.ftype
     # handle file type: directory
     when 'directory'
-      my_dir = arguments[:output] + path
-      my_dir.mkpath unless arguments[:dry_run]
+      my_dir = options.output + path
+      my_dir.mkpath unless options.dryrun
     # handle file type: symlinks
     when 'link'
       link_target = first_path.readlink
-      if true_for_all?( path, arguments, false ) {|filepath, arch|
-        my_symlink = arguments[:input] + arch + path
+      if true_for_all?( path, options, false ) {|filepath, arch|
+        my_symlink = options.input + arch + path
         my_symlink.readlink == link_target
       }
-        link_output = arguments[:output] + path
+        link_output = options.output + path
         unless link_output.symlink? or link_output.exist?
           FileUtils.copy_entry(
             first_path,
@@ -242,21 +220,21 @@
         # DEBUG: link targets differ
       end
     when 'file'
-      if true_for_all?( path, arguments, false ) {|filepath, arch|
+      if true_for_all?( path, options, false ) {|filepath, arch|
         FileUtils.identical?( filepath, first_path )
       }
-        copy( first_path, arguments[:output] + path, arguments )
+        copy( first_path, options.output + path, options )
         Find.prune
       end
 
       case path.extname
       # handle file type: header files
       when '.h', '.hpp'
-        unless ( arguments[:output] + path ).exist? and !arguments[:force]
-          open( arguments[:output] + path, 'w' ) {|my_file|
+        unless ( options.output + path ).exist? and !options.force
+          open( options.output + path, 'w' ) {|my_file|
             ARGS.each {|arch|
-              my_file.printf "#ifdef __%s__\n", arch
-              my_file.puts open( arguments[:input] + arch + path, 'r' ).read
+              my_file.puts '#ifdef __%s__' % arch
+              my_file.puts open( options.input + arch + path, 'r' ).read
               my_file.puts '#endif'
             }
           }
@@ -264,9 +242,9 @@
       # handle file type: pkg-config files
       when '.pc'
         ARGS.each {|arch|
-          copy_target = arguments[:output] + path.dirname + arch + path.basename
-          copy_target.dirname.mkpath unless arguments[:dry_run]
-          copy( arguments[:input] + arch + path, copy_target, arguments )
+          copy_target = options.output + path.dirname + arch + path.basename
+          copy_target.dirname.mkpath unless options.dryrun
+          copy( options.input + arch + path, copy_target, options )
         }
       # handle file type: other files
       else
@@ -274,18 +252,18 @@
         case file_output
         # handle file type: ar archives
         when %r{^current ar archive}
-          check_singlearch( path, arguments, %r{^current ar archive} )
-          lipo( path, ARGS, arguments )
+          check_singlearch( path, options, %r{^current ar archive} )
+          lipo( path, ARGS, options )
         # handle file type: mach-o files
         when %r{^Mach-O}
-          check_singlearch( path, arguments, %r{^Mach-O} )
+          check_singlearch( path, options, %r{^Mach-O} )
           links = Hash.new
           ARGS.each {|my_arch|
             links[my_arch] = %x{
               #{
                 my_arch[-2..-1] == '64' ? 'otool64' : 'otool'
               } -arch #{ my_arch } -LX #{
-                arguments[:input] + my_arch + path
+                options.input + my_arch + path
               }
             }.split( "\n" ).collect {|dep_line|
               dep_line.lstrip.gsub(
@@ -304,18 +282,19 @@
               end
             end
           }
-          lipo( path, ARGS, arguments )
+          lipo( path, ARGS, options )
         when 'Bourne shell script text executable'
           unless path.basename.to_s[-7..-1] == '-config'
             Find.prune
-            # ERROR: no way to handle a shell script in general
+            # DEBUG: no way to handle a shell script in general
           end
+          # handle file type: config script
           ARGS.each {|arch|
-            copy_target=arguments[:output] + path.dirname + arch + path.basename
-            copy_target.dirname.mkpath unless arguments[:dry_run]
-            copy( arguments[:input] + arch + path, copy_target, arguments )
+            copy_target=options.output + path.dirname + arch + path.basename
+            copy_target.dirname.mkpath unless options.dryrun
+            copy( options.input + arch + path, copy_target, options )
           }
-          make_wrapper( path, arguments )
+          make_wrapper( path, first_path, options )
         else
           # DEBUG: unable to determine file type
         end

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070708/f60b8334/attachment.html


More information about the macports-changes mailing list