#!/usr/bin/env perl use v5.12.0; use warnings; use Pod::Usage (); use Getopt::Long (); use File::Spec::Functions qw(catfile catdir); use LWP::UserAgent (); use Data::Validate::URI qw(is_uri); use FindBin qw($Bin); =head1 NAME generate-garmin-img-from-osm - Generate a garmin F<.img> file from an OpenStreetMap F<.osm> file =head1 SYNOPSIS generate-garmin-img-from-osm --osm "/var/www/osm.nix.is/dump/$(date --iso-8601).osm.bz2" --date=$(date --iso-8601) --min-osm-size=$((2*10**6)) --mkgmap-path=/usr/share/mkgmap/mkgmap.jar --osm2mp-dir=/home/avar/src/osm2mp --mapname 13314530 --description="Iceland OSM" --out-dir /var/www/osm.nix.is/root --out-file=Iceland.osm --out-mp=Iceland.mp =head1 DESCRIPTION Generate maps for L in one giant ugly script. Stick something like this in cron: perl /var/www/osm.nix.is/script/generate-garmin-img-from-osm --osm "/var/www/osm.nix.is/dump/$(date --iso-8601).osm.bz2" --date=$(date --iso-8601) --min-osm-size=$((2*10**6)) --mkgmap-path=/usr/share/mkgmap/mkgmap.jar --osm2mp-dir=/home/avar/src/osm2mp --mapname 13314530 --description="Iceland OSM" --out-dir /var/www/osm.nix.is/root --out-file=Iceland.osm --out-mp=Iceland.mp Around an hour or so after running F. =head1 OPTIONS =over =item -h, --help Display this help message =item --osm The path to the F<.osm> file, can be an URI in which case the script will fetch the file with LWP. =item --min-osm-size Minimum size of the F<.osm> file, for sanity checking. =item --mkgmap-path The path to the mkgmap directory, F should be under it. =item --osm2mp-dir The path to the F directory, for creating routeable maps. =item --mapname 8 digit UID for the map, see C help for --mapname for further info. =item --description Map description. =item --out-dir Output directory where we'll create F and F with the F<.osm> and F<.img> files. =item --out-file Output F<.osm> filename. =item --out-mp Output F<.mp> filename. =back =cut # Get command line options Getopt::Long::Parser->new( config => [ qw(bundling no_ignore_case no_require_order) ], )->getoptions( 'h|help' => \my $help, 'osm=s' => \my $osm, 'min-osm-size=s' => \my $min_osm_size, 'mkgmap-path=s' => \my $mkgmap_path, 'mapname=s' => \my $mapname, 'country-name=s' => \my $country_name, 'country-abbr=s' => \my $country_abbr, # IOC or UNDP code?? 'description=s' => \my $description, 'osm2mp-dir=s' => \my $osm2mp_dir, 'out-dir=s' => \my $out_dir, 'out-file=s' => \my $out_file, 'out-mp=s' => \my $out_mp, 'date=s' => \(my $date = do { my $d = `date --iso-8601`; chomp $d; $d }), ) or help(); my $real_date = `date --iso-8601`; chomp $real_date; help() if $help; chdir $out_dir or die "Can't chdir($out_dir): $!"; # Directories my $script_dir = $Bin; my $archive_dir = catdir($out_dir, 'archive'); my $latest_dir = catdir($out_dir, 'latest'); my $latest_dir_all = catdir($out_dir, 'latest', 'all'); my $latest_dir_default = catdir($out_dir, 'latest', 'default'); my $latest_dir_cyclemap = catdir($out_dir, 'latest', 'cyclemap'); my $today_dir = catdir($archive_dir, $date); my $today_dir_all = catdir($archive_dir, $date, 'all'); my $today_dir_default = catdir($archive_dir, $date, 'default'); my $today_dir_cyclemap = catdir($archive_dir, $date, 'cyclemap'); # Swap system "sudo swapon /swapfile 2>/dev/null"; system "mkdir -p $today_dir"; system "mkdir -p $today_dir_all"; system "mkdir -p $today_dir_default"; system "mkdir -p $today_dir_cyclemap"; # The rest will be symlinked system "mkdir -p $latest_dir"; chdir $today_dir or die "Can't chdir($today_dir): $!"; # I don't want this in the root, urgh! my $cycle_out_file = $out_file; $cycle_out_file =~ s/\./-cycle./; # Convert to full path $out_file = catfile($today_dir, $out_file); $out_mp = catfile($today_dir, $out_mp); my $out_stats = catfile($today_dir, 'STATS.txt'); if ($osm =~ /^http/) { system qq[wget --user-agent="See http://wiki.openstreetmap.org/index.php/Garmin_map_of_Iceland" -q -O- $osm | bzip2 -d - > $out_file] and die "wget: $!"; } else { if ($osm =~ /\.bz2/) { system qq[nice -n 19 bzcat $osm > $out_file] and die "bzcat cp: $!"; } else { system qq[cp $osm $out_file] and die "cp: $!"; } } # Sanity check, should be more than around 20 MB my $size = ((stat($out_file))[7]); if ($min_osm_size and $min_osm_size > $size) { die "$out_file should be more than around 20 MB, it's $size bytes"; } # # Generate IMG files # my $country = (defined $country_name ? " --country-name='$country_name' " : '') . (defined $country_abbr ? " --country-abbr='$country_abbr' " : ''); ## Default chdir $today_dir_default or die "Can't chdir($today_dir_default): $!"; my $cmd = qq[nice -n 19 java -Xmx1024M -jar $mkgmap_path --max-jobs --generate-sea=multipolygon --overview-mapname=$mapname --mapname=] . ($mapname+1) . qq[ --description="$description" --latin1 --family-id=639 --series-name="OSM Iceland" --family-name="OSM Iceland" --tdbfile $country --gmapsupp --route --net $out_file]; system $cmd and die "mkgmap: $!"; ## Cyclemap - see http://wiki.openstreetmap.org/index.php/OSM_Map_On_Garmin/Cycle_map $mapname += 2; chdir $today_dir_cyclemap or die "Can't chdir($today_dir_cyclemap): $!"; my $preprocess = catfile($script_dir, 'preprocess-osm-with-cvs'); my $cycling_csv = catfile(catdir($script_dir, 'res'), 'cycling-map-features.csv'); $cmd = qq[nice -n 19 $^X $preprocess --csv $cycling_csv --osm $out_file --out $cycle_out_file >/dev/null]; system $cmd and die "preprocess: $!"; $cmd = qq[nice -n 19 java -Xmx1024M -enableassertions -jar $mkgmap_path --max-jobs --map-features=$cycling_csv --generate-sea=multipolygon --overview-mapname=$mapname --mapname=] . ($mapname+1) . qq[ --description="$description cyclemap" --latin1 --family-id=640 --series-name="OSM Iceland Cycle" --family-name="OSM Iceland Cycle" --tdbfile $country --gmapsupp --route --net $out_file]; system $cmd and die "mkgmap: $!"; #system qq[bzip2 $cycle_out_file]; # save space system qq[rm $cycle_out_file]; ## Default routeable #$mapname += 1; if ($osm2mp_dir) { # run osm2mp on the .osm file to create a .mp file chdir $osm2mp_dir or die "Can't chdir($osm2mp_dir): $!"; system qq[$^X osm2mp.pl --mapid 13314530 --mapname "Iceland" --waterback --translit $out_file > $out_mp 2>/dev/null]; } ## All chdir $today_dir_all or die "Can't chdir($today_dir_all): $!"; system qq[nice -n 19 java -Xmx1024M -jar $mkgmap_path --max-jobs --gmapsupp $today_dir_default/gmapsupp.img $today_dir_cyclemap/gmapsupp.img] and die "mkgmap: $!"; # urgh, gmapsupp brings some crap along with it, nuke map { system "rm $_" } grep { $_ ne 'gmapsupp.img' and $_ !~ /\.tdb$/ } glob "*"; # Compress the .osm and .mp files system qq[nice -n 19 bzip2 $out_file]; if ($osm2mp_dir) { system qq[nice -n 19 bzip2 $out_mp]; } ## Generate VERSION.txt chdir $today_dir or die "Can't chdir($today_dir): $!"; open my $version, ">", "VERSION.txt" or die "Can't open VERSION.txt: $!"; print $version "This map package from http://osm.nix.is was generated using\n"; print $version "OpenStreetMap data from $date\n"; print $version "\n"; print $version "Versions of programs used to build the package:\n"; print $version " mkgmap\n"; print $version qx[dpkg -l | grep mkgmap | tr ' ' '\\n' | grep svn | sed "s/^/ /"]; if ($osm2mp_dir) { print $version "\n osm2mp\n"; #print $version qx[svn info $osm2mp_dir | egrep "^(Last Changed Date|Revision)" | sed "s/^/ /"]; print $version qx[git --git-dir=$osm2mp_dir/.git show | grep svn-id | perl -pe 's/.*?: //' | sed "s/^/ /"]; } close $version; # # Generate MapSource installer for the default map # my $gmi_dir = '/home/avar/src/osm.nix.is/osm-applications-utils-garmin-mapsource-installer/dist'; chdir $today_dir_default or die "Can't chdir($today_dir_default): $!"; system "cp ../VERSION.txt ." and die "cp: $!"; system "$^X -pi -e 's/\\n/\\r\\n/g' VERSION.txt" and die "perl/unix2dos: $!"; system "nice -n 19 zip --quiet -j OSM_IS_default.zip [0-9]*img [0-9]*tdb VERSION.txt $gmi_dir/Setup.exe $gmi_dir/garmin-mapsource-installer.ini" and die "zip: $!"; system "rm VERSION.txt" and die "rm: $!"; # # Symlink stuff now that we're finished # chdir $today_dir or die "Can't chdir($today_dir): $!"; my @generated = glob "*"; # Symlink latest to the new stuff chdir $out_dir or die "Can't chdir($out_dir): $!"; # If I'm generating a map file for some day in the past I don't want # to replace latest/ if ($date eq $real_date) { for my $file (@generated) { my $from = catfile($today_dir, $file); my $to = catfile($latest_dir, $file); unlink $to if -l $to; symlink $from, $to or die "symlink($from, $to): $!"; } } # Unswap system "sudo swapoff /swapfile 2>/dev/null"; sub help { my %arg = @_; Pod::Usage::pod2usage( -verbose => $arg{ verbose }, -exitval => $arg{ exitval } || 0, ); }