Add module makers to repo
[webmin.git] / makemodulerpm.pl
1 #!/usr/bin/perl
2 # makemodulerpm.pl
3 # Create an RPM for a webmin or usermin module or theme
4
5 $target_dir = "/tmp";   # where to copy the RPM to
6
7 if (-d "/usr/src/OpenLinux") {
8         $basedir = "/usr/src/OpenLinux";
9         }
10 else {
11         $basedir = "/usr/src/redhat";
12         }
13 $licence = "Freeware";
14 $release = 1;
15 $< = $>;                # If running setuid
16 $ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin";
17
18 # Parse command-line args
19 while(@ARGV) {
20         local $a = &untaint(shift(@ARGV));
21         if ($a eq "--force-theme") {
22                 $force_theme = 1;
23                 }
24         elsif ($a eq "--rpm-dir") {
25                 $basedir = &untaint(shift(@ARGV));
26                 }
27         elsif ($a eq "--licence" || $a eq "--license") {
28                 $licence = &untaint(shift(@ARGV));
29                 }
30         elsif ($a eq "--rpm-depends") {
31                 $rpmdepends = 1;
32                 }
33         elsif ($a eq "--no-prefix") {
34                 $no_prefix = 1;
35                 }
36         elsif ($a eq "--vendor") {
37                 $vendor = &untaint(shift(@ARGV));
38                 }
39         elsif ($a eq "--provides") {
40                 $provides = &untaint(shift(@ARGV));
41                 }
42         elsif ($a eq "--url") {
43                 $url = shift(@ARGV);
44                 }
45         elsif ($a eq "--release") {
46                 $release = &untaint(shift(@ARGV));
47                 }
48         elsif ($a eq "--usermin") {
49                 $force_usermin = 1;
50                 }
51         elsif ($a eq "--target-dir") {
52                 $target_dir = &untaint(shift(@ARGV));
53                 }
54         elsif ($a eq "--dir") {
55                 $final_mod = &untaint(shift(@ARGV));
56                 }
57         elsif ($a eq "--requires") {
58                 push(@extrareqs, shift(@ARGV));
59                 }
60         elsif ($a eq "--allow-overwrite") {
61                 $allow_overwrite = 1;
62                 }
63         elsif ($a =~ /^\-\-/) {
64                 print STDERR "Unknown option $a\n";
65                 exit(1);
66                 }
67         else {
68                 if (!defined($dir)) {
69                         $dir = $a;
70                         }
71                 else {
72                         $ver = $a;
73                         }
74                 }
75         }
76
77 # Validate args
78 if (!$dir) {
79         print STDERR "usage: makemodulerpm.pl [--force-theme]\n";
80         print STDERR "                        [--rpm-dir directory]\n";
81         print STDERR "                        [--rpm-depends]\n";
82         print STDERR "                        [--no-prefix]\n";
83         print STDERR "                        [--vendor name]\n";
84         print STDERR "                        [--licence name]\n";
85         print STDERR "                        [--url url]\n";
86         print STDERR "                        [--provides provides]\n";
87         print STDERR "                        [--usermin]\n";
88         print STDERR "                        [--release number]\n";
89         print STDERR "                        [--target-dir directory]\n";
90         print STDERR "                        [--dir directory-in-package]\n";
91         print STDERR "                        [--allow-overwrite]\n";
92         print STDERR "                        <module> [version]\n";
93         exit(1);
94         }
95 chop($par = `/usr/bin/dirname $dir`);
96 $par = &untaint($par);
97 chop($source_mod = `/bin/basename $dir`);
98 $source_mod = &untaint($source_mod);
99 $source_dir = "$par/$source_mod";
100 $mod = $final_mod || $source_mod;
101 if (!-d $basedir) {
102         die "RPM directory $basedir does not exist";
103         }
104 if ($mod eq "." || $mod eq "..") {
105         die "directory must be an actual directory (module) name, not \"$mod\"";
106         }
107 $spec_dir = "$basedir/SPECS";
108 $rpm_source_dir = "$basedir/SOURCES";
109 $rpm_dir = "$basedir/RPMS/noarch";
110 if (!-d $spec_dir || !-d $rpm_source_dir || !-d $rpm_dir) {
111         die "RPM directory $basedir is not valid";
112         }
113
114 # Is this actually a module or theme directory?
115 -d $source_dir || die "$dir is not a directory";
116 if (&read_file("$source_dir/module.info", \%minfo) && $minfo{'desc'}) {
117         $depends = join(" ", map { s/\/[0-9\.]+//; $_ }
118                                 grep { !/^[0-9\.]+$/ }
119                                   split(/\s+/, $minfo{'depends'}));
120         if ($minfo{'usermin'} && (!$minfo{'webmin'} || $force_usermin)) {
121                 $prefix = "usm-";
122                 $desc = "Usermin module for '$minfo{'desc'}'";
123                 $prog = "usermin";
124                 }
125         else {
126                 $prefix = "wbm-";
127                 $desc = "Webmin module for '$minfo{'desc'}'";
128                 $prog = "webmin";
129                 }
130         $iver = $minfo{'version'};
131         $post_config = 1;
132         }
133 elsif (&read_file("$source_dir/theme.info", \%tinfo) && $tinfo{'desc'}) {
134         if ($tinfo{'usermin'} && (!$tinfo{'usermin'} || $force_usermin)) {
135                 $prefix = "ust-";
136                 $desc = "Usermin theme '$tinfo{'desc'}'";
137                 $prog = "usermin";
138                 }
139         else {
140                 $prefix = "wbt-";
141                 $desc = "Webmin theme '$tinfo{'desc'}'";
142                 $prog = "webmin";
143                 }
144         $iver = $tinfo{'version'};
145         $istheme = 1;
146         $post_config = 0;
147         }
148 else {
149         die "$source_dir does not appear to be a webmin module or theme";
150         }
151 $prefix = "" if ($no_prefix);
152 $ucprog = ucfirst($prog);
153 $ver ||= $iver;         # Use module.info version, or 1
154 $ver ||= 1;
155
156 # Copy the directory to a temp location for tarring
157 system("/bin/mkdir -p /tmp/makemodulerpm");
158 system("cd $par && /bin/cp -rpL $source_mod /tmp/makemodulerpm/$mod");
159 system("/usr/bin/find /tmp/makemodulerpm -name .svn | xargs rm -rf");
160 system("/usr/bin/find /tmp/makemodulerpm -name .xvpics | xargs rm -rf");
161 system("/usr/bin/find /tmp/makemodulerpm -name '*.bak' | xargs rm -rf");
162 system("/usr/bin/find /tmp/makemodulerpm -name '*~' | xargs rm -rf");
163 system("/usr/bin/find /tmp/makemodulerpm -name '*.rej' | xargs rm -rf");
164 system("/usr/bin/find /tmp/makemodulerpm -name core | xargs rm -rf");
165 system("/bin/chown -R root:bin /tmp/makemodulerpm/$mod");
166
167 # Tar up the directory
168 system("cd /tmp/makemodulerpm && tar czhf $rpm_source_dir/$mod.tar.gz $mod");
169 system("/bin/rm -rf /tmp/makemodulerpm");
170
171 # Build list of dependencies on other RPMs, for inclusion as an RPM
172 # Requires: header
173 if ($rpmdepends) {
174         foreach $d (split(/\s+/, $minfo{'depends'})) {
175                 local ($dwebmin, $dmod, $dver);
176                 if ($d =~ /^[0-9\.]+$/) {
177                         # Depends on a version of Webmin
178                         $dwebmin = $d;
179                         }
180                 elsif ($d =~ /^(\S+)\/([0-9\.]+)$/) {
181                         # Depends on some version of a module
182                         $dmod = $1;
183                         $dver = $2;
184                         }
185                 else {
186                         # Depends on any version of a module
187                         $dmod = $d;
188                         }
189
190                 # If the module is part of Webmin, we don't need to depend on it
191                 if ($dmod) {
192                         local %dinfo;
193                         &read_file("$dmod/module.info", \%dinfo);
194                         next if ($dinfo{'longdesc'});
195                         }
196                 push(@rdeps, $dwebmin ? ("webmin", ">=", $dwebmin) :
197                              $dver ? ($prefix.$dmod, ">=", $dver) :
198                                      ($prefix.$dmod));
199                 }
200         }
201 $rdeps = join(" ", @rdeps, @extrareqs);
202
203 # Create the SPEC file
204 $providesheader = $provides ? "Provides: $provides" : undef;
205 $vendorheader = $vendor ? "Vendor: $vendor" : undef;
206 $urlheader = $url ? "URL: $url" : undef;
207 open(SPEC, ">$spec_dir/$prefix$mod.spec");
208 print SPEC <<EOF;
209 %define __spec_install_post %{nil}
210
211 Summary: $desc
212 Name: $prefix$mod
213 Version: $ver
214 Release: $release
215 PreReq: /bin/sh /usr/bin/perl /usr/libexec/$prog
216 Requires: /bin/sh /usr/bin/perl /usr/libexec/$prog $rdeps
217 AutoReq: 0
218 License: $licence
219 Group: System/Tools
220 Source: $mod.tar.gz
221 Vendor: Jamie Cameron
222 BuildRoot: /tmp/%{name}-%{version}
223 BuildArchitectures: noarch
224 $providesheader
225 $vendorheader
226 $urlheader
227 %description
228 $desc in RPM format
229
230 %prep
231 %setup -n $mod
232
233 %build
234 (find . -name '*.cgi' ; find . -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)'
235 (find . -name '*.cgi' ; find . -name '*.pl') | xargs chmod +x
236
237 %install
238 mkdir -p %{buildroot}/usr/libexec/$prog/$mod
239 cp -rp * %{buildroot}/usr/libexec/$prog/$mod
240 echo rpm >%{buildroot}/usr/libexec/$prog/$mod/install-type
241
242 %clean
243 [ "%{buildroot}" != "/" ] && rm -rf %{buildroot}
244
245 %files
246 /usr/libexec/$prog/$mod
247
248 %pre
249 # Check if webmin/usermin is installed
250 if [ ! -r /etc/$prog/config -o ! -d /usr/libexec/$prog ]; then
251         echo "$ucprog does not appear to be installed on your system."
252         echo "This RPM cannot be installed unless the RPM version of $ucprog"
253         echo "is installed first."
254         exit 1
255 fi
256 if [ "$depends" != "" -a "$rpmdepends" != 1 ]; then
257         # Check if depended webmin/usermin modules are installed
258         for d in $depends; do
259                 if [ ! -r /usr/libexec/$prog/\$d/module.info ]; then
260                         echo "This $ucprog module depends on the module \$d, which is"
261                         echo "not installed on your system."
262                         exit 1
263                 fi
264         done
265 fi
266 # Check if this module is already installed
267 if [ -d /usr/libexec/$prog/$mod -a "\$1" = "1" -a "\$allow_overwrite" != "1" ]; then
268         echo "This $ucprog module is already installed on your system."
269         exit 1
270 fi
271
272 %post
273 if [ "$post_config" = "1" ]; then
274         # Copy config file to /etc/webmin or /etc/usermin
275         os_type=`grep "^os_type=" /etc/$prog/config | sed -e 's/os_type=//g'`
276         os_version=`grep "^os_version=" /etc/$prog/config | sed -e 's/os_version=//g'`
277         /usr/bin/perl /usr/libexec/$prog/copyconfig.pl \$os_type \$os_version /usr/libexec/$prog /etc/$prog $mod
278
279         # Update the ACL for the root user, or the first user in the ACL
280         grep "^root:" /etc/$prog/webmin.acl >/dev/null
281         if [ "\$?" = "0" ]; then
282                 user=root
283         else
284                 user=`head -1 /etc/$prog/webmin.acl | cut -f 1 -d :`
285         fi
286         mods=`grep \$user: /etc/$prog/webmin.acl | cut -f 2 -d :`
287         echo \$mods | grep " $mod" >/dev/null
288         if [ "\$?" != "0" ]; then
289                 grep -v ^\$user: /etc/$prog/webmin.acl > /tmp/webmin.acl.tmp
290                 echo \$user: \$mods $mod > /etc/$prog/webmin.acl
291                 cat /tmp/webmin.acl.tmp >> /etc/$prog/webmin.acl
292                 rm -f /tmp/webmin.acl.tmp
293         fi
294 fi
295 if [ "$force_theme" != "" -a "$istheme" = "1" ]; then
296         # Activate this theme
297         grep -v "^preroot=" /etc/$prog/miniserv.conf >/etc/$prog/miniserv.conf.tmp
298         (cat /etc/$prog/miniserv.conf.tmp ; echo preroot=$mod) > /etc/$prog/miniserv.conf
299         rm -f /etc/$prog/miniserv.conf.tmp
300         grep -v "^theme=" /etc/$prog/config >/etc/$prog/config.tmp
301         (cat /etc/$prog/config.tmp ; echo theme=$mod) > /etc/$prog/config
302         rm -f /etc/$prog/config.tmp
303         (/etc/$prog/stop && /etc/$prog/start) >/dev/null 2>&1
304 fi
305 rm -f /etc/$prog/module.infos.cache
306
307 # Run post-install function
308 if [ "$prog" = "webmin" ]; then
309         cd /usr/libexec/$prog
310         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/run-postinstalls.pl $mod
311 fi
312
313 # Run post-install shell script
314 if [ -r "/usr/libexec/$prog/$mod/postinstall.sh" ]; then
315         cd /usr/libexec/$prog
316         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/$mod/postinstall.sh
317 fi
318
319 %preun
320 # De-activate this theme, if in use and if we are not upgrading
321 if [ "$istheme" = "1" -a "\$1" = "0" ]; then
322         grep "^preroot=$mod" /etc/$prog/miniserv.conf >/dev/null
323         if [ "\$?" = "0" ]; then
324                 grep -v "^preroot=$mod" /etc/$prog/miniserv.conf >/etc/$prog/miniserv.conf.tmp
325                 (cat /etc/$prog/miniserv.conf.tmp) > /etc/$prog/miniserv.conf
326                 rm -f /etc/$prog/miniserv.conf.tmp
327                 grep -v "^theme=$mod" /etc/$prog/config >/etc/$prog/config.tmp
328                 (cat /etc/$prog/config.tmp) > /etc/$prog/config
329                 rm -f /etc/$prog/config.tmp
330                 (/etc/$prog/stop && /etc/$prog/start) >/dev/null 2>&1
331         fi
332 fi
333 # Run the pre-uninstall script, if we are not upgrading
334 if [ "$prog" = "webmin" -a "\$1" = "0" -a -r "/usr/libexec/$prog/$mod/uninstall.pl" ]; then
335         cd /usr/libexec/$prog
336         WEBMIN_CONFIG=/etc/$prog WEBMIN_VAR=/var/$prog /usr/libexec/$prog/run-uninstalls.pl $mod
337 fi
338 /bin/true
339
340 %postun
341 EOF
342 close(SPEC);
343
344 # Build the actual RPM
345 $cmd = -x "/usr/bin/rpmbuild" ? "/usr/bin/rpmbuild" : "/bin/rpm";
346 system("$cmd -ba $spec_dir/$prefix$mod.spec") && exit;
347 unlink("$rpm_source_dir/$mod.tar.gz");
348 if ($target_dir =~ /:/) {
349         # scp to dest
350         system("scp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
351         }
352 else {
353         # Just copy
354         system("/bin/cp $rpm_dir/$prefix$mod-$ver-$release.noarch.rpm $target_dir/$prefix$mod-$ver-$release.noarch.rpm");
355         }
356
357 # read_file(file, &assoc, [&order], [lowercase])
358 # Fill an associative array with name=value pairs from a file
359 sub read_file
360 {
361 open(ARFILE, $_[0]) || return 0;
362 while(<ARFILE>) {
363         s/\r|\n//g;
364         if (!/^#/ && /^([^=]+)=(.*)$/) {
365                 $_[1]->{$_[3] ? lc($1) : $1} = $2;
366                 push(@{$_[2]}, $1) if ($_[2]);
367                 }
368         }
369 close(ARFILE);
370 return 1;
371 }
372  
373 sub untaint
374 {
375 $_[0] =~ /^(.*)$/;
376 return $1;
377 }
378