[interchange-cvs] interchange - heins modified lib/Vend/Config.pm
interchange-cvs at icdevgroup.org
interchange-cvs at icdevgroup.org
Sun May 22 08:55:24 EDT 2005
User: heins
Date: 2005-05-22 12:55:24 GMT
Modified: lib/Vend Config.pm
Log:
* Add uninstall convention for Feature.
* Adds one more special extension file in the feature directory,
*.uninstall. These are ITL files that can perform any uninstall
functions, and they run with temporary AllowGlobal access to
allow dropping of tables, unlinking of files, etc.
* Automated uninstall features include removing any files installed
as a part of the feature -- providing they have not changed. If
the file was edited and is not identical to the originally installed
file, then it is left there and a warning issued.
* Creates a file ConfDir/init/<feature>/uninstall file to note the
uninstall, and which prevents the Init process from happening
again (assuming Interchange has not been restarted since the
feature installation).
* The routine is defined in Vend::Config, and called with an
[uninstall-feature <feature>] tag call.
* WARNING: The catalog user must remove the Feature directive from their
catalog.cfg *before* running [uninstall-feature FEATURE], otherwise
the Feature will be re-installed the next time Interchange is
restarted!
* NOTE: There is a short window where a SQL table, if dropped
as a part of the uninstall procedure, could be re-instantiated
based on the existence of the configuration in memory. It
is recommended that if [uninstall-feature] is called, a
[reconfig] tag is called shortly thereafter to reduce this
possiblility to a minimum.
Revision Changes Path
2.178 +190 -4 interchange/lib/Vend/Config.pm
rev 2.178, prev_rev 2.177
Index: Config.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Config.pm,v
retrieving revision 2.177
retrieving revision 2.178
diff -u -r2.177 -r2.178
--- Config.pm 22 May 2005 12:49:46 -0000 2.177
+++ Config.pm 22 May 2005 12:55:24 -0000 2.178
@@ -1,6 +1,6 @@
# Vend::Config - Configure Interchange
#
-# $Id: Config.pm,v 2.177 2005/05/22 12:49:46 mheins Exp $
+# $Id: Config.pm,v 2.178 2005/05/22 12:55:24 mheins Exp $
#
# Copyright (C) 2002-2003 Interchange Development Group
# Copyright (C) 1996-2002 Red Hat, Inc.
@@ -52,7 +52,7 @@
use Vend::Data;
use Vend::Cron;
-$VERSION = substr(q$Revision: 2.177 $, 10);
+$VERSION = substr(q$Revision: 2.178 $, 10);
my %CDname;
my %CPname;
@@ -749,6 +749,7 @@
open GCHUNK, "< $fn"
or config_error("read global chunk %s: %s", $fn, $!);
+#::logDebug("GCHUNK length: " . -s $fn);
while(<GCHUNK>) {
my $line = $_;
my($lvar, $value) = read_config_value($_, \*GCHUNK);
@@ -759,6 +760,9 @@
if($@ =~ /Duplicate\s+usertag/i) {
next;
}
+ if($@) {
+ ::logDebug("error running global $lvar: $@");
+ }
}
close GCHUNK;
@@ -1329,7 +1333,9 @@
set_readonly_config();
# Ugly legacy stuff so API won't break
$C->{Special} = $C->{SpecialPage} if defined $C->{SpecialPage};
- return $C;
+ my $return = $C;
+ undef $C;
+ return $return;
}
sub read_container {
@@ -1910,7 +1916,6 @@
ADDTAGS: {
Vend::Parse::global_init;
}
- undef $GlobalRead unless $Global::AccumulateCode;
## Pulls in the places where code can be found when AccumulatingTags
get_repos_code() if $Global::AccumulateCode;
@@ -2206,18 +2211,32 @@
return $c;
}
+ # Get the global install files and remove them from the config list
my @gfiles = glob("$fdir/*.global");
my %seen;
@seen{@gfiles} = @gfiles;
+
+ # Get the init files and remove them from the config list
my @ifiles = glob("$fdir/*.init");
@seen{@ifiles} = @ifiles;
+
+ # Get the uninstall files and remove them from the config list
+ my @ufiles = glob("$fdir/*.uninstall");
+ @seen{@ufiles} = @ifiles;
+
+ # Any other files are config files
my @cfiles = grep ! $seen{$_}++, glob("$fdir/*");
+ # directories are for copying
my @cdirs = grep -d $_, @cfiles;
+
+ # strip the directories from the config list, leaving catalog.cfg stuff
@cfiles = grep -f $_, @cfiles;
+ # Don't install global more than once
@gfiles = grep ! $Global::FeatureSeen{$_}++, @gfiles;
+ # Place the catalog configuration in the config list
unshift @include, @cfiles;
my @copy;
@@ -2236,6 +2255,7 @@
#::logDebug("gfiles=" . ::uneval(\@gfiles));
#::logDebug("cfiles=" . ::uneval(\@cfiles));
#::logDebug("ifiles=" . ::uneval(\@ifiles));
+#::logDebug("ufiles=" . ::uneval(\@ufiles));
#::logDebug("cdirs=" . ::uneval(\@cdirs));
#::logDebug("copy=" . ::uneval(\@copy));
@@ -2267,9 +2287,24 @@
if(@ifiles) {
my $initdir = Vend::File::catfile($C->{ConfDir}, 'init', $value);
File::Path::mkpath($initdir) unless -d $initdir;
+ my $unfile = Vend::File::catfile($initdir, 'uninstall');
+
+ ## Feature was previously uninstalled, we *do* need to run init
+ my $ignore = -f $unfile;
+
+ if($ignore) {
+ unlink $unfile
+ or die errmsg("Couldn't unlink $unfile: $!");
+ }
+
for(@ifiles) {
my $fn = $_;
$fn =~ s{^$fdir/}{};
+ if($ignore) {
+ unlink "$initdir/$fn"
+ or die errmsg("Couldn't unlink $fn: $!");
+ }
+
next if -f "$initdir/$fn";
$C->{Init} ||= [];
push @{$C->{Init}}, [$_, "$initdir/$fn"];
@@ -2281,6 +2316,157 @@
$c->{$value} = 1;
return $c;
}
+
+sub uninstall_feature {
+ my ($value) = @_;
+ my $c = $Vend::Cfg
+ or die "Not in catalog context.\n";
+
+#::logDebug("Running uninstall for cat=$Vend::Cat, from cfg ref=$c->{CatalogName}");
+ $value =~ s/^\s+//;
+ $value =~ s/\s+$//;
+ my $fdir = Vend::File::catfile($Global::FeatureDir, $value);
+
+ unless(-d $fdir) {
+ config_warn("Feature '%s' not found, skipping.", $value);
+ return $c;
+ }
+
+ my $etag = errmsg("feature %s uninstall -- ", $value);
+
+ # Get the global install files and remove them from the config list
+ my @gfiles = glob("$fdir/*.global");
+ my %seen;
+ @seen{@gfiles} = @gfiles;
+
+ # Get the init files and remove them from the config list
+ my @ifiles = glob("$fdir/*.init");
+ @seen{@ifiles} = @ifiles;
+
+ # Get the uninstall files and remove them from the config list
+ my @ufiles = glob("$fdir/*.uninstall");
+ @seen{@ufiles} = @ifiles;
+
+ # Any other files are config files
+ my @cfiles = grep ! $seen{$_}++, glob("$fdir/*");
+
+ # directories are for copying
+ my @cdirs = grep -d $_, @cfiles;
+
+ my $Tag = new Vend::Tags;
+
+ my @copy;
+ my @errors;
+ my @warnings;
+
+ my $wanted = sub {
+ return unless -f $_;
+ my $n = $File::Find::name;
+ $n =~ s{^$fdir/}{};
+ my $d = $File::Find::dir;
+ $d =~ s{^$fdir/}{};
+ push @copy, [$n, $d];
+ };
+
+ if(@cdirs) {
+ File::Find::find($wanted, @cdirs);
+ }
+#::logDebug("ufiles=" . ::uneval(\@ufiles));
+#::logDebug("ifiles=" . ::uneval(\@ifiles));
+#::logDebug("cdirs=" . ::uneval(\@cdirs));
+#::logDebug("copy=" . ::uneval(\@copy));
+
+ for(@ufiles) {
+#::logDebug("Running uninstall file $_");
+ my $save = $Global::AllowGlobal->{$Vend::Cat};
+ $Global::AllowGlobal->{$Vend::Cat} = 1;
+ open UNFILE, "< $_"
+ or do {
+ push @errors, $etag . errmsg("error reading %s: %s", $_, $!);
+ };
+ my $chunk = join "", <UNFILE>;
+ close UNFILE;
+
+#::logDebug("uninstall chunk length=" . length($chunk));
+
+ my $out;
+ eval {
+ $out = Vend::Interpolate::interpolate_html($chunk);
+ };
+
+ if($@) {
+ push @errors, $etag . errmsg("error running uninstall %s: %s", $_, $@);
+ }
+
+ push @warnings, $etag . errmsg("message from %s: %s", $_, $out)
+ if $out =~ /\S/;
+
+ $Global::AllowGlobal->{$Vend::Cat} = $save;
+ }
+
+ for(@copy) {
+ my ($n, $d) = @$_;
+
+ my $tf = Vend::File::catfile($c->{VendRoot}, $n);
+ next unless -f $tf;
+
+ my $contents1 = Vend::File::readfile($tf);
+
+ my $sf = "$fdir/$n";
+
+ open UNSRC, "< $sf"
+ or die $etag . errmsg("Couldn't read uninstall source file %s: %s", $sf, $!);
+
+ local $/;
+ my $contents2 = <UNSRC>;
+
+ if($contents1 ne $contents2) {
+ push @warnings, $etag . errmsg("will not uninstall %s, changed.", $tf);
+ next;
+ }
+
+ unlink $tf
+ or do {
+ push @errors,
+ $etag . errmsg("$etag couldn't unlink file %s: %s", $tf, $!);
+ next;
+ };
+
+ my $td = Vend::File::catfile($c->{VendRoot}, $d);
+ my @left = glob("$td/*");
+ push @left, glob("$td/.?*");
+ next if @left;
+ File::Path::rmtree($td);
+ }
+
+ if(@ifiles) {
+#::logDebug("running uninstall touch and init");
+ my $initdir = Vend::File::catfile($c->{ConfDir}, 'init', $value);
+ File::Path::mkpath($initdir) unless -d $initdir;
+ my $fn = Vend::File::catfile($initdir, 'uninstall');
+#::logDebug("touching uninstall file $fn");
+ open UNFILE, ">> $fn"
+ or die errmsg("Couldn't create uninstall flag file %s: %s", $fn, $!);
+ print UNFILE $etag . errmsg("uninstalled at %s.\n", scalar(localtime));
+ close UNFILE;
+ }
+
+
+ my $errors;
+ for(@errors) {
+ $Tag->error({ set => $_});
+ ::logError($_);
+ $errors++;
+ }
+
+ for(@warnings) {
+ $Tag->warnings($_);
+ ::logError($_);
+ }
+
+ return ! $errors;
+}
+
# Changes configuration directives into Variable settings, i.e.
# DescriptionField becomes __DescriptionField__, ProductFiles becomes
More information about the interchange-cvs
mailing list