Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
#!/usr/bin/perl
# -*- perl -*-
=head1 NAME
apt-unstable - APT package handling utility -- wrapper script
=head1 SYNOPSIS
apt-unstable [options] [command] [package...]
=head1 DESCRIPTION
F is the wrapper script to use unstable packages on a
stable system. When this script is called, it executes F or
F with some additional appropriate options.
I is one of:
=over 4
=item * update
=item * source
=item * check
=item * clean
=item * search
=item * show
=back
These commands are equivalent to commands of F and
F.
=head1 OPTIONS
=over 4
=item -n
Prints real command.
=item -v, --version
Prints the version of this script.
=item --revision STRING
Sets C as the local revision string.
=back
F accepts other options and passes them to F or
F without the C<--config> option to specify a configuration
file.
=head1 ENVIRONMENT
=over 4
=item DEBEMAIL, EMAIL
It will be used as the maintainer/uploader's email address in any new
changelog sections created. If both are set, DEBEMAIL will take
precedence. If neither is set, F will do nothing to
update changelog.
=item DEBFULLNAME
The maintainer/uploader's full name to be used in new changelog
sections. If unset, F will do nothing to update
changelog.
=back
=head1 FILES
=over 4
=item HOME/.apt-unstable/
The root of hierarchy of configuration files and working files.
=item HOME/.apt-unstable/etc/apt.conf
Alternative F.
=item HOME/.apt-unstable/etc/sources.list
Alternative F.
=back
=head1 SEE ALSO
F(1), F(1), F(5), F(5)
=head1 TODO
=over 4
=item * install
Improvement to accept C command is needed. But, I have no
idea to decide which package have to be re-packaged in packages which
the requested package depends.
=item * upgrade
I think that C command to upgrade local packages which are
generated with F is also usefull.
=back
=head1 AUTHOR
TSUCHIYA Masatoshi
=head1 COPYRIGHT
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
=cut
use strict;
use File::Path qw/ mkpath /;
use File::Basename qw/ dirname basename /;
use File::Copy qw/ copy /;
use IO::Handle;
use IO::Pipe;
### Configuration Variables:
my $CONFDIR = sprintf( "%s/.apt-unstable", $ENV{'HOME'} );
my $PROFILE = "$CONFDIR/etc/apt.conf";
my $IDENT = sprintf( 'local+%s', $ENV{'HOSTNAME'} );
my $BUILD = 0;
my @BUILDOPT = ( '-us', '-uc', '-rfakeroot' );
my %COMMAND = ( 'update' => [ 'apt-get', '-c', $PROFILE, ],
'source' => [ 'apt-get', '-c', $PROFILE, '--no-compile' ],
'check' => [ 'apt-get', '-c', $PROFILE, ],
'clean' => [ 'apt-get', '-c', $PROFILE, ],
'search' => [ 'apt-cache', '-c', $PROFILE, ],
'show' => [ 'apt-cache', '-c', $PROFILE, ] );
my $VERSION = sprintf( '0.%d.%d', q$Revision: 1.3 $ =~ /(\d+)\.(\d+)/ );
### Code:
&main( @ARGV );
sub main {
my( @argv ) = @_;
my $scheme;
my $debug;
my $build = -1;
my @option;
while( $_ = shift @argv ){
if( $_ eq '-n' ){
$debug = 1;
} elsif( /^-(?:v|-version)$/ ){
printf( "%s %s\n", basename($0), $VERSION );
exit 1;
} elsif( $_ eq '--revision' ){
$IDENT = shift @argv;
} elsif( /^--revision=(.*)/ ){
$IDENT = $1;
} elsif( /^-(?:b|-(?:compile|build))$/ ){
$build = 1;
} elsif( /^-(?:-no-(?:b(?:uild)?|compile)|(?:b|-(?:compile|build))=no)/ ){
$build = 0;
} elsif( /^-c(?:onfig-file)?$/ ){
die "Can't specify path of configuration file.\n";
} else {
if( defined $COMMAND{$_} ){
$scheme = $_;
last;
}
push( @option, $_ );
}
}
die "Can't detect scheme.\n" unless $scheme;
push( @option, '-q' ) if $ENV{'TERM'} =~ /^(?:dumb|emacs)$/;
my @command;
push( @command, @{$COMMAND{$scheme}} );
push( @command, @option );
push( @command, $scheme );
push( @command, @argv );
if( $debug ){
print join( " ", @command ), "\n";
} else {
&make_profile();
&read_profile();
$build >= 0 or $build = $BUILD;
system @command;
$scheme eq 'source' and grep( &update_changelog( $_, $build ), @argv );
}
}
sub update_changelog {
my( $package, $build ) = @_;
my $tarball = &get_source_tarball( $package );
my( $src_package, $src_version ) =
( $tarball =~ /^([^_]+)_(.*?)\.(?:orig\.)?tar\.gz$/ );
( $src_package and $src_version )
or die "Can't parse tarball's file name($tarball).\n";
&add_changelog_entry( $src_package, $src_version );
if( $build ){
if( chdir sprintf( '%s-%s', $src_package, $src_version ) ){
system 'dpkg-buildpackage', @BUILDOPT;
chdir '..';
}
}
}
sub add_changelog_entry {
my( $package, $upstream_version ) = @_;
my $changelog = "$package-$upstream_version/debian/changelog";
open( F, "< $changelog" ) or die "Can't open file($changelog) to read: $!\n";
my( @buf ) = ;
close F;
unshift( @buf, &generate_changelog_entry( $changelog ) );
open( F, "> $changelog" ) or die "Can't open file($changelog) to write: $!\n";
print F @buf;
close F;
}
sub generate_changelog_entry {
my( $changelog ) = @_;
my %changelog;
for( &call_process( 'dpkg-parsechangelog', "-l$changelog" ) ){
chomp;
/^([^:]+):\s+(.*)/ and $changelog{lc($1)} = $2;
}
my $source = $changelog{source} || die "Can't detect package's source name.\n";
my $version = $changelog{version} || die "Can't detect package's current version.\n";
my $distribution = $changelog{distribution} || die "Can't detect package's distribution.\n";
my $urgency = $changelog{urgency} || die "Can't detect package's urgency.\n";
my $pat = sprintf( '%s', quotemeta $IDENT );
my $local_version = ( $version =~ s/$pat(\d+)$// ) ? $1 : 0;
my $num;
if( $version =~ s/^([^-]+)-(.*)/$1/ ){
$2 =~ /^(.*?)([1-9]+)[^1-9]*$/;
$version = sprintf( "%s-%s", $version, $1 );
$num = $2;
} else {
$version =~ s/^(.*?)([1-9]+)[^1-9]*$/$1/;
$num = $2;
}
$version = sprintf( "%s%s%s%d",
$version,
( $local_version ? $num : sprintf( "%d.9", $num - 1 ) ),
$IDENT,
$local_version + 1 );
defined( $ENV{'DEBFULLNAME'} )
or die "Can't detect re-packager's name, set DEBFULLNAME environment.\n";
my $packager = $ENV{'DEBFULLNAME'};
defined( $ENV{'DEBEMAIL'} ) or defined( $ENV{'EMAIL'} )
or die "Can't detect re-packager's mail address, set DEBEMAIL or EMAIL environment.\n";
my $email = $ENV{'DEBEMAIL'} || $ENV{'EMAIL'};
my $date = `822-date`;
die "Can't get date." unless $date;
my $s = sprintf( "%s (%s) %s; urgency=%s\n\n" .
" * Re-packaging for local use.\n\n".
" -- %s <%s> %s\n",
$source, $version, $distribution, $urgency,
$packager, $email, $date );
print $s;
$s;
}
# Function to get file name of source tarball of the specified package.
sub get_source_tarball {
my( $package ) = @_;
for my $s ( &call_process( 'apt-get', '-c', $PROFILE, '-q',
'--print-uris', 'source', $package ) ){
if( $s =~ s/^'[^\']*'\s+// ){
$s =~ s/^(\S+)\s.*/$1/;
$s =~ /\.tar\.gz$/ and return $s;
}
}
undef;
}
sub call_process {
my( @argv ) = @_;
my $read = new IO::Pipe;
FORK: {
if( my $pid = fork ){
# Parent process.
$read->reader;
} elsif( defined $pid ){
# Child process.
$read->writer;
STDOUT->fdopen( $read, "w" );
STDERR->fdopen( $read, "w" );
STDIN->close();
exec @argv;
exit 0;
} elsif( $! =~ /No more process/ ){
sleep 5;
redo FORK;
} else {
die "Can't fork: $!\n";
}
}
my( $s, $t );
while( defined( $s = $read->getline() ) ){
$t .= $s;
}
split( /\n/, $t );
}
sub read_profile {
open( F, "< $PROFILE" ) or die "Can't open file($PROFILE) to read: $!\n";
while( ){
/^\s*Apt::Get::Compile\s+"(false|true)";/
and $BUILD = ( $1 eq 'true' );
/^\s*DPkg::Build-Options\s+"([^\"]*)";/
and @BUILDOPT = split( /\s+/, $1 );
}
close F;
}
sub make_profile {
my $mode = 0777 ^ umask;
my $etc_dir = dirname( $PROFILE );
my $cache_dir = "$CONFDIR/cache";
my $state_dir = "$CONFDIR/state";
my $status_file = "$CONFDIR/status";
my $sources_file = "$etc_dir/sources.list";
mkpath( $etc_dir, 0, $mode );
mkpath( "$cache_dir/archives/partial", 0, $mode );
mkpath( "$state_dir/lists/partial", 0, $mode );
unless( -f $PROFILE ){
my @buf;
open( F, "apt-config dump 2>&1 |" ) or die;
while( ){
/^\s*Dir::(?:Etc|Cache|State(?:::status)?)\s/
or push( @buf, $_ );
}
close F;
push( @buf, "Dir::Etc \"$etc_dir/\";\n" );
push( @buf, "Dir::Cache \"$cache_dir/\";\n" );
push( @buf, "Dir::State \"$state_dir/\";\n" );
push( @buf, "Dir::State::status \"$status_file\";\n" );
open( F, "> $PROFILE" ) or die "Can't open file($PROFILE) to write: $!\n";
print F @buf;
close F;
}
unless( -f $sources_file ){
my @buf;
open( F, "< /etc/apt/sources.list" ) or die;
while( ){
my( $method, $path, $dist, $comp ) = split( /\s+/, $_, 4 );
unless( $path =~ m!^http://security.debian.org/$! ){
$dist =~ s/^(?:(?:un)?stable|potato|woody|sarge)/unstable/
and push( @buf, "$method $path $dist $comp" );
}
}
close F;
my %tag;
open( F, "> $sources_file" ) or die "Can't open file($sources_file) to write: $!\n";
for( @buf ){
unless( defined $tag{$_} ){
print F $_;
$tag{$_}++;
}
}
close F;
print STDERR "$sources_file is generated automatically based on /etc/apt/sources.list.";
}
unless( -f $status_file ){
my $file = '/var/lib/dpkg/status';
open( F, "apt-config dump 2>&1 |" ) or die;
while( ){
/^\s*Dir::State::status\s+"(.*?)";/ and $file = $1, last;
}
close F;
copy( $file, $status_file )
or die "Can't copy file($file -> $status_file): $!\n";
}
}