Все задачи

Генерация конфигурации, с хорошим бекапом

26 Oct 2014

Программист исправил ошибку в генерации конфигов из предыдущей задачи.

Кроме того, он улучшил бекап старых конфигов: теперь предыдущие версии будут попадать последовательно в файлы app.conf.bak.1, app.conf.bak.2 и т.п.

Удобно? Да, но есть одна особенность…

#!/usr/bin/perl

use strict;
use warnings;

use File::Slurp;
use IO::Prompt;

my $conf_file = "./app.conf";

my $new_conf = generate_conf();

if (-e $conf_file && prompt(-yn, "backup old conf? [yn]" )){
    backup_old_conf();
}

write_file($conf_file, {}, $new_conf);

exit;


sub generate_conf
{
    my $conf = '';

    #...
    
    return $conf;
}

sub backup_old_conf
{
    my $i = 0;
    # бекапим старые версии в файлах .bak.1, .bak.2 и т.д.
    # проверяем, какие файлы уже существуют...
    while(-e $conf_file.".bak.".$i++ ){
    }
    # ... и создаем файл с следующим номером
    rename($conf_file, $conf_file.".bak.".$i) or die "can't backup old conf";
}

Подсказка

Показать

Новый конфиг генерится, предложение забекапить старый конфиг появляется и обрабатывается.

Подсказка-2

Показать

Вот только старых версий хранится слишком малое количество.

Подсказка-3

Показать

Прямо скажем: ровно одна старая версия сохраняется в app.conf.bak.1, при следующих запусках перезаписывается этот же файл, а app.conf.bak.2 никогда не появляется.

Разоблачение

Показать

Проблема классическая, C-подобная, и происходит из-за постфиксного инкремента ($i++) вот в этом цикле:

while(-e $conf_file.".bak.".$i++ ){ }

Сначала проверяется существование файла с номером из текущего значения $i, потом $i увеличивается на единицу, и с таким номером записывается файл в строке

rename($conf_file, $conf_file.".bak.".$i) or die "can't backup old conf";

Первый бекап происходит так: проверяем наличие файла с номером 0, его нет, записываем файл с номером 1. То же самое происходит и при создании всех следующих резервных копий.

Чтобы исправить ошибку, стоило бы использовать префиксный инкремент:

while(-e $conf_file.".bak.".++$i ){ 
}
rename($conf_file, $conf_file.".bak.".$i) or die "can't backup old conf";

Или же не пожалеть лишней строчки кода и написать совсем явно:

$i++;
while(-e $conf_file.".bak.".$i ){ 
}
rename($conf_file, $conf_file.".bak.".$i) or die "can't backup old conf";