diff options
Diffstat (limited to 'tools/install-xml-file-list')
| -rwxr-xr-x | tools/install-xml-file-list | 227 | 
1 files changed, 172 insertions, 55 deletions
| diff --git a/tools/install-xml-file-list b/tools/install-xml-file-list index df760ae32..64c70b9c6 100755 --- a/tools/install-xml-file-list +++ b/tools/install-xml-file-list @@ -1,22 +1,35 @@  #!/usr/bin/perl +use FileHandle;  use MDK::Common;  use XML::Parser;  use Data::Dumper; +use File::Glob;  use Config;  use Cwd 'cwd'; -@ARGV == 2 or die "usage: install-xml-file-list <xml file> <destination>\n"; +my $want_sudo = $ARGV[0] eq '--sudo' && shift @ARGV; + +@ARGV == 2 or die "usage: install-xml-file-list [--sudo] <xml file> <destination>\n";  my ($xml_file_list, $DEST) = @ARGV; +my $sudo = ''; +if ($>) { +    $sudo = "sudo" if $want_sudo; +    $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}"; +} + +my $verbose; +#$verbose = 1; +  my $initial_dir = cwd();  my $ARCH = arch() =~ /i.86/ ? 'i386' : arch(); +$ARCH =~ s/^(arm).*/$1/;  my $LIB = arch() =~ /x86_64/ ? "lib64" : "lib";  my $base_cpio_options = '-pumd --quiet'; -system("rm -rf $DEST"); - +my $problem;  my $tree = XML::Parser->new(Style => 'Tree')->parsefile($xml_file_list);  my $main_node = decompose($tree); @@ -25,13 +38,21 @@ $main_node->{tag} eq 'list' or die "bad file $xml_file_list (main tag should be  handle_nodes({}, $main_node); +$problem and exit 1; +  install_needed_libraries();  final_cleanup(); +sub error { +    my ($err) = @_; +    warn "FATAL: $err\n"; +    $problem = 1; +} +  sub final_cleanup() {      #- cpio creates directory 700, that's not nice -    system("find $DEST -type d | xargs chmod 755"); +    system("find $DEST -type d -print0 | xargs -0 $sudo chmod 755");  }  sub handle_nodes { @@ -62,6 +83,8 @@ sub valid_cond {      every {  	if ($_ eq 'ARCH') {  	    $ARCH =~ /$attr->{$_}/; +	} elsif ($_ eq 'set') { +	    $ENV{$attr->{$_}};  	} else {  	    die "<if>: unknown condition $_\n";  	} @@ -70,7 +93,7 @@ sub valid_cond {  sub add_to_env {      my ($env, $tag, $attr) = @_; -    my %env = map_each { $::a => +{%$::b} } %$env; +    my %env = map_each { $::a => +{ %$::b } } %$env;      foreach (keys %$attr) {  	!$env{$tag}{$_} or die qq(overriding attribute <$tag $_="$env{$tag}{$_}"> with $_="$attr->{$_}"\n);   	$env{$tag}{$_} = $attr->{$_}; @@ -92,6 +115,11 @@ sub group_by_n {      @r;  } +sub identify_file { +    my ($dev, $ino) = @_; +    "$dev:$ino"; +} +  sub all_files_rec_ {      my ($d) = @_; @@ -113,16 +141,42 @@ sub collect_needed_libraries {  	my $to_check = join(' ', @to_check);  	my @l = `ldd $to_check 2>/dev/null` =~ m! => (/\S+)!g;  	foreach (@l) { -	    s!^(/lib(64)?/).*?/!$1! if $main_node->{attr}{'no-arch-libraries'}; #- replace /lib/tls or /lib/i686 with /lib +	    if ($main_node->{attr}{'no-arch-libraries'}) { +		#- replace /lib/tls or /lib/i686 with /lib +		s!^(/lib(64)?/).*?/!$1! if arch() !~ /x86_64/; +	    }  	}  	@to_check = grep { !$needed_libraries{$_}++ } @l;	  	@to_check = ();      }  } -sub install_needed_libraries { +sub install_needed_libraries() {      copy_files('', $DEST, [ keys %needed_libraries ], '', '--dereference');  } +sub collect_needed_perl_files { +    my ($local_rep, @scripts) = @_; + +    my (%local, %global); +    foreach my $script (@scripts) { +	foreach (`strace -efile perl -cw -I$local_rep $script 2>&1`) { +	    my ($f) = /^open(?:at\([^,]*, |)"(.*?)",.*\)\s*=\s*\d+$/ or next; +	    if ($f =~ m!^\Q$local_rep\E/(.*)!) { +		$local{$1} = 1; +	    } elsif (begins_with($f, '/dev/')) { +		# skip +	    } elsif (begins_with($f, '/')) { +		if ($main_node->{attr}{'no-arch-libraries'}) { +		    #- replace /lib/tls or /lib/i686 with /lib +		    $f =~ s!^(/lib(64)?/).*?/!$1! if arch() !~ /x86_64/; +		} +		$global{$f} = 1; +	    } +	} +    } +    [ keys %local ], [ keys %global ]; +} +  sub copy_files {      my ($working_dir, $to_dir, $files, $b_flatten, @options) = @_; @@ -131,12 +185,12 @@ sub copy_files {  	my $options = join(' ', '-r', @options);  	foreach (group_by_n(20, $files)) {  	    warn "cp $options to_dir $to_dir from $working_dir: @$_\n" if $verbose; -	    system("cd $working_dir ; cp $options @$_ $to_dir"); +	    system("cd $working_dir ; $sudo cp $options @$_ $to_dir");  	}      } else {  	my $options = join(' ', $base_cpio_options, @options); -	warn "cpio $options to_dir $to_dir from $working_dir: @$files\n" if $verbose; -	open(my $F, "| cd $working_dir ; cpio $options $to_dir"); +	warn "cpio $options to_dir=$to_dir from=$working_dir: @$files\n" if $verbose; +	open(my $F, "| cd $working_dir ; $sudo cpio $options $to_dir");  	print $F "$_\n" foreach @$files;  	close($F) or die "cpio $to_dir failed\n";      } @@ -145,8 +199,9 @@ sub copy_files {  sub install {      my ($env, $text) = @_; -    my $from_dir = $env->{from}{dir}; +    my $from_dir = expand_macros($env->{from}{dir});      my $to_dir = $DEST . expand_macros($env->{to}{dir} || $env->{to}{flatten} && $from_dir || ''); +    my $copy_mode = $env->{mode}{copy} || '';      my $working_dir = '.';      my $expand = $env->{from}{expand} || ''; @@ -161,30 +216,38 @@ sub install {  	my @l = $f;  	chdir $working_dir;  	if ($f =~ /\*/ || $b_full_glob) { -	    @l = glob($f) or die "no match for $f\n";  - -	    @l == 1 || $b_full_glob or die "multiple match for $f\n";	     -	} else { -	    -e $f or die "missing file $f\n"; +	    @l = File::Glob::bsd_glob($f); #- using bsd_glob because CORE::glob() splits on whitespace and we don't want this +	    if (@l == 0) {  +		error("no match for $f"); +	    } elsif (@l == 1 || $b_full_glob) { +	    } else {  +		error("multiple match for $f"); +		@l = (); +	    } +	} elsif (! -e $f) { +	    error("missing file $f ($rel) in $working_dir"); +	    @l = ();  	}  	if (@l == 1 && -d $l[0] && $b_recursive_dirs) {  	    @l = all_files_rec_($l[0]);  	} -	@l = grep { !m!/CVS($|/)! } @l; -	if (my $re = $env->{from}{matching}) { +	@l = grep { !m!/(\.svn|CVS)($|/)! } @l; +	if (my $re = expand_macros($env->{from}{matching})) {  	    @l = grep { eval $re } @l;  	} -	collect_needed_libraries(grep { -x $_ } @l); +	collect_needed_libraries(grep { -f $_ && -x $_ } @l);  	chdir $initial_dir;  	@l;      }; +    my @text_l = $env->{from}{spaces_in_filename} ? $text =~ /^\s*(.*?)\s*$/ : split(' ', $text);      my @files;      if ($expand eq 'tar') { -	foreach (split(' ', $text)) { -	    system('tar', 'xfj', $from_file->($_), '-C', $to_dir); +	foreach (@text_l) { +	    my ($tarball) = $from_file->($_) or next; +	    system('tar', 'xfj', $tarball, '-C', $to_dir);  	}  	# not filling @files, things are already done @@ -193,41 +256,80 @@ sub install {      } elsif ($expand eq 'glob') {  	#- glob done in $from_file -	@files = split(' ', $text); +	@files = @text_l;      } elsif ($expand eq 'binary') {  	$disallow_from_dir->(); -	my @PATH = qw(/sbin /bin /usr/bin /usr/sbin /usr/X11R6/bin); -	foreach my $name (split(' ', $text)) { +	my @PATH = qw(/usr/sbin /usr/bin /usr/X11R6/bin); +	unshift(@PATH, "/bin") unless -l "/bin"; +	unshift(@PATH, "/sbin") unless -l "/sbin"; +	foreach my $name (map { expand_macros($_) } @text_l) {  	    my @l = grep { -x $_ } map { "$_/$name" } @PATH; -	    @l or die "can't find binary $name\n"; -	    if (my @m = grep { ! -l $_ } @l) { -		@l = @m; +	    @l or error("can't find binary $name"), next; +	    if (@l > 1) { +		my @m = grep { ! -l $_ } @l; +		if (@m == 1) { +		    my $id = identify_file($m[0]); +		    push @files, grep { -l $_ && identify_file($_) eq $id } @l; +		} +		@l = @m if @m;  	    } -	    @l == 1 or die "many matches for binary $name: " . join(' ', @l) . "\n"; -	    push @files, @l; -	} +	    if (@l > 1) { +		warn "many matches for binary $name: " . join(' ', @l) . ", choosing $l[0]\n"; +	    } +	    my $f = $l[0]; +	    while (1) { +		push @files, $f; +		$copy_mode ne 'dereference' or last; +		my $l = readlink($f) or last; +		if ($l =~ m!/! && $l !~ m!^\.\..*/s?bin/[^/]+$!) { +		    warn "keeping symlink $f -> $l as is\n"; +		    last; +		} +		$f = dirname($f) . '/' . $l; +	    } +	}	 +	$copy_mode ||= 'keep-links';  	$env->{filter}{command} ||= 'strip';      } elsif ($expand eq 'rpm') {  	$disallow_from_dir->(); -	foreach my $rpm (split(' ', $text)) { -	    my @l = chomp_(`rpm -ql $rpm`) or die "rpm $rpm must be installed\n"; +	foreach my $rpm (@text_l) { +	    my @l = chomp_(`rpm -ql $rpm`) or error("rpm $rpm must be installed");  	    push @files, @l;  	} +    } elsif ($expand eq 'perl-bin') { +	$disallow_from_dir->(); +	$from_dir = '/usr/LIB/perl5/vendor_perl/'; +	@files = @text_l;      } elsif ($expand eq 'perl') {  	$disallow_from_dir->(); -	$from_dir = '/usr/lib/perl5/vendor_perl/*'; -	@files = split(' ', $text); +	$from_dir = '/usr/share/perl5/vendor_perl/'; +	@files = @text_l;      } elsif ($expand eq 'main-perl') {  	$disallow_from_dir->();  	$from_dir = $Config{privlib}; -	@files = split(' ', $text); +	@files = @text_l; +    } elsif ($expand eq 'main-perl-bin') { +	$disallow_from_dir->(); +	$from_dir = $Config{archlib}; +	@files = @text_l; +    } elsif ($expand =~ /collect-perl-files/) { +	my (undef, $local, $to) = split(' ', $expand); + +	@files = @text_l; +	warn "collect-perl-files $local $to @files ($env->{filter}{command})\n"; +	my ($local_perl_files, $global_perl_files) = collect_needed_perl_files($local, @files); +	warn "collect-perl-files gave: ", join(' ', @$local_perl_files), "\n"; +#	warn "                    and: ", join(' ', @$global_perl_files), "\n"; +	copy_and_filter($local =~ m!/! ? $local : "$working_dir/$local", "$DEST$to", $local_perl_files, $env->{filter}, '', '--dereference'); +	copy_and_filter('', $DEST, $global_perl_files, $env->{filter}, '', '--dereference'); +      } elsif ($expand) {  	die "unknown expand method $expand\n";      } else { -	@files = split(' ', $text); +	@files = @text_l;  	$env->{filter}{command} ||= 'strip' if $to_dir =~ m!/bin$!;      } @@ -238,33 +340,48 @@ sub install {      }      my @all_files = map { $from_file->($_, $expand eq 'glob', $expand ne 'rpm') } @files; - -     -    my $copy_mode = $env->{mode}{copy} || ''; +         my @options = (  	if_($copy_mode ne 'keep-links', '--dereference'),      ); -    copy_files($working_dir, $to_dir, \@all_files, $env->{to}{flatten}, @options); +    if (@all_files) { +	copy_and_filter($working_dir, $to_dir, \@all_files, $env->{filter}, $env->{to}{flatten}, @options); +    } +} -    { -	chdir $to_dir; -	foreach (group_by_n(20, \@all_files)) { -	    my @l = $env->{to}{flatten} ? (map { basename($_) } @$_) : (map { "./$_" } @$_); -	    @l = grep { ! -d $_ } @l; +sub copy_and_filter { +    my ($working_dir, $to_dir, $all_files, $filter, $flatten, @copy_options) = @_; -	    if (my $subst = $env->{filter}{subst}) { -		system('perl', '-pi', '-e', $subst, @l); -	    } -	    if (my $command = $env->{filter}{command}) { -		my @options = ( -		    if_($command eq 'gzip', '-9'), -		    if_($command eq 'strip', '2>/dev/null'), -		); -		system(join(' ', $command, @options, @l)); +    copy_files($working_dir, $to_dir, $all_files, $flatten, @copy_options); +    apply_filter($to_dir, $filter, $all_files, $flatten); +} + +sub apply_filter { +    my ($to_dir, $filter, $all_files, $b_flatten) = @_; + +    chdir $to_dir; +    foreach (group_by_n(20, $all_files)) { +	my @l = $b_flatten ? (map { basename($_) } @$_) : (map { "./$_" } @$_); +	@l = grep { ! -d $_ } @l or next; + +	if (my $subst = $filter->{subst}) { +	    warn "running substition $subst \n" if $verbose; +	    system('perl', '-pi', '-e', $subst, @l); +	} +	if (my $command = $filter->{command}) { +	    $command = $initial_dir . "/$command" if $command =~ m!^..?/!; +	    if ($command =~ /simplify-drakx-modules/) { +		@l = grep { !/\.so($|\.)/ } @l or next;  	    } +	    my @options = ( +		if_($command eq 'gzip', '-9f'), +		if_($command eq 'strip', '2>/dev/null'), +	    ); +	    warn "running $command @options @l\n" if $verbose; +	    system(join(' ', $command, @options, @l));  	} -	chdir $initial_dir;      } +    chdir $initial_dir;  }  sub decompose { | 
