Comparing installed packages with the changelog...
SlackwareThis Forum is for the discussion of Slackware Linux.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
al@AB60R:~$ cd .check_ftp al@AB60R:~/.check_ftp$ pwd
/home/al/.check_ftp al@AB60R:~/.check_ftp$ ls -la
<snipped>
-rw-r--r-- 1 al users 1912 2007-12-28 00:35 .conf
al@AB60R:~/.check_ftp$ cat .conf
<snipped>
WARNING Do not use the same site name more than once! WARNING
WARNING WARNING
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
As root, I use a Slack pkg named cpan2tgz it's available on the internet. That above command gets Mail::Send installed as a Slack pkg AND I have Slack pkg of it outputs to the pkgdir (for use on other machines).
Today I just discovered that check_ftp uses my (I don't have a domain) localdomain or localhost when attempting to send email outbound.
This isn't going to work since valid domain smtp servers won't accept from a non domain (they can't be an open relay for spammers).
So, you would need to either 1. direct the email to your localhost using a user email address on your localhost (keeps the email from trying to go out to anywhere else)
Or 2. do what I did. Run:
check_ftp add
Then do not enter an email address (defaults to STDOUT)
messages thus will print to screen instead of being emailed.
Whenever the ChangeLog.txt has been changed (the changelog changes whenever new updates happen) the output message will say so.
Will incorporate into a later version. May parse changelog then instead of list mirror server's dir contents. Hey, right now, I run it on my machine -- it's fast -- only a second or two of run time and it's done.
Why does Pat keep the changelog so big? It's still got Slack 11 on it too. Or, is it for all of the "stable" and currently security update supported versions of Slackware?
(changelog) It's a huge file to be pumping across the www every time someone wants to check on Slack 12 patches (reason to join the security updates emailing list, I guess).
Yes. It had a bug in that section too. But not now; I fixed it.
More help comments included now. Re labled/named some section(s). Hopefully more clarity exist now of what is happening when.
Code:
#!/usr/bin/perl
use warnings;
use strict;
# use diagnostics;
# 12-26-2007 unfinished. See at bottom of code for yet to do
# reports whether or not any new (not yet installed) Slackware
# patches/updates are available
# compares a mirror server's updates with /var/log/packages
my $url = 'ftp://slackware.mirrors.tds.net/pub/slackware/slackware-12.0/patches/packages';
my $pid;
my $upd_pkgs;
$pid = open $upd_pkgs, "-|", "lynx", "-dump", "$url" or die "cant fork: $!\n";
print "pid is: $pid\n";
my @patches;
while (<$upd_pkgs>) {
next unless /slack.+patches$/i .. /eof/; # range operator
s#^.+slackware-12.0/patches/packages/##;
s#\.tgz##;
# print unless /\d.+patches$|\.asc|\.txt/;
push @patches, $_ unless /\d.+patches$|\.asc|\.txt/;
} # got patches file names in the @patches array
# next section strips the numeric part of patch file names
# which leaves us with only the leading alpha and dashes
# up to but not including any of the digits
# begin of alpha_only (number, numeric not allowed)
my $apend;
my @dashes;
my @dashes2;
foreach ( @patches ) {
@dashes = split(/-/, $_);
$apend .= $dashes[0];
$apend .= '-';
$apend .= $dashes[1];
if ( $apend =~ s/-\d.+$// ) {
push @dashes2, $apend;
# print $apend, "hi1\n"; # pkg name leading alpha and dashes
$apend = '';
} else {
$apend .= '-';
$apend .= $dashes[2];
$apend =~ s/-\d.+$//;
# print $apend, "hi2\n"; # pkg name leading alpha and dashes
push @dashes2, $apend;
$apend = '';
}
} # got alpha_only and dashes in the @dashes2 array
# end of alpha_only
# print @dashes2, "\n";
print "Patches on mirror server:\n";
print @patches; # mirror server's patches print to screen
print "\n---\n\n";
my $pid2;
my $sys_pkgs;
$pid2 = open $sys_pkgs, "-|", "find", "/var/log/packages" or die "cant fork: $!\n";
print "pid is: $pid2\n";
my @sys_pkg_list;
while (<$sys_pkgs>) {
next if /packages$/;
s#/var/log/packages/##;
push @sys_pkg_list, $_;
} # got /var/log/packages into the @sys_pkg_list array
@sys_pkg_list = sort { $a cmp $b } @sys_pkg_list;
# and we now have a sorted or ordered list
# next, using the alpha_only and dashes (@dashes2 array) we
# compare each with each that's in the @sys_pkg_list array
# @alpha_matches array gets items from /var/log/packages
# that have a match on the mirror server
# though the digit portion may or may
# not match at this point in the game
# thus the array name of matches via alpha or alpha_matches
my @alpha_matches;
foreach my $x (@sys_pkg_list) {
foreach (@dashes2) {
# print $x if $x =~ /^$_-\d/;
# make sure is followed by a dash digit not a dash alpha
# thus the -\d (dash digit) in the next regex
push @alpha_matches, $x if $x =~ /^$_-\d/;
}
} # @alpha_matches tells us, irrespective of version number,
# which pkgs exist on both our sys and on the mirror server
# IOW @patches and @alpha_matches should each now be holding
# the same pkg name contents though version #'s may not match
# next, the need to discern and report about yes/no version
# differences between sys pkgs and mirror server patches
# (hint -- we'll likely use a hash since hash keys must be
# unique) IOW version matches will be gone and the only
# remaining will be an "either -- or" that is either yes
# new updates exist or no all our pkgs currently up to date
# if yes, it will list which pkgs updates but if no then it
# will say "Your sys pkgs are currently 100% up to date there
# are no new updates for your sys on the mirror server".
# until we resume coding, for now, we'll just print @alpha_matches
# matches via alpha which exist on our sys print to screen
print "From sys the pkg matches via alpha to patches:\n";
print @alpha_matches, "\n";
# end
--
Alan
I may be missing some subtlety of your code, but you should be able to replace the entire "Here 1" section with
Code:
#code not tested
my @dashes2 = map {s/-\d.*$//} @patches;
I haven't sufficiently learned map yet. But I had guessed there was a way to do it using map.
What's with the long string of 1's ?? as per my console output when I tested it enclosed near the bottom of this post.
I could modify my code so as to make use of your code. But I'm confused by the long string of 1's printed out from the @dashes2 array???
Code:
# got patches file names in the @patches array
# next section strips the numeric part of patch file names
# which leaves us with only the leading alpha and dashes
# up to but not including any of the digits
# begin of alpha_only (number, numeric not allowed)
my @dashes2 = map {s/-\d.+$//} @patches;
# got alpha_only and dashes in the @dashes2 array
# end of alpha_only
print @dashes2, "\n";
print "Patches on mirror server:\n";
print @patches; # mirror server's patches print to screen
print "\n---\n\n";
----------
I tested it. It puts a long string of 1's into @dashes2
@patches gets the dash-digits removed
In a roundabout way it does what I wanted though I wanted @patches to remain unchanged or untouched and I wanted @patches contents transferred to @dashes2 but with the dash-digits removed from @dashes2
al@AB60R:~$ slak_updck2b
pid is: 3717
111111111111111111111111111
Patches on mirror server:
bind
cairo
cups
gimp
glibc-zoneinfo
<snipped>
The "1" is because the substitution was successful. So it is basically reporting that it was able to perform the substitution, rather than giving you back the result. Adding the additional "line" to the block returns the result of the substitution.
A better way, which will leave your original array undisturbed, make it easier to modify in the future, make it easier to understand, and make it easier to debug, would be
Code:
sub GetPackageName {
my $string = shift;
$string =~ s/-\d.*$//;
return $string;
}
my @dashes2 = map {GetPackageName($_)} @packages;
OK, this is my last one (once you get going, you know...).
This version compares all the patches and extra packages with those installed on the system and prints out when they are different. Problems arise primarily with extra, especially if there is a package in extra which is also in the main tree. So for example it will "fail" on kernel-generic because the ChangeLog shows a 2.6.18 version in the /extra directory, and it compares that to the 2.6.21 from the /a series (which should be installed on a vanilla system) and reports a "new" version.
Anyway, slackpkg is the way to go for this (it's sophisticated and has been well-tested), but for the sake of learning:
Code:
#!/usr/bin/perl
use strict;
use LWP::Simple;
my $url = 'ftp://ftp.slackware.com/pub/slackware/slackware-12.0/ChangeLog.txt';
my $change_log = get $url
or die "Could not download ChangeLog";
my @change_log = split "\n", $change_log;
my @installed_packages = `ls /var/log/packages`;
my (%installed_version, %latest_version, %package_location, %installed_build, %latest_build);
sub GetPackageInfo {
my $string = shift;
my ($package_name, $version) = $string =~ m/(.*)-(\d[^-]*)-.*$/;
return ($package_name, $version);
}
for my $line (@change_log) {
next unless ($line =~ m:^patches/:) || ($line =~ m:^extra/:);
my ($package_location, $package_file_name) = $line =~ m:^(.*/.*/)(.*)$:;
my ($package_name, $package_version) = GetPackageInfo($package_file_name
);
next if $latest_version{$package_name};
$latest_version{$package_name} = $package_version;
$package_location{$package_name} = $package_location;
}
%installed_version = map {GetPackageInfo($_)} @installed_packages;
for (sort keys %latest_version) {
next unless $installed_version{$_};
if ($installed_version{$_} ne $latest_version{$_}) {
print "New version of $_ available:\nInstalled: $installed_version{$_}\nAvailable: $latest_version{$_}\nLocation: $package_location{$_}\n";
}
}
Two thirds to three quarters or more of that changelog is Slackware 11.0 version; only what's left or the remainder of said changelog is Slackware 12.0
for my $line (@change_log) {
last if /^Released as Slackware 12/; # not parse 11.0 changelog
-----------------------
Such last if line (above) (stops parse of 11.0 changelog)
next (snippet's last line) is snippet from changelog (Slack 11.0) where got your "updated" kernel from /extra
Thu Feb 15 14:43:45 CST 2007
a/cxxlibs-6.0.8-i486-2.tgz: Replaced libstdc++.so.6.0.8 with the version built
by gcc-4.1.2. Pruned some ancient libs unlikely to be used by anyone.
a/pkgtools-11.0.9-noarch-3.tgz: Moved X related files into x11-skel.
a/kernel-generic-2.6.18.6-i486-1.tgz: Moved from /extra.
--------------------------------
Some of your code went only a little over my head. It's late now but I would like ask a few questions about portions of your code.
I used the mirror switch of wget; and it doesn't download the changelog again unless the changelog has changed.
(if you want to try what I did) For now, need be in your home dir and do
$ mkdir .slak_updck
(2 text files, changelog and wget log will be kept there)
Then run the below code and it will only download the changelog once
From then on, it parses the updated wget log and it will only download the changelog again only if the changelog has changed. (speedier, saves bandwidth, the mirrors like us more) :-)
note hard coded paths (2 of them) to my home folder
Perl doesn't expand ~/.slak_updck/dl_log.txt
I don't know how to do that without hard code the path in Perl.
For some reason it's getting "use of uninitialized value" errors from in your part of the code -- but it didn't do this before until I came along -- I suspect it has something to do with my lexical filehandle -- but I don't know the cause, not yet.
Code:
#!/usr/bin/perl
use strict;
use warnings;
system("wget -m -nd -P.slak_updck ftp://slackware.mirrors.tds.net/pub/slackware/slackware-12.0/ChangeLog.txt -o ~/.slak_updck/dl_log.txt");
my $new_updates;
my $downl_log = '/home/al/.slak_updck/dl_log.txt'; # path to wget log (dl_log.txt)
open my $logfil, "<", $downl_log or die "cant open $downl_log: $!";
while ( <$logfil> ) {
print if /RETR ChangeLog.txt/;
$new_updates = 'newstuff' if /RETR ChangeLog.txt/;
last if /RETR ChangeLog.txt/;
}
close($logfil) or die "Could not close input: $!";
my $chnglogfil = '/home/al/.slak_updck/ChangeLog.txt'; # path to ChangeLog.txt
if ( $new_updates ) {
print $new_updates, " on mirror\n\n";
open my $change_log, '<', $chnglogfil or die "could not open '$chnglogfil' $!";
my @change_log = do { local $/; <$change_log> }; # Slurp
print @change_log, "\n";
# print "yesir\n" if $new_updates;
# __END__
# my @change_log = split "\n", $change_log;
my @installed_packages = `ls /var/log/packages`;
my (%installed_version, %latest_version, %package_location, %installed_build, %latest_build);
sub GetPackageInfo {
my $string = shift;
my ($package_name, $version, $build) = $string =~ m/(.*)-(\d[^-]*)-.*$/;
return ($package_name, $version);
}
for my $line (@change_log) {
last if /^Released as Slackware 12/; # not parse 11.0 changelog
next unless ($line =~ m:^patches/:) || ($line =~ m:^extra/:);
my ($package_location, $package_file_name) = $line =~ m:^(.*/.*/)(.*)$:;
my ($package_name, $package_version) = GetPackageInfo($package_file_name
);
next if $latest_version{$package_name};
$latest_version{$package_name} = $package_version;
$package_location{$package_name} = $package_location;
}
%installed_version = map {GetPackageInfo($_)} @installed_packages;
for (sort keys %latest_version) {
next unless $installed_version{$_};
if ($installed_version{$_} ne $latest_version{$_}) {
print "New version of $_ available:\nInstalled: $installed_version{$_}\nAvailable: $latest_version{$_}\nLocation: $package_location{$_}\n";
}
}
} else {
print "no new updates on mirror server\n";
}
# end
if ("wget log informs us new updates do exist"){
DL and save to disk the changelog
then run all the Perl code
} else {
# do nothing whatsoever except
print "no new updates on mirror server\N";
------------------------------------
wrapped in the if did changed the scope
I wonder if such change in scope is what is causing the
"uninitialized value in list operator" errors.
--
It's very late here. Tomorrow is another day. Thanks.
Ok, I'll take a look it. Just didn't know that such tool, which knows whether the packgage was split into several others or some others were merged, exists. The only automated way in current for me was comparing package trees when having full install.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.