File Coverage

blib/lib/Config/Model/BackendMgr.pm
Criterion Covered Total %
statement 225 238 94.5
branch 76 108 70.3
condition 30 53 56.6
subroutine 26 26 100.0
pod 1 12 8.3
total 358 437 81.9


line stmt bran cond sub pod time code
1             #
2             # This file is part of Config-Model
3             #
4             # This software is Copyright (c) 2005-2022 by Dominique Dumont.
5             #
6             # This is free software, licensed under:
7             #
8             # The GNU Lesser General Public License, Version 2.1, February 1999
9             #
10             package Config::Model::BackendMgr 2.153; # TRIAL
11              
12 59     59   479 use Mouse;
  59         221  
  59         462  
13 59     59   23839 use strict;
  59         216  
  59         1610  
14 59     59   367 use warnings;
  59         249  
  59         2094  
15              
16 59     59   436 use Carp;
  59         225  
  59         3745  
17 59     59   862 use 5.10.1;
  59         292  
18              
19 59     59   509 use Config::Model::Exception;
  59         182  
  59         1800  
20 59     59   414 use Data::Dumper;
  59         201  
  59         4126  
21 59     59   493 use Storable qw/dclone/;
  59         206  
  59         3650  
22 59     59   539 use Scalar::Util qw/weaken reftype/;
  59         197  
  59         3718  
23 59     59   445 use Log::Log4perl qw(get_logger :levels);
  59         206  
  59         536  
24 59     59   8712 use Path::Tiny 0.070;
  59         1829  
  59         15283  
