Line # Revision Author
1 761 ahitrov #!/usr/bin/env perl
2 10 ahitrov@rambler.ru
3 ##############################################################################
4 # $HeadURL: http://svn.dev.rambler.ru/cndinst/trunk/bin/install $
5 # $Id: install 65 2009-12-18 12:09:37Z abavykin $
6 ##############################################################################
7
8 use strict;
9 use File::Spec;
10 use FindBin qw($RealBin);
11 use Getopt::Long;
12 use User::grent;
13 use User::pwent;
14
15 # defaults
16 my $options = {
17 svn_program => (`which svn` =~ /(.*)/)[0],
18 133 ahitrov core_repository => ($ENV{CORE_REPOSITORY} || 'http://contenido.me/repos/Contenido/utf8/core'),
19 10 ahitrov@rambler.ru server => (`hostname` =~ /(.*)/)[0],
20 httpd_port => ($ENV{HTTPD_PORT} || 0),
21 db_type => 'R',
22 backups => '/spool/backups',
23 crosslinks => '/spool/crosslinks',
24 sessions => '/spool/sessions',
25 };
26
27 my ($force, $help);
28 GetOptions('force' => \$force, 'help' => \$help);
29
30 if ($help) {
31 &usage;
32 exit;
33 }
34
35 my $yes_no = { y => 'YES', n => 'NO' };
36 my $db_types = { N => 'NONE', R => 'REMOTE', S => 'SINGLE' };
37
38 # begin
39 my ($user, $group, $umask) = (getpwuid($>), getgrgid($)), sprintf('%03o', umask));
40 my $destdir = $ENV{CNDINST_DESTDIR} || undef;
41 (my $home = $user->dir) =~ s/\/+$//;
42
43 load_conf($home, $options);
44
45 START:
46 while ($umask !~ /^\d0\d$/) {
47 my $a = user_prompt("Current umask ($umask) isn't group friendly. Are you sure?", default => 'n');
48 last if $a eq 'y';
49 next unless $a eq 'n';
50 print "Correct umask and try again!\n";
51 exit 0;
52 }
53
54 print sprintf (<<'EOM'
55 Start installation as:
56 User: %s [%d]
57 Group: %s [%d]
58 Home: %s
59 Shell: %s
60 Umask: %s
61 EOM
62 , $user->name, $user->uid, $group->name, $group->gid, $home, $user->shell, $umask);
63
64 while (1) {
65 my $a = lc(user_prompt('Is it correct?', default => 'y'));
66 last if $a eq 'y';
67 next unless $a eq 'n';
68 print "Bye, see you later!\n";
69 exit 0;
70 }
71
72 while (1) {
73 $destdir = user_prompt('Enter installation directory (absolute path)', default => $destdir ? $destdir : $home."/Contenido", ignore_force=>1);
74 next unless $destdir;
75
76 $destdir = File::Spec->canonpath($destdir);
77 $destdir =~ s/\/*$//;
78
79 if (-d $destdir) {
80 unless (is_dir_empty($destdir)) {
81 print "Directory exists and non-empty!\n";
82 undef $destdir;
83 next;
84 }
85 unless (-w $destdir) {
86 print "Directory exists, but you have no write permissions in it!\n";
87 undef $destdir;
88 next;
89 }
90 } else {
91 my @dirs = split /\/+/, $destdir;
92 my $pdir = '/'.join('/', @dirs[0..$#dirs-1]);
93 unless (-w $pdir) {
94 print "You have no permissions to create directory!\n";
95 undef $destdir;
96 next;
97 }
98 }
99 last;
100 }
101
102 while (1) {
103 my $a = lc(user_prompt('Which is svn executable?', default => $options->{svn_program}));
104 unless ($a && -x $a) {
105 print "There is no svn executable!\n";
106 next;
107 }
108 $options->{svn_program} = $a;
109 save_conf($home, $options);
110 last;
111 }
112
113 while (1) {
114 my $a = user_prompt('Which Contenido repository will be checked out?', default => $options->{core_repository});
115 $a =~ s/\/$//;
116 print "Contacting repository... ";
117 next if system("$options->{svn_program} ls $a >/dev/null");
118 print "success\n";
119 $options->{core_repository} = $a;
120 save_conf($home, $options);
121 last;
122 }
123
124 while (1) {
125 my $a = user_prompt('Enter server name', default => $options->{server});
126 next unless $a =~ /^[\w\-\+\.]+$/i;
127 $options->{server} = $a;
128 save_conf($home, $options);
129 last;
130 }
131
132 while (1) {
133 my $a = user_prompt('Enter HTTP port', default => $options->{httpd_port}, ignore_force=>1);
134 next unless $a =~ /^(\d)+$/i;
135 next if int($a)<1024 || int($a)>65535;
136 my %occupied = map {chomp; s/.*?(\d+)$/$1/; $_ => 1} `netstat -na | grep LISTEN | awk '{print \$4}'`;
137 if ($occupied{$a}) {
138 my $ao;
139 while (1) {
140 $ao = lc(user_prompt('Port seems busy. Are you sure?', default => 'n'));
141 last if $ao eq 'y';
142 next unless $ao eq 'n';
143 last;
144 }
145 next unless $ao eq 'y';
146 }
147 $options->{httpd_port} = $a;
148 save_conf($home, $options);
149 last;
150 }
151
152 while (1) {
153 my $a = user_prompt('Select database type: [N]ONE [R]EMOTE [S]INGLE', default => $options->{db_type}, ignore_force=>1);
154 next unless $a =~ /^[NRS]$/i;
155 $options->{db_type} = uc($a);
156 save_conf($home, $options);
157 last;
158 }
159
160 while (1) {
161 my $a = user_prompt('Enter backups directory', default => $options->{backups});
162 next unless $a;
163 $options->{backups} = $a;
164 save_conf($home, $options);
165 last;
166 }
167
168 while (1) {
169 my $a = user_prompt('Enter crosslinks directory', default => $options->{crosslinks});
170 next unless $a;
171 $options->{crosslinks} = $a;
172 save_conf($home, $options);
173 last;
174 }
175
176 while (1) {
177 my $a = user_prompt('Enter sessions directory', default => $options->{sessions});
178 next unless $a;
179 $options->{sessions} = $a;
180 save_conf($home, $options);
181 last;
182 }
183
184
185
186 print <<EOM
187
188
189 Summary:
190 Installation directory: $destdir
191 Executable svn: $options->{svn_program}
192 Contenido repository: $options->{core_repository}
193 Server name: $options->{server}
194 HTTP port: $options->{httpd_port}
195 Database type: $db_types->{$options->{db_type}}
196 Backups directory: $options->{backups}
197 Crosslinks directory: $options->{crosslinks}
198 Sessions directory: $options->{sessions}
199 EOM
200 ;
201
202 while (1) {
203 my $a = lc(user_prompt('Is it correct?', default => 'y'));
204 last if $a eq 'y';
205 next unless $a eq 'n';
206 print "\n\nRestarting config procedure\n\n\n";
207 goto START;
208 }
209
210 print "\nGreat, start installation!\n\n";
211
212 print "Creating installation directory...\n";
213 mkdir $destdir, 0775 or die "Can't mkdir: $destdir - $!" unless -d $destdir;
214
215 print "Creating installation layout...\n";
216 system("cp -R $RealBin/../skel/* $destdir/") and die "Can't copy: skel - $!";
217 system("find $destdir -depth -type d -name .svn -exec rm -Rf {} \\;") and die "Can't clean - $!";
218 system("find $destdir -depth \\! -perm +20 -exec chmod g+w {} \\;") and die "Can't chmod - $!";
219 unlink "$destdir/config.mk.proto" or die $!;
220
221 print "Checking out Contenido core...\n";
222 system("$options->{svn_program} co $options->{core_repository} $destdir/src/core/") and
223 die <<EOM
224
225 ****************************************************************
226 Fatal error occured, please resolve problem by hands.
227 Don't forget about your installation directory: $destdir
228 ****************************************************************
229
230 EOM
231 ;
232 print "done\n";
233
234 print "Creating installation config.mk...";
235 my $rewrites = {
236 OWNER => $user->name,
237 ROOT_DIR => $destdir,
238 SERVER => $options->{server},
239 HTTPD_PORT => $options->{httpd_port},
240 DB_TYPE => $db_types->{$options->{db_type}},
241 BACKUPS => $options->{backups},
242 CROSSLINKS => $options->{crosslinks},
243 SESSIONS => $options->{sessions},
244 };
245 open PROTO, "< $RealBin/../skel/config.mk.proto" or die "Can't read: config.mk.proto - $!";
246 open MK, "> $destdir/config.mk" or die "Can't create: config.mk - $!";
247 print MK @{ rewrite([<PROTO>], $rewrites) };
248 close MK;
249 close PROTO;
250 print " done\n";
251
252 print <<EOM
253
254 *****************************************************************
255 First step of Contenido installation finished.
256 Now change dir to '$destdir'.
257 Here, you can adjust some build options in 'config.mk' by hands.
258 After all run 'make install' and hope it will be successfull :)
259 *****************************************************************
260 EOM
261 ;
262
263 exit 0;
264
265
266 ### utils
267
268 sub user_prompt {
269 my ($prompt, %opts) = @_;
270
271 print $prompt.(exists $opts{default} ? " [$opts{default}]" : "").": ";
272 #if ($force && $opts{default} && !$opts{ignore_force}) {
273 if ($force && $opts{default}) {
274 print "[forced default answer]\n";
275 #print "$opts{default} [forced answer]\n";
276 sleep 1;
277 return $opts{default};
278 }
279 my $answer = <>;
280 chomp $answer;
281 return $answer ? $answer : $opts{default};
282 }
283
284 sub is_dir_empty {
285 my $dir = shift;
286
287 opendir D, $dir;
288 while ($_ = readdir D) {
289 next if $_ eq '.' || $_ eq '..';
290 return 0;
291 }
292 closedir D;
293
294 return 1;
295 }
296
297 sub load_conf {
298 my ($home, $options) = @_;
299
300 return save_conf($home, $options) unless -f "$home/.cndinst/install.conf";
301
302 open CONF, "< $home/.cndinst/install.conf" or die "Can't read: $home/.cndinst/install.conf - $!";
303 while (<CONF>) {
304 chomp;
305 next if /^\s*#/;
306 next unless /^\s*([^\s]+)\s*=\s*([^\s]+)/;
307 next unless exists $options->{$1};
308 $options->{$1} = $2;
309 }
310 close CONF;
311 return $options;
312 }
313
314 sub save_conf {
315 my ($home, $options) = @_;
316
317 mkdir "$home/.cndinst", 0775 or die "Can't mkdir: $home/.cndinst - $!" unless -d $home.'/.cndinst';
318
319 open CONF, "> $home/.cndinst/install.conf" or die "Can't create: $home/.cndinst/install.conf - $!";
320 print CONF "# Contenido installer config file\n\n";
321 printf CONF "%-20s = %s\n", $_, $options->{$_} for sort keys %{$options};
322 close CONF;
323 }
324
325 sub rewrite {
326 my ($lines, $rewrites) = @_;
327 s/\@([A-Z0-9\_]+)\@/$rewrites->{$1}/ms for @{$lines};
328 return $lines;
329 }
330
331 sub usage {
332 print <<EOM;
333 Usage:
334 $FindBin::Script options
335
336 Options:
337 -h, --help Print this message
338 -f, --force Force mode (automatically apply default answers
339 on none-critical questions)
340 EOM
341 }