Move un-used modules to special category, show link to refresh
[webmin.git] / makedebian.pl
1 #!/usr/local/bin/perl
2 # Build a Debian package of Webmin
3
4 use POSIX;
5
6 if ($ARGV[0] eq "--webmail" || $ARGV[0] eq "-webmail") {
7         $webmail = 1;
8         shift(@ARGV);
9         }
10 if ($0 =~ /useradmin|usermin/ || `pwd` =~ /useradmin|usermin/) {
11         if ($webmail) {
12                 $product = "usermin-webmail";
13                 }
14         else {
15                 $product = "usermin";
16                 }
17         $baseproduct = "usermin";
18         $port = 20000;
19         }
20 else {
21         $product = "webmin";
22         $baseproduct = "webmin";
23         $port = 10000;
24         }
25 $ucproduct = ucfirst($baseproduct);
26 $tmp_dir = "/tmp/debian";
27 $debian_dir = "$tmp_dir/DEBIAN";
28 $control_file = "$debian_dir/control";
29 $usr_dir = "$tmp_dir/usr/share/$baseproduct";
30 $pam_dir = "$tmp_dir/etc/pam.d";
31 $init_dir = "$tmp_dir/etc/init.d";
32 @rc_dirs = ( "$tmp_dir/etc/rc2.d", "$tmp_dir/etc/rc3.d", "$tmp_dir/etc/rc5.d" );
33 $pam_file = "$pam_dir/$baseproduct";
34 $preinstall_file = "$debian_dir/preinst";
35 $postinstall_file = "$debian_dir/postinst";
36 $preuninstall_file = "$debian_dir/prerm";
37 $postuninstall_file = "$debian_dir/postrm";
38 $copyright_file = "$debian_dir/copyright";
39 $changelog_file = "$debian_dir/changelog";
40
41 -d "tarballs" || die "makedebian.pl must be run in the $ucproduct root directory";
42 -r "/etc/debian_version" || die "makedebian.pl must be run on Debian";
43 chop($webmin_dir = `pwd`);
44
45 @ARGV == 1 || die "usage: makedebian.pl [--webmail] <version>";
46 $ver = $ARGV[0];
47 -r "tarballs/$product-$ver.tar.gz" || die "tarballs/$product-$ver.tar.gz not found";
48
49 # Create the base directories
50 print "Creating Debian package of ",ucfirst($product)," ",$ver," ...\n";
51 system("rm -rf $tmp_dir");
52 mkdir($tmp_dir, 0755);
53 mkdir($debian_dir, 0755);
54 system("mkdir -p $pam_dir");
55 if ($baseproduct eq "usermin") {
56         system("mkdir -p $init_dir");
57         foreach $d (@rc_dirs) {
58                 system("mkdir -p $d");
59                 }
60         }
61 system("mkdir -p $usr_dir");
62
63 # Un-tar the package to the correct locations
64 system("gunzip -c tarballs/$product-$ver.tar.gz | (cd $tmp_dir ; tar xf -)") &&
65         die "un-tar failed!";
66 system("mv $tmp_dir/$product-$ver/* $usr_dir");
67 rmdir("$tmp_dir/$product-$ver");
68 system("mv $usr_dir/$baseproduct-pam $pam_file");
69 system("cd $usr_dir && (find . -name '*.cgi' ; find . -name '*.pl') | perl perlpath.pl /usr/bin/perl -");
70 system("cd $usr_dir && rm -f mount/freebsd-mounts*");
71 system("cd $usr_dir && rm -f mount/openbsd-mounts*");
72 if ($product eq "webmin") {
73         system("cd $usr_dir && rm -f mount/macos-mounts*");
74         system("cd $usr_dir && rm -f webmin-gentoo-init");
75         system("cd $usr_dir && rm -rf format bsdexports hpuxexports sgiexports zones rbac");
76         }
77 else {
78         # Need to create init script
79         system("mv $usr_dir/$baseproduct-init $init_dir/$baseproduct");
80         foreach $d (@rc_dirs) {
81                 system("ln -s ../init.d/$baseproduct $d/S99$baseproduct");
82                 }
83         }
84 system("echo deb >$usr_dir/install-type");
85 system("echo $product >$usr_dir/deb-name");
86 system("cd $usr_dir && chmod -R og-w .");
87 if ($< == 0) {
88         system("cd $usr_dir && chown -R root:bin .");
89         }
90 $size = int(`du -sk $tmp_dir`);
91
92 # Create the control file
93 open(CONTROL, ">$control_file");
94 print CONTROL <<EOF;
95 Package: $product
96 Version: $ver
97 Section: admin
98 Priority: optional
99 Architecture: all
100 Essential: no
101 Depends: bash, perl, libnet-ssleay-perl, openssl, libauthen-pam-perl, libpam-runtime, libio-pty-perl, libmd5-perl
102 Pre-Depends: bash, perl
103 Installed-Size: $size
104 Maintainer: Jamie Cameron <jcameron\@webmin.com>
105 Provides: $baseproduct
106 EOF
107 if ($product eq "webmin") {
108         print CONTROL <<EOF;
109 Replaces: webmin-adsl, webmin-apache, webmin-bandwidth, webmin-bind, webmin-burner, webmin-cfengine, webmin-cluster, webmin-core, webmin-cpan, webmin-dhcpd, webmin-exim, webmin-exports, webmin-fetchmail, webmin-firewall, webmin-freeswan, webmin-frox, webmin-fsdump, webmin-grub, webmin-heartbeat, webmin-htaccess, webmin-inetd, webmin-jabber, webmin-ldap-netgroups, webmin-ldap-user-simple, webmin-ldap-useradmin, webmin-lilo, webmin-logrotate, webmin-lpadmin, webmin-lvm, webmin-mailboxes, webmin-mon, webmin-mysql, webmin-nis, webmin-openslp, webmin-postfix, webmin-postgresql, webmin-ppp, webmin-pptp-client, webmin-pptp-server, webmin-procmail, webmin-proftpd, webmin-pserver, webmin-quota, webmin-samba, webmin-sarg, webmin-sendmail, webmin-shorewall, webmin-slbackup, webmin-smart-status, webmin-snort, webmin-software, webmin-spamassassin, webmin-squid, webmin-sshd, webmin-status, webmin-stunnel, webmin-updown, webmin-usermin, webmin-vgetty, webmin-webalizer, webmin-wuftpd, webmin-wvdial, webmin-xinetd
110 Description: A web-based administration interface for Unix systems.
111              Using Webmin you can configure DNS, Samba, NFS, local/remote
112              filesystems and more using your web browser.  After installation,
113              enter the URL https://localhost:10000/ into your browser and
114              login as root with your root password.
115 EOF
116         }
117 else {
118         print CONTROL <<EOF;
119 Replaces: usermin-at, usermin-changepass, usermin-chfn, usermin-commands, usermin-cron, usermin-cshrc, usermin-fetchmail, usermin-forward, usermin-gnupg, usermin-htaccess, usermin-htpasswd, usermin-mailbox, usermin-man, usermin-mysql, usermin-plan, usermin-postgresql, usermin-proc, usermin-procmail, usermin-quota, usermin-schedule, usermin-shell, usermin-spamassassin, usermin-ssh, usermin-tunnel, usermin-updown, usermin-usermount
120 Description: A web-based user account administration interface for Unix systems.
121              After installation, enter the URL http://localhost:20000/ into your             browser and login as any user on your system.
122 EOF
123         }
124 close(CONTROL);
125
126 # Create the copyright file
127 $nowstr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime(time()));
128 open(COPY, ">$copyright_file");
129 print COPY <<EOF;
130 This package was debianized by Jamie Cameron <jcameron\@webmin.com> on
131 $nowstr.
132
133 It was downloaded from: http://www.webmin.com/
134
135 Upstream author: Jamie Cameron <jcameron\@webmin.com>
136
137 Copyright:
138
139 EOF
140 open(BSD, "$usr_dir/LICENCE");
141 while(<BSD>) {
142         print COPY $_;
143         }
144 close(BSD);
145 close(COPY);
146
147 # Get the changes for each module and version
148 $changes = { };
149 foreach $f (sort { $a cmp $b } ( glob("*/CHANGELOG"), "CHANGELOG" )) {
150         # Get the module name and type
151         local $mod = $f =~ /^(\S+)\/CHANGELOG/ ? $1 : "core";
152         next if ($mod ne "core" && -l $mod);
153         local $desc;
154         if ($mod eq "core") {
155                 $desc = "$ucproduct Core";
156                 }
157         else {
158                 local $m = $f;
159                 local %minfo;
160                 $m =~ s/CHANGELOG/module.info/;
161                 &read_file($m, \%minfo);
162                 next if (!$minfo{'longdesc'});
163                 $desc = $minfo{'desc'};
164                 }
165
166         # Read its change log file
167         local $inversion;
168         open(LOG, $f);
169         while(<LOG>) {
170                 s/\r|\n//g;
171                 if (/^----\s+Changes\s+since\s+(\S+)\s+----/) {
172                         $inversion = $1;
173                         }
174                 elsif ($inversion && /\S/) {
175                         push(@{$changes->{$inversion}->{$desc}}, $_);
176                         }
177                 }
178         }
179
180 # Create the changelog file from actual changes, plus the historical changelog
181 open(CHANGELOG, ">$changelog_file");
182 foreach $v (sort { $a <=> $b } (keys %$changes)) {
183         if ($ver > $v && sprintf("%.2f0", $ver) == $v) {
184                 $forv = $ver;
185                 }
186         else {
187                 $forv = sprintf("%.2f0", $v+0.01);
188                 }
189         @st = stat("tarballs/webmin-$forv.tar.gz");
190         $vtimestr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime($st[9]));
191         print CHANGELOG "$baseproduct ($forv) stable; urgency=low\n";
192         print CHANGELOG "\n";
193         foreach $desc (keys %{$changes->{$v}}) {
194                 foreach $c (@{$changes->{$v}->{$desc}}) {
195                         @lines = &wrap_lines("$desc : $c", 65);
196                         print CHANGELOG " * $lines[0]\n";
197                         foreach $l (@lines[1 .. $#lines]) {
198                                 print CHANGELOG "   $l\n";
199                                 }
200                         }
201                 }
202         print CHANGELOG "\n";
203         print CHANGELOG "-- Jamie Cameron <jcameron\@webmin.com> $vtimestr\n";
204         print CHANGELOG "\n";
205         }
206 close(CHANGELOG);
207
208 # Get the temp-directory creator script
209 open(TEMP, "maketemp.pl");
210 while(<TEMP>) {
211         $maketemp .= $_;
212         }
213 close(TEMP);
214 $maketemp =~ s/\\/\\\\/g;
215 $maketemp =~ s/`/\\`/g;
216 $maketemp =~ s/\$/\\\$/g;
217
218 # Create the pre-install script
219 # No need for an OS check, as all debians are supported.
220 open(SCRIPT, ">$preinstall_file");
221 print SCRIPT <<EOF;
222 #!/bin/sh
223 perl <<EOD;
224 $maketemp
225 EOD
226 if [ "\$1" != "upgrade" ]; then
227         if [ "\$WEBMIN_PORT\" != \"\" ]; then
228                 port=\$WEBMIN_PORT
229         else
230                 port=$port
231         fi
232         perl -e 'use Socket; socket(FOO, PF_INET, SOCK_STREAM, getprotobyname("tcp")); setsockopt(FOO, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); bind(FOO, pack_sockaddr_in(\$ARGV[0], INADDR_ANY)) || exit(1); exit(0);' \$port
233         if [ "\$?" != "0" ]; then
234                 echo Port \$port is already in use
235                 exit 2
236         fi
237 fi
238 EOF
239 close(SCRIPT);
240 system("chmod 755 $preinstall_file");
241
242 # Create the post-install script
243 open(SCRIPT, ">$postinstall_file");
244 print SCRIPT <<EOF;
245 #!/bin/sh
246 inetd=`grep "^inetd=" /etc/$baseproduct/miniserv.conf 2>/dev/null | sed -e 's/inetd=//g'`
247 if [ "\$1" = "upgrade" ]; then
248         # Upgrading the package, so stop the old webmin properly
249         if [ "\$inetd" != "1" ]; then
250                 /etc/init.d/$baseproduct stop >/dev/null 2>&1 </dev/null
251         fi
252 fi
253 cd /usr/share/$baseproduct
254 config_dir=/etc/$baseproduct
255 var_dir=/var/$baseproduct
256 perl=/usr/bin/perl
257 autoos=3
258 if [ "\$WEBMIN_PORT\" != \"\" ]; then
259         port=\$WEBMIN_PORT
260 else
261         port=$port
262 fi
263 login=root
264 if [ -r /etc/shadow ]; then
265         crypt=x
266 else
267         crypt=`grep "^root:" /etc/passwd | cut -f 2 -d :`
268 fi
269 host=`hostname`
270 ssl=1
271 atboot=1
272 nochown=1
273 autothird=1
274 noperlpath=1
275 nouninstall=1
276 nostart=1
277 export config_dir var_dir perl autoos port login crypt host ssl nochown autothird noperlpath nouninstall nostart allow atboot
278 ./setup.sh >/tmp/.webmin/$product-setup.out 2>&1
279 if [ "$product" = "webmin" ]; then
280         grep sudo= /etc/$product/miniserv.conf >/dev/null 2>&1
281         if [ "\$?" = 1 ]; then
282                 # Allow sudo-based logins for Ubuntu
283                 echo sudo=1 >>/etc/$product/miniserv.conf
284         fi
285 fi
286 rm -f /var/lock/subsys/$baseproduct
287 if [ "$inetd" != "1" ]; then
288         if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
289                 invoke-rc.d $baseproduct start >/dev/null 2>&1 </dev/null
290         else
291                 /etc/init.d/$baseproduct start >/dev/null 2>&1 </dev/null
292         fi
293 fi
294 cat >/etc/$baseproduct/uninstall.sh <<EOFF
295 #!/bin/sh
296 printf "Are you sure you want to uninstall $ucproduct? (y/n) : "
297 read answer
298 printf "\\n"
299 if [ "\\\$answer" = "y" ]; then
300         echo "Removing $ucproduct package .."
301         dpkg --remove $product
302         echo "Done!"
303 fi
304 EOFF
305 chmod +x /etc/$baseproduct/uninstall.sh
306 port=`grep "^port=" /etc/$baseproduct/miniserv.conf | sed -e 's/port=//g'`
307 perl -e 'use Net::SSLeay' >/dev/null 2>/dev/null
308 sslmode=0
309 if [ "\$?" = "0" ]; then
310         grep ssl=1 /etc/$baseproduct/miniserv.conf >/dev/null 2>/dev/null
311         if [ "\$?" = "0" ]; then
312                 sslmode=1
313         fi
314 fi
315 if [ "\$sslmode" = "1" ]; then
316         echo "$ucproduct install complete. You can now login to https://\$host:\$port/"
317 else
318         echo "$ucproduct install complete. You can now login to http://\$host:\$port/"
319 fi
320 if [ "$product" = "webmin" ]; then
321         echo "as root with your root password, or as any user who can use sudo"
322         echo "to run commands as root."
323 else
324         echo "as any user on the system."
325 fi
326 EOF
327 close(SCRIPT);
328 system("chmod 755 $postinstall_file");
329
330 # Create the pre-uninstall script
331 open(SCRIPT, ">$preuninstall_file");
332 print SCRIPT <<EOF;
333 #!/bin/sh
334 if [ "\$1" != "upgrade" ]; then
335         grep root=/usr/share/$baseproduct /etc/$baseproduct/miniserv.conf >/dev/null 2>&1
336         if [ "\$?" = 0 ]; then
337                 # Package is being removed, and no new version of webmin
338                 # has taken it's place. Run uninstalls and stop the server
339                 if [ "$product" = "webmin" ]; then
340                         echo "Running uninstall scripts .."
341                         (cd /usr/share/$baseproduct ; WEBMIN_CONFIG=/etc/$baseproduct WEBMIN_VAR=/var/$baseproduct LANG= /usr/share/$baseproduct/run-uninstalls.pl)
342                 fi
343                 /etc/init.d/$baseproduct stop >/dev/null 2>&1 </dev/null
344                 /etc/$baseproduct/stop >/dev/null 2>&1 </dev/null
345                 /bin/true
346         fi
347 fi
348 EOF
349 close(SCRIPT);
350 system("chmod 755 $preuninstall_file");
351
352 # Create the post-uninstall script
353 open(SCRIPT, ">$postuninstall_file");
354 print SCRIPT <<EOF;
355 #!/bin/sh
356 if [ "\$1" != "upgrade" ]; then
357         grep root=/usr/share/$baseproduct /etc/$baseproduct/miniserv.conf >/dev/null 2>&1
358         if [ "\$?" = 0 ]; then
359                 # Package is being removed, and no new version of webmin
360                 # has taken it's place. Delete the config files
361                 rm -rf /etc/$baseproduct /var/$baseproduct
362         fi
363 fi
364 EOF
365 close(SCRIPT);
366 system("chmod 755 $postuninstall_file");
367
368 # Run the actual build command
369 system("fakeroot dpkg --build $tmp_dir deb/${product}_${ver}_all.deb") &&
370         die "dpkg failed";
371 #system("rm -rf $tmp_dir");
372 print "Wrote deb/${product}_${ver}_all.deb\n";
373 $md5 = `md5sum tarballs/$product-$ver.tar.gz`;
374 $md5 =~ s/\s+.*\n//g;
375 @st = stat("tarballs/$product-$ver.tar.gz");
376
377 # Create the .diff file, which just contains the debian directory
378 $diff_orig_dir = "$tmp_dir/$product-$ver-orig";
379 $diff_new_dir = "$tmp_dir/$product-$ver";
380 mkdir($diff_orig_dir, 0755);
381 mkdir($diff_new_dir, 0755);
382 system("cp -r $debian_dir $diff_new_dir");
383 system("cd $tmp_dir && diff -r -N -u $product-$ver-orig $product-$ver >$webmin_dir/deb/${product}_${ver}.diff");
384 $diffmd5 = `md5sum deb/${product}_${ver}.diff`;
385 $diffmd5 =~ s/\s+.*\n//g;
386 @diffst = stat("deb/${product}_${ver}.diff");
387
388 # Create the .dsc file
389 open(DSC, ">deb/${product}_$ver.plain");
390 print DSC <<EOF;
391 Format: 1.0
392 Source: $product
393 Version: $ver
394 Binary: $product
395 Maintainer: Jamie Cameron <jcameron\@webmin.com>
396 Architecture: all
397 Standards-Version: 3.6.1
398 Build-Depends-Indep: debhelper (>= 4.1.16), debconf (>= 0.5.00), perl
399 Uploaders: Jamie Cameron <jcameron\@webmin.com>
400 Files:
401  $md5 $st[7] ${product}-${ver}.tar.gz
402  $diffmd5 $diffst[7] ${product}_${ver}.diff
403
404 EOF
405 close(DSC);
406 unlink("deb/${product}_$ver.dsc");
407 system("gpg --output deb/${product}_$ver.dsc --clearsign deb/${product}_$ver.plain");
408 unlink("deb/${product}_$ver.plain");
409 print "Wrote source deb/${product}_$ver.dsc\n";
410
411 if (!$webmail) {
412         # Add to our repository
413         chdir("/usr/local/webadmin/deb/repository");
414         system("reprepro -Vb . remove sarge $product");
415         system("reprepro -Vb . includedeb sarge ../${product}_${ver}_all.deb");
416         }
417
418 # read_file(file, &assoc, [&order], [lowercase])
419 # Fill an associative array with name=value pairs from a file
420 sub read_file
421 {
422 local $_;
423 open(ARFILE, $_[0]) || return 0;
424 while(<ARFILE>) {
425         chomp;
426         local $hash = index($_, "#");
427         local $eq = index($_, "=");
428         if ($hash != 0 && $eq >= 0) {
429                 local $n = substr($_, 0, $eq);
430                 local $v = substr($_, $eq+1);
431                 $_[1]->{$_[3] ? lc($n) : $n} = $v;
432                 push(@{$_[2]}, $n) if ($_[2]);
433                 }
434         }
435 close(ARFILE);
436 if (defined($main::read_file_cache{$_[0]})) {
437         %{$main::read_file_cache{$_[0]}} = %{$_[1]};
438         }
439 return 1;
440 }
441
442 # wrap_lines(text, width)
443 # Given a multi-line string, return an array of lines wrapped to
444 # the given width
445 sub wrap_lines
446 {
447 local @rv;
448 local $w = $_[1];
449 local $rest;
450 foreach $rest (split(/\n/, $_[0])) {
451         if ($rest =~ /\S/) {
452                 while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) {
453                         push(@rv, $1);
454                         $rest = $2;
455                         }
456                 }
457         else {
458                 # Empty line .. keep as it is
459                 push(@rv, $rest);
460                 }
461         }
462 return @rv;
463 }
464
465