2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 16:56:54 +00:00

Added support for a cleaner installation of pgm2 via updatefhem.

git-svn-id: https://svn.fhem.de/fhem/trunk@1569 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
mfr69bs 2012-05-20 15:24:11 +00:00
parent 1a827f9530
commit b59ab0dab4
5 changed files with 366 additions and 60 deletions

View File

@ -26,7 +26,11 @@
- feature: at attribute alignTime added
- feature: FHEMWEB attribute values via dropdown, slider for dimmer
- feature: new attribute group for FHEMWEB (Boris)
- change: 11_FHT.pm, 50_WS300.pm, 59_Weather.pm migrated to redingsUpdate mechanism (Boris)
- change: 11_FHT.pm, 50_WS300.pm, 59_Weather.pm migrated to redingsUpdate
mechanism (Boris)
- change: updatefhem modifications to support a clean install of fhem and
pgm2 installation, see commandref.html (M. Fischer)
- change: FHEMWEB support for the new www/pgm2 directroy added (M. Fischer)
- 2011-12-31 (5.2)
- bugfix: applying smallscreen attributes to firefox/opera

View File

@ -1,5 +1,6 @@
##############################################
# $Id$
# modified by M. Fischer
package main;
use strict;
use warnings;
@ -8,9 +9,11 @@ use IO::Socket;
sub CommandUpdatefhem($$);
sub CommandCULflash($$);
sub GetHttpFile($$@);
sub CreateBackup($);
sub FileList($);
my $server = "fhem.de:80";
my $sdir = "/fhemupdate";
my $sdir = "/fhemupdate2";
my $ftime = "filetimes.txt";
my $dfu = "dfu-programmer";
@ -35,24 +38,157 @@ CommandUpdatefhem($$)
my ($cl, $param) = @_;
my $lt = "";
my $ret = "";
my $moddir = (-d "FHEM.X" ? "FHEM.X" : "$attr{global}{modpath}/FHEM");
my $modpath = (-d "updatefhem.dir" ? "updatefhem.dir" : $attr{global}{modpath});
my $moddir = "$modpath/FHEM";
my $wwwdir = "$modpath/www";
my $backuppaths = "";
my $preserve = 0;
my $housekeeping = 0;
my $clean = 0;
my $msg;
## backup by RueBe, simplified by rudi
if(!$param && !-d $wwwdir) {
$ret = "Usage: updatefhem [<backup>|<filename>|<housekeeping> [<clean>] [<yes>]|<preserve> [<filename>]]\n";
$ret .= "Please note: The update routine has changed! Please consider the manual of command 'updatefhem'!";
return $ret;
}
# split arguments
my @args = split(/ +/,$param);
# Check if the first parameter is "backup"
if(@args && uc($args[0]) eq "BACKUP") {
my $bdir = AttrVal("global", "backupdir", "$moddir.backup");
my $dateTime = TimeNow();
$dateTime =~ s/ /_/g;
my $ret = `(mkdir -p $bdir && tar hcf - $moddir | gzip > $bdir/FHEM.$dateTime.tgz) 2>&1`;
return $ret if($ret);
shift @args;
$param = join("", @args);
if(@args) {
# Check if the first parameter is "backup"
# backup by RueBe, simplified by rudi, modified by M.Fischer
if(uc($args[0]) eq "BACKUP") {
return "Usage: updatefhem <backup>" if(@args > 1);
if(-d $wwwdir) {
# backup new structure
$backuppaths = "FHEM www";
} else {
# backup old structure
$backuppaths = "FHEM";
}
my $ret = CreateBackup($backuppaths);
if($ret !~ m/backup done.*/) {
Log 1, "updatefhem backup: The operation was canceled. Please check manually!";
$msg = "Something went wrong during backup:\n$ret\n";
$msg .= "The operation was canceled. Please check manually!";
return $msg;
} else {
Log 1, "updatefhem $ret";
}
return $ret if($ret);
# Check whether the old structure to be maintained
} elsif (uc($args[0]) eq "PRESERVE") {
# Check if new wwwdir already exists and an argument is given
if(-d $wwwdir && @args > 1) {
Log 1, "updatefhem The operation was canceled! Argument <preserve> not allowed in new structure!";
$ret = "Usage: updatefhem [<backup>|<filename>]\n";
$ret .= "Please note: It seems as if 'updatefhem <housekeeping>' has already executed.\n";
$ret .= "The operation was canceled. Argument <preserve> is not allowed in new structure!";
return $ret;
}
# Check if new wwwdir already exists
if(-d $wwwdir) {
Log 1, "updatefhem The operation was canceled. Please check manually!";
$ret = "Please note: It seems as if 'updatefhem <housekeeping>' has already executed.\n";
$ret .= "The operation was canceled. Please check manually!";
return $ret;
}
# set old sourcedir for update
$sdir = "/fhemupdate";
$preserve = 1;
# discard first argument
shift @args;
$param = join("", @args);
# Check whether the new structure is to be established.
} elsif (uc($args[0]) eq "HOUSEKEEPING") {
if(@args >3 ||
(defined($args[1]) && uc($args[1]) ne "CLEAN") ||
((defined($args[1]) && uc($args[1]) eq "CLEAN") && (defined($args[2]) && uc($args[2]) ne "YES"))
) {
return "Usage: updatefhem <housekeeping> [<clean>] [<yes>]";
}
# Check if new wwwdir already exists
if(-d $wwwdir && @args == 1) {
Log 1, "updatefhem The operation was canceled. Please check manually!";
$ret = "Please note: It seems as if 'updatefhem <housekeeping>' has already executed.\n";
$ret .= "The operation is canceled now. Please check manually!";
return $ret;
}
# user decided to delete old files
if (@args == 2 && uc($args[1]) eq "CLEAN") {
# returns a warning
$ret = "WARNING: The option <clean> will remove existing files!\n";
$ret .= "If local changes have been made, they will be lost!\n";
$ret .= "If you are sure, then call 'updatefhem <housekeeping> <clean> <yes>'.";
return $ret;
# user decided to delete old files, really
} elsif (@args == 3 && uc($args[1]) eq "CLEAN" && uc($args[2]) eq "YES") {
# set cleanup structure
$clean = 1;
}
# Backup existing structure
if(-d $wwwdir) {
# backup new structure
$backuppaths = "FHEM www";
} else {
# backup old structure
$backuppaths = "FHEM";
}
my $ret = CreateBackup($backuppaths);
if($ret !~ m/backup done.*/) {
Log 1, "updatefhem backup: The operation was canceled. Please check manually!";
$msg = "Something went wrong during backup:\n$ret\n";
$msg .= "The operation was canceled. Please check manually!";
return $msg;
} else {
Log 1, "updatefhem $ret";
}
# prepare for housekeeping
$housekeeping = 1;
# set new sourcedir for update
$sdir = "/fhemupdate2";
# Create new pgm2 path
$ret = `(mkdir -p $wwwdir/pgm2)`;
chomp $ret;
# return on errors
if($ret) {
Log 1, "updatefhem \"$ret\"";
return $ret;
}
# remove old filetimes.txt
if(-e "$moddir/$ftime") {
unlink("$moddir/$ftime");
}
# discard arguments
@args = ();
$param = join("", @args);
# user wants to update a file / module of the old structure
} elsif (!-d $wwwdir) {
return "Usage: updatefhem [<backup>|<housekeeping> [<clean>] [<yes>]|<preserve> [<filename>]]";
}
}
# Read in the OLD filetimes.txt
my %oldtime;
my %oldtime = ();
if(open FH, "$moddir/$ftime") {
while(my $l = <FH>) {
chomp($l);
@ -65,7 +201,7 @@ CommandUpdatefhem($$)
my $filetimes = GetHttpFile($server, "$sdir/$ftime");
return "Can't get $ftime from $server" if(!$filetimes);
my (%filetime, %filesize);
my (%filetime, %filesize) = ();
foreach my $l (split("[\r\n]", $filetimes)) {
chomp($l);
return "Corrupted filetimes.txt file"
@ -77,26 +213,41 @@ CommandUpdatefhem($$)
my @reload;
my $newfhem = 0;
my $localfile;
my $remfile;
my $oldfile;
my $delfile;
foreach my $f (sort keys %filetime) {
if($param) {
next if($f ne $param);
next if($f !~ m/$param/);
} else {
next if($oldtime{$f} && $filetime{$f} eq $oldtime{$f});
if(!$clean) {
next if($oldtime{$f} && $filetime{$f} eq $oldtime{$f});
}
next if($f =~ m/.hex$/); # skip firmware files
}
my $localfile = "$moddir/$f";
my $remfile = $f;
if(!$preserve) {
$localfile = "$modpath/$f";
if($f =~ m/^www\/pgm2\/(\d\d_.*\.pm)$/) {
my $pgm2 = $1;
$localfile = "$moddir/$pgm2";
}
$remfile = $f;
} else {
$localfile = "$moddir/$f";
$remfile = $f;
}
if($f eq "fhem.pl") {
$ret .= "updated fhem.pl, 'shutdown restart' is required\n";
if($f =~ m/fhem.pl$/) {
$newfhem = 1;
$localfile = $0 if(! -d "FHEM.X");
$localfile = $0 if(! -d "updatefhem.dir");
$remfile = "$f.txt";
}
if($f =~ m/^(\d\d_)(.*).pm$/) {
my $m = $2;
push @reload, $f if($modules{$m} && $modules{$m}{LOADED});
if($f =~ m/^.*(\d\d_)(.*).pm$/) {
my $mf = "$1$2";
my $m = $2;
push @reload, $mf if($modules{$m} && $modules{$m}{LOADED});
}
my $content = GetHttpFile($server, "$sdir/$remfile");
@ -108,7 +259,19 @@ CommandUpdatefhem($$)
print FH $content;
close(FH);
$ret .= "updated $f\n";
Log 1, "updated $f";
Log 1, "updatefhem updated $f";
if(!$preserve && $clean && $f =~ m/^www\/pgm2\/(.*)$/) {
my $oldfile = $1;
if($oldfile !~ m /^.*\.pm$/) {
$delfile = $oldfile;
if(-e "$moddir/$delfile") {
unlink("$moddir/$delfile");
$ret .= "deleted FHEM/$delfile\n";
Log 1, "updatefhem deleted FHEM/$delfile";
}
}
}
}
return "Can't write $moddir/$ftime" if(!open(FH, ">$moddir/$ftime"));
@ -119,11 +282,41 @@ CommandUpdatefhem($$)
foreach my $m (@reload) {
$ret .= "reloading module $m\n";
my $cret = CommandReload($cl, $m);
Log 1, "updatefhem reloaded module $m" if($cret);
return "$ret$cret" if($cret);
}
}
$ret .= "update finished\n";
# final housekeeping
if($clean) {
my @fl;
push(@fl, FileList("$moddir/.*(example.*|gplot|html|css|js|gif|jpg|png|svg)"));
foreach my $file (@fl) {
my $cmdret .= `(mv $moddir/$file $wwwdir/pgm2/)`;
$ret .= "moved $moddir/$file\n";
Log 1, "updatefhem move $file to www/pgm2 $cmdret";
}
}
if($housekeeping) {
$ret .= "Housekeeping finished. 'shutdown restart' is recommended!";
my $backupdir;
if ($attr{global}{backupdir}) {
$backupdir = $attr{global}{backupdir};
} else {
$backupdir = "$modpath/backup";
}
$ret .= "\n=> Files for WebGUI pgm2 were moved to '$wwwdir/pgm2'" if($clean);
$ret .= "\n=> A backup has been created in '$backupdir'";
Log 1, "updatefhem Housekeeping finished, 'shutdown restart' is recommended!";
} else {
$ret .= "update finished";
}
if($newfhem) {
$ret .= "\nA new version of fhem.pl was installed, 'shutdown restart' is required!";
Log 1, "updatefhem New version of fhem.pl, 'shutdown restart' is required!";
}
return $ret;
}
@ -131,7 +324,8 @@ sub
CommandCULflash($$)
{
my ($cl, $param) = @_;
my $moddir = (-d "FHEM.X" ? "FHEM.X" : "$attr{global}{modpath}/FHEM");
my $modpath = (-d "update" ? "update" : $attr{global}{modpath});
my $moddir = "$modpath/FHEM";
my %ctypes = (
CUL_V2 => "at90usb162",
@ -183,9 +377,9 @@ CommandCULflash($$)
CUL_SimpleWrite($defs{$cul}, "B01");
sleep(4); # B01 needs 2 seconds for the reset
}
Log 1, $cmd;
Log 1, "updatefhem $cmd";
my $result = `$cmd`;
Log 1, $result;
Log 1, "updatefhem $result";
return $result;
}
@ -198,7 +392,8 @@ GetHttpFile($$@)
$filename =~ s/%/%25/g;
my $conn = IO::Socket::INET->new(PeerAddr => $host);
if(!$conn) {
Log 1, "Can't connect to $host\n";
Log 1, "updatefhem Can't connect to $host\n";
undef $conn;
return undef;
}
$host =~ s/:.*//;
@ -213,7 +408,8 @@ GetHttpFile($$@)
vec($rin, $conn->fileno(), 1) = 1;
my $nfound = select($rout=$rin, undef, undef, $timeout);
if($nfound <= 0) {
Log 1, "GetHttpFile: Select timeout/error: $!";
Log 1, "updatefhem GetHttpFile: Select timeout/error: $!";
undef $conn;
return undef;
}
@ -223,8 +419,55 @@ GetHttpFile($$@)
}
$ret=~ s/(.*?)\r\n\r\n//s; # Not greedy: switch off the header.
Log 4, "Got http://$host$filename, length: ".length($ret);
Log 4, "updatefhem Got http://$host$filename, length: ".length($ret);
undef $conn;
return $ret;
}
sub
CreateBackup($)
{
my ($backuppaths) = shift;
my $modpath = (-d "updatefhem.dir" ? "updatefhem.dir" : $attr{global}{modpath});
my ($dir,$conf) = $attr{global}{configfile} =~ m/(.*\/)(.*)$/;
my $backupdir;
my $ret;
if ($attr{global}{backupdir}) {
$backupdir = $attr{global}{backupdir};
} else {
$backupdir = "$modpath/backup";
}
$ret = `(cp $attr{global}{configfile} $modpath/)`;
$backuppaths .= " $conf";
my $dateTime = TimeNow();
$dateTime =~ s/ /_/g;
# prevents tar's output of "Removing leading /" and return total bytes of archive
$ret = `(mkdir -p $backupdir && tar -C $modpath -cf - $backuppaths | gzip > $backupdir/FHEM.$dateTime.tar.gz) 2>&1`;
unlink("$modpath/$conf");
if($ret) {
chomp $ret;
return $ret;
}
my $size = -s "$backupdir/FHEM.$dateTime.tar.gz";
return "backup done: FHEM.$dateTime.tar.gz ($size Bytes)";
}
sub
FileList($)
{
my ($fname) = @_;
$fname =~ m,^(.*)/([^/]*)$,;
my ($dir,$re) = ($1, $2);
return if(!$re);
$re =~ s/%./[A-Za-z0-9]*/g;
my @ret;
return @ret if(!opendir(DH, $dir));
while(my $f = readdir(DH)) {
next if($f !~ m,^$re$,);
push(@ret, $f);
}
closedir(DH);
return sort @ret;
}
1;

View File

@ -494,3 +494,5 @@
- Fr Feb 24 2012 (Willi)
- New modules TRX for RFXCOM RFXtrx transceiver
- So May 20 2012 (M. Fischer)
- Added support for a cleaner installation of pgm2 via updatefhem.

View File

@ -749,29 +749,65 @@ A line ending with \ will be concatenated with the next one, so long lines
<a name="updatefhem"></a>
<h3>updatefhem</h3>
<ul>
<code>updatefhem [backup] [filename]</code> <br>
<code>updatefhem [&lt;backup&gt;|&lt;filename&gt;|&lt;housekeeping&gt; [&lt;clean&gt;] [&lt;yes&gt;]|&lt;preserve&gt; [&lt;filename&gt;]]</code> <br>
<br>
Update the fhem modules and documentation from a nightly SVN chekout. For
Update the fhem modules and documentation from a nightly SVN checkout. For
this purpose fhem contacts http://fhem.de/fhemupdate, compares the stored
timestamps of the local files with the filelist on the server, and
downloads the files changed on the server. For all downloaded modules a
reload will be scheduled if the corresponding module is loaded.<br>
If an explicit filename is given, then only this file will be downloaded.
reload will be scheduled if the corresponding module is loaded.
<br>
<br>
Note: Since Version 5.3 a new directory structure is used by Fhem. The
WebInterface pgm2 is separated from <a href="#modpath">modpath</a>/FHEM
directory. The directory modpath/www/pgm2 is the new home of pgm2 and
of its files. It is recommended to update to the new structure via the
&lt;housekeeping&gt; arguments.
<br>
<br>
If &lt;backup&gt; is specified, then the complete FHEM directory (containing
the modules), the WebInterface pgm2 (if installed) and the config-file will
be saved into a .tar.gz file. The file is stored with a timestamp in the
modpath/backup directory or to a directory specified
by the <a href="#backupdir">backupdir</a> global attribute.<br>
Note: tar and gzip must be installed to use this feature.
<br>
<br>
If an explicit &lt;filename&gt; is given, then only this file will be
downloaded.
<br>
<br>
If &lt;housekeeping&gt; is specified, then updatefhem switch your Fhem
installation to the new directory structure for the pgm2 WebInterface.
The old files are archived like the &lt;backup&gt; argument and the new
files are stored to modpath/www/pgm2. None of the existing files of pgm2
in modpath/FHEM will be deleted, but are no longer in use.<br>
If you like to delete the no more needed files for pgm2 in modpath/FHEM,
you should call &lt;housekeeping&gt; with the argument &lt;clean&gt; &lt;yes&gt;.
All files of pgm2 are removed from modpath/FHEM and files like
.*example.*, .gplot, .html .css, .js, and .(gif|jpg|png|svg) are moved
to modpath/www/pgm2.
<br>
<br>
If &lt;preserve&gt; is specified, you could preserve the old directory
structure. All files of pgm2 are updated and stored in modpath/FHEM like
the former (before Fhem 5.3) updatefhem funktion. To update an explicit
file to the old structure append the file as &lt;filename&gt;.<br>
Note: After running the housekeeping process, the argument &lt;preserve&gt;
is no longer necessary and no more supported.
<br>
<br>
Notes:
<ul>
<li>If the main program (fhem.pl) is changed, a manual restart of fhem
will be necessary to apply the changes.</li>
<li>After running &lt;housekeeping&gt; it is recommended to restart Fhem.</li>
</ul>
<br>
Note: if the main program (fhem.pl) is changed, a manual restart of fhem
will be necessary to apply the changes.
<br>
If backup is specified, then the complete FHEM directory (containing the
modules and .gplot files) will be saved into a .tar.gz file with a
timestamp in the <a href="#modpath">modpath</a>/FHEM.backup directory or to
a directory specified by the <a href="#backupdir">backupdir</a> global
attribute. Note: tar and gzip must be installed to use this feature.
<br>
<br>
<b>Attributes</b> <ul>
<b>Attributes</b>
<ul>
<a name="backupdir"></a>
<li>backupdir<br>
A folder where updatefhem will store the compressed backup file.
@ -779,8 +815,8 @@ A line ending with \ will be concatenated with the next one, so long lines
<ul>
attr global backupdir /Volumes/BigHD<br>
</ul>
</li><br>
</ul><br>
</li>
</ul>
</ul>

View File

@ -36,7 +36,8 @@ sub FW_pH(@);
sub FW_pHPlain(@);
sub FW_pO(@);
use vars qw($FW_dir); # moddir (./FHEM), needed by SVG
use vars qw($FW_dir); # moddir (./FHEM in old structure, www/pgm2 in new structure), needed by SVG
use vars qw($MW_dir); # moddir (./FHEM), needed by edit Files in new structure
use vars qw($FW_ME); # webname (default is fhem), needed by 97_GROUP
use vars qw($FW_ss); # is smallscreen, needed by 97_GROUP/95_VIEW
use vars qw($FW_tp); # is touchpad (iPad / etc)
@ -339,8 +340,12 @@ FW_AnswerCall($)
$FW_RET = "";
$FW_RETTYPE = "text/html; charset=$FW_encoding";
$FW_ME = "/" . AttrVal($FW_wname, "webname", "fhem");
#$FW_dir = AttrVal($FW_wname, "fwmodpath", "$attr{global}{modpath}/www/pgm2");
$FW_dir = AttrVal($FW_wname, "fwmodpath", "$attr{global}{modpath}/FHEM");
if(-d "$attr{global}{modpath}/www/pgm2") {
$FW_dir = AttrVal($FW_wname, "fwmodpath", "$attr{global}{modpath}/www/pgm2");
} else {
$FW_dir = AttrVal($FW_wname, "fwmodpath", "$attr{global}{modpath}/FHEM");
}
$MW_dir = AttrVal($FW_wname, "fwmodpath", "$attr{global}{modpath}/FHEM");
$FW_ss = AttrVal($FW_wname, "smallscreen", 0);
$FW_tp = AttrVal($FW_wname, "touchpad", $FW_ss);
my $prf = AttrVal($FW_wname, "stylesheetPrefix", "");
@ -1537,7 +1542,8 @@ FW_style($$)
my @fl = ("fhem.cfg");
push(@fl, "");
push(@fl, FW_fileList("$FW_dir/.*(sh|Util.*|cfg|holiday)"));
#push(@fl, FW_fileList("$FW_dir/.*(sh|Util.*|cfg|holiday)"));
push(@fl, FW_fileList("$MW_dir/.*(sh|Util.*|cfg|holiday)"));
push(@fl, "");
push(@fl, FW_fileList("$FW_dir/.*.(css|svg)"));
push(@fl, "");
@ -1587,8 +1593,16 @@ FW_style($$)
} elsif($a[1] eq "edit") {
$a[2] =~ s,/,,g; # little bit of security
my $f = ($a[2] eq "fhem.cfg" ? $attr{global}{configfile} :
"$FW_dir/$a[2]");
#my $f = ($a[2] eq "fhem.cfg" ? $attr{global}{configfile} :
# "$FW_dir/$a[2]");
my $f;
if($a[2] eq "fhem.cfg") {
$f = $attr{global}{configfile};
} elsif ($a[2] =~ m/.*(sh|Util.*|cfg|holiday)/ && $a[2] ne "fhem.cfg") {
$f = "$MW_dir/$a[2]";
} else {
$f = "$FW_dir/$a[2]";
}
if(!open(FH, $f)) {
FW_pO "$f: $!";
return;
@ -1616,8 +1630,15 @@ FW_style($$)
$fName = $FW_webArgs{saveName}
if($FW_webArgs{saveAs} && $FW_webArgs{saveName});
$fName =~ s,/,,g; # little bit of security
$fName = ($fName eq "fhem.cfg" ? $attr{global}{configfile} :
"$FW_dir/$fName");
#$fName = ($fName eq "fhem.cfg" ? $attr{global}{configfile} :
# "$FW_dir/$fName");
if($fName eq "fhem.cfg") {
$fName = $attr{global}{configfile};
} elsif ($fName =~ m/.*(sh|Util.*|cfg|holiday)/ && $fName ne "fhem.cfg") {
$fName = "$MW_dir/$fName";
} else {
$fName = "$FW_dir/$fName";
}
if(!open(FH, ">$fName")) {
FW_pO "$fName: $!";
return;