File Coverage

blib/lib/Lab/Moose/DataFolder.pm
Criterion Covered Total %
statement 105 106 99.0
branch 15 20 75.0
condition 1 3 33.3
subroutine 25 25 100.0
pod 0 1 0.0
total 146 155 94.1


line stmt bran cond sub pod time code
1             package Lab::Moose::DataFolder;
2             $Lab::Moose::DataFolder::VERSION = '3.900';
3             #ABSTRACT: Create a data directory with meta data
4              
5 27     27   428 use v5.20;
  27         102  
6              
7 27     27   178 use warnings;
  27         73  
  27         964  
8 27     27   172 use strict;
  27         117  
  27         644  
9              
10 27     27   163 use Moose;
  27         64  
  27         219  
11 27     27   187944 use MooseX::StrictConstructor;
  27         72  
  27         275  
12 27     27   90960 use MooseX::Params::Validate;
  27         83  
  27         284  
13              
14 27     27   13001 use Carp;
  27         86  
  27         1992  
15              
16 27     27   13107 use Lab::Moose::Catfile 'our_catfile';
  27         95  
  27         1772  
17 27     27   241 use File::Basename qw/basename dirname/;
  27         62  
  27         2306  
18 27     27   14223 use File::Copy 'copy';
  27         66703  
  27         1688  
19 27     27   224 use List::Util 'max';
  27         73  
  27         1713  
20 27     27   12660 use Sys::Hostname;
  27         30349  
  27         1780  
21 27     27   230 use Time::HiRes qw/gettimeofday tv_interval/;
  27         64  
  27         623  
22 27     27   4420 use POSIX qw/strftime/;
  27         79  
  27         218  
23 27     27   46962 use namespace::autoclean;
  27         69  
  27         233  
24 27     27   3382 use Encode 'decode';
  27         28603  
  27         1559  
25              
26 27     27   763 use utf8;
  27         77  
  27         245  
27              
28 27     27   13719 use Lab::Moose::DataFile::Meta;
  27         116  
  27         2189  
