source: trunk/Build.PL

Last change on this file was 1450, checked in by Dominic Hargreaves, 9 years ago

Use mkpath to create the custom template directory rather than mkdir, for cases where the parent directory doesn't already exist

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.5 KB
Line 
1use strict;
2use lib "lib";
3use Getopt::Long;
4
5eval {
6    require Config::Tiny;
7    # OpenGuides::Build and OpenGuides::Config both use Config::Tiny.
8    require OpenGuides::Build;
9    require OpenGuides::Config;
10};
11
12die "Problem loading OpenGuides module or a missing module\n\n$@.\n" if $@;
13
14my $force;
15
16GetOptions('force' => \$force);
17
18
19unless ($force || $ENV{'AUTOMATED_TESTING'}) {
20        print <<EOF;
21
22Beginning install process... if you already have an OpenGuides
23configuration file and you don't want to have to type in all your config
24parameters over again, abort this process now, copy that file to this
25directory, and start again.
26
27EOF
28
29my $continue = Module::Build->y_n("Continue with install?", "y");
30exit 0 unless $continue;
31}
32
33my $existing_config_file = 'wiki.conf';
34my $existing_config;
35
36if (-f $existing_config_file) {
37    $existing_config = OpenGuides::Config->new(file => $existing_config_file);
38} else {
39    print <<EOF;
40No existing configuration file found; assuming this is a new install.
41See the message above if this isn't correct.
42
43EOF
44    $existing_config = OpenGuides::Config->new();
45}
46
47my %yn_vars = map { $_ => 1 }
48   qw(use_plucene enable_page_deletion navbar_on_home_page backlinks_in_title
49      moderation_requires_password enable_node_image enable_common_categories
50      enable_common_locales recent_changes_on_home_page use_leaflet
51      random_page_omits_locales random_page_omits_categories
52      content_above_navbar_in_html show_gmap_in_node_display force_wgs84
53      send_moderation_notifications read_only);
54
55my $skip_config = $force || $ENV{AUTOMATED_TESTING} ? 'y' : Module::Build->y_n("Skip OpenGuides configuration?", "n");
56if ( $skip_config ) {
57    print <<EOF;
58===========================================================================
59Skipping OpenGuides configuration - any configuration options previously
60saved will be used instead.  You may tweak your configuration now by
61editing the 'wiki.conf' file produced by this script.
62===========================================================================
63EOF
64}
65
66my @answers;
67
68# It is an ancient Configurer, and he chooseth one of three.
69my $dbtype;
70my $dbtype_qu = $existing_config->dbtype__qu;
71if ( $skip_config ) {
72    $dbtype = $existing_config->dbtype;
73} else {
74    until ( $dbtype ) {
75        my $def = $existing_config->dbtype;
76        $dbtype = Module::Build->prompt("\n$dbtype_qu", $def);
77        $dbtype = lc($dbtype);
78        $dbtype =~ s/^\s*//;
79        $dbtype =~ s/\s*$//;
80        unless ( $dbtype eq "postgres" or $dbtype eq "mysql"
81                 or $dbtype eq "sqlite" ) {
82            undef $dbtype;
83        }
84    }
85}
86
87# Check they have the relevant DBD driver installed.
88my %drivers = ( postgres => "DBD::Pg",
89                mysql    => "DBD::mysql",
90                sqlite   => "DBD::SQLite",
91              );
92eval "require $drivers{$dbtype}";
93warn "$drivers{$dbtype} is needed to run a $dbtype database" if $@;
94
95push @answers, { question => $dbtype_qu,
96                 variable => "dbtype",
97                 value    => $dbtype };
98
99my $install_directory; # used to suggest template paths
100my $use_plucene = 1; # keep track of this so we know what to put in prereqs
101my $use_leaflet; # if true, we skip the GMaps questions
102my %gmaps_vars = map { $_ => 1 } qw( gmaps_api_key centre_long centre_lat
103                                default_gmaps_zoom default_gmaps_search_zoom );
104my $centre_lat = ''; # contains centre lat derived from Google Maps URL
105foreach my $var ( qw(
106   dbname dbuser dbpass dbhost dbport script_name
107   install_directory template_path custom_template_path script_url
108   custom_lib_path use_plucene indexing_directory enable_page_deletion
109   admin_pass stylesheet_url site_name navbar_on_home_page
110   recent_changes_on_home_page random_page_omits_locales
111   random_page_omits_categories content_above_navbar_in_html home_name
112   site_desc default_city default_country contact_email default_language
113   formatting_rules_node backlinks_in_title use_leaflet gmaps_api_key
114   centre_long centre_lat show_gmap_in_node_display default_gmaps_zoom
115   default_gmaps_search_zoom force_wgs84 google_analytics_key
116   licence_name licence_url licence_info_url moderation_requires_password
117   enable_node_image enable_common_categories enable_common_locales
118   spam_detector_module host_checker_module static_path static_url
119   send_moderation_notifications read_only
120  ) ) {
121    my $q_method = $var . "__qu";
122    my $qu  = $existing_config->$q_method;
123    my $type = $yn_vars{$var} ? "y_n" : "";
124    my $def = $existing_config->$var;
125    my $val = $def;
126
127    # Override dbname question for SQLite only.
128    if ( $dbtype eq "sqlite" and $var eq "dbname" ) {
129        $qu = "what's the full filename of the SQLite database this site runs on?";
130    }
131
132    if ( $dbtype eq "sqlite" and
133         ( $var eq "dbuser" or $var eq "dbpass" or $var eq "dbhost" or
134           $var eq "dbport")
135       ) {
136        print "$var not relevant for SQLite... skipping...\n"
137            unless $skip_config;
138        push @answers, { question => $qu,
139                            variable => $var,
140                         value    => "not-used" };
141        next;
142    }
143
144    # We don't ask this for new installs as Search::InvertedIndex is
145    # deprecated
146    if ( $var eq "use_plucene" and $existing_config->$var == 1) {
147        print "Skipping question about plucene\n"
148            unless $skip_config;
149        push @answers, { question => $qu,
150                         variable => $var,
151                         value => 1 };
152        next;
153    }
154
155    # If we're using Leaflet, we can skip the GMaps stuff.  Don't erase any
156    # previous answers from their config file though.
157    if ( $use_leaflet && $gmaps_vars{$var} ) {
158        push @answers, { question => $qu,
159                         variable => $var,
160                         value => $val };
161        next;
162    }
163
164    # Make sensible suggestions for template paths if we don't already
165    # have them stored.  Not really a default, but a useful hint/shortcut.
166    if ( $var eq "template_path" && !defined $existing_config->$var ) {
167        $def = $install_directory;
168        $def .= "/" unless $def =~ m|/$|;
169        $def .= "templates";
170    }
171    if ( $var eq "custom_template_path" && !defined $existing_config->$var ) {
172        $def = $install_directory;
173        $def .= "/" unless $def =~ m|/$|;
174        $def .= "custom-templates";
175    }
176
177    # If a Google Maps URL was provided last time we know the centre_lat
178    if ( $var eq 'centre_lat' && $centre_lat ) {
179        $val = $centre_lat;
180        next;
181    }   
182
183    # Here is where we actually ask the questions.
184    unless ( $skip_config ) {
185        if ( $type eq "y_n" ) {
186            # may be stored as true/false integer value
187            if ( $def =~ /^\d+$/ ) {
188                $def = $def ? "y" : "n";
189            }
190            $val = Module::Build->y_n("\n$qu ", $def);
191        } else {
192            $val = Module::Build->prompt("\n$qu ", $def);
193        }
194    }
195
196    # Allow user to use a Google Maps URL rather than enter lat/long by hand.
197    # We assume centre_long is being asked for first; ensure so in big list above.
198    if ( $var eq 'centre_long' ) {
199        if ( $val =~ /ll=([-\d.]+),([-\d.]+)/ ) {
200            print "Got a Google Maps URL with centre long,lat: [$1, $2]\n";
201            $val = $1;
202            $centre_lat = $2;
203        }
204    }
205
206    # Store install_directory so we can use it to suggest template paths.
207    $install_directory = $val if $var eq "install_directory";
208
209    # Keep track of chosen search method so we know what to put in prereqs.
210    # From Module::Build docs: ->y_n returns a Perl boolean true or false.
211    $use_plucene = 1 if $var eq "use_plucene" and $val;
212
213    # If they've just chosen to use Leaflet, we won't need to ask any of the
214    # GMaps questions.
215    $use_leaflet = 1 if $var eq "use_leaflet" and $val;
216
217    # Make sure that script_url ends in a /
218    if ( $var eq "script_url" and $val !~ /\/$/ ) {
219        $val .= "/";
220    }
221
222    push @answers, { question => $qu,
223                     variable => $var,
224                     value    => $val };
225}
226
227# Now deal with the geo stuff.
228my $geo_handler;
229my $geo_handler_qu = "Distance calculation methods available are:"
230                   . "\n  1) British National Grid"
231                   . "\n  2) Irish National Grid"
232                   . "\n  3) UTM ellipsoid"
233                   . "\nWhich would you like to use?";
234
235if ( $skip_config ) {
236    # We default to GB National Grid for historical reasons.
237    $geo_handler = $existing_config->geo_handler;
238} else {
239    my $choice;
240    until ( $choice ) {
241        my $def = $existing_config->geo_handler;
242        $choice = Module::Build->prompt("\n".$geo_handler_qu, $def);
243        $choice =~ s/^\s*//;
244        $choice =~ s/\s*$//;
245        unless ( $choice eq "1" or $choice eq "2" or $choice eq "3" ) {
246            undef $choice;
247        }
248    }
249    $geo_handler = $choice;
250}
251
252$geo_handler_qu =~ s/\n//gs;
253push @answers, {
254                 question => $geo_handler_qu,
255                 variable => "geo_handler",
256                 value    => $geo_handler,
257               };
258
259if ( $geo_handler eq "3" ) {
260    my $qu = $existing_config->ellipsoid__qu;
261    my $ellipsoid;
262    if ( $skip_config ) {
263        $ellipsoid = $existing_config->ellipsoid;
264    } else {
265        my $def = $existing_config->ellipsoid;
266        $ellipsoid = Module::Build->prompt("\n".$qu, $def);
267        $ellipsoid =~ s/^\s*//;
268        $ellipsoid =~ s/\s*$//;
269    }
270    push @answers, {
271                     question => $qu,
272                     variable => "ellipsoid",
273                     value    => $ellipsoid,
274                   };
275}
276
277# Create a user-friendly config file from answers to prompts.
278open FILE, ">wiki.conf" or die "Can't open wiki.conf for writing: $!";
279foreach my $ans (@answers) {
280    print FILE "# $ans->{question}\n";
281    print FILE "$ans->{variable} = $ans->{value}\n\n";
282}
283close FILE or die "Can't close wiki.conf: $!";
284
285# We currently only support Plucene for new installs, but may support
286# others in future
287my $search_module = $use_plucene ? "Plucene" : "Search::InvertedIndex";
288
289# Create the build object.
290my $build = OpenGuides::Build->new(
291    sign => 1,
292    dist_name => "OpenGuides",
293    dist_abstract => "A complete web application for managing a collaboratively-written guide to a city or town.",
294    module_name => "OpenGuides",
295    dist_version_from => "wiki.cgi",
296    license => "perl",
297    requires => {
298        'Algorithm::Diff'                     => '0.13',  # for sdiff
299        'CGI'                                 => '2.92',  # avoid escapeHTML bug
300        'CGI::Carp'                           => 0,
301        'CGI::Cookie'                         => 0,
302        'Wiki::Toolkit'                       => '0.80',
303        'Wiki::Toolkit::Feed::Atom'           => 0,
304        'Wiki::Toolkit::Feed::RSS'            => 0,
305        'Wiki::Toolkit::Formatter::UseMod'    => 0.24, #for external_link_class
306        'Wiki::Toolkit::Plugin::Categoriser'  => 0,
307        'Wiki::Toolkit::Plugin::Diff'         => 0,
308        'Wiki::Toolkit::Plugin::JSON'         => 0,
309        'Wiki::Toolkit::Plugin::Locator::Grid'=> 0,
310        'Wiki::Toolkit::Plugin::RSS::Reader'  => 0,
311        'Class::Accessor'                     => 0,
312        'Config::Tiny'                        => 0,
313        'Data::Dumper'                        => 0,
314        $drivers{$dbtype}                     => 0,
315        'File::Spec::Functions'               => 0,
316        'File::Temp'                          => 0,
317        'HTML::Entities'                      => 0,
318        'JSON'                                => 0, # W::T::P::JSON uses anyway
319        'LWP::Simple'                         => 0,
320        'MIME::Lite'                          => 0,
321        'Parse::RecDescent'                   => 0,
322        $search_module                        => 0,
323        'POSIX'                               => 0,
324        'Template'                            => '2.24', # for .lower vmethod
325        'Template::Plugin::JSON::Escape'      => 0,
326        'Time::Piece'                         => 0,
327        'URI::Escape'                         => 0,
328        'XML::RSS'                            => 0,
329        'Data::Validate::URI'                 => 0,
330        'Net::Netmask'                        => 0,
331        'List::Util'                          => 0,
332        'Geo::Coordinates::UTM'               => 0,
333        'Geo::Coordinates::OSGB'              => 0,
334        'Geo::Coordinates::ITM'               => 0,
335        },
336    build_requires => {
337        'Module::Build' => '0.26', # API change for accessing config data
338        'Class::Accessor'                     => 0,
339        'Config::Tiny'                        => 0,
340        'Data::Dumper'                        => 0,
341        'File::Path'                          => 0,
342        },
343    configure_requires => {
344        'Config::Tiny'                        => 0,
345        'Class::Accessor'                     => 0,
346        'Module::Build' => '0.26', # API change for accessing config data
347        },
348    recommends => {
349        'DBD::SQLite'                         => 0, # for testing
350        'Test::HTML::Content'                 => 0, # for testing, oddly enough
351        'Wiki::Toolkit::Plugin::Ping' => 0, # for pinging external services
352        'Geo::HelmertTransform'  => 0,      # for correct WGS84 lat/long
353        'Test::Pod'                           => 0,
354
355    },
356  meta_merge     => {
357    resources => {
358      MailingList => 'openguides-dev@lists.openguides.org',
359      homepage => 'http://openguides.org',
360      bugtracker => 'http://dev.openguides.org',
361      repository  => 'https://urchin.earth.li/svn/openguides', 
362    }
363  },
364    dynamic_config => 1,
365    create_makefile_pl => "passthrough"
366);
367
368$build->add_to_cleanup( "t/indexes/" );
369$build->add_to_cleanup( "t/node.db" );
370$build->add_to_cleanup( "t/prefs.db" );
371$build->add_to_cleanup( "t/templates/tmp/" );
372
373# Tell OpenGuides::Build which additional scripts and templates to install.
374$build->config_data( __extra_scripts => 
375                      [ "wiki.conf", "preferences.cgi", "search.cgi",
376                        "newpage.cgi" ] );
377$build->config_data( __templates     => [
378                      "admin_home.tt",
379                      "admin_revert_user.tt",
380                      "autocreate_content.tt",
381                      "backlink_results.tt",
382                      "banner.tt",
383                      "blacklisted_host.tt",
384                      "delete_confirm.tt",
385                      "delete_done.tt",
386                      "delete_password_wrong.tt",
387                      "differences.tt",
388                      "display_metadata.tt",
389                      "json_index.tt",
390                      "metadata.tt",
391                      "edit_form.tt",
392                      "edit_form_actions.tt",
393                      "edit_form_preview.tt",
394                      "error.tt",
395                      "footer.tt",
396                      "header.tt",
397                      "home_node.tt",
398                      "index_form.tt",
399                      "map_index.tt",
400                      "map_index_leaflet.tt",
401                      "missing_metadata.tt",
402                      "moderate_confirm.tt",
403                      "moderate_password_wrong.tt",
404                      "navbar.tt",
405                      "navbar_categories.tt",
406                      "navbar_locales.tt",
407                      "navbar_help.tt",
408                      "navbar_admin.tt",
409                      "navbar_home_link.tt",
410                      "navbar_options.tt",
411                      "navbar_revision_info.tt",
412                      "navbar_search.tt",
413                      "navbar_this_page.tt",
414                      "navbar_tools.tt",
415                      "needing_moderation.tt",
416                      "newpage.tt",
417                      "node.tt",
418                      "node_history.tt",
419                      "node_image.tt",
420                      "node_image_fields.tt",
421                      "node_photo_notes.tt",
422                      "node_rdf.tt",
423                      "openguides_information_boxes.tt",
424                      "preferences.tt",
425                      "random_page_failure.tt",
426                      "rdf_index.tt",
427                      "read_only.tt",
428                      "recent_changes.tt",
429                      "search_results.tt",
430                      "search_results_leaflet.tt",
431                      "site_index.tt",
432                      "search.tt",
433                      "spam_detected.tt",
434                      "userstats.tt",
435                      "wanted_pages.tt"
436    ] );
437
438$build->config_data( __static_files => [
439        "map-leaflet.js",
440        "openguides-base.css",
441    ] );
442
443# Finally write the build script.
444$build->create_build_script;
Note: See TracBrowser for help on using the repository browser.