[latex3-commits] [git/LaTeX3-latex3-l3build] ctan-post: copied from ctan-post repo (2a1e243)
David Carlisle
d.p.carlisle at gmail.com
Sat Jul 21 21:43:42 CEST 2018
Repository : https://github.com/latex3/l3build
On branch : ctan-post
Link : https://github.com/latex3/l3build/commit/2a1e2438c33851d7543f569599d2c89afc6b6ca5
>---------------------------------------------------------------
commit 2a1e2438c33851d7543f569599d2c89afc6b6ca5
Author: David Carlisle <d.p.carlisle at gmail.com>
Date: Sat Jul 21 20:43:42 2018 +0100
copied from ctan-post repo
>---------------------------------------------------------------
2a1e2438c33851d7543f569599d2c89afc6b6ca5
l3build-ctan-post.lua | 254 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 254 insertions(+)
diff --git a/l3build-ctan-post.lua b/l3build-ctan-post.lua
new file mode 100644
index 0000000..50644ee
--- /dev/null
+++ b/l3build-ctan-post.lua
@@ -0,0 +1,254 @@
+
+-- ctan_upload
+--
+-- takes a package configuration table and an optional boolean
+--
+-- if the upload parameter is not supplied or is not true, only package validation
+-- is used, if upload is true then package upload will be attempted if validation
+-- succeeds.
+
+-- fields are given as a string, or optionally for fields allowing multiple
+-- values, as a table of strings.
+
+-- Mandatory fields are checked in Lua
+-- Maximum string lengths are checked.
+
+-- Currently string values are not checked, eg licence names, or URL syntax.
+
+-- The input form could be used to constrict a post body but
+-- luasec is not included in texlua.
+
+-- Instead an external program is used to post.
+-- As Windows (since April 2018) includes curl now default to curl.
+
+-- A global variable controls the backend to use.
+-- ctan_post_command=="curl"
+-- ctan_post_command=="ctan-o-mat"
+--
+-- ctan-o-mat inroduces a dependency on perl but it is installed with texlive
+-- in the default path and is maintained by Gerd Neugebauer of the CTAN team.
+--
+-- The ctan-o-mat configuration is written out as ctan-upload.txt
+-- in the current version it is a fixed name and not deleted after use,
+-- as a debugging aid.
+
+
+-- the main interface is
+-- ctan_upload (c,upload)
+-- with a configuration table c and optional upload parameter
+-- if upload is omitted or nil or false, onloy validation is attempted
+-- if upload is true the ctan upload URL will be used after validation
+-- if upload is anything else, the user will beprompted whether to upload.
+
+ctan_post_command="curl"
+curl_debug=false -- posting is disabled while testing
+
+function ctan_upload (c,upload)
+
+ if ctan_post_command=="ctan-o-mat" then
+ c.cfg = io.open("ctan-upload.txt","w")
+ else
+ if ctan_post_command=="curl" then
+ c.cfg="curl "
+ else
+ error("no https post command set")
+ end
+ end
+
+
+ -- cfg field max desc mandatory multi
+ -- ----------------------------------------------------
+ ctan_field(c,"pkg",32,"the package name", true,false)
+ ctan_field(c,"version",32,"the package version",true,false)
+ ctan_field(c,"author",128,"the author name", true,false)
+ ctan_field(c,"email",255,"the email of uploader",true,false)
+ ctan_field(c,"uploader",255,"the name of uploader",true,false)
+ ctan_field(c,"ctanPath",255,"the CTAN path", false,false)
+ ctan_field(c,"license",2048,"Package License", true,true)
+ ctan_field(c,"home",255,"URL of home page", false,false)
+ ctan_field(c,"bugtracker",255,"URL of bug tracker",false,false)
+ ctan_field(c,"support",255,"URL of support channels",false,true)
+ ctan_field(c,"repository",255,"URL of source repositories",false,true)
+ ctan_field(c,"development",255,"URL of development channels",false,true)
+ ctan_field(c,"update",8,",true for an update false otherwise",false,false)
+ ctan_field(c,"topic",1024,"topic", false,true)
+ ctan_field(c,"announcement",8192,"announcement",false,false)
+ ctan_field(c,"summary",128,"summary", true,false) -- ctan-o-mat doc says optional
+ ctan_field(c,"description",4096,"description", false,false)
+ ctan_field(c,"note",4096,"internal note to ctan",false,false)
+
+ if ctan_post_command=="ctan-o-mat" then
+ ctan_field(c,"file",4096,"zip file to upload", true,false)
+ io.close(c.cfg)
+ else
+ if ctan_post_command=="curl" then
+ c.cfg=c.cfg .. " --form 'file=@" .. tostring(c.file) .. ";filename=" .. tostring(c.file) .. "'"
+ c.cfg=c.cfg .. " https://ctan.org/submit/"
+ else
+ error("no https post command set")
+ end
+ end
+
+
+ -- avoid lower level error from post command if zip file missing
+ local zip=io.open(trim_space(tostring(c.file)),"r")
+ if zip~=nil then
+ io.close(zip)
+ else
+ error("missing zip file " .. tostring(c.file))
+ end
+
+ -- call post command to validate the upload at CTAN's validate URL
+ local exit_status=0
+ local fp_return=""
+ if ctan_post_command=="ctan-o-mat" then
+ exit_status=os.execute("ctan-o-mat --validate ctan-upload.txt")
+ else
+ if ctan_post_command=="curl" then
+-- use popen not execute so get the return body local exit_status=os.execute(c.cfg .. "validate")
+ if(curl_debug==false) then
+ local fp = assert(io.popen(c.cfg .. "validate", 'r'))
+ fp_return = assert(fp:read('*a'))
+ fp:close()
+ else
+ fp_return="WARNING: curl_debug==true: posting disabled disabled"
+ print(c.cfg)
+ end
+ if string.match(fp_return,"WARNING") or string.match(fp_return,"ERROR") then
+ exit_status=1
+ end
+ else
+ error("no https post command set")
+ end
+ end
+
+ -- if upload requested and validation succeeded repost to the upload URL
+ if (exit_status==0 or exit_status==nil) then
+ if(upload ~=nil and upload ~=false and upload ~= true) then
+ print("Validation successful, do you want to upload to CTAN?" )
+ local answer=""
+ io.write("> ")
+ io.flush()
+ answer=io.read()
+ if(string.lower(answer,1,1)=="y") then
+ upload=true
+ end
+ end
+ if(upload==true) then
+ if ctan_post_command=="ctan-o-mat" then
+ exit_status=os.execute("ctan-o-mat ctan-upload.txt")
+ else
+ if ctan_post_command=="curl" then
+ local fp = assert(io.popen(c.cfg .. "upload", 'r'))
+ fp_return = assert(fp:read('*a'))
+ fp:close()
+
+-- this is just html, could save to a file
+-- or echo a cleaned up version
+ print('Response from CTAN:')
+ print(fp_return)
+ if string.match(fp_return,"WARNING") or string.match(fp_return,"ERROR") then
+ exit_status=1
+ end
+ else
+ error("no https post command set")
+ end
+ end
+ else
+ print("CTAN validation successful")
+ end
+ else
+ error("Warnings from CTAN package validation:\n" .. fp_return)
+ end
+end
+
+function trim_space(s)
+ return (s:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+function ctan_field(c,f,max,desc,mandatory,multi)
+ if(type(c) ~= "table") then
+ error("The configuration argument must be a Lua table")
+ end
+ if(type(c[f])=="table" and multi==true) then
+ for i, v in pairs(c[f]) do
+ ctan_single_field(c,f,v,max,desc,mandatory and i==1)
+ end
+ else
+ ctan_single_field(c,f,c[f],max,desc,mandatory)
+ end
+end
+
+-- for URL %-encoding but not used presently
+local char_to_hex = function(c)
+ return string.format("%%%02X", string.byte(c))
+end
+
+function ctan_single_field(c,f,v,max,desc,mandatory)
+ if(v==nil or type(v)~="table") then
+ local vs=trim_space(tostring(v))
+ if (mandatory==true and (v == nil or vs=="")) then
+ error("The field " .. f .. " must contain " .. desc)
+ end
+ if(v ~=nil and string.len(vs) > 0) then
+ if (max > 0 and string.len(vs) > max) then
+ error("The field " .. f .. " is longer than " .. max)
+ end
+ if ctan_post_command=="ctan-o-mat" then
+ c.cfg:write("\n\\begin{" .. f .. "}\n" .. vs .. "\n\\end{" .. f .. "}\n")
+ else
+ if ctan_post_command=="curl" then
+-- curl supports using \" in " delimited strings but not \' in ' delimited omes
+-- c.cfg=c.cfg .." --form " .. f .. "='" .. vs:gsub("([^%w])",char_to_hex) .. "'"
+ c.cfg=c.cfg .." --form " .. f .. '="' .. vs:gsub('"','\\"') . '"'
+ else
+ error("no https post command set")
+ end
+ end
+ end
+ else
+ error("The value of the field '" .. f .."' must be a scalar not a table")
+ end
+end
+
+
+-- function for interactive multiline fields
+
+
+function input_multi_line_field (name)
+ print("Enter " .. name .. " three <return> or ctrl-D to stop")
+
+ local field=""
+
+ local answer_line
+ local return_count=0
+ repeat
+ io.write("> ")
+ io.flush()
+ answer_line=io.read()
+ if answer_line=="" then
+ return_count=return_count+1
+ else
+ for i=1,return_count,1 do
+ field = field .. "\n"
+ end
+ return_count=0
+ if answer_line~=nil then
+ field = field .. "\n" .. answer_line
+ end
+ end
+ until (return_count==3 or answer_line==nil)
+ return field
+end
+
+function input_single_line_field(name)
+ print("Enter " .. name )
+
+ local field=""
+
+ io.write("> ")
+ io.flush()
+ field=io.read()
+ return field
+end
+
More information about the latex3-commits
mailing list