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

Last change on this file since 411 was 411, checked in by g7moreau, 5 years ago
  • Better help command (completion) and add completion on --dataset option
  • Property svn:executable set to *
File size: 24.1 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.2');
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
149 project-meta dap-unpublish
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   my $meta = load_metadata();
216   my $current_dir = Cwd::getcwd();
217   my $acronym     = $meta->{'project'}{'identifier'}{'acronym'};
218   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
219   my $data_set    = $meta->{'public-dap'}{'data-set'};
220
221   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENSE.txt';
222   {
223      # Remove doublon
224      my %seen = ();
225      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
226      }
227
228   # Create a list of the folder
229   my %folders;
230   for my $dataset (@{$data_set}) {
231      addfolder2list(\%folders, $dataset);
232      }
233
234   print "chmod o+rX,o-w '$current_dir'\n";
235   print "mkdir -p '$dap_folder/$acronym'\n" if not -d "$dap_folder/$acronym";
236   for my $folder (sort keys %folders) {
237      print "chmod o+rX,o-w '$current_dir/$folder'\n";
238      print "mkdir '$dap_folder/$acronym/$folder'\n" if -d "$current_dir/$folder";
239      }
240
241   for my $dataset (@{$data_set}) {
242      if ($dataset =~ m{/}) {
243         # sub-folder case
244         my $folder = $dataset =~ s{/[^/]+$}{}r;
245         print "chmod -R o+rX,o-w '$current_dir/$dataset'\n";
246         print "ln --symbolic --target-directory '$dap_folder/$acronym/$folder/' '$current_dir/$dataset'\n";
247         }
248      else {
249         # Root case
250         print "ln --symbolic --target-directory '$dap_folder/$acronym/' '$current_dir/$dataset'\n";
251         }
252
253      }
254   print "chmod -R o+rX,o-w '$dap_folder/$acronym/'\n";
255   }
256
257#---------------------------------------------------------------
258
259sub cmd_dap_unpublish {
260   my $meta = load_metadata();
261   my $current_dir = Cwd::getcwd();
262   my $acronym     = $meta->{'project'}{'identifier'}{'acronym'};
263   my $dap_folder  = $meta->{'public-dap'}{'dap-folder'};
264
265   die "Error: DAP folder match current folder" if $dap_folder =~ m{$current_dir} or $current_dir =~ m{$dap_folder};
266
267   print "find '$dap_folder/$acronym/' -type l -o -type d -exec ls -l {} \+\n";
268   print "find '$dap_folder/$acronym/' -type l -delete\n";
269   print "find '$dap_folder/$acronym/' -type d -delete\n";
270   }
271
272#---------------------------------------------------------------
273
274sub cmd_dataset_list {
275   local @ARGV = @_;
276
277   my $meta = load_metadata();
278
279   die "Error: no dataset\n"
280      if not defined $meta->{'public-dap'}
281      or not defined $meta->{'public-dap'}{'data-set'};
282
283   my $data_set = $meta->{'public-dap'}{'data-set'};
284   if(ref($data_set) eq 'HASH') {
285      print "$_\n" for sort keys %{$data_set};
286      }
287   else {
288      print "default uname dataset\n";
289      }
290   }
291
292#---------------------------------------------------------------
293
294sub cmd_dataset_size {
295   local @ARGV = @_;
296   my ($verbose, $dataset_name);
297
298   Getopt::Long::GetOptions(
299      'verbose'        => \$verbose,
300      'dataset|d=s'    => \$dataset_name,
301      );
302
303   my $meta = load_metadata();
304   my $data_set = $meta->{'public-dap'}{'data-set'};
305   if ($dataset_name) {
306      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
307         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
308         }
309      else {
310         die "Error, dataset $dataset_name does'nt exists\n";
311         }
312      }
313   my $total;
314   for my $dataset (@{$data_set}) {
315      my $cmd = qx{du -sm $dataset};
316      chomp $cmd;
317      my ($size, $inode) = split /\s+/, $cmd;
318      $total += $size;
319      printf "%-7i %s\n", $size, $inode;
320      }
321   printf "%-7i %s\n", $total, 'TOTAL';
322   }
323
324#---------------------------------------------------------------
325
326sub cmd_make_zip {
327   local @ARGV = @_;
328   my ($verbose, $dataset_name);
329
330   Getopt::Long::GetOptions(
331      'verbose'        => \$verbose,
332      'dataset|d=s'    => \$dataset_name,
333      );
334
335   my $meta = load_metadata();
336   my $current_dir = Cwd::getcwd();
337   my $data_set = $meta->{'public-dap'}{'data-set'};
338   if ($dataset_name) {
339      if (exists $meta->{'public-dap'}{'data-set'}{$dataset_name}) {
340         $data_set = $meta->{'public-dap'}{'data-set'}{$dataset_name};
341         }
342      else {
343         die "Error, dataset $dataset_name does'nt exists\n";
344         }
345      }
346
347   my $acronym = $meta->{'project'}{'identifier'}{'acronym'};
348
349   push @{$data_set}, 'AUTHORS.txt', 'COPYRIGHT.txt', 'LICENSE.txt';
350   {
351      # Remove doublon
352      my %seen = ();
353      @{$data_set} = grep { ! $seen{$_}++ } @{$data_set};
354      }
355
356   # Create a Zip file
357   my $zip = Archive::Zip->new();
358
359   for my $dataset (@{$data_set}) {
360      if (-d $dataset) {
361         # Folder case
362         $zip->addTree($dataset, "$acronym/$dataset");
363         }
364      elsif (-f $dataset) {
365         # File case
366         $zip->addFile($dataset, "$acronym/$dataset");
367         }
368      else {
369         # Strange case
370         print "Error: entry $dataset doesn't exists\n";
371         }
372      }
373
374   my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime time;
375   $year += 1900;
376   $mon++;
377   my $date = sprintf '%04i%02i%02i-%02i%02i', $year, $mon, $mday, $hour, $min;
378
379   # Save the Zip file
380   my $zipname = "$acronym";
381   $zipname .= "-$dataset_name" if $dataset_name;
382   $zipname .= "--$date";
383   unless ($zip->writeToFileNamed("$current_dir/$zipname.zip") == AZ_OK) {
384      die 'Error: zip write error';
385      }
386   }
387
388#---------------------------------------------------------------
389
390sub cmd_make_allfiles {
391   cmd_make_file_author();
392   cmd_make_file_license();
393   cmd_make_file_copyright();
394   }
395
396#---------------------------------------------------------------
397
398sub cmd_make_file_author {
399   my $meta = load_metadata();
400
401   my $current_dir = Cwd::getcwd();
402
403   my $acronym    = $meta->{'project'}{'identifier'}{'acronym'};
404   my $authors_list = $meta->{'project'}{'creator'};
405
406   if (-f "$current_dir/AUTHORS.txt") {
407      # Test for manual or automatically generated file
408      # Automatically generated file by project-meta
409      my $automatic;
410      open my $fh, '<', "$current_dir/AUTHORS.txt" or die $!;
411      for my $line (<$fh>) {
412         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
413         }
414      close $fh;
415
416      if (not $automatic) {
417         print "Warning: AUTHORS.txt already exists\n";
418         return;
419         }
420
421      print "Warning: update AUTHORS.txt\n";
422      }
423
424   my $tt = Template->new(INCLUDE_PATH => '/usr/share/project-meta/template.d');
425   my $msg_format = '';
426   $tt->process('AUTHORS.tt',
427      {
428         acronym    => $acronym,
429         authorlist => $authors_list,
430      }, \$msg_format) || die $tt->error;
431
432   open my $fh,  '>', "$current_dir/AUTHORS.txt" or die $!;
433   print $fh "$msg_format\n\n";
434   close $fh;
435   }
436
437#---------------------------------------------------------------
438
439sub cmd_make_file_license {
440   my $meta = load_metadata();
441
442   my $current_dir = Cwd::getcwd();
443
444   if (-f "$current_dir/LICENSE.txt") {
445      print "Warning: LICENSE.txt already exists\n";
446      return;
447      }
448
449   my $license = $meta->{'project'}{'rights'};
450
451   if (not -f "/usr/share/project-meta/license.d/$license.txt") {
452      print "Error: license $license doesn't exists in project-meta database\n";
453      exit 1;
454      }
455
456   copy("/usr/share/project-meta/license.d/$license.txt", "$current_dir/LICENSE.txt")
457      or die "Error: license copy failed - $!";
458
459   print "Info: LICENSE.txt file create\n";
460   return;
461   }
462
463#---------------------------------------------------------------
464
465sub cmd_make_file_copyright {
466   my $meta = load_metadata();
467
468   my $current_dir = Cwd::getcwd();
469
470   if (-f "$current_dir/COPYRIGHT.txt") {
471      # Test for manual or automatically generated file
472      # Automatically generated file by project-meta
473      my $automatic;
474      open my $fh, '<', "$current_dir/COPYRIGHT.txt" or die $!;
475      for my $line (<$fh>) {
476         $line =~ m/Automatically generated .* project-meta/i and $automatic++;
477         }
478      close $fh;
479
480      if (not $automatic) {
481         print "Warning: COPYRIGHT.txt already exists\n";
482         return;
483         }
484
485      print "Warning: update COPYRIGHT.txt\n";
486      }
487   
488   my $tt = Template->new(
489      INCLUDE_PATH   => '/usr/share/project-meta/template.d',
490      POST_CHOMP     => 1, # Remove space and carriage return after %]
491      );
492   my $msg_format = '';
493   my $doi_first  = '';
494   if (exists $meta->{'project'}{'relation'}) {
495      for my $doi (@{$meta->{'project'}{'relation'}}) {
496         next if not exists $doi->{'doi'};
497         $doi_first = $doi->{'doi'};
498         last;
499         }
500      }
501   $tt->process('COPYRIGHT.tt',
502      {
503         title       => $meta->{'project'}{'title'},
504         acronym     => $meta->{'project'}{'identifier'}{'acronym'},
505         authorlist  => $meta->{'project'}{'creator'},
506         description => $meta->{'project'}{'description'},
507         license     => $meta->{'project'}{'rights'},
508         doi         => $doi_first,
509      }, \$msg_format) || die $tt->error;
510
511   open my $fh, '>', "$current_dir/COPYRIGHT.txt" or die $!;
512   print $fh "$msg_format\n\n";
513   close $fh;
514   }
515
516#---------------------------------------------------------------
517
518sub cmd_list_license {
519   opendir my $dh, '/usr/share/project-meta/license.d/' or die $!;
520   for my $license (readdir $dh) {
521      # Keep only file
522      next if not -f "/usr/share/project-meta/license.d/$license";
523     
524      # Keep only .txt file
525      next if not $license =~ m/\.txt$/;
526
527      $license =~ s/\.txt$//;
528      print "$license\n";
529      }
530   closedir $dh;
531   }
532
533################################################################
534# documentation
535################################################################
536
537__END__
538
539=head1 NAME
540
541project-meta - opendata project metafile manager
542
543
544=head1 USAGE
545
546 project-meta help
547 project-meta version
548 project-meta check
549 project-meta dap-publish
550 project-meta dap-unpublish
551 project-meta dataset-list
552 project-meta dataset-size [--verbose|-v] [--dataset|-d dataset]
553 project-meta make-zip [--verbose|-v] [--dataset|-d dataset]
554 project-meta list-license
555 project-meta make-file-license
556 project-meta make-file-author
557 project-meta make-file-copyright
558 project-meta upgrade
559
560
561=head1 DESCRIPTION
562
563Project-Meta is a small tool to maintain a set of open data files.
564In order to help you in this task, C<project-meta> command has a set of action
565to generated and maintain many files in your dataset.
566
567Everything is declare in the metafile F<PROJECT-META.yml>.
568This YAML file must exist in your root projet folder.
569See L</METAFILE SPECIFICATION>.
570
571
572=head1 COMMANDS
573
574Some command are defined in the source code but are not documented here.
575Theses could be not well defined, not finished, not well tested...
576You can read the source code and use them at your own risk
577(like for all the Project-Meta code).
578
579=head2 check
580
581 project-meta check
582
583Check your F<PROJECT-META.yml> has the good key.
584If your metafile is not a valid YAML file,
585you can use C<yamllint> or C<ysh> commands to check just it's format.
586
587=head2 dap-publish
588
589 project-meta dap-publish
590
591Publish data on an OpeNDAP server.
592Because data can be very large,
593This command just create UNIX soft links on the OpeNDAP folder to the real data.
594There is no copy.
595Files F<AUTHORS.txt>, F<LICENSE.txt> and F<COPYRIGHT.txt> are mandatory but could be generated (see below).
596The main keys use in the F<PROJECT-META.yml> are:
597
598=over
599
600=item * C<project/identifier/acronym>: the project short acronym, add to the OpeNDAP root folder
601
602=item * C<public-dap/dap-folder>: the OpeNDAP root folder
603
604=item * C<public-dap/data-set>: a list of files or folder to push
605
606=back
607
608Because this command could be dangerous, it does nothing!
609It print on terminal shell command to be done.
610You have to verify ouput before eval it.
611
612 project-meta dap-publish
613 project-meta dap-publish | bash
614
615=head2 dap-unpublish
616
617 project-meta dap-unpublish
618
619Unpublish data from the OpeNDAP server.
620In practice, it remove links in OpeNDAP folder for that projet.
621Because command C<rm> is always dangerous,
622we use here the command C<find> limited to folder and link.
623
624Please verify the returned values before excuted it with the C<-delete> option.
625
626=head2 dataset-list
627
628 project-meta dataset-list
629
630=head2 dataset-size
631
632 project-meta dataset-size [--verbose|-v] [--dataset|-d dataset]
633
634=head2 make-zip
635
636 project-meta make-zip [--verbose|-v] [--dataset|-d dataset]
637
638Create a ZIP archive with the open data set.
639Files F<AUTHORS.txt>, F<LICENSE.txt> and F<COPYRIGHT.txt> are mandatory but could be generated (see below).
640The main keys use in the F<PROJECT-META.yml> are:
641
642=over
643
644=item * C<project/identifier/acronym>: the project short acronym, use as root folder
645
646=item * C<public-dap/data-set>: a list of files or folder to push
647
648=back
649
650=head2 make-allfiles
651
652 project-meta make-allfiles
653
654Generate or update all files: F<AUTHORS.txt>, F<COPYRIGHT.txt> and F<LICENSE.txt>.
655This command is just a shortcut for L</make-file-author>, L</make-file-copyright> and L</make-file-license>.
656
657
658=head2 list-license
659
660 project-meta list-license
661
662Give the list of all the open data licenses supported by the project-meta license database.
663At this time the possible licenses are:
664
665=over
666
667=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>
668        (permissive - allow users to freely share and adapt)
669
670=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>
671        (copyleft - allow users to freely share and adapt while maintaining this same freedom for others)
672
673=item * L<creative-common-attribution-v4.0|https://creativecommons.org/licenses/by/4.0/legalcode.txt>
674        (copyleft - allow users to freely share and adapt while maintaining this same freedom for others)
675
676=item * L<creative-common-zero-v1.0|https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt>
677        (like public domain)
678
679=item * L<licence-ouverte-v2.0|https://www.etalab.gouv.fr/wp-content/uploads/2017/04/ETALAB-Licence-Ouverte-v2.0.pdf>
680        (copyleft - opendata french goverment)
681
682=item * L<open-database-license-v1.0|https://opendatacommons.org/files/2018/02/odbl-10.txt>
683        (copyleft - allow users to freely share, modify, and use the database while maintaining this same freedom for others)
684
685=back
686
687Note that these licenses are dedicated to open data.
688Please do not use an open license that would have been thought for source code or documentation and not for open data.
689Here are some links about open data licence context:
690
691=over
692
693=item * A good article about Community Data License Agreement and Open Data Licence in general
694   L<Licenses for data|https://lwn.net/Articles/753648/> written on 9 May 2018.
695
696=item * A french page about French Public Open Data licence
697   L<https://www.etalab.gouv.fr/licence-ouverte-open-licence>.
698
699=back
700
701=head2 make-file-license
702
703 project-meta make-file-license
704
705Copy the license file from the project-meta license database at the current folder
706with the file name: F<LICENSE.txt>.
707
708The license is defined in the F<PROJECT-META.yml> specification under the key C<public-dap/data-license>.
709The list of possible license is given with the command L</list-license>.
710
711=head2 make-file-author
712
713 project-meta make-file-author
714
715Create or update the F<AUTHORS.txt> file at the current folder.
716Authors data are extracted from the C<PROJECT-META.yml> file.
717
718=head2 make-file-copyright
719
720 project-meta make-file-copyright
721
722Create or update the F<COPYRIGHT.txt> file at the current folder.
723Authors, license and copyright data are extracted from the C<PROJECT-META.yml> file.
724
725=head2 upgrade
726
727 project-meta upgrade
728
729Upgrade config file to last version.
730Create a file F<PROJECT-META-vVERSION.yml> in the current directory if it's not exists, error otherwise.
731Please maually verify this autogenerated config file before rename and using it.
732
733
734=head1 METAFILE SPECIFICATION
735
736Each project must have an open data metafile describing the project : C<PROJECT-META.yml>.
737The file is in YAML format because this is a human-readable text file style.
738Other formats could have been Plain XML, RDF, JSON... but they are much less readable.
739
740You can find in the project-meta software a
741L<PROJECT-META.sample.yml|http://servforge.legi.grenoble-inp.fr/pub/soft-trokata/project-meta/PROJECT-META.sample.yml> example.
742This one is actually the master reference specification!
743
744Some interresting papers or links about Open Meta Data Schema:
745
746=over
747
748=item * L<Metadata for the open data portals|http://devinit.org/wp-content/uploads/2018/01/Metadata-for-open-data-portals.pdf>
749        writen in december 2016.
750
751=item * L<Project Open Data Metadata Schema v1.1|https://project-open-data.cio.gov/v1.1/schema/> from US governement
752        based on L<DCAT|http://www.w3.org/TR/vocab-dcat/>.
753
754=item * L<Metadata Standards|http://knowhow.opendatamonitor.eu/odresearch/metadata-standards/>
755        from OpenDataMonitor.
756
757=item * L<G8 Metadata Mapping|https://github.com/project-open-data/G8_Metadata_Mapping/blob/master/index.md>
758        mapping between the metadata on datasets published by G8 Members through their open data portals.
759
760=back
761
762
763=head1 KNOWN BUGS
764
765 - not really check keys and tags before doing action!
766
767
768=head1 SEE ALSO
769
770yamllint(1), ysh(1), YAML, Archive::Zip
771
772In Debian GNU/Linux distribution, packages for C<yamllint> and C<ysh> are:
773
774=over
775
776=item * C<yamllint> - Linter for YAML files (Python)
777
778=item * C<libyaml-shell-perl> - YAML test shell (Perl)
779
780=back
781
782
783Own project ressources:
784
785=over
786
787=item * L<Web site|http://servforge.legi.grenoble-inp.fr/projects/soft-trokata/wiki/SoftWare/ProjectMeta>
788
789=item * L<Online Manual|http://servforge.legi.grenoble-inp.fr/pub/soft-trokata/project-meta/project-meta.html>
790
791=item * L<SVN repository|http://servforge.legi.grenoble-inp.fr/svn/soft-trokata/trunk/project-meta>
792
793=back
794
795
796=head1 AUTHOR
797
798Written by Gabriel Moreau <Gabriel.Moreau(A)univ-grenoble-alpes.fr>
799
800
801=head1 SPECIAL THANKS
802
803The list of people below did not directly contribute to project-meta's source code
804but provided me with some data, returned bugs
805or helped me in another task like having new ideas, specifications...
806Maybe I forgot your contribution in recent years,
807please forgive me in advance and send me an e-mail to correct this.
808
809Joel Sommeria, Julien Chauchat, Cyrille Bonamy, Antoine Mathieu.
810
811
812=head1 LICENSE AND COPYRIGHT
813
814License GNU GPL version 2 or later and Perl equivalent
815
816Copyright (C) 2017-2019, LEGI UMR 5519 / CNRS UGA G-INP, Grenoble, France
Note: See TracBrowser for help on using the repository browser.