diff options
30 files changed, 1206 insertions, 1 deletions
diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.am b/Build/source/texk/texlive/linked_scripts/Makefile.am index 0891b7cd457..d33c711428e 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.am +++ b/Build/source/texk/texlive/linked_scripts/Makefile.am @@ -72,6 +72,7 @@ texmf_dist_other_scripts = \ bundledoc/bundledoc \ cachepic/cachepic.tlu \ context/perl/mptopdf.pl \ + ctanupload/ctanupload.pl \ de-macro/de-macro \ dviasm/dviasm.py \ ebong/ebong.py \ diff --git a/Build/source/texk/texlive/linked_scripts/Makefile.in b/Build/source/texk/texlive/linked_scripts/Makefile.in index 7e8fb94fc84..d7752662b68 100644 --- a/Build/source/texk/texlive/linked_scripts/Makefile.in +++ b/Build/source/texk/texlive/linked_scripts/Makefile.in @@ -210,6 +210,7 @@ texmf_dist_other_scripts = \ bundledoc/bundledoc \ cachepic/cachepic.tlu \ context/perl/mptopdf.pl \ + ctanupload/ctanupload.pl \ de-macro/de-macro \ dviasm/dviasm.py \ ebong/ebong.py \ diff --git a/Build/source/texk/texlive/linked_scripts/ctanupload/ctanupload.pl b/Build/source/texk/texlive/linked_scripts/ctanupload/ctanupload.pl new file mode 100644 index 00000000000..70bb018217e --- /dev/null +++ b/Build/source/texk/texlive/linked_scripts/ctanupload/ctanupload.pl @@ -0,0 +1,450 @@ +#!/usr/bin/perl +################################################################################ +# Copyright (c) 2011 Martin Scharrer <martin@scharrer-online.de> +# This is open source software under the GPL v3 or later. +################################################################################ +use strict; +use warnings; + +sub fromenv; +sub load_data; +sub save_data; + +my $VERSION = 'v1.1'; +my %CTAN_SERVERURLS = ( + dante => 'http://dante.ctan.org/upload.html', + de => 'http://dante.ctan.org/upload.html', + uktug => 'http://www.tex.ac.uk/upload/', + 'uk-tug' => 'http://www.tex.ac.uk/upload/', + uk => 'http://www.tex.ac.uk/upload/', + cambridge => 'http://www.tex.ac.uk/upload/', +); +my $CTAN_URL = $CTAN_SERVERURLS{dante}; + +my @FIELDS = qw(contribution version name email summary directory DoNotAnnounce announce notes license freeversion file); +my @REQUIRED = qw(contribution version name email summary license file); +my %FIELDS = map { $_ => fromenv($_) } @FIELDS; + + +my %FIELDS_DESC = ( + contribution => 'Name of your contribution', + version => 'Version number', + name => 'Your name', + email => 'Your email', + summary => 'Summary description', + directory => 'Suggested CTAN directory', + DoNotAnnounce => 'No need to announce this update', + announce => 'Short description for announcement', + notes => 'Optional notes to the CTAN maintainers', + license => 'License type', + freeversion => 'Which free license', + file => 'File to upload', +); + +my @LICENSES = qw( free nocommercial nosell nosource shareware artistic other-nonfree); + +my %LICENSES = ( + free => 'Free', + nocommercial => 'Nocommercial', + nosell => 'Nosell', + nosource => 'Nosource', + shareware => 'Shareware', + artistic => 'Perl Artistic (Clarified or later)', + 'other-nonfree' => 'Other nonfree License', +); + +my @FREEVERSIONS = qw( apache2 artistic fdl gfl gpl lgpl lppl ofl pd other-free); + +my %FREEVERSIONS = ( + apache2 => 'Apache License v2.0', + artistic => 'Perl Artistic License (version 2)', + fdl => 'GNU Free Documentation License', + gfl => 'GUST Font License', + gpl => 'GNU General Public License', + lgpl => 'Lesser GPL', + lppl => 'LaTeX Project', + ofl => 'Open Font License', + pd => 'Public Domain', + 'other-free' => 'Other Free', +); + +my $QUIET = 0; +my $ASK = 1; +my $FORCE = 0; +my $PROMPT = -t STDIN ? 1 : 0; + +sub usage { + my $warn = shift; + if ($warn) { + print STDERR "Unknown option '$warn'\n"; + } + print STDERR <<"EOT"; +ctanupload script $VERSION +Uploads a contribution to CTAN. + +Usage: +ctanupload <options> --<name>=<value> + +Arguments can also be given using the CTANUPLOAD environment variable which are processed first, so that +explicit arguments will overwrite them. + +Options: + -h Print this help and exit. + -y Do not ask for confirmation, but submit immediately. + -u <URL> CTAN URL to upload to. + -U <name> CTAN server to upload to, either 'dante' or 'uktug'. + -F <file> Read data from file + -f Force upload even if input seems incorrect (unknown license etc.). + -p Prompt for missing values. (default if run in terminal) + -P Do not prompt for missing values. (default if not run in terminal) + -v Verbose mode. + -q Quiet mode. + -V Print version number. + +The following fields exists and can be given as +--<name>=<value>, --<name> <value>, --<name>-file=<file>, --<name>-file <file> +or as environment variables: CTAN_<NAME>, CTAN_<name>, <NAME> or <name>. + +EOT + + foreach my $field (@FIELDS) { + printf STDERR " %15s %s\n", $field, $FIELDS_DESC{$field}; + } + + printf STDERR "\nValid license types:\n"; + for my $license (@LICENSES) { + printf STDERR " %15s %s\n", $license, $LICENSES{$license}; + } + + printf STDERR "\nValid free license:\n"; + for my $license (@FREEVERSIONS) { + printf STDERR " %15s %s\n", $license, $FREEVERSIONS{$license}; + } + + exit ($warn ? 1 : 0); +} + +if (exists $ENV{'CTANUPLOAD'}) { + unshift @ARGV, (split /\s+/, $ENV{'CTANUPLOAD'}); +} + +while (my $arg = shift @ARGV) { + if ($arg =~ /^--(.*?)(?:=(.*))?$/) { + my $name = $1; + my $value = defined $2 ? $2 : shift @ARGV; + my $file; + if ($name =~ /(.*)-file$/) { + $name = $1; + $file = $value; + } + if (exists $FIELDS{$name}) { + if ($file) { + if (open (my $valfile, '<', $file)) { + $value = join '', <$valfile>; + close ($valfile); + } + else { + warn "Couldn't read file '$file'!\n"; + $value = ''; + } + } + $FIELDS{$name} = $value; + } + else { + usage('--' . $name . ($file ? '-file' : '')); + } + } + elsif ($arg =~ /^-([a-z]+)$/i) { + for my $char (split //, $1) { + if ($char eq 'h') { + usage(0); + } + elsif ($char eq 'q') { + $QUIET = 1; + } + elsif ($char eq 'v') { + $QUIET = 0; + } + elsif ($char eq 'y') { + $ASK = 0; + } + elsif ($char eq 'F') { + my $file = shift @ARGV; + load_data ($file); + } + elsif ($char eq 'f') { + $FORCE = 1; + } + elsif ($char eq 'p') { + $PROMPT = 1; + } + elsif ($char eq 'P') { + $PROMPT = 0; + } + elsif ($char eq 'u') { + $CTAN_URL = shift @ARGV; + } + elsif ($char eq 'U') { + my $server = lc shift @ARGV; + if (not exists $CTAN_SERVERURLS{ $server }) { + die "Error: Unknown CTAN server '$server'.\n"; + } + $CTAN_URL = $CTAN_SERVERURLS{ $server }; + } + elsif ($char eq 'V') { + print STDERR "ctanupload script $VERSION.\n"; + exit (0); + } + else { + usage('-' . $char); + } + } + } + else { + usage($arg); + } +} + +PROMPT: + +if ($PROMPT) { + foreach my $field (@FIELDS) { + if (!defined $FIELDS{$field} || !length $FIELDS{$field}) { + my $input = ''; + if ($field eq 'notes' || $field eq 'announce') { + next if $field eq 'announce' and $FIELDS{DoNotAnnounce}; + print "\u$FIELDS_DESC{$field}: (press CTRL-Z (Windows) or CTRL-D (Linux) to stop)\n"; + while (<STDIN>) { + $input .= $_; + } + } + elsif ($field eq 'DoNotAnnounce') { + print "\uNo need to announce upload? [y/N]: "; + $input = <STDIN>; + } + elsif ($field eq 'license') { + print "\u$FIELDS_DESC{$field}:\n"; + my $num = 1; + foreach my $license (@LICENSES) { + printf " [%d] %s\n", $num++, $LICENSES{$license}; + } + print "Selection: "; + $input = lc (<STDIN> || ''); + if ($input =~ /^\s*(\d+)\s*$/) { + $input = $LICENSES[$1-1]; + } + } + elsif ($field eq 'freeversion') { + next if $FIELDS{license} ne 'free'; + print "\u$FIELDS_DESC{$field}:\n"; + my $num = 1; + foreach my $license (@FREEVERSIONS) { + printf " [%d] %s\n", $num++, $FREEVERSIONS{$license}; + } + print "Selection: "; + $input = lc (<STDIN> || ''); + if ($input =~ /^\s*(\d+)\s*$/) { + $input = $FREEVERSIONS[$1-1]; + } + } + else { + print "\u$FIELDS_DESC{$field}: "; + $input = <STDIN>; + } + $input = '' if not defined $input; + chomp $input; + $input =~ s/^\s+//; + $input =~ s/\s+$//; + $FIELDS{$field} = $input; + } + } +} + +my $abort = 0; +foreach my $required (@REQUIRED) { + if (!length $FIELDS{$required}) { + print "Required field '$required' is missing!\n"; + $abort++; + } +} +if (not exists $LICENSES{ $FIELDS{license} }) { + print "Unknown license type '$FIELDS{license}'!\n"; + $abort++ if not $FORCE; +} +if ($FIELDS{license} ne 'free') { + $FIELDS{freeversion} = '-not-selected-'; +} elsif (!$FIELDS{freeversion}) { + print "Required field 'freeversion' is missing!\n"; + $abort++; +} elsif (not exists $FREEVERSIONS{ $FIELDS{freeversion} }) { + print "Unknown free license '$FIELDS{freeversion}'!\n"; + $abort++ if not $FORCE; +} +if ($FIELDS{file} && ! -f $FIELDS{file}) { + print "File '$FIELDS{file}' not found!\n"; + $abort++; +} +if ($abort) { + print "Aborting!\n"; + exit (2); +} + +my $DoNotAnnounce; +if ($FIELDS{DoNotAnnounce}) { + $FIELDS{DoNotAnnounce} = 'No'; + $DoNotAnnounce = '[x]'; +} +else { + $FIELDS{DoNotAnnounce} = undef; + $DoNotAnnounce = '[ ]'; +} + +if (!$FIELDS{directory}) { + $FIELDS{directory} = '/macros/latex/contrib/' . $FIELDS{contribution}; +} + +print "\nThe following data will be submitted to CTAN ($CTAN_URL):\n"; + +foreach my $field (@FIELDS) { + if ($field eq 'DoNotAnnounce') { + print "$FIELDS_DESC{$field}: $DoNotAnnounce\n"; + } + elsif ($field eq 'license') { + print "$FIELDS_DESC{$field}: $LICENSES{$FIELDS{$field}}\n"; + } + elsif ($field eq 'freeversion') { + print "$FIELDS_DESC{$field}: $FREEVERSIONS{$FIELDS{$field}}\n"; + } + else { + print "$FIELDS_DESC{$field}: $FIELDS{$field}\n"; + } +} + +if ($ASK) { + print "\nUpload? [(y/N/(e)dit/(s)ave] "; + my $response = lc <STDIN>; + chomp ($response); + + unless ($response eq 'y' or $response eq 'yes') { + if ($response eq 'e' or $response eq 'edit') { + my $file = 'ctanupload.dat'; + save_data($file); + if (not defined $ENV{EDITOR}) { + print "No EDITOR environment variable defined.\n"; + print "Data was stored in file '$file'. Please edit manually and load with the -F option.\n"; + exit (1); + } + else { + system($ENV{EDITOR}, $file); + load_data($file); + goto PROMPT; + } + } + elsif ($response eq 's' or $response eq 'save') { + my $file = 'ctanupload.dat'; + save_data($file); + print "Data was stored in file '$file'.\n"; + exit (2); + } + else { + print "\nUpload aborted!\n"; + exit (1); + } + } +} + + +use WWW::Mechanize; +my $mech = WWW::Mechanize->new(quiet => $QUIET, autocheck => 1); + +print "Accessing CTAN upload page ...\n"; +$mech->get( $CTAN_URL ); +print "Uploading ...\n"; +$mech->submit_form( + form_number => 1, + fields => \%FIELDS, +); + +if ($mech->success()) { + print "Upload successfull!\n"; +} +else { + print "Upload failed: ", $mech->response()->message(), "\n"; +} + +print "\nResponse:\n"; +eval { + use HTML::TreeBuilder; + use HTML::FormatText; + my $tree = HTML::TreeBuilder->new_from_content( $mech->content() ); + my $formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 80); + my @response = split /\n/, $formatter->format($tree); + local $, = "\n"; + print @response[3..$#response-3]; +} or do { + print "Can't display HTML response, storing reponse if log file 'ctanupload_response.html'\n"; + open (LOG, '>', 'ctanupload_response.html'); + print LOG $mech->content(); + close (LOG); +}; + +exit (0); + + +sub fromenv { + my $name = shift; + foreach my $var ('CTAN_' . uc $name, uc $name, 'CTAN_' . $name, $name) { + return $ENV{$var} if exists $ENV{$var}; + } + return undef; +} + +sub load_data { + my $file = shift; + open (my $load, '<', $file) or die "Couldn't open data file '$file'!\n"; + LOAD_LOOP: + while (my $line = <$load>) { + if ($line =~ /^([a-z]+)\s*=\s*(.*)$/i) { + my ($name,$value) = ($1,$2); + if (!exists $FIELDS{$name}) { + print STDERR "Ignoring unknown variable '$name' from file '$file' (line $.)!\n"; + next; + } + $FIELDS{$name} = $value; + if ($name eq 'announce' || $name eq 'notes') { + $FIELDS{$name} .= "\n"; + while ($line = <$load>) { + last if ($line =~ /^[a-z]+\s*=/i); + $FIELDS{$name} .= $line; + } + $FIELDS{$name} =~ s/^[\s\n]+//; + $FIELDS{$name} =~ s/[\s\n]+$//; + redo LOAD_LOOP if not eof $load; + } + } + else { + print STDERR "Ignoring incorrect line '$line' from file '$file' (line $.)!\n"; + } + } + close ($load); +} + +sub save_data { + my $file = shift; + $file = 'ctanupload.dat' if not defined $file; + open (my $save, '>', $file) or do { warn "Couldn't save data to file '$file'!\n"; return; }; + foreach my $field (@FIELDS) { + if ($field eq 'DoNotAnnounce') { + print {$save} "$field = ", $FIELDS{DoNotAnnounce} ? '1' : '0', "\n"; + } + else { + print {$save} "$field = ", $FIELDS{$field} || '', "\n"; + } + } + close ($save); + return; +} + + + +__END__ diff --git a/Master/bin/alpha-linux/ctanupload b/Master/bin/alpha-linux/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/alpha-linux/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/amd64-freebsd/ctanupload b/Master/bin/amd64-freebsd/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/amd64-freebsd/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/amd64-kfreebsd/ctanupload b/Master/bin/amd64-kfreebsd/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/amd64-kfreebsd/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-cygwin/ctanupload b/Master/bin/i386-cygwin/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-cygwin/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-freebsd/ctanupload b/Master/bin/i386-freebsd/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-freebsd/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-kfreebsd/ctanupload b/Master/bin/i386-kfreebsd/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-kfreebsd/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-linux/ctanupload b/Master/bin/i386-linux/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-linux/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-netbsd/ctanupload b/Master/bin/i386-netbsd/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-netbsd/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/i386-solaris/ctanupload b/Master/bin/i386-solaris/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/i386-solaris/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/mips-irix/ctanupload b/Master/bin/mips-irix/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/mips-irix/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/powerpc-aix/ctanupload b/Master/bin/powerpc-aix/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/powerpc-aix/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/powerpc-linux/ctanupload b/Master/bin/powerpc-linux/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/powerpc-linux/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/sparc-linux/ctanupload b/Master/bin/sparc-linux/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/sparc-linux/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/sparc-solaris/ctanupload b/Master/bin/sparc-solaris/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/sparc-solaris/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/universal-darwin/ctanupload b/Master/bin/universal-darwin/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/universal-darwin/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/win32/ctanupload.exe b/Master/bin/win32/ctanupload.exe Binary files differnew file mode 100755 index 00000000000..5777d90a17a --- /dev/null +++ b/Master/bin/win32/ctanupload.exe diff --git a/Master/bin/x86_64-darwin/ctanupload b/Master/bin/x86_64-darwin/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/x86_64-darwin/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/x86_64-linux/ctanupload b/Master/bin/x86_64-linux/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/x86_64-linux/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/bin/x86_64-solaris/ctanupload b/Master/bin/x86_64-solaris/ctanupload new file mode 120000 index 00000000000..40bd522d6f0 --- /dev/null +++ b/Master/bin/x86_64-solaris/ctanupload @@ -0,0 +1 @@ +../../texmf-dist/scripts/ctanupload/ctanupload.pl
\ No newline at end of file diff --git a/Master/texmf-dist/doc/support/ctanupload/Makefile.example b/Master/texmf-dist/doc/support/ctanupload/Makefile.example new file mode 100644 index 00000000000..ec35030541e --- /dev/null +++ b/Master/texmf-dist/doc/support/ctanupload/Makefile.example @@ -0,0 +1,25 @@ +# Example Makefile which uses ctanify and ctanupload to pack and upload a LaTeX package +# The required data is passed using environment variables. +CONTRIBUTION = foobar +NAME = John Doe +EMAIL = john.doe@inter.net +DIRECTORY = /macros/latex/contrib/${CONTRIBUTION} +LICENSE = free +FREEVERSION = lppl +FILE = ${CONTRIBUTION}.tar.gz +export CONTRIBUTION VERSION NAME EMAIL SUMMARY DIRECTORY DONOTANNOUNCE ANNOUNCE NOTES LICENSE FREEVERSION FILE + +ctanify: ${FILE} + +${CONTRIBUTION}.sty: ${CONTRIBUTION}.ins ${CONTRIBUTION}.dtx + yes | tex $< + +${CONTRIBUTION}.pdf: ${CONTRIBUTION}.dtx ${CONTRIBUTION}.sty + latexmk $< + +${FILE}: ${CONTRIBUTION}.dtx ${CONTRIBUTION}.ins ${CONTRIBUTION}.sty README ${CONTRIBUTION}.pdf + ctanify $^ + +upload: ctanify + ctanupload -p + diff --git a/Master/texmf-dist/doc/support/ctanupload/README b/Master/texmf-dist/doc/support/ctanupload/README new file mode 100644 index 00000000000..7a613440dee --- /dev/null +++ b/Master/texmf-dist/doc/support/ctanupload/README @@ -0,0 +1,66 @@ +ctanupload script +~~~~~~~~~~~~~~~~~ +This Perl script allows the uploads of a contribution to CTAN from the command line. +It is intended to simplify the release process for LaTeX package authors. + +Copyright (C) by Martin Scharrer <martin@scharrer-online.de> +Source code repository: https://bitbucket.org/martin_scharrer/ctanupload +Please report bugs and feature requests at https://bitbucket.org/martin_scharrer/ctanupload/issues/ + +Usage: +ctanupload <options> --<name>=<value> + +Arguments can also be given using the CTANUPLOAD environment variable which are processed first, so that +explicit arguments will overwrite them. + +Options: + -h Print this help and exit. + -y Do not ask for confirmation, but submit immediately. + -u <URL> CTAN URL to upload to. + -U <name> CTAN server to upload to, either 'dante' or 'uktug'. + -F <file> Read data from file + -f Force upload even if input seems incorrect (unknown license etc.). + -p Prompt for missing values. (default if run in terminal) + -P Do not prompt for missing values. (default if not run in terminal) + -v Verbose mode. + -q Quiet mode. + -V Print version number. + +The following fields exists and can be given as +--<name>=<value>, --<name> <value>, --<name>-file=<file>, --<name>-file <file> +or as environment variables: CTAN_<NAME>, CTAN_<name>, <NAME> or <name>. + + contribution Name of your contribution + version Version number + name Your name + email Your email + summary Summary description + directory Suggested CTAN directory + DoNotAnnounce No need to announce this update + announce Short description for announcement + notes Optional notes to the CTAN maintainers + license License type + freeversion Which free license + file File to upload + +Valid license types: + free Free + nocommercial Nocommercial + nosell Nosell + nosource Nosource + shareware Shareware + artistic Perl Artistic (Clarified or later) + other-nonfree Other nonfree License + +Valid free license: + apache2 Apache License v2.0 + artistic Perl Artistic License (version 2) + fdl GNU Free Documentation License + gfl GUST Font License + gpl GNU General Public License + lgpl Lesser GPL + lppl LaTeX Project + ofl Open Font License + pd Public Domain + other-free Other Free + diff --git a/Master/texmf-dist/doc/support/ctanupload/ctanupload.pdf b/Master/texmf-dist/doc/support/ctanupload/ctanupload.pdf Binary files differnew file mode 100644 index 00000000000..7e4930d7fdc --- /dev/null +++ b/Master/texmf-dist/doc/support/ctanupload/ctanupload.pdf diff --git a/Master/texmf-dist/doc/support/ctanupload/ctanupload.tex b/Master/texmf-dist/doc/support/ctanupload/ctanupload.tex new file mode 100644 index 00000000000..79d266062a8 --- /dev/null +++ b/Master/texmf-dist/doc/support/ctanupload/ctanupload.tex @@ -0,0 +1,192 @@ +\documentclass{ydoc} + +\title{The \textsf{ctanupload} script} +\author{Martin Scharrer} +\email{martin@scharrer.me} +\date{Version v1.1 -- 2011/09/06} + +\providecommand\envvar{\texttt} + +\makeatletter +\define@Macro@handler\DescribeScript{} +\makeatother + +\begin{document} +\maketitle +\begin{abstract} + This Perl script allows the uploads of a contribution to CTAN from the command line. + It is intended to simplify the release process for LaTeX package authors. +\end{abstract} + +\section{Introduction} +The Comprehensive TeX Archive Network (CTAN) is the place to get materials related to the \TeX\ typesetting system. +It provides an web form to upload contributions, like \LaTeX\ packages, to one of the main servers +\url{http://dante.ctan.org/upload} (DANTE server, German TeX users group) or +\url{http://www.tex.ac.uk/upload/} (UK-TUG server, UK TeX users group). +The third main server \url{http://tug.ctan.org/} (TUG, US and International TeX users group) currently does not accept uploads. +After uploading the contribution to one of these servers it will be distributed to the CTAN mirrors where it can be downloaded by other users. + +The \texttt{ctanupload} script allows to automate these uploads which is from benefit for \LaTeX\ package authors which +write and maintain a larger number of packages. The script is designed to be used from the command line or from a Makefile or other script +in a full or semi-automatic way. Constant data like the package and author names can be passed automatically to the script while the +variable fields like the version number or announcement text can be entered manually. + +The script first collects the required data, applies some sanity checks before it is displayed again for confirmation. +If the data is correct it is uploaded and the status and response from the CTAN upload server is printed. + +\section{Usage} +\DescribeScript{ctanupload}<options>~'--'<name>'='<value>~!\ldots! +\DescribeScript{ctanupload}<options>~'--'<name>~<value>~!\ldots! +\DescribeScript{ctanupload}<options>~'--'<name>'-file='<file with value>~!\ldots! +\DescribeScript{ctanupload}<options>~'--'<name>'-file'~<file with value>~!\ldots! + +The script accepts single letter options and awaits the upload form fields as double slash arguments. +These fields can also be read from text files or given using environment variables in the form +\MacroArgs'CTAN_'<NAME>, \MacroArgs'CTAN_'<name>, \MacroArgs<NAME> or \MacroArgs<name>\relax (in this order). +The support of environment variable simplifies the usage inside Makefiles. + +All arguments can also be given using the \envvar{CTANUPLOAD} environment variable which are processed first, so that +explicit arguments will overwrite them. + +\subsubsection*{Options} +The following options control the behaviour of the script. They can also be grouped together, i.e.\ a single dash +followed by multiple options. + +\par\medskip\par\noindent +\begin{tabular}{>{\ttfamily}ll} +\toprule + \normalfont Option & Description \\ +\midrule + -h & Print this help and exit.\\ + -y & Do not ask for confirmation, but submit immediately.\\ + -u <URL> & CTAN URL to upload to.\\ + -U <name> & CTAN server to upload to, either 'dante' or 'uktug'.\\ + -F <file> & Read all data from file. (See below)\\ + -f & Force upload even if input seems incorrect (unknown license etc.).\\ + -p & Prompt for missing values.\\ + -P & Do not prompt for missing values. (default)\\ + -v & Verbose mode. (Passed to the underlying WWW Perl module)\\ + -q & Quiet mode. (Passed to the underlying WWW Perl module)\\ + -V & Print version number.\\ +\bottomrule +\end{tabular} + +\subsubsection*{Fields} +The following fields exists in the CTAN upload form. At least the ones marked as mandatory must be provided. +\par\medskip\par\noindent +\begin{tabular}{>{\ttfamily}llc} +\toprule + \normalfont Field & Description & Mandatory \\ +\midrule + contribution & Name of your contribution & * \\ + version & Version number & *\\ + name & Your name & *\\ + email & Your email & *\\ + summary & Summary description & *\\ + directory & Suggested CTAN directory\\ + DoNotAnnounce & No need to announce this update\\ + announce & Short description for announcement\\ + notes & Optional notes to the CTAN maintainers\\ + license & License type (see below) & *\\ + freeversion & Which free license (see below)\\ + file & File to upload & *\\ +\bottomrule +\end{tabular} + +\subsubsection*{Valid license types} +The \texttt{license} field can have the following values to indicate the license type: +\par\medskip\par\noindent +\begin{tabular}{>{\ttfamily}ll} +\toprule + \normalfont License Type & Description \\ +\midrule + free & Free\\ + nocommercial & Nocommercial\\ + nosell & Nosell\\ + nosource & Nosource\\ + shareware & Shareware\\ + artistic & Perl Artistic (Clarified or later)\\ + other-nonfree & Other nonfree License\\ +\bottomrule +\end{tabular} + +\subsubsection*{Valid free licenses} +If a free license was choosen using \texttt{license=free} +the specific free license can be selected using the \texttt{freeversion} field which +can have one of the following values: + +\par\medskip\par\noindent +\begin{tabular}{>{\ttfamily}ll} +\toprule + \normalfont License Type & Description \\ +\midrule + apache2 & Apache License v2.0\\ + artistic & Perl Artistic License (version 2)\\ + fdl & GNU Free Documentation License\\ + gfl & GUST Font License\\ + gpl & GNU General Public License\\ + lgpl & Lesser GPL\\ + lppl & LaTeX Project\\ + ofl & Open Font License\\ + pd & Public Domain\\ + other-free & Other Free\\ +\bottomrule +\end{tabular} + +\section{Examples} + +\def\example#1{\par\medskip\par\noindent\textbf{#1}\par} +\lstset{numbers=none,basicstyle=\ttfamily\small} + +\example{Interactive mode (prompt for all values not read from environment variables):} +\begin{lstlisting} +ctanupload -p +\end{lstlisting} + +\example{Fill complete form:} +\begin{lstlisting} +ctanupload --contribution=somepackage --version=v0.1 \ + --name "John Doe" --email=john@doe.com \ + --summary "New package to do something." \ + --directory=/macros/latex/contrib/somepackage \ + --DoNotAnnounce=0 \ + --announce "This package allows to ..." \ + --notes "Some note to the CTAN admins (if required)" \ + --license=free --freeversion=lppl + --file=somepackage.tar.gz +\end{lstlisting} + +\example{Use of environment variables:} +\noindent +The environment variables can be given in the command line or in a user specific configuration file +which is read by the shell (e.g.\ \texttt{~/.bashrc} for the Bash shell). +Shown here is the Bash shell syntax, which is the common shell for Linux. +The static author data is given as environment variables and the contribution name as argument, while +the script will prompt the user for the rest. + +\par\noindent +\begin{lstlisting} +export CTAN_NAME="John Doe" +export CTAN_EMAIL="john@doe.com" +ctanupload --contribution=somepackage -p +\end{lstlisting} + +\example{Read date from file:} +\noindent +Here the announcement text is read from a file \texttt{announcement.txt} while the script will prompt the user +for the rest of the fields. + +\par\noindent +\begin{lstlisting} +ctanupload --announce-file announcement.txt -p +\end{lstlisting} + + +\example{Example Makefile:} +\noindent +The following Makefile (see \url{http://www.gnu.org/software/make/manual/make.html}) uses the \texttt{ctanify} script (\url{http://www.ctan.org/pkg/ctanify}) +to create a compressed file for submission using \texttt{ctanupload}. + +\lstinputlisting{Makefile.example} + +\end{document} diff --git a/Master/texmf-dist/scripts/ctanupload/ctanupload.pl b/Master/texmf-dist/scripts/ctanupload/ctanupload.pl new file mode 100644 index 00000000000..70bb018217e --- /dev/null +++ b/Master/texmf-dist/scripts/ctanupload/ctanupload.pl @@ -0,0 +1,450 @@ +#!/usr/bin/perl +################################################################################ +# Copyright (c) 2011 Martin Scharrer <martin@scharrer-online.de> +# This is open source software under the GPL v3 or later. +################################################################################ +use strict; +use warnings; + +sub fromenv; +sub load_data; +sub save_data; + +my $VERSION = 'v1.1'; +my %CTAN_SERVERURLS = ( + dante => 'http://dante.ctan.org/upload.html', + de => 'http://dante.ctan.org/upload.html', + uktug => 'http://www.tex.ac.uk/upload/', + 'uk-tug' => 'http://www.tex.ac.uk/upload/', + uk => 'http://www.tex.ac.uk/upload/', + cambridge => 'http://www.tex.ac.uk/upload/', +); +my $CTAN_URL = $CTAN_SERVERURLS{dante}; + +my @FIELDS = qw(contribution version name email summary directory DoNotAnnounce announce notes license freeversion file); +my @REQUIRED = qw(contribution version name email summary license file); +my %FIELDS = map { $_ => fromenv($_) } @FIELDS; + + +my %FIELDS_DESC = ( + contribution => 'Name of your contribution', + version => 'Version number', + name => 'Your name', + email => 'Your email', + summary => 'Summary description', + directory => 'Suggested CTAN directory', + DoNotAnnounce => 'No need to announce this update', + announce => 'Short description for announcement', + notes => 'Optional notes to the CTAN maintainers', + license => 'License type', + freeversion => 'Which free license', + file => 'File to upload', +); + +my @LICENSES = qw( free nocommercial nosell nosource shareware artistic other-nonfree); + +my %LICENSES = ( + free => 'Free', + nocommercial => 'Nocommercial', + nosell => 'Nosell', + nosource => 'Nosource', + shareware => 'Shareware', + artistic => 'Perl Artistic (Clarified or later)', + 'other-nonfree' => 'Other nonfree License', +); + +my @FREEVERSIONS = qw( apache2 artistic fdl gfl gpl lgpl lppl ofl pd other-free); + +my %FREEVERSIONS = ( + apache2 => 'Apache License v2.0', + artistic => 'Perl Artistic License (version 2)', + fdl => 'GNU Free Documentation License', + gfl => 'GUST Font License', + gpl => 'GNU General Public License', + lgpl => 'Lesser GPL', + lppl => 'LaTeX Project', + ofl => 'Open Font License', + pd => 'Public Domain', + 'other-free' => 'Other Free', +); + +my $QUIET = 0; +my $ASK = 1; +my $FORCE = 0; +my $PROMPT = -t STDIN ? 1 : 0; + +sub usage { + my $warn = shift; + if ($warn) { + print STDERR "Unknown option '$warn'\n"; + } + print STDERR <<"EOT"; +ctanupload script $VERSION +Uploads a contribution to CTAN. + +Usage: +ctanupload <options> --<name>=<value> + +Arguments can also be given using the CTANUPLOAD environment variable which are processed first, so that +explicit arguments will overwrite them. + +Options: + -h Print this help and exit. + -y Do not ask for confirmation, but submit immediately. + -u <URL> CTAN URL to upload to. + -U <name> CTAN server to upload to, either 'dante' or 'uktug'. + -F <file> Read data from file + -f Force upload even if input seems incorrect (unknown license etc.). + -p Prompt for missing values. (default if run in terminal) + -P Do not prompt for missing values. (default if not run in terminal) + -v Verbose mode. + -q Quiet mode. + -V Print version number. + +The following fields exists and can be given as +--<name>=<value>, --<name> <value>, --<name>-file=<file>, --<name>-file <file> +or as environment variables: CTAN_<NAME>, CTAN_<name>, <NAME> or <name>. + +EOT + + foreach my $field (@FIELDS) { + printf STDERR " %15s %s\n", $field, $FIELDS_DESC{$field}; + } + + printf STDERR "\nValid license types:\n"; + for my $license (@LICENSES) { + printf STDERR " %15s %s\n", $license, $LICENSES{$license}; + } + + printf STDERR "\nValid free license:\n"; + for my $license (@FREEVERSIONS) { + printf STDERR " %15s %s\n", $license, $FREEVERSIONS{$license}; + } + + exit ($warn ? 1 : 0); +} + +if (exists $ENV{'CTANUPLOAD'}) { + unshift @ARGV, (split /\s+/, $ENV{'CTANUPLOAD'}); +} + +while (my $arg = shift @ARGV) { + if ($arg =~ /^--(.*?)(?:=(.*))?$/) { + my $name = $1; + my $value = defined $2 ? $2 : shift @ARGV; + my $file; + if ($name =~ /(.*)-file$/) { + $name = $1; + $file = $value; + } + if (exists $FIELDS{$name}) { + if ($file) { + if (open (my $valfile, '<', $file)) { + $value = join '', <$valfile>; + close ($valfile); + } + else { + warn "Couldn't read file '$file'!\n"; + $value = ''; + } + } + $FIELDS{$name} = $value; + } + else { + usage('--' . $name . ($file ? '-file' : '')); + } + } + elsif ($arg =~ /^-([a-z]+)$/i) { + for my $char (split //, $1) { + if ($char eq 'h') { + usage(0); + } + elsif ($char eq 'q') { + $QUIET = 1; + } + elsif ($char eq 'v') { + $QUIET = 0; + } + elsif ($char eq 'y') { + $ASK = 0; + } + elsif ($char eq 'F') { + my $file = shift @ARGV; + load_data ($file); + } + elsif ($char eq 'f') { + $FORCE = 1; + } + elsif ($char eq 'p') { + $PROMPT = 1; + } + elsif ($char eq 'P') { + $PROMPT = 0; + } + elsif ($char eq 'u') { + $CTAN_URL = shift @ARGV; + } + elsif ($char eq 'U') { + my $server = lc shift @ARGV; + if (not exists $CTAN_SERVERURLS{ $server }) { + die "Error: Unknown CTAN server '$server'.\n"; + } + $CTAN_URL = $CTAN_SERVERURLS{ $server }; + } + elsif ($char eq 'V') { + print STDERR "ctanupload script $VERSION.\n"; + exit (0); + } + else { + usage('-' . $char); + } + } + } + else { + usage($arg); + } +} + +PROMPT: + +if ($PROMPT) { + foreach my $field (@FIELDS) { + if (!defined $FIELDS{$field} || !length $FIELDS{$field}) { + my $input = ''; + if ($field eq 'notes' || $field eq 'announce') { + next if $field eq 'announce' and $FIELDS{DoNotAnnounce}; + print "\u$FIELDS_DESC{$field}: (press CTRL-Z (Windows) or CTRL-D (Linux) to stop)\n"; + while (<STDIN>) { + $input .= $_; + } + } + elsif ($field eq 'DoNotAnnounce') { + print "\uNo need to announce upload? [y/N]: "; + $input = <STDIN>; + } + elsif ($field eq 'license') { + print "\u$FIELDS_DESC{$field}:\n"; + my $num = 1; + foreach my $license (@LICENSES) { + printf " [%d] %s\n", $num++, $LICENSES{$license}; + } + print "Selection: "; + $input = lc (<STDIN> || ''); + if ($input =~ /^\s*(\d+)\s*$/) { + $input = $LICENSES[$1-1]; + } + } + elsif ($field eq 'freeversion') { + next if $FIELDS{license} ne 'free'; + print "\u$FIELDS_DESC{$field}:\n"; + my $num = 1; + foreach my $license (@FREEVERSIONS) { + printf " [%d] %s\n", $num++, $FREEVERSIONS{$license}; + } + print "Selection: "; + $input = lc (<STDIN> || ''); + if ($input =~ /^\s*(\d+)\s*$/) { + $input = $FREEVERSIONS[$1-1]; + } + } + else { + print "\u$FIELDS_DESC{$field}: "; + $input = <STDIN>; + } + $input = '' if not defined $input; + chomp $input; + $input =~ s/^\s+//; + $input =~ s/\s+$//; + $FIELDS{$field} = $input; + } + } +} + +my $abort = 0; +foreach my $required (@REQUIRED) { + if (!length $FIELDS{$required}) { + print "Required field '$required' is missing!\n"; + $abort++; + } +} +if (not exists $LICENSES{ $FIELDS{license} }) { + print "Unknown license type '$FIELDS{license}'!\n"; + $abort++ if not $FORCE; +} +if ($FIELDS{license} ne 'free') { + $FIELDS{freeversion} = '-not-selected-'; +} elsif (!$FIELDS{freeversion}) { + print "Required field 'freeversion' is missing!\n"; + $abort++; +} elsif (not exists $FREEVERSIONS{ $FIELDS{freeversion} }) { + print "Unknown free license '$FIELDS{freeversion}'!\n"; + $abort++ if not $FORCE; +} +if ($FIELDS{file} && ! -f $FIELDS{file}) { + print "File '$FIELDS{file}' not found!\n"; + $abort++; +} +if ($abort) { + print "Aborting!\n"; + exit (2); +} + +my $DoNotAnnounce; +if ($FIELDS{DoNotAnnounce}) { + $FIELDS{DoNotAnnounce} = 'No'; + $DoNotAnnounce = '[x]'; +} +else { + $FIELDS{DoNotAnnounce} = undef; + $DoNotAnnounce = '[ ]'; +} + +if (!$FIELDS{directory}) { + $FIELDS{directory} = '/macros/latex/contrib/' . $FIELDS{contribution}; +} + +print "\nThe following data will be submitted to CTAN ($CTAN_URL):\n"; + +foreach my $field (@FIELDS) { + if ($field eq 'DoNotAnnounce') { + print "$FIELDS_DESC{$field}: $DoNotAnnounce\n"; + } + elsif ($field eq 'license') { + print "$FIELDS_DESC{$field}: $LICENSES{$FIELDS{$field}}\n"; + } + elsif ($field eq 'freeversion') { + print "$FIELDS_DESC{$field}: $FREEVERSIONS{$FIELDS{$field}}\n"; + } + else { + print "$FIELDS_DESC{$field}: $FIELDS{$field}\n"; + } +} + +if ($ASK) { + print "\nUpload? [(y/N/(e)dit/(s)ave] "; + my $response = lc <STDIN>; + chomp ($response); + + unless ($response eq 'y' or $response eq 'yes') { + if ($response eq 'e' or $response eq 'edit') { + my $file = 'ctanupload.dat'; + save_data($file); + if (not defined $ENV{EDITOR}) { + print "No EDITOR environment variable defined.\n"; + print "Data was stored in file '$file'. Please edit manually and load with the -F option.\n"; + exit (1); + } + else { + system($ENV{EDITOR}, $file); + load_data($file); + goto PROMPT; + } + } + elsif ($response eq 's' or $response eq 'save') { + my $file = 'ctanupload.dat'; + save_data($file); + print "Data was stored in file '$file'.\n"; + exit (2); + } + else { + print "\nUpload aborted!\n"; + exit (1); + } + } +} + + +use WWW::Mechanize; +my $mech = WWW::Mechanize->new(quiet => $QUIET, autocheck => 1); + +print "Accessing CTAN upload page ...\n"; +$mech->get( $CTAN_URL ); +print "Uploading ...\n"; +$mech->submit_form( + form_number => 1, + fields => \%FIELDS, +); + +if ($mech->success()) { + print "Upload successfull!\n"; +} +else { + print "Upload failed: ", $mech->response()->message(), "\n"; +} + +print "\nResponse:\n"; +eval { + use HTML::TreeBuilder; + use HTML::FormatText; + my $tree = HTML::TreeBuilder->new_from_content( $mech->content() ); + my $formatter = HTML::FormatText->new(leftmargin => 0, rightmargin => 80); + my @response = split /\n/, $formatter->format($tree); + local $, = "\n"; + print @response[3..$#response-3]; +} or do { + print "Can't display HTML response, storing reponse if log file 'ctanupload_response.html'\n"; + open (LOG, '>', 'ctanupload_response.html'); + print LOG $mech->content(); + close (LOG); +}; + +exit (0); + + +sub fromenv { + my $name = shift; + foreach my $var ('CTAN_' . uc $name, uc $name, 'CTAN_' . $name, $name) { + return $ENV{$var} if exists $ENV{$var}; + } + return undef; +} + +sub load_data { + my $file = shift; + open (my $load, '<', $file) or die "Couldn't open data file '$file'!\n"; + LOAD_LOOP: + while (my $line = <$load>) { + if ($line =~ /^([a-z]+)\s*=\s*(.*)$/i) { + my ($name,$value) = ($1,$2); + if (!exists $FIELDS{$name}) { + print STDERR "Ignoring unknown variable '$name' from file '$file' (line $.)!\n"; + next; + } + $FIELDS{$name} = $value; + if ($name eq 'announce' || $name eq 'notes') { + $FIELDS{$name} .= "\n"; + while ($line = <$load>) { + last if ($line =~ /^[a-z]+\s*=/i); + $FIELDS{$name} .= $line; + } + $FIELDS{$name} =~ s/^[\s\n]+//; + $FIELDS{$name} =~ s/[\s\n]+$//; + redo LOAD_LOOP if not eof $load; + } + } + else { + print STDERR "Ignoring incorrect line '$line' from file '$file' (line $.)!\n"; + } + } + close ($load); +} + +sub save_data { + my $file = shift; + $file = 'ctanupload.dat' if not defined $file; + open (my $save, '>', $file) or do { warn "Couldn't save data to file '$file'!\n"; return; }; + foreach my $field (@FIELDS) { + if ($field eq 'DoNotAnnounce') { + print {$save} "$field = ", $FIELDS{DoNotAnnounce} ? '1' : '0', "\n"; + } + else { + print {$save} "$field = ", $FIELDS{$field} || '', "\n"; + } + } + close ($save); + return; +} + + + +__END__ diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index 7e034926afb..959085401c4 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -110,7 +110,7 @@ my @TLP_working = qw( courier-scaled courseoutline coursepaper coverpage covington cprotect crop crossreference crossword crosswrd cryst csbulletin - csquotes csquotes-de csvsimple csvtools ctable ctex ctex-faq + csquotes csquotes-de csvsimple csvtools ctanupload ctable ctex ctex-faq cursolatex cuisine currfile currvita curve curve2e curves custom-bib cutwin cv cweb-latex cyklop cyrillic diff --git a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc index f39e8506e70..91fb59a5c27 100644 --- a/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-binextra.tlpsrc @@ -11,6 +11,7 @@ depend bibtex8 depend bibtexu depend bundledoc depend chktex +depend ctanupload depend ctie depend cweb depend de-macro diff --git a/Master/tlpkg/tlpsrc/ctanupload.tlpsrc b/Master/tlpkg/tlpsrc/ctanupload.tlpsrc new file mode 100644 index 00000000000..56e0d45eb0b --- /dev/null +++ b/Master/tlpkg/tlpsrc/ctanupload.tlpsrc @@ -0,0 +1 @@ +binpattern f bin/${ARCH}/ctanupload |