I'm forwarding this commit message to the full Module::Build list as I
consider it a relative 'big' change with some degree of risk that
everyone needs to be aware of.

Please read the extensive log message.  Anyone who knows this code
passably well, please skim the commit. Anyone who does any custom
install path work with Module::Build or does custom install
configuration, please check out trunk and give it a try with your
code/site.

Thank you,
David

---------- Forwarded message ----------
From:  <dagol...@cvs.perl.org>
Date: Wed, Aug 19, 2009 at 11:26 AM
Subject: [svn:Module-Build] r13208 - in Module-Build/trunk: . lib/Module/Build t
To: svn-commit-modules-module-bu...@perl.org


Author: dagolden
Date: Wed Aug 19 08:26:19 2009
New Revision: 13208

Modified:
  Module-Build/trunk/Changes
  Module-Build/trunk/lib/Module/Build/Base.pm
  Module-Build/trunk/t/install_extra_target.t

Log:
Fixed preservation of custom install_paths on resume (RT#41166)

This required a fairly sweeping change to calculation of install paths.

Old way: Generate default install paths from config and store them
in the object properties during object creation.  User modifications are
made directly to these object properties.  The problem is in the timing.
Creation of defaults need to happen 'late' after any --config options are
processed, but this was overwriting any custom install paths restored from
_build (which happens "early")

New way: Default install paths are generated "on demand" based on whatever
config values are in force and are not stored in the object.  Accessors for all
the install path properties now merge custom install paths in object
properties with the generated defaults on the fly.  Among other things, this
allows config values to be changed programatically after object construction
and change the resulting install paths.

There is a subtle semantic change in that setting an install path to "undef"
stores that in the object properties.  This ensures the generated default
is masked, giving an "undef" result.  (The old way deleted the install path
from the object properties.)  I think the end result is the same -- asking
for a "deleted" path returns an undef value.

Special thanks to Thorben Jaendling for writing a new test file to help me
confirm the bug and the subsequent fix.



Modified: Module-Build/trunk/Changes
==============================================================================
--- Module-Build/trunk/Changes  (original)
+++ Module-Build/trunk/Changes  Wed Aug 19 08:26:19 2009
@@ -5,6 +5,7 @@
 Bug fixes:
 - Multiple test fixes for OS2 [Ilya Zakharevich]
 - Generated.ppd files use :utf8 if possible (RT#48827) [Olivier Mengue]
+ - Fixed preservation of custom install_paths on resume (RT#41166)

 0.34_05 - Sun Aug  9 22:31:37 EDT 2009


Modified: Module-Build/trunk/lib/Module/Build/Base.pm
==============================================================================
--- Module-Build/trunk/lib/Module/Build/Base.pm (original)
+++ Module-Build/trunk/lib/Module/Build/Base.pm Wed Aug 19 08:26:19 2009
@@ -42,7 +42,6 @@
  $self->dist_name;
  $self->dist_version;

-  $self->_set_install_paths;
  $self->_find_nested_builds;

  return $self;
@@ -86,8 +85,6 @@

  $self->{invoked_action} = $self->{action} ||= 'build';

-  $self->_set_install_paths;
-
  return $self;
 }

@@ -208,10 +205,12 @@
 }


-sub _set_install_paths {
+# install paths must be generated when requested to be sure all changes
+# to config (from various sources) are included
+sub _default_install_paths {
  my $self = shift;
  my $c = $self->{config};
-  my $p = $self->{properties};
+  my $p = {};

  my @libstyle = $c->get('installstyle') ?
      File::Spec->splitdir($c->get('installstyle')) : qw(lib perl5);
@@ -318,7 +317,7 @@
             libhtml    => ['html'],
            },
    };
-
+    return $p
 }

 sub _find_nested_builds {
@@ -1839,6 +1838,8 @@
 sub _merge_arglist {
  my( $self, $opts1, $opts2 ) = @_;

+  $opts1 ||= {};
+  $opts2 ||= {};
  my %new_opts = %$opts1;
  while (my ($key, $val) = each %$opts2) {
    if ( exists( $opts1->{$key} ) ) {
@@ -4022,73 +4023,118 @@
  return $map->{$type} = $value;
 }

+sub install_sets {
+  # Usage: install_sets('site'), install_sets('site', 'lib'),
+  #   or install_sets('site', 'lib' => $value);
+  my ($self, $dirs, $key, $value) = @_;
+  $dirs = $self->installdirs unless defined $dirs;
+  # update property before merging with defaults
+  if ( @_ == 4 && defined $dirs && defined $key) {
+    # $value can be undef; will mask default
+    $self->{properties}{install_sets}{$dirs}{$key} = $value;
+  }
+  my $map = { $self->_merge_arglist(
+    $self->{properties}{install_sets},
+    $self->_default_install_paths->{install_sets}
+  )};
+  if ( defined $dirs && defined $key ) {
+    return $map->{$dirs}{$key};
+  }
+  elsif ( defined $dirs ) {
+    return $map->{$dirs};
+  }
+  else {
+    croak "Can't determine installdirs for install_sets()";
+  }
+}
+
+sub original_prefix {
+  # Usage: original_prefix(), original_prefix('lib'),
+  #   or original_prefix('lib' => $value);
+  my ($self, $key, $value) = @_;
+  # update property before merging with defaults
+  if ( @_ == 3 && defined $key) {
+    # $value can be undef; will mask default
+    $self->{properties}{original_prefix}{$key} = $value;
+  }
+  my $map = { $self->_merge_arglist(
+    $self->{properties}{original_prefix},
+    $self->_default_install_paths->{original_prefix}
+  )};
+  return $map unless defined $key;
+  return $map->{$key}
+}
+
 sub install_base_relpaths {
  # Usage: install_base_relpaths(), install_base_relpaths('lib'),
  #   or install_base_relpaths('lib' => $value);
  my $self = shift;
-  my $map = $self->{properties}{install_base_relpaths};
+  if ( @_ > 1 ) { # change values before merge
+    $self->_set_relpaths($self->{properties}{install_base_relpaths}, @_);
+  }
+  my $map = { $self->_merge_arglist(
+    $self->{properties}{install_base_relpaths},
+    $self->_default_install_paths->{install_base_relpaths}
+  )};
  return $map unless @_;
-  return $self->_relpaths($map, @_);
+  my $relpath = $map->{$_[0]};
+  return defined $relpath ? File::Spec->catdir( @$relpath ) : undef;
 }

-
-# Translated from ExtUtils::MM_Any::init_INSTALL_from_PREFIX
-sub prefix_relative {
-  my ($self, $type) = @_;
-  my $installdirs = $self->installdirs;
-
-  my $relpath = $self->install_sets($installdirs)->{$type};
-
-  return $self->_prefixify($relpath,
-                          $self->original_prefix($installdirs),
-                          $type,
-                         );
+# Defaults to use in case the config install paths cannot be prefixified.
+sub prefix_relpaths {
+  # Usage: prefix_relpaths('site'), prefix_relpaths('site', 'lib'),
+  #   or prefix_relpaths('site', 'lib' => $value);
+  my $self = shift;
+  my $installdirs = shift || $self->installdirs
+    or croak "Can't determine installdirs for prefix_relpaths()";
+  if ( @_ > 1 ) { # change values before merge
+    $self->{properties}{prefix_relpaths}{$installdirs} ||= {};
+    $self->_set_relpaths($self->{properties}{prefix_relpaths}{$installdirs},
@_);
+  }
+  my $map = {$self->_merge_arglist(
+    $self->{properties}{prefix_relpaths}{$installdirs},
+    $self->_default_install_paths->{prefix_relpaths}{$installdirs}
+  )};
+  return $map unless @_;
+  my $relpath = $map->{$_[0]};
+  return defined $relpath ? File::Spec->catdir( @$relpath ) : undef;
 }

-sub _relpaths {
+sub _set_relpaths {
  my $self = shift;
-  my( $map, $type, $value ) = ( @_, '<empty>' );
+  my( $map, $type, $value ) = @_;

  Carp::croak( 'Type argument missing' )
    unless defined( $type );

-  my @value = ();
-
-  # delete existing value if $value is literal undef()
-  unless ( defined( $value ) ) {
-    delete( $map->{$type} );
-    return undef;
-  }
-
-  # return existing value if no new $value is given
-  elsif ( $value eq '<empty>' ) {
-    return undef unless exists $map->{$type};
-   �...@value = @{ $map->{$type} };
+  # set undef if $value is literal undef()
+  if ( ! defined( $value ) ) {
+    $map->{$type} = undef;
+    return;
  }
-
  # set value if $value is a valid relative path
  else {
    Carp::croak( "Value must be a relative path" )
      if File::Spec::Unix->file_name_is_absolute($value);

-   �...@value = split( /\//, $value );
+    my @value = split( /\//, $value );
    $map->{$type} = \...@value;
  }
-
-  return File::Spec->catdir( @value );
 }

-# Defaults to use in case the config install paths cannot be prefixified.
-sub prefix_relpaths {
-  # Usage: prefix_relpaths('site'), prefix_relpaths('site', 'lib'),
-  #   or prefix_relpaths('site', 'lib' => $value);
-  my $self = shift;
-  my $installdirs = shift || $self->installdirs;
-  my $map = $self->{properties}{prefix_relpaths}{$installdirs};
-  return $map unless @_;
-  return $self->_relpaths($map, @_);
-}
+# Translated from ExtUtils::MM_Any::init_INSTALL_from_PREFIX
+sub prefix_relative {
+  my ($self, $type) = @_;
+  my $installdirs = $self->installdirs;

+  my $relpath = $self->install_sets($installdirs)->{$type};
+
+  return $self->_prefixify($relpath,
+                          $self->original_prefix($installdirs),
+                          $type,
+                         );
+}

 # Translated from ExtUtils::MM_Unix::prefixify()
 sub _prefixify {

Modified: Module-Build/trunk/t/install_extra_target.t
==============================================================================
--- Module-Build/trunk/t/install_extra_target.t (original)
+++ Module-Build/trunk/t/install_extra_target.t Wed Aug 19 08:26:19 2009
@@ -128,13 +128,10 @@

 $output = stdout_of sub { $dist->run_build('install') };

-TODO: {
-  local $TODO = "RT#4116 not fixed";
-  $error = 0;
-  $error++ unless ok(-e "$installdest/etc/simple/config", "installed
etc/config");
-  $error++ unless ok(-e "$installdest/share/simple/data", "installed
share/data");
-  $error++ unless ok(-e "$installdest/share/simple/html/index.html",
"installed share/html");
-  diag "OUTPUT:\n$output" if $error;
-}
+$error = 0;
+$error++ unless ok(-e "$installdest/etc/simple/config", "installed
etc/config");
+$error++ unless ok(-e "$installdest/share/simple/data", "installed
share/data");
+$error++ unless ok(-e "$installdest/share/simple/html/index.html",
"installed share/html");
+diag "OUTPUT:\n$output" if $error;

 $dist->remove();

Reply via email to