29              
30             # Get a copy of @ARGV, before it get's mangled by the user script.
31              
32             our @ARGV_COPY;
33              
34             BEGIN {
35 27     27   18726 @ARGV_COPY = ( $0, @ARGV );
36             }
37              
38              
39             has path => (
40             is => 'ro',
41             isa => 'Str',
42             writer => '_path',
43             predicate => 'has_path',
44             );
45              
46             has date_prefix => (
47             is => 'ro',
48             isa => 'Bool',
49             default => 1
50             );
51              
52             has time_prefix => (
53             is => 'ro',
54             isa => 'Bool',
55             default => 1
56             );
57              
58             has meta_file => (
59             is => 'ro',
60             isa => 'Lab::Moose::DataFile::Meta',
61             init_arg => undef,
62             writer => '_meta_file'
63             );
64              
65             has copy_script => (
66             is => 'ro',
67             isa => 'Bool',
68             default => 1
69             );
70              
71             has script_name => (
72             is => 'ro',
73             isa => 'Str',
74             );
75              
76             sub BUILD {
77 73     73 0 135 my $self = shift;
78              
79 73 100       2582 if ( not $self->has_path() ) {
80 1         33 $self->_path('MEAS');
81             }
82              
83 73         2062 my $folder = $self->path();
84 73         2309 my $dirname = dirname($folder);
85 73         1490 my $basename = basename($folder);
86              
87 73 100       2283 if ( $self->time_prefix ) {
88 34         2009 $basename = strftime( '%H-%M-%S', localtime() ) . "_$basename";
89 34         252 $folder = our_catfile( $dirname, $basename );
90             }
91              
92 73 100       2249 if ( $self->date_prefix ) {
93 34         1538 $basename = strftime( '%Y-%m-%d', localtime() ) . "_$basename";
94 34         182 $folder = our_catfile( $dirname, $basename );
95             }
96              
97 73         233 my $folder_number = _get_folder_number(
98             basename => $basename,
99             dirname => $dirname
100             );
101              
102 73         491 $folder .= sprintf( '_%03d', $folder_number );
103              
104 73 50       4978 mkdir $folder
105             or croak "cannot make directory '$folder': $!";
106              
107 73         3435 $self->_path($folder);
108              
109 73         269 $self->_create_meta_file();
110              
111 73 50       3287 if ( $self->copy_script ) {
112 73         222 $self->_copy_user_script();
113             }
114              
115             }
116              
117             sub _copy_user_script {
118 73     73   141 my $self = shift;
119 73         160 my $script = $0;
120              
121 73         112 my $basename;
122 73         2066 my $script_name = $self->script_name();
123              
124 73 100       180 if ($script_name) {
125 1         3 $basename = $script_name;
126             }
127             else {
128 72         1976 $basename = basename($script);
129             }
130              
131 73         2219 my $copy = our_catfile( $self->path, $basename );
132              
133 73 50       312 copy( $script, $copy )
134             or croak "copy of $script to $copy failed: $!";
135             }
136              
137             sub _create_meta_file {
138 73     73   137 my $self = shift;
139 73         267 my $time = [ gettimeofday() ];
140              
141             my %meta_data = (
142             argv => [@ARGV_COPY],
143              
144             # See http://stackoverflow.com/questions/3526420/how-do-i-get-the-current-user-in-perl-in-a-portable-way
145             user => getlogin() || getpwuid($<),
146             host => hostname(),
147             date => strftime( "%c", localtime() ),
148 73   33     17794 timestamp => join( '.', @{$time} ),
  73         4056  
149             version => _get_version(),
150             );
151              
152 73         3232 my $meta_file = Lab::Moose::DataFile::Meta->new(
153             folder => $self,
154             filename => 'META.yml',
155             );
156              
157 73         2401 $self->_meta_file($meta_file);
158              
159 73         282 $meta_file->log( meta => \%meta_data );
160             }
161              
162             sub _get_version {
163 27     27   333 no strict 'vars'; ## no critic
  27         65  
  27         9093  
164 73 50   73   245 if ( defined $VERSION ) {
165 73         640 return $VERSION;
166             }
167             else {
168 0         0 return 'git';
169             }
170             }
171              
172             sub _get_folder_number {
173 73     73   453 my ( $basename, $dirname ) = validated_list(
174             \@_,
175             basename => { isa => 'Str' },
176             dirname => { isa => 'Str' },
177             );
178              
179 73 50       24037 opendir my $dh, $dirname
180             or croak "cannot open directory '$dirname'";
181              
182 73         2659 my @entries = readdir $dh;
183              
184 73         294 @entries = map { decode( 'UTF-8', $_ ) } @entries;
  765         23892  
185              
186             my $max = max map {
187 73         2356 my $entry = $_;
  765         1216  
188 765 100       2828 if ( $entry =~ /^\Q${basename}\E_([0-9]+)$/ ) {
189 543         1622 my $num = $1;
190             }
191             else {
192 222         645 my $num = 0;
193             }
194             } @entries;
195              
196 73         1497 return $max + 1;
197             }
198              
199             __PACKAGE__->meta->make_immutable();
200             1;
201              
202             __END__
203              
204             =pod
205              
206             =encoding UTF-8
207              
208             =head1 NAME
209              
210             Lab::Moose::DataFolder - Create a data directory with meta data
211              
212             =head1 VERSION
213              
214             version 3.900
215              
216             =head1 DESCRIPTION
217              
218             A data logging setup consists of one Lab::Moose::DataFolder and one or more
219             L<Lab::Moose::DataFile> objects which live inside the DataFolder.
220              
221             =head1 METHODS
222              
223             =head2 new
224              
225             my $folder = Lab::Moose::DataFolder->new(path => 'foldername');
226             # or equivalently use Lab::Moose loader:
227             use Lab::Moose; my $folder = datafolder(path => 'foldername');
228              
229             The actual foldername will consist of the C<path> argument and a numeric
230             suffix. Calling this function repeatedly will create the directories
231             F<foldername_001>, F<foldername_002>, ..., F<foldername_999>,
232             F<foldername_1000>.
233              
234             After creation, the actual filename is contained in the C<path> attribute:
235              
236             my $path = $folder->path();
237              
238             This method will create the following files in the folder:
239              
240             =over
241              
242             =item F<< <SCRIPT> .pl >>
243              
244             A copy of the user script. You can change the name of this script by setting
245             the C<script_name> attribute in the constructor. In case you don't want the
246             script to be copied, just set C<copy_script> to 0 when creating your DataFolder.
247              
248             =item F<META.yml>
249              
250             A YAML file containing meta data.
251             The L<Lab::Moose::DataFile::Meta> object is contained in the C<meta_file>
252             attribute:
253              
254             my $meta_file = $folder->meta_file();
255              
256             =back
257              
258             =head1 COPYRIGHT AND LICENSE
259              
260             This software is copyright (c) 2023 by the Lab::Measurement team; in detail:
261              
262             Copyright 2016 Simon Reinhardt
263             2017-2018 Andreas K. Huettel, Simon Reinhardt
264             2020 Andreas K. Huettel
265             2021 Fabian Weinelt
266              
267              
268             This is free software; you can redistribute it and/or modify it under
269             the same terms as the Perl 5 programming language system itself.
270              
271             =cut