source: trunk/project-meta/project-meta @ 189

Last change on this file since 189 was 189, checked in by g7moreau, 6 years ago
  • Add make-link doc
  • Property svn:executable set to *
File size: 12.6 KB
Line 
1#!/usr/bin/env perl
2#
3# 2018/01/17 Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
4#
5# apt-get install yamllint libyaml-syck-perl libtemplate-perl libarchive-zip-perl
6
7use strict;
8use warnings;
9
10use File::Copy qw{copy};   
11use YAML::Syck;
12use Getopt::Long();
13use Cwd();
14use Template;
15use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
16
17
18my ($verbose);
19Getopt::Long::GetOptions(
20   'verbose' => \$verbose,
21   );
22
23
24my %CMD_DB = (
25   'help'            => \&cmd_help,
26   'version'         => \&cmd_version,
27   'check'           => \&cmd_check,
28   'make-link'       => \&cmd_make_link,
29   'make-zip'        => \&cmd_make_zip,
30   'make-author'     => \&cmd_make_author,
31   'make-licence'    => \&cmd_make_licence,
32   'make-copyright'  => \&cmd_make_copyright,
33   'list-licence'    => \&cmd_list_licence,
34   );
35
36################################################################
37# main program
38################################################################
39
40my $cmd = shift @ARGV || 'help';
41if (defined $CMD_DB{$cmd}) {
42   $CMD_DB{$cmd}->(@ARGV);
43   }
44else {
45   print {*STDERR} "project-meta: command $cmd not found\n\n";
46   $CMD_DB{'help'}->();
47   exit 1;
48   }
49
50exit;
51
52################################################################
53# subroutine
54################################################################
55
56sub print_ok {
57   my ($key, $test) = @_;
58   
59   printf "%-35s : %s\n", $key, $test ? 'yes' : 'no';
60   }
61
62################################################################
63
64sub addfolder2list {
65   my ($folderdb, $folder) = @_;
66   
67   $folder =~ s{/[^/]+$}{};
68   
69   return if $folder !~ m{/};
70
71   $folderdb->{$folder}++;
72   return addfolder2list($folderdb, $folder);
73   }
74
75################################################################
76# command
77################################################################
78
79sub cmd_help {
80   print <<'END';
81project-meta - opendata project metafile manager
82
83 project-meta help
84 project-meta version
85 project-meta check
86 project-meta make-link
87 project-meta make-zip
88 project-meta make-author
89 project-meta make-licence
90 project-meta make-copyright
91 project-meta make-licence
92 project-meta list-licence
93END
94   }
95
96################################################################
97
98sub cmd_version {
99   print "0.0.2\n";
100   }
101
102################################################################
103
104sub cmd_check {
105   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
106
107   my $acronym     = $meta->{'project'}{'acronym'};
108   my $current_dir = Cwd::getcwd();
109   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
110
111   print_ok 'project/acronym',                  $acronym =~ m{\d\d\w[\w\d_]+};
112   print_ok 'public-dap/dap-folder',            $dap_folder ne '' and $dap_folder =~ m{^/};
113   print_ok 'dap-folder not match current_dir', $dap_folder !~ m{$current_dir};
114
115   #print YAML::Syck::Dump($meta);
116   }
117
118################################################################
119
120sub cmd_make_link {
121   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
122   my $current_dir = Cwd::getcwd();
123   my $acronym     = $meta->{'project'}{'acronym'};
124   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
125   my $data_set    = $meta->{'public-dap'}{'data-set'};
126
127   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENCE.txt';
128   {
129      # Remove doublon
130      my %seen = ();
131      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
132      }
133
134   # Create a list of the folder
135   my %folders;
136   for my $dataset (@{$data_set}) {
137      addfolder2list(\%folders, $dataset);
138      }
139
140   print "chmod o+rX,o-w $current_dir\n";
141   print "mkdir -p $dap_folder/$acronym\n" if not -d "$dap_folder/$acronym";
142   for my $folder (sort keys %folders) {
143      print "chmod o+rX,o-w $current_dir/$folder\n";
144      print "mkdir -p $dap_folder/$acronym/$folder\n" if -d "$current_dir/$folder";
145      }
146
147   for my $dataset (@{$data_set}) {
148      if ($dataset =~ m{/}) {
149         # Folder case
150         my $folder = $dataset =~ s{/[^/]+$}{}r;
151         print "ln --symbolic --target-directory $dap_folder/$acronym/$folder/ $current_dir/$dataset\n";
152         }
153      else {
154         # File case
155         print "ln --symbolic --target-directory $dap_folder/$acronym/ $current_dir/$dataset\n";
156         }
157
158      }
159   print "chmod -R o+rX,o-w $dap_folder/$acronym/\n";
160   }
161
162################################################################
163
164sub cmd_make_zip {
165   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
166   my $current_dir = Cwd::getcwd();
167   my $data_set    = $meta->{'public-dap'}{'data-set'};
168   my $acronym     = $meta->{'project'}{'acronym'};
169
170   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENCE.txt';
171   {
172      # Remove doublon
173      my %seen = ();
174      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
175      }
176
177   # Create a Zip file
178   my $zip = Archive::Zip->new();
179
180   for my $dataset (@{$data_set}) {
181      if (-d $dataset) {
182         # Folder case
183         $zip->addTree($dataset, "$acronym/$dataset");
184         }
185      elsif (-f $dataset) {
186         # File case
187         $zip->addFile($dataset, "$acronym/$dataset");
188         }
189      else {
190         # Strange case
191         print "Error: entry $dataset doesn't exists\n";
192         }
193      }
194
195   my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime time;
196   $year += 1900;
197   $mon++;
198   my $date = sprintf '%04i%02i%02i-%02i%02i', $year, $mon, $mday, $hour, $min;
199
200   # Save the Zip file
201   unless ($zip->writeToFileNamed("$current_dir/$acronym--$date.zip") == AZ_OK) {
202      die 'Error: zip write error';
203      }
204   }
205
206################################################################
207
208sub cmd_make_author {
209   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
210
211   my $current_dir = Cwd::getcwd();
212
213   my $acronym    = $meta->{'project'}{'acronym'};
214   my $authors_list = $meta->{'project'}{'authors'};
215
216   if (-f "$current_dir/AUTHORS.txt") {
217      # Test for manual or automatically generated file
218      # Automatically generated file by project-meta
219      my $automatic;
220      open my $fh, '<', "$current_dir/AUTHORS.txt" or die $!;
221      for my $line (<$fh>) {
222         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
223         }
224      close $fh;
225
226      if (not $automatic) {
227         print "Warning: AUTHORS.txt already exists\n";
228         return;
229         }
230
231      print "Warning: update AUTHORS.txt\n";
232      }
233
234   my $tt = Template->new(INCLUDE_PATH => '/usr/share/project-meta/template.d');
235   my $msg_format = '';
236   $tt->process('AUTHORS.tt',
237      {
238         acronym    => $acronym,
239         authorlist => $authors_list,
240      }, \$msg_format) || die $tt->error;
241
242   open my $fh,  '>', "$current_dir/AUTHORS.txt" or die $!;
243   print $fh "$msg_format\n\n";
244   close $fh;
245   }
246
247################################################################
248
249sub cmd_make_licence {
250   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
251
252   my $current_dir = Cwd::getcwd();
253
254   if (-f "$current_dir/LICENCE.txt") {
255      print "Warning: LICENCE.txt already exists\n";
256      return;
257      }
258
259   my $licence = $meta->{'public-dap'}{'data-licence'};
260
261   if (not -f "/usr/share/project-meta/licence.d/$licence.txt") {
262      print "Error: licence $licence doesn't exists in project-meta database\n";
263      exit 1;
264      }
265
266   copy("/usr/share/project-meta/licence.d/$licence.txt", "$current_dir/LICENCE.txt")
267      or die "Error: licence copy failed - $!";
268
269   print "Info: LICENCE.txt file create\n";
270   return;
271   }
272
273################################################################
274
275sub cmd_make_copyright {
276   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
277
278   my $current_dir = Cwd::getcwd();
279
280   if (-f "$current_dir/COPYRIGHT.txt") {
281      # Test for manual or automatically generated file
282      # Automatically generated file by project-meta
283      my $automatic;
284      open my $fh, '<', "$current_dir/COPYRIGHT.txt" or die $!;
285      for my $line (<$fh>) {
286         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
287         }
288      close $fh;
289
290      if (not $automatic) {
291         print "Warning: COPYRIGHT.txt already exists\n";
292         return;
293         }
294
295      print "Warning: update COPYRIGHT.txt\n";
296      }
297   
298   my $tt = Template->new(
299      INCLUDE_PATH   => '/usr/share/project-meta/template.d',
300      POST_CHOMP     => 1, # Remove space and carriage return after %]
301      );
302   my $msg_format = '';
303   $tt->process('COPYRIGHT.tt',
304      {
305         title       => $meta->{'project'}{'title'},
306         acronym     => $meta->{'project'}{'acronym'},
307         authorlist  => $meta->{'project'}{'authors'},
308         description => $meta->{'project'}{'short-description'},
309         licence     => $meta->{'public-dap'}{'data-licence'},
310         doi         => $meta->{'publication'}{'doi'},
311      }, \$msg_format) || die $tt->error;
312
313   open my $fh,  '>', "$current_dir/COPYRIGHT.txt" or die $!;
314   print $fh "$msg_format\n\n";
315   close $fh;
316   }
317
318################################################################
319
320sub cmd_list_licence {
321   opendir my $dh, '/usr/share/project-meta/licence.d/' or die $!;
322   for my $licence (readdir $dh) {
323      # Keep only file
324      next if not -f "/usr/share/project-meta/licence.d/$licence";
325     
326      # Keep only .txt file
327      next if not $licence =~ m/\.txt$/;
328
329      $licence =~ s/\.txt$//;
330      print "$licence\n";
331      }
332   closedir $dh;
333   }
334
335################################################################
336# documentation
337################################################################
338
339__END__
340
341=head1 NAME
342
343project-meta - opendata project metafile manager
344
345
346=head1 USAGE
347
348 project-meta help
349 project-meta version
350 project-meta check
351 project-meta make-link
352 project-meta make-zip
353 project-meta make-author
354 project-meta make-licence
355 project-meta make-copyright
356 project-meta make-licence
357 project-meta list-licence
358
359=head1 DESCRIPTION
360
361Project-Meta is a small tool to maintain a set of open data files.
362In order to help you in this task, C<project-meta> command has a set of action
363to generated and maintain many files in your dataset.
364
365Everything is declare in the metafile F<PROJECT-META.yml>.
366This YAML file must exist in your root projet folder.
367See L</METAFILE SPECIFICATION>.
368
369=head1 COMMANDS
370
371Some command are defined in the source code but are not documented here.
372Theses could be not well defined, not finished, not well tested...
373You can read the source code and use them at your own risk
374(like for all the Project-Meta code).
375
376=head2 check
377
378 project-meta check
379
380Check your F<PROJECT-META.yml> has the good key.
381If your metafile is not a valid YAML file,
382you can use C<yamllint> command to check just it's format.
383
384=head2 make-link
385
386 project-meta make-link
387
388Create UNIX soft links on the OpeNDAP folder to the real data.
389Files F<AUTHORS.txt>, F<LICENCE.txt> and F<COPYRIGHT.txt> are mandatory but could be generated (see below).
390The main keys use in the F<PROJECT-META.yml> are:
391
392=over
393
394=item * C<project/acronym>: the project short acronym
395=item * C<public-dap/dap-folder>: the OpeNDAP folder
396=item * C<public-dap/data-set>: a list of files or folder to push
397
398=back
399
400=head2 make-licence
401
402 project-meta make-licence
403
404Copy the licence file from the project-meta licence database at the current folder
405with the file name: F<LICENCE.txt>.
406
407The licence is defined in the F<PROJECT-META.yml> specification under the key C<public-dap/data-licence>.
408The list of possible licence is given with the command L</list-licence>.
409
410=head2 list-licence
411
412 project-meta list-licence
413
414Give the list of all the open data licence supported by the project-meta licence database.
415At this time the possible licence are:
416
417 license-ouverte-v2.0
418 open-database-license-v1.0
419
420Note that these licences are dedicated to open data.
421Please do not use open licence that have been written for code or documentation for data.
422
423
424=head1 METAFILE SPECIFICATION
425
426Each project must have an open data metafile which describe the project : C<PROJECT-META.yml>.
427The file is in YAML format because this is a human readable style of text file.
428
429You can find in the project-meta software a C<PROJECT-META.sample.yml> example.
430This one is actually the master reference specification!
431
432
433=head1 KNOWN BUGS
434
435 - not really check keys and tags before doing action!
436
437=head1 SEE ALSO
438
439yamllint
440
441
442=head1 AUTHOR
443
444Written by Gabriel Moreau, LEGI UMR5519, CNRS, Grenoble - France
445
446=head1 SPECIAL THANKS
447
448The list of people below did not directly contribute to project-meta's source code
449but provided me with some data, returned bugs
450or helped me in another task like having new ideas, specifications...
451Maybe I forgot your contribution in recent years,
452please forgive me in advance and send me an e-mail to correct this.
453
454Joel Sommeria, Julien Chauchat, Cyrille Bonamy, Antoine Mathieu.
455
456
457=head1 LICENSE AND COPYRIGHT
458
459Licence GNU GPL version 2 or later and Perl equivalent
460
461Copyright (C) 2017-2018 Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>.
Note: See TracBrowser for help on using the repository browser.