25              
26             my $logger = get_logger('BackendMgr');
27             my $user_logger = get_logger('User');
28              
29             # one BackendMgr per file
30              
31             has 'node' => (
32             is => 'ro',
33             isa => 'Config::Model::Node',
34             weak_ref => 1,
35             required => 1
36             );
37             has 'file_backup' => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
38              
39             has 'rw_config' => (
40             is => 'ro',
41             isa => 'HashRef',
42             required => 1
43             );
44              
45             has 'backend_obj' => (
46             is => 'rw',
47             isa => 'Config::Model::Backend::Any',
48             lazy => 1 ,
49             builder => '_build_backend_obj',
50             );
51              
52             sub _build_backend_obj {
53 93     93   235 my $self = shift;
54              
55 93         312 my $backend = $self->rw_config->{backend};
56             $logger->warn("function parameter for a backend is deprecated. Please implement 'read' method in backend $backend")
57 93 50       398 if $self->rw_config->{function};
58             # try to load a specific Backend class
59 93   50     438 my $f = $self->rw_config->{function} || 'read';
60 93         356 my $c = $self->load_backend_class( $backend, $f );
61              
62 59     59   598 no strict 'refs'; ## no critic (ProhibitNoStrict)
  59         205  
  59         173887  
63             return $c->new(
64             node => $self->node,
65             name => $backend,
66             auto_create => $self->rw_config->{auto_create},
67             auto_delete => $self->rw_config->{auto_delete},
68 93         2605 );
69             }
70              
71             has support_annotation => (
72             is => 'ro',
73             isa => 'Bool',
74             default => 0,
75             );
76              
77             with "Config::Model::Role::ComputeFunction";
78             with "Config::Model::Role::FileHandler";
79              
80             # check if dir is present. May create it in auto_create write mode
81             sub get_cfg_dir_path {
82 117     117 0 195 my $self = shift;
83 117         535 my %args = @_;
84              
85 117   100     504 my $w = $args{write} || 0;
86 117         529 my $dir = $self->get_tuned_config_dir(%args);
87              
88 117 50 100     6770 if ( not $dir->is_dir and $w and $args{auto_create} ) {
      66        
89 1         30 $logger->info("creating directory $dir");
90 1         20 $dir->mkpath;
91             }
92              
93 117 100       3826 unless ( $dir->is_dir ) {
94 4 50       58 my $mode = $w ? 'write' : 'read';
95 4         23 $logger->info( "$args{backend}: missing directory $dir ($mode mode)" );
96 4         81 return ( 0, $dir );
97             }
98              
99 113   50     2136 $logger->trace( "dir: " . $dir // '<undef>' );
100              
101 113         2310 return ( 1, $dir );
102             }
103              
104             # return (1, config file path) constructed from arguments or return
105             # (0). May create directory in auto_create write mode.
106             sub get_cfg_file_path {
107 142     142 0 291 my $self = shift;
108 142         985 my %args = @_;
109              
110 142   100     611 my $w = $args{write} || 0;
111              
112             # config file override
113 142         269 my $cfo = $args{config_file};
114              
115 142 100       393 if ( defined $cfo) {
116             my $override
117 25 100       195 = $args{root} ? $args{root}->child($cfo)
    100          
118             : $cfo =~ m!^/! ? path($cfo)
119             : path('.')->child($cfo);
120              
121 25 100       1469 my $mode = $w ? 'write' : 'read';
122 25         108 $logger->trace("$args{backend} override target file is $override ($mode mode)");
123 25         501 return ( 1, $override );
124             }
125              
126 117         489 my ( $dir_ok, $dir ) = $self->get_cfg_dir_path(%args);
127              
128 117 100       496 if ( defined $args{file} ) {
129 101 100       801 my $file = $args{skip_compute} ? $args{file} : $self->node->compute_string($args{file});
130 101         346 my $res = $dir->child($file);
131 101         4551 $logger->trace("get_cfg_file_path: returns $res");
132 101         1703 return ( $dir_ok, $res );
133             }
134              
135 16         92 return 0;
136             }
137              
138             sub open_read_file {
139 69     69 0 201 my ($self, $file_path) = @_;
140              
141 69 100       264 if ( $file_path->is_file ) {
142 66         1806 $logger->debug("open_read_file: open $file_path for read");
143             # store a backup in memory in case there's a problem
144 66         1251 $self->file_backup( [ $file_path->lines_utf8 ] );
145 66         33573 return $file_path->filehandle("<", ":utf8");
146             }
147             else {
148 3         82 return;
149             }
150             }
151              
152             # called at configuration node creation
153             #
154             # New subroutine "load_backend_class" extracted - Thu Aug 12 18:32:37 2010.
155             #
156             sub load_backend_class {
157 186     186 0 353 my $self = shift;
158 186         314 my $backend = shift;
159 186         288 my $function = shift;
160              
161 186         867 $logger->trace("load_backend_class: called with backend $backend, function $function");
162 186         1510 my %c;
163              
164 186         724 my $k = "Config::Model::Backend::" . ucfirst($backend);
165 186         546 my $f = $k . '.pm';
166 186         1026 $f =~ s!::!/!g;
167 186         573 $c{$k} = $f;
168              
169             # try another class
170 186         647 $k =~ s/_(\w)/uc($1)/ge;
  46         220  
171 186         489 $f =~ s/_(\w)/uc($1)/ge;
  46         134  
172 186         427 $c{$k} = $f;
173              
174 186         733 foreach my $c ( sort keys %c ) {
175 192 100       1822 if ( $c->can($function) ) {
176              
177             # no need to load class
178 169         849 $logger->debug("load_backend_class: $c is already loaded (can $function)");
179 169         1698 return $c;
180             }
181             }
182              
183             # look for file to load
184 17         64 my $class_to_load;
185 17         68 foreach my $c ( sort keys %c ) {
186 23         190 $logger->trace("load_backend_class: looking to load class $c");
187 23         226 foreach my $prefix (@INC) {
188 246         769 my $realfilename = "$prefix/$c{$c}";
189 246 100       3358 $class_to_load = $c if -f $realfilename;
190             }
191             }
192              
193 17 50       163 if (not defined $class_to_load) {
194 0         0 Config::Model::Exception::Model->throw(
195             object => $self->node,
196             error => "backend error: cannot find Perl class for backend: '$backend'",
197             );
198             };
199 17         64 my $file_to_load = $c{$class_to_load};
200              
201 17         130 $logger->trace("load_backend_class: loading class $class_to_load, $file_to_load");
202 17         175 eval { require $file_to_load; };
  17         10256  
203              
204 17 50       2057 if ($@) {
205 0         0 die "Error with backend $backend: could not parse $file_to_load: $@\n";
206             }
207 17         95 return $class_to_load;
208             }
209              
210             sub read_config_data {
211 99     99 0 472 my ( $self, %args ) = @_;
212              
213 99         591 $logger->trace( "called for node ", $self->node->location );
214              
215 99         1034 my $check = delete $args{check};
216 99         255 my $config_file_override = delete $args{config_file};
217 99         223 my $auto_create_override = delete $args{auto_create};
218              
219 99 50       279 croak "unexpected args " . join( ' ', keys %args ) . "\n" if %args;
220              
221 99         2874 my $rw_config = dclone $self->rw_config ;
222              
223 99         570 my $instance = $self->node->instance();
224              
225             # root override is passed by the instance
226 99         311 my $root_dir = $instance->root_dir ;
227              
228 99         261 my $auto_create = $rw_config->{auto_create};
229 99         201 my $backend = $rw_config->{backend};
230              
231 99 100       305 if ( $rw_config->{default_layer} ) {
232 2         8 $self->read_config_sub_layer( $rw_config, $root_dir, $config_file_override, $check,
233             $backend );
234             }
235              
236 99         401 my ( $res, $file ) =
237             $self->try_read_backend( $rw_config, $root_dir, $config_file_override, $check, $backend );
238              
239 99 50 0     1072 Config::Model::Exception::ConfigFile::Missing->throw (
      66        
      66        
240             file => $file || "<unknown>",
241             object => $self->node,
242             ) unless $res or $auto_create_override or $auto_create;
243              
244             }
245              
246             sub read_config_sub_layer {
247 2     2 0 9 my ( $self, $rw_config, $root_dir, $config_file_override, $check, $backend ) = @_;
248              
249 2         5 my $layered_config = delete $rw_config->{default_layer};
250 2         25 my $layered_read = dclone $rw_config ;
251              
252 2         8 foreach my $item ( qw/file config_dir os_config_dir/ ) {
253 6         13 my $lc = delete $layered_config->{$item};
254 6 100       19 $layered_read->{$item} = $lc if $lc;
255             }
256              
257             Config::Model::Exception::Model->throw(
258 2 50       9 error => "backend error: unexpected default_layer parameters: "
259             . join( ' ', sort keys %$layered_config ),
260             object => $self->node,
261             ) if %$layered_config;
262              
263 2         11 my $i = $self->node->instance;
264 2         7 my $already_in_layered = $i->layered;
265              
266             # layered stuff here
267 2 50       9 if ( not $already_in_layered ) {
268 2         12 $i->layered_clear;
269 2         9 $i->layered_start;
270             }
271              
272 2         11 $self->try_read_backend( $layered_read, $root_dir, $config_file_override, $check, $backend );
273              
274 2 50       14 if ( not $already_in_layered ) {
275 2         19 $i->layered_stop;
276             }
277             }
278              
279             # called at configuration node creation, NOT when writing
280             #
281             # New subroutine "try_read_backend" extracted - Sun Jul 14 11:52:58 2013.
282             #
283             sub try_read_backend {
284 101     101 0 209 my $self = shift;
285 101         169 my $rw_config = shift;
286 101         178 my $root_dir = shift;
287 101         170 my $config_file_override = shift;
288 101         216 my $check = shift;
289 101         182 my $backend = shift;
290              
291 101         616 my $read_dir = $self->get_tuned_config_dir(%$rw_config);
292              
293 101         4616 my @read_args = (
294             %$rw_config,
295             root => $root_dir,
296             config_dir => $read_dir,
297             backend => $backend,
298             check => $check,
299             config_file => $config_file_override
300             );
301              
302 101         1201 my $backend_obj = $self->backend_obj();
303              
304 101 50       2853 if ($backend_obj->can('suffix')) {
305 0         0 $logger->warn("suffix method is deprecated. you can remove it from backend $backend");
306             }
307              
308 101         482 my ( $file_ok, $file_path ) = $self->get_cfg_file_path(
309             @read_args,
310             skip_compute => $backend_obj->skip_open,
311             );
312              
313 101         295 my $fh;
314 101 100 100     328 if (not $backend_obj->skip_open and $file_ok) {
315 69         286 $fh = $self->open_read_file($file_path) ;
316             }
317              
318 101   50     7061 my $f = $self->rw_config->{function} || 'read';
319 101 100       431 if ($logger->is_info) {
320 2 50       35 my $fp = defined $file_path ? " on $file_path":'' ;
321 2         34 $logger->info( "Read with $backend " . reftype($backend_obj) . "::$f".$fp);
322             }
323              
324 101         948 my $res;
325              
326 101         219 eval {
327 101         797 $res = $backend_obj->$f(
328             @read_args,
329             file_path => $file_path,
330             object => $self->node,
331             );
332             };
333 101         563 my $error = $@;
334              
335             # catch eval error
336 101 50 33     803 if ( ref($error) and $error->isa('Config::Model::Exception::Syntax') ) {
    50 33        
    50          
    50          
337              
338 0 0       0 $error->parsed_file( $file_path) unless $error->parsed_file;
339 0         0 $error->rethrow;
340             }
341             elsif ( ref $error and $error->isa('Config::Model::Exception') ) {
342 0         0 $error->rethrow ;
343             }
344             elsif ( ref $error ) {
345 0         0 die $error ;
346             }
347             elsif ( $error ) {
348 0         0 die "Backend $backend failed to read $file_path: $error";
349             }
350              
351             # only backend based on C::M::Backend::Any can support annotations
352 101 50       557 if ($backend_obj->can('annotation')) {
353 101         349 $self->{support_annotation} = $backend_obj->annotation ;
354             }
355              
356 101         1871 return ( $res, $file_path );
357             }
358              
359             sub auto_write_init {
360 93     93 0 250 my ( $self, %args ) = @_;
361              
362 93 50       241 croak "auto_write_init: unexpected args " . join( ' ', sort keys %args ) . "\n"
363             if %args;
364              
365 93         2989 my $rw_config = dclone $self->rw_config ;
366              
367 93         560 my $instance = $self->node->instance();
368              
369             # root override is passed by the instance
370 93         295 my $root_dir = $instance->root_dir;
371              
372 93         279 my $backend = $rw_config->{backend};
373              
374 93         605 my $write_dir = $self->get_tuned_config_dir(%$rw_config);
375              
376 93         4784 $logger->trace( "auto_write_init creating write cb ($backend) for ", $self->node->name );
377              
378 93         1301 my @wr_args = (
379             %$rw_config, # model data
380             config_dir => $write_dir, # override from instance
381             write => 1, # for get_cfg_file_path
382             root => $root_dir, # override from instance
383             );
384              
385             # used bby C::M::Dumper and C::M::DumpAsData
386             # TODO: is this needed once multi backend are removed
387 93         345 $self->{auto_write}{$backend} = 1;
388              
389 93         214 my $wb;
390 93   50     425 my $f = $rw_config->{function} || 'write';
391 93         296 my $backend_class = $self->load_backend_class( $backend, $f );
392 93         502 my $location = $self->node->name;
393 93         297 my $node = $self->node; # closure
394              
395             # provide a proper write back function
396             $wb = sub {
397 52     52   244 my %cb_args = @_;
398              
399 52         154 my $force_delete = delete $cb_args{force_delete} ;
400 52 100       401 $logger->debug( "write cb ($backend) called for $location ", $force_delete ? '' : ' (deleted)' );
401 52         610 my $backend_obj = $self->backend_obj();
402              
403 52         137 my ($fh, $file_ok, $file_path );
404              
405 52 100       311 if (not $backend_class->skip_open) {
406 41         220 ( $file_ok, $file_path ) = $self->get_cfg_file_path( @wr_args, %cb_args);
407             }
408              
409 52 100       560 if ($file_ok) {
410 37         211 $fh = $self->open_file_to_write( $backend, $file_path, delete $cb_args{backup} );
411             }
412              
413             # override needed for "save as" button
414 52         7241 my %backend_args = (
415             @wr_args,
416             file_path => $file_path,
417             object => $node,
418             %cb_args # override from user
419             );
420              
421 52         184 my $res;
422 52 100       219 if ($force_delete) {
423 1         11 $backend_obj->delete(%backend_args);
424             }
425             else {
426 51         110 $res = eval { $backend_obj->$f( %backend_args ); };
  51         450  
427 51         3471 my $error = $@;
428 51 50       190 $logger->error( "write backend $backend $backend_class" . '::' . "$f failed: $error" )
429             if $error;
430 51         378 $self->close_file_to_write( $error, $file_path, $rw_config->{file_mode} );
431              
432             $self->auto_delete($file_path, \%backend_args)
433 51 100 100     1152 if $rw_config->{auto_delete} and not $backend_class->skip_open ;
434             }
435              
436 52 50       1760 return defined $res ? $res : $@ ? 0 : 1;
    100          
437 93         857 };
438              
439 93         450 $logger->trace( "registering write $backend in node " . $self->node->name );
440              
441 93         1274 $instance->register_write_back( $self->node->location, $backend, $wb );
442             }
443              
444             sub auto_delete {
445 7     7 1 30 my ($self, $file_path, $args) = @_;
446              
447 7 100       35 return unless $file_path;
448              
449 3         5 my $perl_data;
450 3 50 50     46 $perl_data = $self->node->dump_as_data( full_dump => $args->{full_dump} // 0)
451             if defined $self->node;
452              
453 3 50       19 my $size = ref($perl_data) eq 'HASH' ? scalar keys %$perl_data
    100          
454             : ref($perl_data) eq 'ARRAY' ? scalar @$perl_data
455             : $perl_data ;
456 3 100       15 if (not $size) {
457 2         10 $logger->info( "Removing $file_path (no data to store)" );
458 2         41 unlink($file_path);
459             }
460             }
461              
462              
463             sub open_file_to_write {
464 37     37 0 152 my ( $self, $backend, $file_path, $backup ) = @_;
465              
466 37         94 my $do_backup = defined $backup;
467 37   50     241 $backup ||= 'old'; # use old only if defined
468 37 50       177 $backup = '.' . $backup unless $backup =~ /^\./;
469              
470             # make sure that parent dir exists before creating file
471 37         213 $file_path->parent->mkpath;
472              
473 37 50 33     6484 if ( $do_backup and $file_path->is_file ) {
474 0 0       0 $file_path->copy( $file_path.$backup ) or die "Backup copy failed: $!";
475             }
476              
477 37         218 $logger->debug("$backend backend opened file $file_path to write");
478 37         740 return $file_path->filehandle(">",":utf8");
479             }
480              
481             sub close_file_to_write {
482 51     51 0 243 my ( $self, $error, $file_path, $file_mode ) = @_;
483              
484 51 100       173 return unless defined $file_path;
485              
486 37 50       117 if ($error) {
487             # restore backup and display error
488 0         0 $logger->warn("Error during write, restoring backup data in $file_path" );
489 0         0 $file_path->append_utf8({ truncate => 1 }, $self->file_backup );
490 0 0 0     0 $error->rethrow if ref($error) and $error->can('rethrow');
491 0         0 die $error;
492             }
493              
494             # TODO: move chmod in a backend role
495 37 100       117 $file_path->chmod($file_mode) if $file_mode;
496              
497             # TODO: move in a backend role
498             # check file size and remove empty files
499 37 50 33     9227 $file_path->remove if -z $file_path and not -l $file_path;
500             }
501              
502             sub is_auto_write_for_type {
503 1     1 0 4 my $self = shift;
504 1         4 my $type = shift;
505 1   50     10 return $self->{auto_write}{$type} || 0;
506             }
507              
508             __PACKAGE__->meta->make_immutable;
509              
510             1;
511              
512             # ABSTRACT: Load configuration node on demand
513              
514             __END__
515              
516             =pod
517              
518             =encoding UTF-8
519              
520             =head1 NAME
521              
522             Config::Model::BackendMgr - Load configuration node on demand
523              
524             =head1 VERSION
525              
526             version 2.153
527              
528             =head1 SYNOPSIS
529              
530             # Use BackendMgr to write data in Yaml file
531             # This example requires Config::Model::Backend::Yaml which is now
532             # shipped outside of Config::Model. Please get it on CPAN
533             use Config::Model;
534              
535             # define configuration tree object
536             my $model = Config::Model->new;
537             $model->create_config_class(
538             name => "Foo",
539             element => [
540             [qw/foo bar/] => {
541             type => 'leaf',
542             value_type => 'string'
543             },
544             ]
545             );
546              
547             $model->create_config_class(
548             name => "MyClass",
549              
550             # rw_config spec is used by Config::Model::BackendMgr
551             rw_config => {
552             backend => 'yaml',
553             config_dir => '/tmp/',
554             file => 'my_class.yml',
555             auto_create => 1,
556             },
557              
558             element => [
559             [qw/foo bar/] => {
560             type => 'leaf',
561             value_type => 'string'
562             },
563             hash_of_nodes => {
564             type => 'hash', # hash id
565             index_type => 'string',
566             cargo => {
567             type => 'node',
568             config_class_name => 'Foo'
569             },
570             },
571             ],
572             );
573              
574             my $inst = $model->instance( root_class_name => 'MyClass' );
575              
576             my $root = $inst->config_root;
577              
578             # put data
579             my $steps = 'foo=FOO hash_of_nodes:fr foo=bonjour -
580             hash_of_nodes:en foo=hello ';
581             $root->load( steps => $steps );
582              
583             $inst->write_back;
584              
585             # now look at file /tmp/my_class.yml
586              
587             =head1 DESCRIPTION
588              
589             This class provides a way to specify how to load or store
590             configuration data within the model.
591              
592             With these specifications, all configuration information is read
593             during creation of a node (which triggers the creation of a backend
594             manager object) and written back when L<write_back|Config::Model::Instance/write_back>
595             method is called either on the instance.
596              
597             =begin comment
598              
599             This feature is also useful if you want to read configuration class
600             declarations at run time. (For instance in a C</etc> directory like
601             C</etc/some_config.d>). In this case, each configuration class must
602             specify how to read and write configuration information.
603              
604             Idea: sub-files name could be <instance>%<location>.cds
605              
606             =end comment
607              
608             This load/store can be done with different backends:
609              
610             =over
611              
612             =item *
613              
614             Any of the C<Config::Model::Backend::*> classes available on your system.
615             For instance C<Config::Model::Backend::Yaml>.
616              
617             =item *
618              
619             C<cds_file>: Config dump string (cds) in a file. I.e. a string that describes the
620             content of a configuration tree is loaded from or saved in a text
621             file. This format is defined by this project. See
622             L<Config::Model::Loader/"load string syntax">.
623              
624             =item *
625              
626             C<perl_file>: Perl data structure (perl) in a file. See L<Config::Model::DumpAsData>
627             for details on the data structure. Now handled by L<Config::Model::Backend::PerlFile>
628              
629             =back
630              
631             When needed, C<write_back> method can be called on the instance (See
632             L<Config::Model::Instance>) to store back all configuration information.
633              
634             =head1 Backend specification
635              
636             The backend specification is provided as an attribute of a
637             L<Config::Model::Node> specification. These attributes are optional:
638             A node without C<rw_config> attribute must rely on another node to
639             read or save its data.
640              
641             When needed (usually for the root node), the configuration class is
642             declared with a C<rw_config> parameter which specifies the read/write
643             backend configuration.
644              
645             =head2 Parameters available for all backends
646              
647             The following parameters are accepted by all backends:
648              
649             =over 4
650              
651             =item config_dir
652              
653             Specify configuration directory. This parameter is optional as the
654             directory can be hardcoded in the backend class. C<config_dir> beginning
655             with 'C<~>' is munged so C<~> is replaced by C<< File::HomeDir->my_data >>.
656             See L<File::HomeDir> for details.
657              
658             =item file
659              
660             Specify configuration file name (without the path). This parameter is
661             optional as the file name can be hardcoded in the backend class.
662              
663             The configuration file name can be specified with C<&index> keyword
664             when a backend is associated to a node contained in a hash. For instance,
665             with C<file> set to C<&index.conf>:
666              
667             service # hash element
668             foo # hash index
669             nodeA # values of nodeA are stored in foo.conf
670             bar # hash index
671             nodeB # values of nodeB are stored in bar.conf
672              
673             Likewise, the keyword C<&element> can be used to specify the file
674             name. For instance, with C<file> set to C<&element-&index.conf>:
675              
676             service # hash element
677             foo # hash index
678             nodeA # values of nodeA are stored in service.foo.conf
679             bar # hash index
680             nodeB # values of nodeB are stored in service.bar.conf
681              
682             =item file_mode
683              
684             C<file_mode> parameter can be used to set the mode of the written
685             file(s). C<file_mode> value can be in any form supported by
686             L<Path::Tiny/chmod>. Example:
687              
688             file_mode => 0664,
689             file_mode => '0664',
690             file_mode => 'g+w'
691              
692             =item os_config_dir
693              
694             Specify alternate location of a configuration directory depending on the OS
695             (as returned by C<$^O>, see L<perlport/PLATFORMS>).
696             For instance:
697              
698             config_dir => '/etc/ssh',
699             os_config_dir => { darwin => '/etc' }
700              
701             =item default_layer
702              
703             Optional. Specifies where to find a global configuration file that
704             specifies default values. For instance, this is used by OpenSSH to
705             specify a global configuration file (C</etc/ssh/ssh_config>) that is
706             overridden by user's file:
707              
708             default_layer => {
709             os_config_dir => { 'darwin' => '/etc' },
710             config_dir => '/etc/ssh',
711             file => 'ssh_config'
712             }
713              
714             Only the 3 above parameters can be specified in C<default_layer>.
715              
716             =item auto_create
717              
718             By default, an exception is thrown if no read was
719             successful. This behavior can be overridden by specifying
720             C<< auto_create => 1 >> in one of the backend specification. For instance:
721              
722             rw_config => {
723             backend => 'IniFile',
724             config_dir => '/tmp',
725             file => 'foo.conf',
726             auto_create => 1
727             },
728              
729             Setting C<auto_create> to 1 is necessary to create a configuration
730             from scratch
731              
732             =item auto_delete
733              
734             Delete configuration files that contains no data. (default is to leave an empty file)
735              
736             =back
737              
738             =head2 Config::Model::Backend::* backends
739              
740             Specify the backend name and the parameters of the backend defined
741             in their documentation.
742              
743             For instance:
744              
745             rw_config => {
746             backend => 'yaml',
747             config_dir => '/tmp/',
748             file => 'my_class.yml',
749             },
750              
751             See L<Config::Model::Backend::Yaml> for more details for this backend.
752              
753             =head2 Your own backend
754              
755             You can also write a dedicated backend. See
756             L<How to write your own backend|Config::Model::Backend::Any/"How to write your own backend">
757             for details.
758              
759             =head1 Test setup
760              
761             By default, configurations files are read from the directory specified
762             by C<config_dir> parameter specified in the model. You may override the
763             C<root> directory for test.
764              
765             =head1 Methods
766              
767             =head2 support_annotation
768              
769             Returns 1 if at least the backend supports read and write annotations
770             (aka comments) in the configuration file.
771              
772             =head1 AUTHOR
773              
774             Dominique Dumont, (ddumont at cpan dot org)
775              
776             =head1 SEE ALSO
777              
778             L<Config::Model>, L<Config::Model::Instance>,
779             L<Config::Model::Node>, L<Config::Model::Dumper>
780              
781             =head1 AUTHOR
782              
783             Dominique Dumont
784              
785             =head1 COPYRIGHT AND LICENSE
786              
787             This software is Copyright (c) 2005-2022 by Dominique Dumont.
788              
789             This is free software, licensed under:
790              
791             The GNU Lesser General Public License, Version 2.1, February 1999
792              
793             =cut