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

Last change on this file since 412 was 412, checked in by g7moreau, 5 years ago
  • Add multi-dataset support for publish and unpublish command
  • Property svn:executable set to *
File size: 25.4 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 libyaml-syck-perl libtemplate-perl libarchive-zip-perl
6# apt-get install yamllint libyaml-shell-perl # check YAML files
7
8use strict;
9use warnings;
10use version; our $VERSION = version->declare('0.2.3');
11
12use File::Copy qw(copy);   
13use YAML::Syck;
14use Getopt::Long();
15use Cwd();
16use Template;
17use Archive::Zip qw(:ERROR_CODES :CONSTANTS);
18
19our $CFG_VERSION = 2;
20
21my %CMD_DB = (
22   'help'                  => \&cmd_help,
23   'version'               => \&cmd_version,
24   'check'                 => \&cmd_check,
25   'dap-publish'           => \&cmd_dap_publish,
26   'dap-unpublish'         => \&cmd_dap_unpublish,
27   'dataset-list'          => \&cmd_dataset_list,
28   'dataset-size'          => \&cmd_dataset_size,
29   'make-zip'              => \&cmd_make_zip,
30   'make-allfiles'         => \&cmd_make_allfiles,
31   'make-file-author'      => \&cmd_make_file_author,
32   'make-file-copyright'   => \&cmd_make_file_copyright,
33   'make-file-license'     => \&cmd_make_file_license,
34   'list-license'          => \&cmd_list_license,
35   'upgrade'               => \&cmd_upgrade,
36   );
37
38################################################################
39# main program
40################################################################
41
42my $cmd = shift @ARGV || 'help';
43if (defined $CMD_DB{$cmd}) {
44   $CMD_DB{$cmd}->(@ARGV);
45   }
46else {
47   print {*STDERR} "project-meta: command $cmd not found\n\n";
48   $CMD_DB{'help'}->();
49   exit 1;
50   }
51
52exit;
53
54################################################################
55# subroutine
56################################################################
57
58#---------------------------------------------------------------
59
60sub get_cmd_name {
61   my ($pkg, $sub) = split /::/, (caller(1))[3];
62   $sub =~ s/^cmd_//;
63   $sub =~ s/_/-/g;
64   return $sub;
65   }
66
67#---------------------------------------------------------------
68
69sub print_ok {
70   my ($key, $test) = @_;
71   
72   printf "%-35s : %s\n", $key, $test ? 'yes' : 'no';
73   }
74
75#---------------------------------------------------------------
76
77sub addfolder2list {
78   my ($folderdb, $folder) = @_;
79   
80   return if $folder !~ m{/};
81   
82   $folder =~ s{/[^/]+$}{};
83
84   $folderdb->{$folder}++;
85   return addfolder2list($folderdb, $folder);
86   }
87
88#---------------------------------------------------------------
89
90sub upgrade_version_1_to_2 {
91   my $meta = shift;
92
93   $meta->{'project'}{'identifier'} ||= {};
94   $meta->{'project'}{'identifier'}{'acronym'} = $meta->{'project'}{'acronym'};
95   delete $meta->{'project'}{'acronym'};
96
97   $meta->{'project'}{'creator'} = $meta->{'project'}{'authors'};
98   delete $meta->{'project'}{'authors'};
99
100   $meta->{'project'}{'description'} = $meta->{'project'}{'short-description'};
101   delete $meta->{'project'}{'short-description'};
102
103   $meta->{'project'}{'rights'} = $meta->{'public-dap'}{'data-license'};
104   delete $meta->{'public-dap'}{'data-license'};
105
106   $meta->{'project'}{'relation'} ||= [];
107   for my $doi (@{$meta->{'publication'}{'doi'}}) {
108      push @{$meta->{'project'}{'relation'}}, {doi => $doi};
109      }
110   delete $meta->{'publication'}{'doi'};
111
112   $meta->{'version'} = 2;
113   return $meta;
114   }
115
116#---------------------------------------------------------------
117
118sub load_metadata {
119   my $meta = YAML::Syck::LoadFile("PROJECT-META.yml");
120
121   my $initial_version = $meta->{'version'};
122   if ($initial_version < $CFG_VERSION) {
123      print "Warning: upgrade config file from version $initial_version to last version $CFG_VERSION\n";
124      my $upgrade = 'upgrade_version_' . ($CFG_VERSION - 1) . '_to_' . $CFG_VERSION;
125      &{$upgrade}($meta);
126      $initial_version = $CFG_VERSION;
127      }
128   elsif ($initial_version < $CFG_VERSION) {
129      die "Error: config file at future version $meta->{'version'}, program only at $CFG_VERSION\n"
130      }
131
132   return wantarray ? ($meta, $initial_version) : $meta;
133   }
134
135################################################################
136# command
137################################################################
138
139sub cmd_help {
140   my ($cmd) = @_;
141
142   my $help = <<'END';
143project-meta - opendata project metafile manager
144
145 project-meta help
146 project-meta version
147 project-meta check
148 project-meta dap-publish [--verbose|-v] [--dataset|-d dataset]
149 project-meta dap-unpublish [--verbose|-v] [--dataset|-d dataset]
150 project-meta dataset-list
151 project-meta dataset-size [--verbose|-v] [--dataset|-d dataset]
152 project-meta make-zip [--verbose|-v] [--dataset|-d dataset]
153 project-meta make-allfiles
154 project-meta list-license
155 project-meta make-file-license
156 project-meta make-file-author
157 project-meta make-file-copyright
158 project-meta upgrade
159END
160
161   if (defined $cmd) {
162      #$help =~ s/$/ /mg;
163      print join("\n", grep(/^\suser-kont\s$cmd(\s|$)/, split/\n/, $help)) . "\n";
164      }
165   else {
166      print $help;
167      }
168   return;
169   }
170
171#---------------------------------------------------------------
172
173sub cmd_version {
174   print "$VERSION\n";
175   }
176
177#---------------------------------------------------------------
178
179sub cmd_upgrade {
180   my ($meta, $initial_version) = load_metadata();
181
182   if ($initial_version < $meta->{'version'}) {
183      my $next_config = "PROJECT-META-v$meta->{'version'}.yml";
184      if (-e $next_config) {
185         die "Error: upgrade propose config file $next_config already exists\n";
186         }
187     
188      print "Warning: create new config file $next_config, please verify before using it\n";
189      YAML::Syck::SaveFile($next_config, $meta);
190      }
191   elsif ($initial_version == $CFG_VERSION) {
192      print "Warning: nothing to do, config file already at version $CFG_VERSION\n";
193      }
194   }
195
196#---------------------------------------------------------------
197
198sub cmd_check {
199   my $meta = load_metadata();
200
201   my $acronym     = $meta->{'project'}{'identifier'}{'acronym'};
202   my $current_dir = Cwd::getcwd();
203   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
204
205   print_ok 'project/identifier/acronym',       $acronym =~ m{\d\d\w[\w\d_/]+};
206   print_ok 'public-dap/dap-folder',            $dap_folder ne '' and $dap_folder =~ m{^/};
207   print_ok 'dap-folder not match current_dir', $dap_folder !~ m{$current_dir};
208
209   #print YAML::Syck::Dump($meta);
210   }
211
212#---------------------------------------------------------------
213
214sub cmd_dap_publish {
215   local @ARGV = @_;
216   my ($verbose, $dataset_name);
217
218   Getopt::Long::GetOptions(
219      'verbose'        => \$verbose,
220      'dataset|d=s'    => \$dataset_name,
221      );
222
223   my $meta = load_metadata();
224   my $current_dir = Cwd::getcwd();
225   my $acronym     = $meta->{'project'}{'identifier'}{'acronym'};
226   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
227   my $data_set    = $meta->{'public-dap'}{'data-set'};
228   if ($dataset_name) {
229      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
230         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
231         }
232      else {
233         die "Error, dataset $dataset_name does'nt exists\n";
234         }
235      }
236
237   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENSE.txt';
238   {
239      # Remove doublon
240      my %seen = ();
241      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
242      }
243
244   # Create a list of the folder
245   my %folders;
246   for my $dataset (@{$data_set}) {
247      addfolder2list(\%folders, $dataset);
248      }
249
250   print "chmod o+rX,o-w '$current_dir'\n";
251   print "mkdir -p '$dap_folder/$acronym'\n" if not -d "$dap_folder/$acronym";
252   if ($dataset_name) {
253      $acronym .= "/$dataset_name";
254      print "mkdir -p '$dap_folder/$acronym'\n" if not -d "$dap_folder/$acronym";
255      }
256   for my $folder (sort keys %folders) {
257      print "chmod o+rX,o-w '$current_dir/$folder'\n";
258      print "mkdir '$dap_folder/$acronym/$folder'\n" if -d "$current_dir/$folder";
259      }
260
261   for my $dataset (@{$data_set}) {
262      if ($dataset =~ m{/}) {
263         # sub-folder case
264         my $folder = $dataset =~ s{/[^/]+$}{}r;
265         print "chmod -R o+rX,o-w '$current_dir/$dataset'\n";
266         print "ln --symbolic --target-directory '$dap_folder/$acronym/$folder/' '$current_dir/$dataset'\n";
267         }
268      else {
269         # Root case
270         print "ln --symbolic --target-directory '$dap_folder/$acronym/' '$current_dir/$dataset'\n";
271         }
272
273      }
274   print "chmod -R o+rX,o-w '$dap_folder/$acronym/'\n";
275   }
276
277#---------------------------------------------------------------
278
279sub cmd_dap_unpublish {
280   local @ARGV = @_;
281   my ($verbose, $dataset_name);
282
283   Getopt::Long::GetOptions(
284      'verbose'        => \$verbose,
285      'dataset|d=s'    => \$dataset_name,
286      );
287
288   my $meta = load_metadata();
289   my $current_dir = Cwd::getcwd();
290   my $acronym     = $meta->{'project'}{'identifier'}{'acronym'};
291   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
292   my $data_set    = $meta->{'public-dap'}{'data-set'};
293   if ($dataset_name) {
294      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
295         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
296         }
297      else {
298         die "Error, dataset $dataset_name does'nt exists\n";
299         }
300      }
301
302   die "Error: DAP folder match current folder" if $dap_folder =~ m{$current_dir} or $current_dir =~ m{$dap_folder};
303
304   $acronym .= "/$dataset_name" if $dataset_name;
305   print "find '$dap_folder/$acronym/' -type l -o -type d -exec ls -l {} \+\n";
306   print "find '$dap_folder/$acronym/' -type l -delete\n";
307   print "find '$dap_folder/$acronym/' -type d -delete\n";
308   }
309
310#---------------------------------------------------------------
311
312sub cmd_dataset_list {
313   local @ARGV = @_;
314
315   my $meta = load_metadata();
316
317   die "Error: no dataset\n"
318      if not defined $meta->{'public-dap'}
319      or not defined $meta->{'public-dap'}{'data-set'};
320
321   my $data_set = $meta->{'public-dap'}{'data-set'};
322   if(ref($data_set) eq 'HASH') {
323      print "$_\n" for sort keys %{$data_set};
324      }
325   else {
326      print "default uname dataset\n";
327      }
328   }
329
330#---------------------------------------------------------------
331
332sub cmd_dataset_size {
333   local @ARGV = @_;
334   my ($verbose, $dataset_name);
335
336   Getopt::Long::GetOptions(
337      'verbose'        => \$verbose,
338      'dataset|d=s'    => \$dataset_name,
339      );
340
341   my $meta = load_metadata();
342   my $data_set = $meta->{'public-dap'}{'data-set'};
343   if ($dataset_name) {
344      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
345         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
346         }
347      else {
348         die "Error, dataset $dataset_name does'nt exists\n";
349         }
350      }
351   my $total;
352   for my $dataset (@{$data_set}) {
353      my $cmd = qx{du -sm $dataset};
354      chomp $cmd;
355      my ($size, $inode) = split /\s+/, $cmd;
356      $total += $size;
357      printf "%-7i %s\n", $size, $inode;
358      }
359   printf "%-7i %s\n", $total, 'TOTAL';
360   }
361
362#---------------------------------------------------------------
363
364sub cmd_make_zip {
365   local @ARGV = @_;
366   my ($verbose, $dataset_name);
367
368   Getopt::Long::GetOptions(
369      'verbose'        => \$verbose,
370      'dataset|d=s'    => \$dataset_name,
371      );
372
373   my $meta = load_metadata();
374   my $current_dir = Cwd::getcwd();
375   my $data_set = $meta->{'public-dap'}{'data-set'};
376   if ($dataset_name) {
377      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
378         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
379         }
380      else {
381         die "Error, dataset $dataset_name does'nt exists\n";
382         }
383      }
384
385   my $acronym = $meta->{'project'}{'identifier'}{'acronym'};
386
387   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENSE.txt';
388   {
389      # Remove doublon
390      my %seen = ();
391      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
392      }
393
394   # Create a Zip file
395   my $zip = Archive::Zip->new();
396
397   for my $dataset (@{$data_set}) {
398      if (-d $dataset) {
399         # Folder case
400         $zip->addTree($dataset, "$acronym/$dataset");
401         }
402      elsif (-f $dataset) {
403         # File case
404         $zip->addFile($dataset, "$acronym/$dataset");
405         }
406      else {
407         # Strange case
408         print "Error: entry $dataset doesn't exists\n";
409         }
410      }
411
412   my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime time;
413   $year += 1900;
414   $mon++;
415   my $date = sprintf '%04i%02i%02i-%02i%02i', $year, $mon, $mday, $hour, $min;
416
417   # Save the Zip file
418   my $zipname = "$acronym";
419   $zipname .= "-$dataset_name" if $dataset_name;
420   $zipname .= "--$date";
421   unless ($zip->writeToFileNamed("$current_dir/$zipname.zip") == AZ_OK) {
422      die 'Error: zip write error';
423      }
424   }
425
426#---------------------------------------------------------------
427
428sub cmd_make_allfiles {
429   cmd_make_file_author();
430   cmd_make_file_license();
431   cmd_make_file_copyright();
432   }
433
434#---------------------------------------------------------------
435
436sub cmd_make_file_author {
437   my $meta = load_metadata();
438
439   my $current_dir = Cwd::getcwd();
440
441   my $acronym    = $meta->{'project'}{'identifier'}{'acronym'};
442   my $authors_list = $meta->{'project'}{'creator'};
443
444   if (-f "$current_dir/AUTHORS.txt") {
445      # Test for manual or automatically generated file
446      # Automatically generated file by project-meta
447      my $automatic;
448      open my $fh, '<', "$current_dir/AUTHORS.txt" or die $!;
449      for my $line (<$fh>) {
450         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
451         }
452      close $fh;
453
454      if (not $automatic) {
455         print "Warning: AUTHORS.txt already exists\n";
456         return;
457         }
458
459      print "Warning: update AUTHORS.txt\n";
460      }
461
462   my $tt = Template->new(INCLUDE_PATH => '/usr/share/project-meta/template.d');
463   my $msg_format = '';
464   $tt->process('AUTHORS.tt',
465      {
466         acronym    => $acronym,
467         authorlist => $authors_list,
468      }, \$msg_format) || die $tt->error;
469
470   open my $fh,  '>', "$current_dir/AUTHORS.txt" or die $!;
471   print $fh "$msg_format\n\n";
472   close $fh;
473   }
474
475#---------------------------------------------------------------
476
477sub cmd_make_file_license {
478   my $meta = load_metadata();
479
480   my $current_dir = Cwd::getcwd();
481
482   if (-f "$current_dir/LICENSE.txt") {
483      print "Warning: LICENSE.txt already exists\n";
484      return;
485      }
486
487   my $license = $meta->{'project'}{'rights'};
488
489   if (not -f "/usr/share/project-meta/license.d/$license.txt") {
490      print "Error: license $license doesn't exists in project-meta database\n";
491      exit 1;
492      }
493
494   copy("/usr/share/project-meta/license.d/$license.txt", "$current_dir/LICENSE.txt")
495      or die "Error: license copy failed - $!";
496
497   print "Info: LICENSE.txt file create\n";
498   return;
499   }
500
501#---------------------------------------------------------------
502
503sub cmd_make_file_copyright {
504   my $meta = load_metadata();
505
506   my $current_dir = Cwd::getcwd();
507
508   if (-f "$current_dir/COPYRIGHT.txt") {
509      # Test for manual or automatically generated file
510      # Automatically generated file by project-meta
511      my $automatic;
512      open my $fh, '<', "$current_dir/COPYRIGHT.txt" or die $!;
513      for my $line (<$fh>) {
514         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
515         }
516      close $fh;
517
518      if (not $automatic) {
519         print "Warning: COPYRIGHT.txt already exists\n";
520         return;
521         }
522
523      print "Warning: update COPYRIGHT.txt\n";
524      }
525   
526   my $tt = Template->new(
527      INCLUDE_PATH   => '/usr/share/project-meta/template.d',
528      POST_CHOMP     => 1, # Remove space and carriage return after %]
529      );
530   my $msg_format = '';
531   my $doi_first  = '';
532   if (exists $meta->{'project'}{'relation'}) {
533      for my $doi (@{$meta->{'project'}{'relation'}}) {
534         next if not exists $doi->{'doi'};
535         $doi_first = $doi->{'doi'};
536         last;
537         }
538      }
539   $tt->process('COPYRIGHT.tt',
540      {
541         title       => $meta->{'project'}{'title'},
542         acronym     => $meta->{'project'}{'identifier'}{'acronym'},
543         authorlist  => $meta->{'project'}{'creator'},
544         description => $meta->{'project'}{'description'},
545         license     => $meta->{'project'}{'rights'},
546         doi         => $doi_first,
547      }, \$msg_format) || die $tt->error;
548
549   open my $fh, '>', "$current_dir/COPYRIGHT.txt" or die $!;
550   print $fh "$msg_format\n\n";
551   close $fh;
552   }
553
554#---------------------------------------------------------------
555
556sub cmd_list_license {
557   opendir my $dh, '/usr/share/project-meta/license.d/' or die $!;
558   for my $license (readdir $dh) {
559      # Keep only file
560      next if not -f "/usr/share/project-meta/license.d/$license";
561     
562      # Keep only .txt file
563      next if not $license =~ m/\.txt$/;
564
565      $license =~ s/\.txt$//;
566      print "$license\n";
567      }
568   closedir $dh;
569   }
570
571################################################################
572# documentation
573################################################################
574
575__END__
576
577=head1 NAME
578
579project-meta - opendata project metafile manager
580
581
582=head1 USAGE
583
584 project-meta help
585 project-meta version
586 project-meta check
587 project-meta dap-publish [--verbose|-v] [--dataset|-d dataset]
588 project-meta dap-unpublish [--verbose|-v] [--dataset|-d dataset]
589 project-meta dataset-list
590 project-meta dataset-size [--verbose|-v] [--dataset|-d dataset]
591 project-meta make-zip [--verbose|-v] [--dataset|-d dataset]
592 project-meta list-license
593 project-meta make-file-license
594 project-meta make-file-author
595 project-meta make-file-copyright
596 project-meta upgrade
597
598
599=head1 DESCRIPTION
600
601Project-Meta is a small tool to maintain a set of open data files.
602In order to help you in this task, C<project-meta> command has a set of action
603to generated and maintain many files in your dataset.
604
605Everything is declare in the metafile F<PROJECT-META.yml>.
606This YAML file must exist in your root projet folder.
607See L</METAFILE SPECIFICATION>.
608
609
610=head1 COMMANDS
611
612Some command are defined in the source code but are not documented here.
613Theses could be not well defined, not finished, not well tested...
614You can read the source code and use them at your own risk
615(like for all the Project-Meta code).
616
617=head2 check
618
619 project-meta check
620
621Check your F<PROJECT-META.yml> has the good key.
622If your metafile is not a valid YAML file,
623you can use C<yamllint> or C<ysh> commands to check just it's format.
624
625=head2 dap-publish
626
627 project-meta dap-publish [--verbose|-v] [--dataset|-d dataset]
628
629Publish data on an OpeNDAP server.
630Because data can be very large,
631This command just create UNIX soft links on the OpeNDAP folder to the real data.
632There is no copy.
633Files F<AUTHORS.txt>, F<LICENSE.txt> and F<COPYRIGHT.txt> are mandatory but could be generated (see below).
634The main keys use in the F<PROJECT-META.yml> are:
635
636=over
637
638=item * C<project/identifier/acronym>: the project short acronym, add to the OpeNDAP root folder
639
640=item * C<public-dap/dap-folder>: the OpeNDAP root folder
641
642=item * C<public-dap/data-set>: a list of files or folder to push
643
644=back
645
646Because this command could be dangerous, it does nothing!
647It print on terminal shell command to be done.
648You have to verify ouput before eval it.
649
650  project-meta dap-publish
651  project-meta dap-publish | bash
652
653=head2 dap-unpublish
654
655 project-meta dap-unpublish [--verbose|-v] [--dataset|-d dataset]
656
657Unpublish data from the OpeNDAP server.
658In practice, it remove links in OpeNDAP folder for that projet.
659Because command C<rm> is always dangerous,
660we use here the command C<find> limited to folder and link.
661
662Please verify the returned values before excuted it with the C<-delete> option.
663
664=head2 dataset-list
665
666 project-meta dataset-list
667
668=head2 dataset-size
669
670 project-meta dataset-size [--verbose|-v] [--dataset|-d dataset]
671
672=head2 make-zip
673
674 project-meta make-zip [--verbose|-v] [--dataset|-d dataset]
675
676Create a ZIP archive with the open data set.
677Files F<AUTHORS.txt>, F<LICENSE.txt> and F<COPYRIGHT.txt> are mandatory but could be generated (see below).
678The main keys use in the F<PROJECT-META.yml> are:
679
680=over
681
682=item * C<project/identifier/acronym>: the project short acronym, use as root folder
683
684=item * C<public-dap/data-set>: a list of files or folder to push
685
686=back
687
688=head2 make-allfiles
689
690 project-meta make-allfiles
691
692Generate or update all files: F<AUTHORS.txt>, F<COPYRIGHT.txt> and F<LICENSE.txt>.
693This command is just a shortcut for L</make-file-author>, L</make-file-copyright> and L</make-file-license>.
694
695
696=head2 list-license
697
698 project-meta list-license
699
700Give the list of all the open data licenses supported by the project-meta license database.
701At this time the possible licenses are:
702
703=over
704
705=item * L<community-data-license-agreement-permissive-v1.0|https://cdla.io/permissive-1-0/wp-content/uploads/sites/52/2017/10/CDLA-Permissive-v1.0.pdf>
706        (permissive - allow users to freely share and adapt)
707
708=item * L<community-data-license-agreement-sharing-v1.0|https://cdla.io/sharing-1-0/wp-content/uploads/sites/52/2017/10/CDLA-Sharing-v1.0.pdf>
709        (copyleft - allow users to freely share and adapt while maintaining this same freedom for others)
710
711=item * L<creative-common-attribution-v4.0|https://creativecommons.org/licenses/by/4.0/legalcode.txt>
712        (copyleft - allow users to freely share and adapt while maintaining this same freedom for others)
713
714=item * L<creative-common-zero-v1.0|https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt>
715        (like public domain)
716
717=item * L<licence-ouverte-v2.0|https://www.etalab.gouv.fr/wp-content/uploads/2017/04/ETALAB-Licence-Ouverte-v2.0.pdf>
718        (copyleft - opendata french goverment)
719
720=item * L<open-database-license-v1.0|https://opendatacommons.org/files/2018/02/odbl-10.txt>
721        (copyleft - allow users to freely share, modify, and use the database while maintaining this same freedom for others)
722
723=back
724
725Note that these licenses are dedicated to open data.
726Please do not use an open license that would have been thought for source code or documentation and not for open data.
727Here are some links about open data licence context:
728
729=over
730
731=item * A good article about Community Data License Agreement and Open Data Licence in general
732   L<Licenses for data|https://lwn.net/Articles/753648/> written on 9 May 2018.
733
734=item * A french page about French Public Open Data licence
735   L<https://www.etalab.gouv.fr/licence-ouverte-open-licence>.
736
737=back
738
739=head2 make-file-license
740
741 project-meta make-file-license
742
743Copy the license file from the project-meta license database at the current folder
744with the file name: F<LICENSE.txt>.
745
746The license is defined in the F<PROJECT-META.yml> specification under the key C<public-dap/data-license>.
747The list of possible license is given with the command L</list-license>.
748
749=head2 make-file-author
750
751 project-meta make-file-author
752
753Create or update the F<AUTHORS.txt> file at the current folder.
754Authors data are extracted from the C<PROJECT-META.yml> file.
755
756=head2 make-file-copyright
757
758 project-meta make-file-copyright
759
760Create or update the F<COPYRIGHT.txt> file at the current folder.
761Authors, license and copyright data are extracted from the C<PROJECT-META.yml> file.
762
763=head2 upgrade
764
765 project-meta upgrade
766
767Upgrade config file to last version.
768Create a file F<PROJECT-META-vVERSION.yml> in the current directory if it's not exists, error otherwise.
769Please maually verify this autogenerated config file before rename and using it.
770
771
772=head1 METAFILE SPECIFICATION
773
774Each project must have an open data metafile describing the project : C<PROJECT-META.yml>.
775The file is in YAML format because this is a human-readable text file style.
776Other formats could have been Plain XML, RDF, JSON... but they are much less readable.
777
778You can find in the project-meta software a
779L<PROJECT-META.sample.yml|http://servforge.legi.grenoble-inp.fr/pub/soft-trokata/project-meta/PROJECT-META.sample.yml> example.
780This one is actually the master reference specification!
781
782Some interresting papers or links about Open Meta Data Schema:
783
784=over
785
786=item * L<Metadata for the open data portals|http://devinit.org/wp-content/uploads/2018/01/Metadata-for-open-data-portals.pdf>
787        writen in december 2016.
788
789=item * L<Project Open Data Metadata Schema v1.1|https://project-open-data.cio.gov/v1.1/schema/> from US governement
790        based on L<DCAT|http://www.w3.org/TR/vocab-dcat/>.
791
792=item * L<Metadata Standards|http://knowhow.opendatamonitor.eu/odresearch/metadata-standards/>
793        from OpenDataMonitor.
794
795=item * L<G8 Metadata Mapping|https://github.com/project-open-data/G8_Metadata_Mapping/blob/master/index.md>
796        mapping between the metadata on datasets published by G8 Members through their open data portals.
797
798=back
799
800
801=head1 KNOWN BUGS
802
803 - not really check keys and tags before doing action!
804
805
806=head1 SEE ALSO
807
808yamllint(1), ysh(1), YAML, Archive::Zip
809
810In Debian GNU/Linux distribution, packages for C<yamllint> and C<ysh> are:
811
812=over
813
814=item * C<yamllint> - Linter for YAML files (Python)
815
816=item * C<libyaml-shell-perl> - YAML test shell (Perl)
817
818=back
819
820
821Own project ressources:
822
823=over
824
825=item * L<Web site|http://servforge.legi.grenoble-inp.fr/projects/soft-trokata/wiki/SoftWare/ProjectMeta>
826
827=item * L<Online Manual|http://servforge.legi.grenoble-inp.fr/pub/soft-trokata/project-meta/project-meta.html>
828
829=item * L<SVN repository|http://servforge.legi.grenoble-inp.fr/svn/soft-trokata/trunk/project-meta>
830
831=back
832
833
834=head1 AUTHOR
835
836Written by Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
837
838
839=head1 SPECIAL THANKS
840
841The list of people below did not directly contribute to project-meta's source code
842but provided me with some data, returned bugs
843or helped me in another task like having new ideas, specifications...
844Maybe I forgot your contribution in recent years,
845please forgive me in advance and send me an e-mail to correct this.
846
847Joel Sommeria, Julien Chauchat, Cyrille Bonamy, Antoine Mathieu.
848
849
850=head1 LICENSE AND COPYRIGHT
851
852License GNU GPL version 2 or later and Perl equivalent
853
854Copyright (C) 2017-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
Note: See TracBrowser for help on using the repository browser.