3 # Create a Debian package for a webmin or usermin module or theme
8 $email = "Jamie Cameron <jcameron\@webmin.com>";
11 $tmp_dir = "/tmp/debian-module";
12 $debian_dir = "$tmp_dir/DEBIAN";
13 $control_file = "$debian_dir/control";
14 $preinstall_file = "$debian_dir/preinst";
15 $postinstall_file = "$debian_dir/postinst";
16 $preuninstall_file = "$debian_dir/prerm";
17 $postuninstall_file = "$debian_dir/postrm";
18 $copyright_file = "$debian_dir/copyright";
19 $changelog_file = "$debian_dir/changelog";
20 $files_file = "$debian_dir/files";
22 -r "/etc/debian_version" || die "makemoduledeb.pl must be run on Debian";
24 # Parse command-line args
26 local $a = shift(@ARGV);
27 if ($a eq "--force-theme") {
30 elsif ($a eq "--licence" || $a eq "--license") {
31 $licence = shift(@ARGV);
33 elsif ($a eq "--email") {
34 $email = shift(@ARGV);
36 elsif ($a eq "--url") {
39 elsif ($a eq "--upstream") {
40 $upstream = shift(@ARGV);
42 elsif ($a eq "--deb-depends") {
45 elsif ($a eq "--no-prefix") {
48 elsif ($a eq "--usermin") {
51 elsif ($a eq "--target-dir") {
52 $target_dir = shift(@ARGV);
54 elsif ($a eq "--dir") {
55 $final_mod = shift(@ARGV);
57 elsif ($a eq "--allow-overwrite") {
60 elsif ($a eq "--dsc-file") {
61 $dsc_file = shift(@ARGV);
63 elsif ($a =~ /^\-\-/) {
64 print STDERR "Unknown option $a\n";
79 print STDERR "usage: makemoduledeb.pl [--force-theme]\n";
80 print STDERR " [--deb-depends]\n";
81 print STDERR " [--no-prefix]\n";
82 print STDERR " [--licence name]\n";
83 print STDERR " [--email 'name <address>']\n";
84 print STDERR " [--upstream 'name <address>']\n";
85 print STDERR " [--provides provides]\n";
86 print STDERR " [--usermin]\n";
87 print STDERR " [--target-dir directory]\n";
88 print STDERR " [--dir directory-in-package]\n";
89 print STDERR " [--allow-overwrite]\n";
90 print STDERR " [--dsc-file file.dsc]\n";
91 print STDERR " <module> [version]\n";
94 chop($par = `dirname $dir`);
95 chop($source_mod = `basename $dir`);
96 $source_dir = "$par/$source_mod";
97 $mod = $final_mod || $source_mod;
98 if ($mod eq "." || $mod eq "..") {
99 die "directory must be an actual directory (module) name, not \"$mod\"";
102 # Is this actually a module or theme directory?
103 -d $source_dir || die "$source_dir is not a directory";
104 if (&read_file("$source_dir/module.info", \%minfo) && $minfo{'desc'}) {
105 $depends = join(" ", map { s/\/[0-9\.]+//; $_ }
106 grep { !/^[0-9\.]+$/ }
107 split(/\s+/, $minfo{'depends'}));
108 if ($minfo{'usermin'} && (!$minfo{'webmin'} || $force_usermin)) {
109 $prefix = "usermin-";
110 $desc = "Usermin module for '$minfo{'desc'}'";
111 $product = "usermin";
115 $desc = "Webmin module for '$minfo{'desc'}'";
118 $iver = $minfo{'version'};
121 elsif (&read_file("$source_dir/theme.info", \%tinfo) && $tinfo{'desc'}) {
122 if ($tinfo{'usermin'} && (!$tinfo{'usermin'} || $force_usermin)) {
123 $prefix = "usermin-";
124 $desc = "Usermin theme '$tinfo{'desc'}'";
125 $product = "usermin";
129 $desc = "Webmin theme '$tinfo{'desc'}'";
132 $iver = $tinfo{'version'};
137 die "$source_dir does not appear to be a webmin module or theme";
139 $prefix = "" if ($no_prefix);
140 $usr_dir = "$tmp_dir/usr/share/$product";
141 $ucproduct = ucfirst($product);
142 $ver ||= $iver; # Use module.info version, or 1
144 $upstream ||= $email;
146 # Create the base directories
147 system("rm -rf $tmp_dir");
148 mkdir($tmp_dir, 0755);
149 mkdir($debian_dir, 0755);
150 system("mkdir -p $usr_dir");
152 # Copy the directory to a temp directory
153 system("cp -r -p -L $source_dir $usr_dir/$mod");
154 system("echo deb >$usr_dir/$mod/install-type");
155 system("cd $usr_dir && chmod -R og-w .");
157 system("cd $usr_dir && chown -R root:bin .");
159 $size = int(`du -sk $tmp_dir`);
160 system("find $usr_dir -name .svn | xargs rm -rf");
161 system("find $usr_dir -name .xvpics | xargs rm -rf");
162 system("find $usr_dir -name '*.bak' | xargs rm -rf");
163 system("find $usr_dir -name '*~' | xargs rm -rf");
164 system("find $usr_dir -name '*.rej' | xargs rm -rf");
165 system("find $usr_dir -name core | xargs rm -rf");
168 system("(find $usr_dir -name '*.cgi' ; find $usr_dir -name '*.pl') | perl -ne 'chop; open(F,\$_); \@l=<F>; close(F); \$l[0] = \"#\!/usr/bin/perl\$1\n\" if (\$l[0] =~ /#\!\\S*perl\\S*(.*)/); open(F,\">\$_\"); print F \@l; close(F)'");
169 system("(find $usr_dir -name '*.cgi' ; find $usr_dir -name '*.pl') | xargs chmod +x");
171 # Build list of dependencies on other Debian packages, for inclusion as a
173 @rdeps = ( "base", "perl", $product );
175 foreach $d (split(/\s+/, $minfo{'depends'})) {
176 local ($dwebmin, $dmod, $dver);
177 if ($d =~ /^[0-9\.]+$/) {
178 # Depends on a version of Webmin
181 elsif ($d =~ /^(\S+)\/([0-9\.]+)$/) {
182 # Depends on some version of a module
187 # Depends on any version of a module
191 # If the module is part of Webmin, we don't need to depend on it
194 &read_file("$dmod/module.info", \%dinfo);
195 next if ($dinfo{'longdesc'});
197 push(@rdeps, $dwebmin ? ("$product (>= $dwebmin)") :
198 $dver ? ("$prefix$dmod (>= $dver)") :
202 $rdeps = join(", ", @rdeps);
204 # Create the control file
205 open(CONTROL, ">$control_file");
214 Pre-Depends: bash, perl
215 Installed-Size: $size
217 Provides: $prefix$mod
222 # Create the copyright file
223 $nowstr = strftime("%a, %d %b %Y %H:%M:%S %z", localtime(time()));
224 open(COPY, ">$copyright_file");
225 print COPY "This package was debianized by $email on\n";
226 print COPY "$nowstr.\n";
229 print COPY "It was downloaded from: $url\n";
232 print COPY "Upstream author: $upstream\n";
234 print COPY "Copyright: $licence\n";
237 # Read the module's CHANGELOG file
239 $f = "$usr_dir/$mod/CHANGELOG";
241 # Read its change log file
246 if (/^----\s+Changes\s+since\s+(\S+)\s+----/) {
249 elsif ($inversion && /\S/) {
250 push(@{$changes->{$inversion}}, $_);
256 # Create the changelog file from actual changes
258 open(CHANGELOG, ">$changelog_file");
259 foreach $v (sort { $a <=> $b } (keys %$changes)) {
260 if ($ver > $v && sprintf("%.2f0", $ver) == $v) {
264 $forv = sprintf("%.2f0", $v+0.01);
266 print CHANGELOG "$prefix$mod ($forv) stable; urgency=low\n";
267 print CHANGELOG "\n";
268 foreach $c (@{$changes->{$v}}) {
269 @lines = &wrap_lines($c, 65);
270 print CHANGELOG " * $lines[0]\n";
271 foreach $l (@lines[1 .. $#lines]) {
272 print CHANGELOG " $l\n";
275 print CHANGELOG "\n";
276 print CHANGELOG "-- $email\n";
277 print CHANGELOG "\n";
282 # Create the pre-install script, which checks if Webmin is installed
283 open(SCRIPT, ">$preinstall_file");
286 if [ ! -r /etc/$product/config -o ! -d /usr/share/$product ]; then
287 echo "$ucproduct does not appear to be installed on your system."
288 echo "This package cannot be installed unless the Debian version of $ucproduct"
289 echo "is installed first."
292 if [ "$depends" != "" -a "$debdepends" != 1 ]; then
293 # Check if depended webmin/usermin modules are installed
294 for d in $depends; do
295 if [ ! -r /usr/share/$product/\$d/module.info ]; then
296 echo "This $ucproduct module depends on the module \$d, which is"
297 echo "not installed on your system."
302 # Check if this module is already installed
303 if [ -d /usr/share/$product/$mod -a "\$1" != "upgrade" -a "\$allow_overwrite" != "1" ]; then
304 echo "This $ucproduct module is already installed on your system."
309 system("chmod 755 $preinstall_file");
311 # Create the post-install script
312 open(SCRIPT, ">$postinstall_file");
315 if [ "$post_config" = "1" ]; then
316 # Copy config file to /etc/webmin or /etc/usermin
317 os_type=`grep "^os_type=" /etc/$product/config | sed -e 's/os_type=//g'`
318 os_version=`grep "^os_version=" /etc/$product/config | sed -e 's/os_version=//g'`
319 /usr/bin/perl /usr/share/$product/copyconfig.pl \$os_type \$os_version /usr/share/$product /etc/$product $mod
321 # Update the ACL for the root user, or the first user in the ACL
322 grep "^root:" /etc/$product/webmin.acl >/dev/null
323 if [ "\$?" = "0" ]; then
326 user=`head -1 /etc/$product/webmin.acl | cut -f 1 -d :`
328 mods=`grep \$user: /etc/$product/webmin.acl | cut -f 2 -d :`
329 echo \$mods | grep " $mod" >/dev/null
330 if [ "\$?" != "0" ]; then
331 grep -v ^\$user: /etc/$product/webmin.acl > /tmp/webmin.acl.tmp
332 echo \$user: \$mods $mod > /etc/$product/webmin.acl
333 cat /tmp/webmin.acl.tmp >> /etc/$product/webmin.acl
334 rm -f /tmp/webmin.acl.tmp
337 if [ "$force_theme" != "" -a "$istheme" = "1" ]; then
338 # Activate this theme
339 grep -v "^preroot=" /etc/$product/miniserv.conf >/etc/$product/miniserv.conf.tmp
340 (cat /etc/$product/miniserv.conf.tmp ; echo preroot=$mod) > /etc/$product/miniserv.conf
341 rm -f /etc/$product/miniserv.conf.tmp
342 grep -v "^theme=" /etc/$product/config >/etc/$product/config.tmp
343 (cat /etc/$product/config.tmp ; echo theme=$mod) > /etc/$product/config
344 rm -f /etc/$product/config.tmp
345 (/etc/$product/stop && /etc/$product/start) >/dev/null 2>&1
347 rm -f /etc/$product/module.infos.cache
349 # Run post-install function
350 if [ "$product" = "webmin" ]; then
351 cd /usr/share/$product
352 WEBMIN_CONFIG=/etc/$product WEBMIN_VAR=/var/$product /usr/share/$product/run-postinstalls.pl $mod
355 # Run post-install shell script
356 if [ -r "/usr/share/$product/$mod/postinstall.sh" ]; then
357 cd /usr/share/$product
358 WEBMIN_CONFIG=/etc/$product WEBMIN_VAR=/var/$product /usr/share/$product/$mod/postinstall.sh
362 system("chmod 755 $postinstall_file");
364 # Create the pre-uninstall script
365 open(SCRIPT, ">$preuninstall_file");
368 # De-activate this theme, if in use and if we are not upgrading
369 if [ "$istheme" = "1" -a "\$1" != "upgrade" ]; then
370 grep "^preroot=$mod" /etc/$product/miniserv.conf >/dev/null
371 if [ "\$?" = "0" ]; then
372 grep -v "^preroot=$mod" /etc/$product/miniserv.conf >/etc/$product/miniserv.conf.tmp
373 (cat /etc/$product/miniserv.conf.tmp) > /etc/$product/miniserv.conf
374 rm -f /etc/$product/miniserv.conf.tmp
375 grep -v "^theme=$mod" /etc/$product/config >/etc/$product/config.tmp
376 (cat /etc/$product/config.tmp) > /etc/$product/config
377 rm -f /etc/$product/config.tmp
378 (/etc/$product/stop && /etc/$product/start) >/dev/null 2>&1
381 # Run the pre-uninstall script, if we are not upgrading
382 if [ "$product" = "webmin" -a "\$1" = "0" -a -r "/usr/share/$product/$mod/uninstall.pl" ]; then
383 cd /usr/share/$product
384 WEBMIN_CONFIG=/etc/$product WEBMIN_VAR=/var/$product /usr/share/$product/run-uninstalls.pl $mod
389 system("chmod 755 $preuninstall_file");
391 # Run the actual build command
392 system("fakeroot dpkg --build $tmp_dir $target_dir/${prefix}${mod}_${ver}_all.deb") &&
394 print "Wrote $target_dir/${prefix}${mod}_${ver}_all.deb\n";
396 # Create the .dsc file, if requested
398 # Create the .diff file, which just contains the debian directory
399 $diff_file = $dsc_file;
400 $diff_file =~ s/[^\/]+$//; $diff_file .= "$prefix$mod-$ver.diff";
401 $diff_orig_dir = "$tmp_dir/$prefix$mod-$ver-orig";
402 $diff_new_dir = "$tmp_dir/$prefix$mod-$ver";
403 mkdir($diff_orig_dir, 0755);
404 mkdir($diff_new_dir, 0755);
405 system("cp -r $debian_dir $diff_new_dir");
406 system("cd $tmp_dir && diff -r -N -u $prefix$mod-$ver-orig $prefix$mod-$ver >$diff_file");
407 $diffmd5 = `md5sum $diff_file`;
408 $diffmd5 =~ s/\s+.*\n//g;
409 @diffst = stat($diff_file);
411 # Create a tar file of the module directory
412 $tar_file = $dsc_file;
413 $tar_file =~ s/[^\/]+$//; $tar_file .= "$prefix$mod-$ver.tar.gz";
414 system("cd $par ; tar czf $tar_file $source_mod");
415 $md5 = `md5sum $tar_file`;
416 $md5 =~ s/\s+.*\n//g;
417 @st = stat($tar_file);
419 # Finally create the .dsc
420 open(DSC, ">$dsc_file");
428 Standards-Version: 3.6.1
429 Build-Depends-Indep: debhelper (>= 4.1.16), debconf (>= 0.5.00), perl
430 Uploaders: Jamie Cameron <jcameron\@webmin.com>
432 $md5 $st[7] ${prefix}${mod}-$ver.tar.gz
433 $diffmd5 $diffst[7] ${prefix}${mod}-${ver}.diff
439 system("rm -rf $tmp_dir");
441 # read_file(file, &assoc, [&order], [lowercase])
442 # Fill an associative array with name=value pairs from a file
445 open(ARFILE, $_[0]) || return 0;
448 if (!/^#/ && /^([^=]+)=(.*)$/) {
449 $_[1]->{$_[3] ? lc($1) : $1} = $2;
450 push(@{$_[2]}, $1) if ($_[2]);
457 # wrap_lines(text, width)
458 # Given a multi-line string, return an array of lines wrapped to
465 foreach $rest (split(/\n/, $_[0])) {
467 while($rest =~ /^(.{1,$w}\S*)\s*([\0-\377]*)$/) {
473 # Empty line .. keep as it is