--- toast 2003/08/26 23:21:16 1.185 +++ toast 2003/08/30 06:47:16 1.186 @@ -160,6 +160,7 @@ "postarmprog" => superuser ? "/sbin/ldconfig" : "", "verbose" => true, "autofind" => true, + "autorename" => true, "autoclean" => true, "autopurge" => false, "autoarm" => true, @@ -1483,7 +1484,7 @@ return &smartgeturl($redir, $dir, $ttl - 1); } -sub autorename($$) +sub autorenamepkg($$) { my($name, $version) = @_; @@ -1515,7 +1516,7 @@ sub get(@) { my($name, $version, $build, @urls) = @_; - my($autorename) = !defined($version); + my($autorename) = !defined($version) && autorename; ($name, $version) = add(@_) if @urls || !isadded($name, $version); @@ -1532,7 +1533,7 @@ optmd($tempdir); smartgeturl($_, $tempdir) foreach @urls; mv($tempdir, $realdir); - ($name, $version) = autorename($name, $version) if $autorename; + ($name, $version) = autorenamepkg($name, $version) if $autorename; ($name, $version); } @@ -2684,6 +2685,115 @@ ############################################################################## +sub upgrade(@) +{ + my($name, $version, $build, @urls) = @_; + error unless defined($name); + error unless defined($version); + error if defined($build); + + @urls = pkgurls($name, $version) unless @urls; + error unless @urls; + + my($pkgname) = pkgname($name, $version); + + my(%linkmap); + my($verpat) = $version =~ /^\d/ ? '\d.*' : '.+'; + + my(%candidates); + my(@newurls); + for(@urls) + { + m!^((http|ftp)://[^\?]+/)([^\?/]*)(\?.*)?$!i || + error("bad URL for upgrade: $_"); + my($dirname, $basename, $query) = undeftoempty($1, $3, $4); + if($basename !~ /^(.*)\Q$version\E(.*)$/) + { + push(@newurls, $_); # URL has no version number; use as-is + } + else + { + my($pre, $post) = ($1, $2); + $linkmap{$dirname} = [linksfromurl($dirname)] + unless exists($linkmap{$dirname}); + my(@links) = @{$linkmap{$dirname}}; + my(%vermap); + for(@links) + { + if(/^\Q$dirname$pre\E($verpat)\Q$post\E(\?.*)?$/) + { + $vermap{$1} = $_; + $candidates{$1} = 1; + } + } + push(@newurls, \%vermap); + } + } + + my($newver); + for(reverse(sort cmpab keys(%candidates))) + { + my($candidate) = $_; + my($ok) = true; + for(@newurls) + { + next unless ref; + my(%vermap) = %$_; + if(!exists($vermap{$candidate})) + { + $ok = false; + last; + } + } + if($ok) + { + $newver = $candidate; + last; + } + } + + error("URLs for $pkgname all seem version-neutral and " . + "autorename is off; aborting") if !defined($version) && !autorename; + + for(@newurls) + { + next unless ref; + error("can't find alternate version for $pkgname") unless defined($newver); + my(%vermap) = %$_; + $_ = $vermap{$newver}; + } + + if(defined($newver)) + { + error("$pkgname appears to be the latest available version") + if $version eq $newver; + my(@vers) = sort cmpab ($version, $newver); + error("only found older versions of $pkgname") if $vers[1] eq $version; + } + + my(@cmdargs) = ($name, $newver, undef, @newurls); + if(isarmed($name, $version) && autoarm) + { + return arm(@cmdargs); + } + elsif(isbuilt($name, $version)) + { + return build(@cmdargs); + } + elsif(isstored($name, $version)) + { + return get(@cmdargs); + } + else # not eligible for autorename + { + error("URLs for unstored package $pkgname seem version-neutral; aborting") + unless defined($newver); + return add(@cmdargs); + } +} + +############################################################################## + sub ensuredisarmed($;$$) { my($name, $version, $build) = @_; @@ -3299,6 +3409,7 @@ sub parse_build(@) { allowempty(uselatestversion(rejectbuilds(parse(@_)))); } sub parse_clean(@) { allowempty(rejectmissing(parse(@_))); } sub parse_arm(@) { rejectempty(uselatestbuild(parse(@_))); } +sub parse_upgrade(@) { rejectempty(rejectmissing(uselatestversion(rejectbuilds(parse(@_))))); } sub parse_disarm(@) { rejectempty(rejectmissing(parse(@_))); } sub parse_demolish(@) { rejectempty(rejectmissing(parse(@_))); } sub parse_purge(@) { rejectempty(rejectmissing(rejectbuilds(parse(@_)))); } @@ -3675,6 +3786,21 @@ (if any). If the latest build is already armed, the command fails; you probably meant to invoke B<toast build> with the C<autoarm> option set. +=item S<B<toast upgrade> I<PACKAGE> ...> + +Checks for a later version of an existing package. The existing package's +URLs are used as a starting point to locate the new version. If the +filename component of a given URL doesn't appear to contain the package's +version number, that URL will be left unmodified for the new version; +otherwise, the directory portion of the URL will be immediately downloaded +and searched for a similar URL containing a higher version number. +The command fails if a single newer version for all version-containing +URLs cannot be found; otherwise, the highest eligible version is used +for all modified URLs and the package itself. The command performs an +implicit <add>, B<get>, B<build> or B<arm> on the extrapolated URLs so +as to match the state of the given existing version, except that the +new package will never be armed if the B<autoarm> option is disabled. + =item S<B<toast disarm> I<BUILD> | I<PACKAGE> ...> Deletes symlinks created by B<toast arm>. This works by removing symbolic @@ -3900,6 +4026,20 @@ been added previously or given explicitly. If no version number is given either, the latest version listed on freshmeat.net will be used. Default: enabled. + +=item S<B<--autorename> | B<--noautorename>> + +When B<autorename> is enabled, B<toast get> may try to use the contents of +the files it downloads to attempt to guess a new name for any implicitly +added package for which no name and/or version number was specified on +the command line or could be guessed from the URLs given. If this method +results in a new name being guessed, the package is renamed automatically +as if by B<toast rename>, and any further processing continues under +the new name. If B<autorename> is disabled, packages with unguessed +or partially guessed names always keep the unique names automatically +assigned by B<toast add> based on URLs alone (version number will be +C<unknown> optionally followed by a serial number for uniqueness; name +may have been guessed or may also be C<unknown>). Default: enabled. =item S<B<--autoclean> | B<--noautoclean>>