#!/usr/bin/perl

=head1 NAME

    change-beta-settings -- переопределить настройки на бете

=head1 SYNOPSIS

    # поменять $Settings::BSRANK_URL на текущей бете (нужно находиться в корне)
    change-beta-settings --define BSRANK_URL=http://bstest01c.yandex.net/rank/24
    # на самом деле не менять, а только вывести, что добавится к SettingsLocal.pm
    change-beta-settings --define BSRANK_URL=http://bstest01c.yandex.net/rank/24 --dry-run

    # можно указать путь к бете явно
    change-beta-settings /var/www/beta.yukaba.8420 --define BSRANK_URL=http://bstest01c.yandex.net/rank/24

    # можно менять несколько настроек
    change-beta-settings --define Moderate::Settings::MODERATE_JSON_URL=http://ppcmoddev1.yandex.ru:8781/jsonrpc/ --define Moderate::Settings::MODERATE_URL=http://ppcmoddev1.yandex.ru:8781/soap/

    # поменять несколько настроек по очереди, делать postupdate только после последнего запуска
    change-beta-settings --define BSRANK_URL=http://bstest01c.yandex.net/rank/24 --no-postupdate
    change-beta-settings --define Moderate::Settings::MODERATE_URL=http://ppcmoddev1.yandex.ru:8781/soap/ --no-postupdate
    change-beta-settings --define Moderate::Settings::MODERATE_JSON_URL=http://ppcmoddev1.yandex.ru:8781/jsonrpc/

    # привести SettingsLocal.pm к исходному виду
    change-beta-settings --reset
    change-beta-settings /var/www/beta.yukaba.8420 --reset

=head1 DESCRIPTION

    Скрипт допишет в SettingsLocal.pm инструкции для переопределения настроек.
    Переопределение настройки задаётся опцией --define:
        
        --define <NAME>=<VALUE>

    Названия настроек (NAME) соответствуют названиям переменных в коде Директа без начального '$'. Поддерживается изменение только скалярных значений-строк и чисел.
    Если настройка из модуля Settings (переменная имеет вид $Settings::VARNAME), то префикс 'Settings::' можно опустить.
    Значение (VALUE) заключать в кавычки не нужно.

    Опции:
        
        -h, --help
            показать справку и выйти
        -d, --define <NAME>=<VALUE>
            задать для настройки NAME значение VALUE (см. выше).
        -n, --dry-run
            ничего не менять, только вывести, что добавится к SettingsLocal.pm
        --no-postupdate
            не выполнять beta-postupdate после изменения настроек (по умолчанию выполняется).
        --reset
            удалить все модификации из SettingsLocal.pm (проигнорирует переданные определения, если они есть)
        --print-var <NAME>
            только напечатать значение настройки NAME

=cut

use strict;
use warnings;

use utf8;

use Getopt::Long;
use Sys::Hostname qw/hostname/;

use ProjectSpecific;
use Yandex::Shell;

run() unless caller();

sub run {
    (my $script_name = $0) =~ s/.*\///;
    my $cmdline = join " ", $script_name, map { yash_quote($_) } @ARGV; 
    my $opt = parse_options();
    my $beta_path = shift @ARGV || '.';

    my @lines;
    push @lines, '', "# generated by $cmdline";
    for my $var (keys %{ $opt->{defines} }) {
        die "invalid variable name '$var'" unless $var =~ /^[A-Za-z0-9_:]+$/;
        $opt->{defines}->{$var} =~ s/\\/\\\\/g;
        $opt->{defines}->{$var} =~ s/'/\\'/g;
        push @lines, "\$$var = '$opt->{defines}->{$var}';";
    }
    push @lines, '1;';

    if ($opt->{dry_run}) {
        print join "\n", @lines;
    } else {
        my $settings_path;
        if ($ProjectSpecific::PROJECT eq 'Direct') {
            $settings_path = 'perl/settings';
        } elsif ($ProjectSpecific::PROJECT =~ /^(Directmod|Geocontext)$/) {
            $settings_path = 'protected';
        } else {
            die "could not determine project for host " . hostname() . "\n";
        }

        chdir $beta_path;
        my $settings_local_file = "$beta_path/$settings_path/SettingsLocal.pm";
        die "$settings_local_file doesn't exist\n" unless -f $settings_local_file;
        if ($opt->{reset}) {
            yash_system('sed', '-i', "/^# generated by $script_name/Q", $settings_local_file);
        } elsif ($opt->{print_var}) {
            my $var_name = $opt->{print_var};
            die "invalid variable name '$var_name'" unless $var_name =~ /^[A-Za-z0-9_:]+$/;
            $var_name = 'Settings::' . $var_name unless $var_name =~ /::/;
            $var_name = '$' . $var_name;
            unshift @INC, "$beta_path/$settings_path";
            eval 'require Settings';
            print eval $var_name;
            print "\n";
        } else {
            open my $fh, '>>', $settings_local_file;
            print $fh join "\n", @lines;
        }

        yash_system('direct-mk', 'beta-postupdate') if $opt->{postupdate};
    }
}

sub parse_options {
    my %O;
    my %defines;
    GetOptions(
        'd|define=s' => \%defines,
        'print-var=s' => \$O{print_var},
        'postupdate!' => \$O{postupdate},
        'n|dry-run' => \$O{dry_run},
        'reset' => \$O{reset},
        'h|help' => sub { system("podselect -section NAME -section SYNOPSIS -section DESCRIPTION $0 | pod2text-utf8 >&2"); exit 0 },
    ) || die "can't parse options, stop\n";
    die "You should specify --define, --print-var or --reset option\n" unless %defines || $O{print_var} || $O{reset};
    $O{defines} = \%defines;
    $O{postupdate} = 0 if $O{print_var};
    $O{postupdate} //= 1;
    return \%O;
}
