MSI: Fix possible use of unintialized variable
[gpg4win.git] / src / pkg-to-nsi.pl
1 #! /usr/bin/perl -w
2 # pkg-to-nsi.pl - Helper script to create NSI snippets from archive files.
3 # Copyright (C) 2007 g10 Code GmbH
4
5 # This file is part of Gpg4win.
6
7 # Gpg4win is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 2 of the License, or
10 # (at your option) any later version.
11
12 # Gpg4win is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16
17 # You should have received a copy of the GNU General Public License
18 # along with this program; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20
21 use strict;
22 use warnings;
23 use diagnostics;
24
25 # This is a small script to convert the list of files in a binary
26 # package to an NSI install or uninstall snippet.
27 #
28 # Usage: ./pkg-to-nsi.pl [--filter FILTER1,FILTER2,...]... \
29 #                        --inst|--uninst PACKAGE
30 #
31 # For example:
32 #
33 #  perl pkg-to-nsi.pl --filter crystal,22x22,32x32,48x48,64x64,128x128 \
34 #                     --inst ../packages/oxygen-icons-20071220-bin.zip
35 #
36 # The result can be used as the basis for a NSI file.  Do NOT cut and paste
37 # this without thinking.  Some merging needs to be done.  For example, some
38 # files will be installed in different locations (bin,lib to root), and
39 # files only included in previous installations may need to be removed from
40 # future installations, etc.
41
42 # Operation.
43 $::op = '--inst';
44
45 # Filter expressions.
46 @::filter = ();
47
48 while ($ARGV[0] =~ m,^-,)
49 {
50     my $opt;
51     $opt = shift @ARGV;
52     if ($opt eq '--inst' or $opt eq '--uninst')
53     {
54         $::op = $opt;
55     }
56     elsif ($opt eq '--filter')
57     {
58         die "--filter needs argument" if ($#ARGV < 0);
59         push @::filter, split (',', shift @ARGV);
60     }
61     else
62     {
63         die "unknown option $opt";
64     }
65 }
66
67 if ($::op ne '--inst' and $::op ne '--uninst')
68 {
69     die "unknown operation $::op";
70 }
71
72 $_ = shift @ARGV;
73 @::files = ();
74
75 if ($_ =~ m/\.zip$/)
76 {
77     @::files = `unzip -l -qq $_ | colrm 1 28`;
78 }
79 elsif ($_ =~ m/\.tar\.gz$/)
80 {
81     @::files = `tar tzf $_`;
82 }
83 elsif ($_ =~ m/\.tar\.bz2$/)
84 {
85     @::files = `tar tjf $_`;
86 }
87 elsif ($_ =~ m/\.tar\.xz$/)
88 {
89     @::files = `tar tJf $_`;
90 }
91 else
92 {
93     die "unknown file type $_";
94 }
95
96
97 @::files = sort @::files;
98
99
100 if ($::op eq '--inst')
101 {
102     my $cdir = "";
103
104     foreach my $file (@::files)
105     {
106         chomp $file;
107         
108         next if ($file =~ m,/$,);
109         my $matches = 0;
110         foreach my $filter (@::filter)
111         {
112             if ($file =~ m,$filter,)
113             {
114                 $matches = 1;
115                 last;
116             }
117         }
118         next if $matches;
119
120         $file =~ m,(?:(.*)/)?([^/]+),;
121         my $dir = $1;
122         my $base = $2;
123         if ($dir ne $cdir)
124         {
125             $cdir = $dir;
126             $dir =~ s,/,\\,g;
127             
128             print "\n" . '  SetOutPath "$INSTDIR\\' . $dir . '"' . "\n\n";
129         }
130         print '  File ${prefix}/' . $file . "\n";
131     }
132 }
133 elsif ($::op eq '--uninst')
134 {
135     my $in_rmdir = 0;
136     # All directories we have seen.
137     my %dir_seen;
138     # All directories that occur.
139     my %dirs;
140
141     @::files = reverse @::files;
142
143     foreach my $file (@::files)
144     {
145         chomp $file;
146
147         # We handle all dirs at the end.
148         next if ($file =~ m,/$,);
149
150         my $matches = 0;
151
152         # Apply filters.
153         foreach my $filter (@::filter)
154         {
155             if ($file =~ m,$filter,)
156             {
157                 $matches = 1;
158                 last;
159             }
160         }
161         next if $matches;
162
163         # Remember directories.
164         my $dir = $file;
165         
166         chomp $dir;
167         while ($dir =~ m,/,)
168         {
169             $dir =~ s,/[^/]+$,/,;
170             $dirs{$dir}++;
171                 $dir =~ s,/$,,;
172         }
173         
174         # Delete file.
175         $file =~ m,(?:(.*)/)?([^/]+),;
176         $dir = $1;
177         $dir_seen{$dir}++;
178         do
179         {
180             $dir =~ s,/[^/]+$,,;
181             $dir_seen{$dir}++;
182         }
183         while ($dir =~ m,/,);
184         
185         if ($in_rmdir)
186         {
187             print "\n";
188             $in_rmdir = 0;
189             }
190         
191         $file =~ s,/,\\,g;
192         print '  Delete "$INSTDIR\\' . $file . '"' . "\n";
193     }
194
195     # Delete all dirs not yet deleted.
196     foreach my $file (reverse sort keys %dirs)
197     {
198         chomp $file;
199
200         if ($file =~ m,/$,)
201         {
202             chop $file;
203
204             next if not defined $dir_seen{$file};
205
206             $file =~ s,/,\\,g;
207
208             if (not $in_rmdir)
209             {
210                 print "\n";
211                 $in_rmdir = 1;
212             }
213
214             print '  RMDir "$INSTDIR\\' . $file . '"' . "\n";
215         }
216     }
217     print '  RMDir "$INSTDIR"'. "\n";
218 }