#!/usr/local/bin/perl # Build a Debian package of Webmin use POSIX; if ($ARGV[0] eq "--webmail" || $ARGV[0] eq "-webmail") { $webmail = 1; shift(@ARGV); } if ($0 =~ /useradmin|usermin/ || `pwd` =~ /useradmin|usermin/) { if ($webmail) { $product = "usermin-webmail"; } else { $product = "usermin"; } $baseproduct = "usermin"; $port = 20000; } else { $product = "webmin"; $baseproduct = "webmin"; $port = 10000; } $ucproduct = ucfirst($baseproduct); $tmp_dir = "/tmp/debian"; $debian_dir = "$tmp_dir/DEBIAN"; $control_file = "$debian_dir/control"; $doc_dir = "$tmp_dir/usr/share/doc/$baseproduct"; $copyright_file = "$doc_dir/copyright"; $usr_dir = "$tmp_dir/usr/share/$baseproduct"; $pam_dir = "$tmp_dir/etc/pam.d"; $init_dir = "$tmp_dir/etc/init.d"; $pam_file = "$pam_dir/$baseproduct"; $preinstall_file = "$debian_dir/preinst"; $postinstall_file = "$debian_dir/postinst"; $preuninstall_file = "$debian_dir/prerm"; $postuninstall_file = "$debian_dir/postrm"; $debian_copyright_file = "$debian_dir/copyright"; $changelog_file = "$debian_dir/changelog"; $changelog_doc_file = "$doc_dir/changelog"; $conffiles_file = "$debian_dir/conffiles"; -d "tarballs" || die "makedebian.pl must be run in the $ucproduct root directory"; -r "/etc/debian_version" || die "makedebian.pl must be run on Debian"; chop($webmin_dir = `pwd`); @ARGV == 1 || @ARGV == 2 || die "usage: makedebian.pl [--webmail] [release]"; $ver = $ARGV[0]; if ($ARGV[1]) { $rel = "-".$ARGV[1]; } -r "tarballs/$product-$ver.tar.gz" || die "tarballs/$product-$ver.tar.gz not found"; # Create the base directories print "Creating Debian package of ",ucfirst($product)," ",$ver,$rel," ...\n"; system("rm -rf $tmp_dir"); mkdir($tmp_dir, 0755); chmod(0755, $tmp_dir); mkdir($debian_dir, 0755); system("mkdir -p $pam_dir"); system("mkdir -p $init_dir"); system("mkdir -p $usr_dir"); system("mkdir -p $doc_dir"); # Un-tar the package to the correct locations system("gunzip -c tarballs/$product-$ver.tar.gz | (cd $tmp_dir ; tar xf -)") && die "un-tar failed!"; system("mv $tmp_dir/$product-$ver/* $usr_dir"); rmdir("$tmp_dir/$product-$ver"); system("mv $usr_dir/$baseproduct-debian-pam $pam_file"); system("cd $usr_dir && (find . -name '*.cgi' ; find . -name '*.pl') | perl perlpath.pl /usr/bin/perl -"); system("cd $usr_dir && rm -f mount/freebsd-mounts*"); system("cd $usr_dir && rm -f mount/openbsd-mounts*"); if ($product eq "webmin") { system("cd $usr_dir && rm -f mount/macos-mounts*"); system("cd $usr_dir && rm -f webmin-gentoo-init"); system("cd $usr_dir && rm -rf format bsdexports hpuxexports sgiexports zones rbac bsdfdisk"); system("cd $usr_dir && rm -rf acl/Authen-SolarisRBAC-0.1*"); } # Create init script system("mv $usr_dir/$baseproduct-init $init_dir/$baseproduct"); chmod(0755, "$init_dir/$baseproduct"); system("echo deb >$usr_dir/install-type"); system("echo $product >$usr_dir/deb-name"); system("cd $usr_dir && chmod -R og-w ."); if ($< == 0) { system("cd $usr_dir && chown -R root:bin ."); } $size = int(`du -sk $tmp_dir`); # Create the control file @deps = ( "perl", "libnet-ssleay-perl", "openssl", "libauthen-pam-perl", "libpam-runtime", "libio-pty-perl", "apt-show-versions", "unzip", "shared-mime-info" ); if ($baseproduct eq "webmin") { push(@deps, "python"); } $deps = join(", ", @deps); open(CONTROL, ">$control_file"); print CONTROL < Provides: $baseproduct EOF if ($product eq "webmin") { print CONTROL <$copyright_file"); print COPY < on $nowstr. It was downloaded from: http://www.webmin.com/ Upstream author: Jamie Cameron Copyright: EOF open(BSD, "$usr_dir/LICENCE"); while() { print COPY $_; } close(BSD); close(COPY); system("cp $copyright_file $debian_copyright_file"); # Create the config files file, for those we don't want to replace open(CONF, ">$conffiles_file"); print CONF "/etc/pam.d/$baseproduct\n"; print CONF "/etc/init.d/$baseproduct\n"; close(CONF); chmod(0644, $conffiles_file); # Get the changes for each module and version $changes = { }; foreach $f (sort { $a cmp $b } ( glob("*/CHANGELOG"), "CHANGELOG" )) { # Get the module name and type local $mod = $f =~ /^(\S+)\/CHANGELOG/ ? $1 : "core"; next if ($mod ne "core" && -l $mod); local $desc; if ($mod eq "core") { $desc = "$ucproduct Core"; } else { local $m = $f; local %minfo; $m =~ s/CHANGELOG/module.info/; &read_file($m, \%minfo); next if (!$minfo{'longdesc'}); $desc = $minfo{'desc'}; } # Read its change log file local $inversion; open(LOG, $f); while() { s/\r|\n//g; if (/^----\s+Changes\s+since\s+(\S+)\s+----/) { $inversion = $1; } elsif ($inversion && /\S/) { push(@{$changes->{$inversion}->{$desc}}, $_); } } } # Create the changelog file from actual changes, plus the historical changelog open(CHANGELOG, ">$changelog_file"); foreach $v (sort { $a <=> $b } (keys %$changes)) { if ($ver > $v && sprintf("%.2f0", $ver) == $v) { $forv = $ver; } else { $forv = sprintf("%.2f0", $v+0.01); } @st = stat("tarballs/webmin-$forv.tar.gz"); $vtimestr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime($st[9])); print CHANGELOG "$baseproduct ($forv) stable; urgency=low\n"; print CHANGELOG "\n"; foreach $desc (keys %{$changes->{$v}}) { foreach $c (@{$changes->{$v}->{$desc}}) { @lines = &wrap_lines("$desc : $c", 65); print CHANGELOG " * $lines[0]\n"; foreach $l (@lines[1 .. $#lines]) { print CHANGELOG " $l\n"; } } } print CHANGELOG "\n"; print CHANGELOG "-- Jamie Cameron $vtimestr\n"; print CHANGELOG "\n"; } close(CHANGELOG); system("iconv -f ISO-8859-1 -t UTF-8 $changelog_file >$changelog_doc_file"); # Get the temp-directory creator script open(TEMP, "maketemp.pl"); while() { $maketemp .= $_; } close(TEMP); $maketemp =~ s/\\/\\\\/g; $maketemp =~ s/`/\\`/g; $maketemp =~ s/\$/\\\$/g; # Create the pre-install script # No need for an OS check, as all debians are supported. open(SCRIPT, ">$preinstall_file"); print SCRIPT <$postinstall_file"); print SCRIPT </dev/null 2>&1 $tempdir/$product-setup.out 2>&1 if [ "$product" = "webmin" ]; then grep sudo= /etc/$product/miniserv.conf >/dev/null 2>&1 if [ "\$?" = 1 ]; then # Allow sudo-based logins for Ubuntu echo sudo=1 >>/etc/$product/miniserv.conf fi fi rm -f /var/lock/subsys/$baseproduct if [ "$inetd" != "1" ]; then if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then invoke-rc.d $baseproduct stop >/dev/null 2>&1 /dev/null 2>&1 /dev/null 2>&1 /dev/null 2>&1 /dev/null 2>&1 fi cat >/etc/$baseproduct/uninstall.sh </dev/null 2>/dev/null if [ "\$?" = "0" ]; then sslmode=1 fi fi if [ "\$sslmode" = "1" ]; then echo "$ucproduct install complete. You can now login to https://\$host:\$port/" else echo "$ucproduct install complete. You can now login to http://\$host:\$port/" fi if [ "$product" = "webmin" ]; then echo "as root with your root password, or as any user who can use sudo" echo "to run commands as root." else echo "as any user on the system." fi EOF close(SCRIPT); system("chmod 755 $postinstall_file"); # Create the pre-uninstall script open(SCRIPT, ">$preuninstall_file"); print SCRIPT </dev/null 2>&1 if [ "\$?" = 0 ]; then # Package is being removed, and no new version of webmin # has taken it's place. Run uninstalls and stop the server if [ "$product" = "webmin" ]; then echo "Running uninstall scripts .." (cd /usr/share/$baseproduct ; WEBMIN_CONFIG=/etc/$baseproduct WEBMIN_VAR=/var/$baseproduct LANG= /usr/share/$baseproduct/run-uninstalls.pl) fi /etc/$baseproduct/stop >/dev/null 2>&1 $postuninstall_file"); print SCRIPT </dev/null 2>&1 if [ "\$?" = 0 ]; then # Package is being removed, and no new version of webmin # has taken it's place. Delete the config files rm -rf /etc/$baseproduct /var/$baseproduct fi fi EOF close(SCRIPT); system("chmod 755 $postuninstall_file"); # Run the actual build command system("fakeroot dpkg --build $tmp_dir deb/${product}_${ver}${rel}_all.deb") && die "dpkg failed"; #system("rm -rf $tmp_dir"); print "Wrote deb/${product}_${ver}${rel}_all.deb\n"; $md5 = `md5sum tarballs/$product-$ver$rel.tar.gz`; $md5 =~ s/\s+.*\n//g; @st = stat("tarballs/$product-$ver.tar.gz"); # Create the .diff file, which just contains the debian directory $diff_orig_dir = "$tmp_dir/$product-$ver-orig"; $diff_new_dir = "$tmp_dir/$product-$ver"; mkdir($diff_orig_dir, 0755); mkdir($diff_new_dir, 0755); system("cp -r $debian_dir $diff_new_dir"); system("cd $tmp_dir && diff -r -N -u $product-$ver-orig $product-$ver >$webmin_dir/deb/${product}_${ver}${rel}.diff"); $diffmd5 = `md5sum deb/${product}_${ver}${rel}.diff`; $diffmd5 =~ s/\s+.*\n//g; @diffst = stat("deb/${product}_${ver}${rel}.diff"); # Create the .dsc file open(DSC, ">deb/${product}_$ver$rel.plain"); print DSC < Architecture: all Standards-Version: 3.6.1 Build-Depends-Indep: debhelper (>= 4.1.16), debconf (>= 0.5.00), perl Uploaders: Jamie Cameron Files: $md5 $st[7] ${product}-${ver}.tar.gz $diffmd5 $diffst[7] ${product}_${ver}.diff EOF close(DSC); print "Creating signature deb/${product}_$ver$rel.dsc\n"; unlink("deb/${product}_$ver$rel.dsc"); $ex = system("gpg --output deb/${product}_$ver$rel.dsc --clearsign deb/${product}_$ver$rel.plain"); if ($ex) { print "Failed to create deb/${product}_$ver$rel.dsc\n"; } else { unlink("deb/${product}_$ver$rel.plain"); print "Wrote source deb/${product}_$ver$rel.dsc\n"; } $dir = "sarge"; if (-d "/usr/local/webadmin/deb/repository") { # Add to our repository chdir("/usr/local/webadmin/deb/repository"); system("reprepro -Vb . remove $dir $product"); system("reprepro -Vb . includedeb $dir ../${product}_${ver}${rel}_all.deb"); chdir("/usr/local/webadmin"); } # Create PGP signature print "Signing sigs/${product}_${ver}${rel}_all.deb-sig.asc\n"; unlink("sigs/${product}_${ver}${rel}_all.deb-sig.asc"); system("gpg --armor --output sigs/${product}_${ver}${rel}_all.deb-sig.asc --default-key jcameron\@webmin.com --detach-sig deb/${product}_${ver}${rel}_all.deb"); print "Wrote sigs/${product}_${ver}${rel}_all.deb-sig.asc\n"; # read_file(file, &assoc, [&order], [lowercase]) # Fill an associative array with name=value pairs from a file sub read_file { local $_; open(ARFILE, $_[0]) || return 0; while() { chomp; local $hash = index($_, "#"); local $eq = index($_, "="); if ($hash != 0 && $eq >= 0) { local $n = substr($_, 0, $eq); local $v = substr($_, $eq+1); $_[1]->{$_[3] ? lc($n) : $n} = $v; push(@{$_[2]}, $n) if ($_[2]); } } close(ARFILE); if (defined($main::read_file_cache{$_[0]})) { %{$main::read_file_cache{$_[0]}} = %{$_[1]}; } return 1; } # wrap_lines(text, width) # Given a multi-line string, return an array of lines wrapped to # the given width sub wrap_lines { local @rv; local $w = $_[1]; local $rest; foreach $rest (split(/\n/, $_[0])) { if ($rest =~ /\S/) { while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) { push(@rv, $1); $rest = $2; } } else { # Empty line .. keep as it is push(@rv, $rest); } } return @rv; }