summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/l3build
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-12-18 23:33:00 +0000
committerKarl Berry <karl@freefriends.org>2018-12-18 23:33:00 +0000
commit25f0a34ef212818e30ee07866877d0ea7985c691 (patch)
tree662b89b9ef15c4f96048f02fb21320600954cd3a /Master/texmf-dist/scripts/l3build
parent39e028ec9200b17474c8bc3c38aee237705bc2d7 (diff)
l3build (18dec18)
git-svn-id: svn://tug.org/texlive/trunk@49450 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/l3build')
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-help.lua2
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-stdmain.lua9
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-upload.lua237
-rw-r--r--Master/texmf-dist/scripts/l3build/l3build-variables.lua4
-rwxr-xr-xMaster/texmf-dist/scripts/l3build/l3build.lua9
5 files changed, 254 insertions, 7 deletions
diff --git a/Master/texmf-dist/scripts/l3build/l3build-help.lua b/Master/texmf-dist/scripts/l3build/l3build-help.lua
index 18caf87daae..8c3877595fc 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-help.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-help.lua
@@ -58,7 +58,7 @@ function help()
end
print("usage: " .. scriptname .. " <command> [<options>] [<names>]")
print("")
- print("The most commonly used l3build commands are:")
+ print("Valid commands are:")
local longest,t = setup_list(target_list)
for _,k in ipairs(t) do
local target = target_list[k]
diff --git a/Master/texmf-dist/scripts/l3build/l3build-stdmain.lua b/Master/texmf-dist/scripts/l3build/l3build-stdmain.lua
index 26a229ce31c..f2d8797c830 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-stdmain.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-stdmain.lua
@@ -58,7 +58,7 @@ target_list =
return 0
end
},
- bundlectan =
+ bundlectan =
{
func = bundlectan
},
@@ -138,7 +138,12 @@ target_list =
bundle_target = true,
desc = "Unpacks the source files into the build tree",
func = unpack
- }
+ },
+ upload =
+ {
+ desc = "Send archive to CTAN for public release",
+ func = upload
+ },
}
--
diff --git a/Master/texmf-dist/scripts/l3build/l3build-upload.lua b/Master/texmf-dist/scripts/l3build/l3build-upload.lua
new file mode 100644
index 00000000000..68692b0af4c
--- /dev/null
+++ b/Master/texmf-dist/scripts/l3build/l3build-upload.lua
@@ -0,0 +1,237 @@
+--[[
+
+File l3build-upload.lua Copyright (C) 2018 The LaTeX3 Project
+
+It may be distributed and/or modified under the conditions of the
+LaTeX Project Public License (LPPL), either version 1.3c of this
+license or (at your option) any later version. The latest version
+of this license is in the file
+
+ http://www.latex-project.org/lppl.txt
+
+This file is part of the "l3build bundle" (The Work in LPPL)
+and all files in that bundle must be distributed together.
+
+-----------------------------------------------------------------------
+
+The development version of the bundle can be found at
+
+ https://github.com/latex3/l3build
+
+for those people who are interested.
+
+--]]
+
+
+-- 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 construct 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 use curl.
+-- A version using ctan-o-mat is available in the ctan-post github repo.
+
+-- the main interface is
+-- upload()
+-- with a configuration table `uploadconfig`
+
+
+local curl_debug = curl_debug or false -- to disable posting
+-- For now, this is undocumented.
+
+local ctanupload = ctanupload or "ask"
+-- if ctanupload is nil or false, only validation is attempted
+-- if ctanupload is true the ctan upload URL will be used after validation
+-- if upload is anything else, the user will be prompted whether to upload.
+-- For now, this is undocumented. I think I would prefer to keep it always set to ask for the time being.
+
+function upload()
+
+ local uploadfile = ctanzip..".zip"
+
+ -- try a sensible default for the package name:
+ uploadconfig.pkg = uploadconfig.pkg or ctanpkg or nil
+
+ -- start building the curl command:
+ ctan_post = curlexe .. " "
+
+ -- build up the curl command field-by-field:
+
+ -- field max desc mandatory multi
+ -- ----------------------------------------------------------------------------------------------------
+ ctan_field("announcement", uploadconfig.announcement, 8192, "Announcement", false, false )
+ ctan_field("author", uploadconfig.author, 128, "Author name", true, false )
+ ctan_field("bugtracker", uploadconfig.bugtracker, 255, "URL(s) of bug tracker", false, true )
+ ctan_field("ctanPath", uploadconfig.ctanPath, 255, "CTAN path", true, false )
+ ctan_field("description", uploadconfig.description, 4096, "Short description of package", false, false )
+ ctan_field("development", uploadconfig.development, 255, "URL(s) of development channels", false, true )
+ ctan_field("email", uploadconfig.email, 255, "Email of uploader", true, false )
+ ctan_field("home", uploadconfig.home, 255, "URL(s) of home page", false, true )
+ ctan_field("license", uploadconfig.license, 2048, "Package license(s)", true, true )
+ ctan_field("note", uploadconfig.note, 4096, "Internal note to ctan", false, false )
+ ctan_field("pkg", uploadconfig.pkg, 32, "Package name", true, false )
+ ctan_field("repository", uploadconfig.repository, 255, "URL(s) of source repositories", false, true )
+ ctan_field("summary", uploadconfig.summary, 128, "One-line summary of package", true, false )
+ ctan_field("support", uploadconfig.support, 255, "URL(s) of support channels", false, true )
+ ctan_field("topic", uploadconfig.topic, 1024, "Topic(s)", false, true )
+ ctan_field("update", uploadconfig.update, 8, "Boolean: true=update, false=new pkg", false, false )
+ ctan_field("uploader", uploadconfig.uploader, 255, "Name of uploader", true, false )
+ ctan_field("version", uploadconfig.version, 32, "Package version", true, false )
+
+ -- finish constructing the curl command:
+ ctan_post = ctan_post .. " --form 'file=@" .. tostring(uploadfile) .. ";filename=" .. tostring(uploadfile) .. "'"
+ ctan_post = ctan_post .. " https://ctan.org/submit/"
+
+ -- avoid lower level error from post command if zip file missing
+ local zip=io.open(trim_space(tostring(uploadfile)),"r")
+ if zip~=nil then
+ io.close(zip)
+ else
+ error("Missing zip file '" .. tostring(uploadfile) .. "'")
+ end
+
+ -- call post command to validate the upload at CTAN's validate URL
+ local exit_status=0
+ local fp_return=""
+
+ -- use popen not execute so get the return body local exit_status=os.execute(ctan_post .. "validate")
+ if (curl_debug==false) then
+ local fp = assert(io.popen(ctan_post .. "validate", 'r'))
+ fp_return = assert(fp:read('*a'))
+ fp:close()
+ else
+ fp_return="WARNING: curl_debug==true: posting disabled"
+ print(ctan_post)
+ end
+ if string.match(fp_return,"WARNING") or string.match(fp_return,"ERROR") then
+ exit_status=1
+ end
+
+ -- if upload requested and validation succeeded repost to the upload URL
+ if (exit_status==0 or exit_status==nil) then
+ if (ctanupload ~=nil and ctanupload ~=false and ctanupload ~= true) then
+ print("Validation successful, do you want to upload to CTAN? [y/n]" )
+ local answer=""
+ io.write("> ")
+ io.flush()
+ answer=io.read()
+ if(string.lower(answer,1,1)=="y") then
+ ctanupload=true
+ end
+ end
+ if (ctanupload==true) then
+ local fp = assert(io.popen(ctan_post .. "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
+ print("CTAN validation successful")
+ end
+ else
+ error("Warnings from CTAN package validation:\n" .. fp_return)
+ end
+ return exit_status
+end
+
+
+function trim_space(s)
+ return (s:gsub("^%s*(.-)%s*$", "%1"))
+end
+
+
+function ctan_field(fname,fvalue,max,desc,mandatory,multi)
+ if (type(fvalue)=="table" and multi==true) then
+ for i, v in pairs(fvalue) do
+ ctan_single_field(fname,v,max,desc,mandatory and i==1)
+ end
+ else
+ ctan_single_field(fname,fvalue,max,desc,mandatory)
+ end
+end
+
+
+function ctan_single_field(fname,fvalue,max,desc,mandatory)
+ print('ctan-post: ' .. fname .. ' ' ..tostring(fvalue or '??'))
+ if ((fvalue==nil and mandatory) or (fvalue == 'ask')) then
+ if (max < 256) then
+ fvalue=input_single_line_field(fname)
+ else
+ fvalue=input_multi_line_field(fname)
+ end
+ end
+ if (fvalue==nil or type(fvalue)~="table") then
+ local vs=trim_space(tostring(fvalue))
+ if (mandatory==true and (fvalue == nil or vs=="")) then
+ error("The field " .. fname .. " must contain " .. desc)
+ end
+ if (fvalue ~=nil and string.len(vs) > 0) then
+ if (max > 0 and string.len(vs) > max) then
+ error("The field " .. fname .. " is longer than " .. max)
+ end
+ vs = vs:gsub('"','\\"')
+ vs = vs:gsub('`','\\`')
+ ctan_post=ctan_post .." --form " .. fname .. '="' .. vs .. '"'
+ end
+ else
+ error("The value of the field '" .. fname .."' 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
+
diff --git a/Master/texmf-dist/scripts/l3build/l3build-variables.lua b/Master/texmf-dist/scripts/l3build/l3build-variables.lua
index b3b999755dd..ad88aed00ce 100644
--- a/Master/texmf-dist/scripts/l3build/l3build-variables.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build-variables.lua
@@ -185,3 +185,7 @@ tpfext = tpfext or ".tpf"
-- Manifest options
manifestfile = manifestfile or "MANIFEST.md"
+
+-- Upload settings
+curlexe = curlexe or "curl"
+uploadconfig = uploadconfig or {}
diff --git a/Master/texmf-dist/scripts/l3build/l3build.lua b/Master/texmf-dist/scripts/l3build/l3build.lua
index e40b8e6da74..3422f4d81a9 100755
--- a/Master/texmf-dist/scripts/l3build/l3build.lua
+++ b/Master/texmf-dist/scripts/l3build/l3build.lua
@@ -1,4 +1,4 @@
-#!/usr/bin/env texlua
+#!/usr/bin/env texlua
--[[
@@ -65,6 +65,7 @@ build_require("unpack")
build_require("manifest")
build_require("manifest-setup")
build_require("tagging")
+build_require("upload")
build_require("stdmain")
-- This has to come after stdmain(),
@@ -96,7 +97,7 @@ end
build_require("variables")
-- Ensure that directories are 'space safe'
-maindir = escapepath(maindir)
+maindir = escapepath(maindir)
docfiledir = escapepath(docfiledir)
sourcefiledir = escapepath(sourcefiledir)
supportdir = escapepath(supportdir)
@@ -125,12 +126,12 @@ check_engines()
--
-- Deal with multiple configs for tests
--
-
+
-- When we have specific files to deal with, only use explicit configs
-- (or just the std one)
if options["names"] then
checkconfigs = options["config"] or {stdconfig}
-else
+else
checkconfigs = options["config"] or checkconfigs
end