Config-Model

 view release on metacpan or  search on metacpan

lib/Config/Model/Instance.pm  view on Meta::CPAN

has on_change_cb => (
    is  => 'rw',
    traits    => ['Code'],
    isa       => 'CodeRef',
    default   => sub { sub { } },
);

has on_message_cb => (
    traits    => ['Code'],
    is        => 'rw',
    isa       => 'CodeRef',
    default   => sub { sub { say @_; } },
    handles   => {
        show_message => 'execute',
    },
);

# initial_load mode: when data is loaded the first time
has initial_load => (
    is      => 'rw',
    isa     => 'Bool',
    default => 0,
    trigger => \&_trace_initial_load,
    traits  => [qw/Bool/],
    handles => {
        initial_load_start => 'set',
        initial_load_stop  => 'unset',
    } );

sub _trace_initial_load {
    my ( $self, $n, $o ) = @_;
    $logger->debug("switched to $n");
    return;
}

# This array holds a set of sub ref that will be invoked when
# the user requires to write all configuration tree in their
# backend storage.
has _write_back => (
    is      => 'ro',
    isa     => 'HashRef',
    traits  => ['Hash'],
    handles => {
        count_write_back     => 'count',    # mostly for tests
        has_no_write_back    => 'is_empty',
        nodes_to_write_back  => 'keys',
        write_back_node_info => 'get',
        delete_write_back    => 'delete',
        clear_write_back     => 'clear',
    },
    default => sub { {} },
);

sub register_write_back {
    my ($self, $path, $backend, $wb) = @_;
    push @{ $self->_write_back->{$path} //= [] }, [$backend, $wb];
    return;
}

# used for auto_read auto_write feature
has [qw/name application backend_arg backup/] => (
    is  => 'ro',
    isa => 'Maybe[Str]',
);

has 'root_dir' => (
    is => 'ro',
    isa => 'Config::Model::TypeContraints::Path',
    coerce => 1
);

has root_path => (
    is  => 'ro',
    isa => 'Path::Tiny',
    lazy_build => 1,
);

sub _build_root_path {
    my $self = shift;
    my $root_dir = $self->root_dir // '';
    return $root_dir ? path($root_dir) : Path::Tiny->cwd;
}

has [qw/config_dir config_file/] => (
    is  => 'ro',
    isa => 'Config::Model::TypeContraints::Path',
    coerce => 1
);

has tree => (
    is      => 'ro',
    isa     => 'Config::Model::Node',
    builder => '_build_tree',
    lazy    => 1,
    clearer => '_clear_config',
    reader  => 'config_root',
    handles => [qw/apply_fixes deep_check grab grab_value/],
);

sub reset_config {
    my $self = shift;
    $self->_clear_config;
    $self->clear_changes;
    return $self->config_root;
}

sub _build_tree {
    my $self = shift;

    return $self->load_node (
        config_class_name => $self->{root_class_name},
        instance          => $self,
        container         => $self,
        config_file       => $self->{config_file},
    );
}

sub preset_start {
    my $self = shift;
    $logger->info("Starting preset mode");
    carp "Cannot start preset mode during layered mode"

lib/Config/Model/Instance.pm  view on Meta::CPAN


    # make sure that root node is loaded
    $self->config_root->init;

    if ($force_write) {
        # make sure that the whole tree is loaded
        my $dump = $self->config_root->dump_tree;
    }

    foreach my $k ( keys %args ) {
        if ($k eq 'config_dir') {
            $args{$k} ||= '';
            $args{$k} .= '/' if $args{$k} and $args{$k} !~ m!/$!;
        }
        elsif ( $k ne 'config_file' ) {
            croak "write_back: wrong parameters $k";
        }
    }

    if ($self->has_no_write_back ) {
        my $info = $self->application ? "the model of application ".$self->application
            : "model ".$self->root_class_name ;
        croak "Don't know how to save data of $self->{name} instance. ",
            "Either $info has no configured ",
            "read/write backend or no node containing a backend was loaded. ",
            "Try with -force option or add read/write backend to $info\n";
    }

    foreach my $path ( sort $self->nodes_to_write_back ) {
        $logger->info("write_back called on node $path");

        if ( $path and $self->{config_file} ) {
            $logger->warn("write_back: cannot override config_file in non root node ($path)");
            delete  $self->{config_file}
        }

        $self->_write_back_node(%args, path => $path, force_write => $force_write) ;
    }
    $self->clear_changes;
    return;
}

sub _write_back_node ($self, %args) {
    my $path = delete $args{path};
    my $force_write   = delete $args{force_write};

    my $node = $self->config_root->grab(
        step => $path,
        type => 'node',
        mode => 'loose',
        autoadd => 0,
    );

    foreach my $wb_info (@{ $self->write_back_node_info($path) }) {
        my ($backend, $cb) = @$wb_info;

        my @wb_args = (
            %args,
            config_file   => $self->{config_file},
            force         => $force_write,
            backup        => $self->backup,
        );

        if (defined $node and ($node->needs_save or $force_write)) {
            my $dir = $args{config_dir};
            mkpath( $dir, 0, oct(755) ) if $dir and not -d $dir;

            # exit when write is successfull
            my $res = $cb->(@wb_args);
            $logger->info( "write_back called with $backend backend, result is ",
                           defined $res ? $res : '<undef>' );
        }

        if (not defined $node) {
            $logger->debug("deleting file for deleted node $path");
            $cb->(@wb_args, force_delete => 1);
            $self->delete_write_back($path);
        }
    }

    $logger->trace( "write_back on node '$path' done" );
    return;
}

sub save {
    goto &write_back;
}

sub update {
    my ($self, %args) = @_;

    my $hook = sub {
        my ($scanner, $data_ref,$node,@element_list) = @_;
        if ($node->can('update')) {
            my $loc = $node->location;
            say "Calling update on node '$loc'" if $loc and not $args{quiet};
            push (@$data_ref, $node->update(%args))
        } ;
    };

    my $leaf_cb = sub ($scanner, $data_ref,$node,$element_name,$index, $leaf_object) {
        push @$data_ref, $leaf_object->update_from_file();
    };

    my $root = $self->config_root ;

    my @msgs ;
    Config::Model::ObjTreeScanner->new(
        node_content_hook => $hook,
        check => ($args{quiet} ? 'no' : 'yes'),
        leaf_cb => $leaf_cb,
        file_value_cb => $leaf_cb,
        dir_value_cb => $leaf_cb,
    )->scan_node( \@msgs, $root );

    return @msgs;
}

sub DEMOLISH {
    my $self = shift;
    $self->clear_write_back; # avoid reference loops



( run in 0.597 second using v1.01-cache-2.11-cpan-39bf76dae61 )