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

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