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.880';
3             #ABSTRACT: Create a data directory with meta data
4              
5 27     27   436 use v5.20;
  27         114  
6              
7 27     27   195 use warnings;
  27         74  
  27         944  
8 27     27   190 use strict;
  27         186  
  27         706  
9              
10 27     27   169 use Moose;
  27         90  
  27         251  
11 27     27   192585 use MooseX::StrictConstructor;
  27         90  
  27         285  
12 27     27   93630 use MooseX::Params::Validate;
  27         88  
  27         314  
13              
14 27     27   13438 use Carp;
  27         88  
  27         1934  
15              
16 27     27   14083 use Lab::Moose::Catfile 'our_catfile';
  27         94  
  27         1800  
17 27     27   225 use File::Basename qw/basename dirname/;
  27         70  
  27         2549  
18 27     27   15896 use File::Copy 'copy';
  27         71245  
  27         1820  
19 27     27   238 use List::Util 'max';
  27         82  
  27         1825  
20 27     27   13652 use Sys::Hostname;
  27         32697  
  27         1813  
21 27     27   273 use Time::HiRes qw/gettimeofday tv_interval/;
  27         71  
  27         671  
22 27     27   4405 use POSIX qw/strftime/;
  27         91  
  27         291  
23 27     27   49285 use namespace::autoclean;
  27         70  
  27         220  
24 27     27   3631 use Encode 'decode';
  27         29052  
  27         1653  
25              
26 27     27   816 use utf8;
  27         100  
  27         296  
27              
28 27     27   14448 use Lab::Moose::DataFile::Meta;
  27         129  
  27         2314  
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   19079 @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 143 my $self = shift;
78              
79 73 100       2617 if ( not $self->has_path() ) {
80 1         32 $self->_path('MEAS');
81             }
82              
83 73         2030 my $folder = $self->path();
84 73         2394 my $dirname = dirname($folder);
85 73         1596 my $basename = basename($folder);
86              
87 73 100       2263 if ( $self->time_prefix ) {
88 34         2349 $basename = strftime( '%H-%M-%S', localtime() ) . "_$basename";
89 34         253 $folder = our_catfile( $dirname, $basename );
90             }
91              
92 73 100       2648 if ( $self->date_prefix ) {
93 34         1661 $basename = strftime( '%Y-%m-%d', localtime() ) . "_$basename";
94 34         207 $folder = our_catfile( $dirname, $basename );
95             }
96              
97 73         257 my $folder_number = _get_folder_number(
98             basename => $basename,
99             dirname => $dirname
100             );
101              
102 73         560 $folder .= sprintf( '_%03d', $folder_number );
103              
104 73 50       5887 mkdir $folder
105             or croak "cannot make directory '$folder': $!";
106              
107 73         3566 $self->_path($folder);
108              
109 73         282 $self->_create_meta_file();
110              
111 73 50       3429 if ( $self->copy_script ) {
112 73         238 $self->_copy_user_script();
113             }
114              
115             }
116              
117             sub _copy_user_script {
118 73     73   141 my $self = shift;
119 73         188 my $script = $0;
120              
121 73         122 my $basename;
122 73         2101 my $script_name = $self->script_name();
123              
124 73 100       184 if ($script_name) {
125 1         9 $basename = $script_name;
126             }
127             else {
128 72         2054 $basename = basename($script);
129             }
130              
131 73         2293 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   146 my $self = shift;
139 73         347 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     18966 timestamp => join( '.', @{$time} ),
  73         4355  
149             version => _get_version(),
150             );
151              
152 73         3333 my $meta_file = Lab::Moose::DataFile::Meta->new(
153             folder => $self,
154             filename => 'META.yml',
155             );
156              
157 73         2481 $self->_meta_file($meta_file);
158              
159 73         283 $meta_file->log( meta => \%meta_data );
160             }
161              
162             sub _get_version {
163 27     27   332 no strict 'vars'; ## no critic
  27         118  
  27         9862  
164 73 50   73   250 if ( defined $VERSION ) {
165 73         683 return $VERSION;
166             }
167             else {
168 0         0 return 'git';
169             }
170             }
171              
172             sub _get_folder_number {
173 73     73   457 my ( $basename, $dirname ) = validated_list(
174             \@_,
175             basename => { isa => 'Str' },
176             dirname => { isa => 'Str' },
177             );
178              
179 73 50       24844 opendir my $dh, $dirname
180             or croak "cannot open directory '$dirname'";
181              
182 73         3492 my @entries = readdir $dh;
183              
184 73         330 @entries = map { decode( 'UTF-8', $_ ) } @entries;
  765         25035  
185              
186             my $max = max map {
187 73         2496 my $entry = $_;
  765         1107  
188 765 100       3099 if ( $entry =~ /^\Q${basename}\E_([0-9]+)$/ ) {
189 543         1735 my $num = $1;
190             }
191             else {
192 222         614 my $num = 0;
193             }
194             } @entries;
195              
196 73         1589 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.880
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