\DocumentMetadata{
  lang        = en,
  pdfstandard = ua-2,
  pdfstandard = a-4f, %or a-4
  tagging=on,
  tagging-setup={math/setup=mathml-SE}
}
\listfiles
\documentclass[fontsize=10pt,paper=a4,abstract=on]{scrartcl}

\DeclareTOCStyleEntry[dynnumwidth=true]{default}{subsection}

\usepackage{unicode-math}

\usepackage[RM={StylisticSet=3}]{plex-otf}

\usepackage[english]{babel}
\usepackage[autostyle]{csquotes}

\usepackage{array,multido}
\usepackage{booktabs} % for examples
%\usepackage{xltabular} % for examples
\usepackage{listings}
\lstset{columns=fixed,basicstyle=\ttfamily\small}
\usepackage[table]{xcolor}
\usepackage{xspace}

\usepackage{longtable}

\usepackage{minted2}
\usemintedstyle{emacs}

\pagestyle{headings}

\usepackage[colorlinks, pdfusetitle, hyperfootnotes=false]{hyperref}
\usepackage{breakurl}
% define \code for url-like breaking of typewriter fragments.
\ifx\nolinkurl\undefined \let\code\url \else \let\code\nolinkurl \fi

% Define \cs to prepend a backslash, and be unbreakable:
\DeclareRobustCommand\cs[1]{\mbox{\texttt{\char`\\#1}}}


\newcommand{\pkgcheck}{\texttt{pkgcheck}\xspace}
\newcommand{\msg}[1]{\texttt{#1}\xspace}

\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}

%  \pdfinfo{
%    /Author (Manfred Lotz)
%    /Title  pkgcheck Utility
% }

%\title{pkgcheck utility}
\include{title}
\author{Manfred Lotz}


\begin{document}
\maketitle
\tableofcontents

\begin{abstract}
  This document describes the \pkgcheck command line utility which is used by the
  author when checking uploaded packages to CTAN.
\end{abstract}


\newpage

\section{Introduction}

Uploaded packages to CTAN must satisfy various requirements in order to get
installed on CTAN.

A first introduction is given here \url{https://ctan.org/help/upload-pkg}.

Even more details are to be found in the excellent CTAN-upload addendum
\url{https://ctan.org/file/help/ctan/CTAN-upload-addendum} written by Petra Rübe-Pugliese.

The \pkgcheck utility which runs on Linux systems only checks those requirements
which can be checked by a program.

\section{pkgcheck utility}

The \pkgcheck utility is a compiled program written in the Rust programming
language. It may run in a Linux or macos environment.

Currently, Windows is not supported. Simply, because the author doesn't use Windows at all.

It will be invoked from the command line, and any error or
warning message has a certain message id. \pkgcheck offers an option to get more
information for a certain error.

\section{Requirements}

\pkgcheck doesn't have any special runtime requirements.

The \pkgcheck is a 64-bit statically linked binary, and should work an any 64-bit Linux.
It is available in the repository in directory \verb|bin/|.

Binaries for macos are also available for \verb|aarch64| and \verb|x86_64| architecture
in the \verb|bin/| directory.

\section{Installation}

Copy the binary from \verb|bin/pkgcheck| to a suitable location on your hard disk, and
(recommended) make sure the directory is in the \verb|PATH| or call \verb|pkgcheck| using an
absolute path name.

\section{Utility usage}

\subsection{Config file}

It is now possible to have a config file for \pkgcheck which must be a YAML
file. A config file can be
specified by using the command line option \verb|--config-file|. If no config
file is specified during invocation of \pkgcheck then \pkgcheck checks two
locations for existence of a config file.

\begin{itemize}
  \item \verb|~/.ctan/pkgcheck.yml|
  \item \verb|.config/ctan/pkgcheck.yml|
\end{itemize}

Currently, the config file may contain only TDS path exceptions. For more
details see message
\hyperlink{i0009----updating-entry-pkgname---tpkg-with-pkgname---new-tpkg-from-config-file}{I0009x}.


\subsection{Generate shell completions}

\pkgcheck offers an option to generate shell completions for various shells,
most notably \texttt{bash}, \texttt{zsh }and \texttt{fish}.


Run

\begin{minted}[linenos=true,frame=single,fontsize=\footnotesize]{sh}
pkgcheck -generate-completion <SHELL>
\end{minted}

and follow the instructions given.

\subsection{Check a package}

A package for CTAN is supposed to be uploaded as a ZIP or a g-zipped
tar archive. The package must have a top level directory.

After unpacking the archive of a package \texttt{mypkg} into directory
\texttt{mypkg/} it can be checked by running \pkgcheck with
option \verb|--package-dir| or shorter \verb|-d|.


\begin{minted}[linenos=true,frame=single,fontsize=\footnotesize]{sh}
  pkgcheck -d mypkg
\end{minted}

\pkgcheck returns 1 if there are any errors, otherwise 0.



\subsection{Check a package which has a TDS archive}

If a package contains a TDS ZIP archive it is supposed to be in the
top level directory of a package.

In order to check the TDS ZIP archive the option
\verb|-T <tds_zip>| or \verb|--tds-zip <tds_zip>| can be used.

Please note that a TDS ZIP archive will always be checked together with
the non-install tree of the package which means that
\verb|--tds-zip| requires option \verb|--package-dir| as well.

Checking package \texttt{mypkg} \pkgcheck will be invoked like follows:

\begin{minted}[linenos=true,frame=single,fontsize=\footnotesize]{sh}
  pkgcheck -d mypkg -T mypkg.tds.zip
\end{minted}


As before \pkgcheck returns 1 if there are any errors, otherwise 0.


\subsection{Pkgcheck messages}

\pkgcheck issues three kind of messages

\begin{itemize}
\item Information messages
\item Warning messages
\item Error messages
\end{itemize}

Messages have unique ids and the detailed explanation of a message can be either
looked up in this document, or it can be displayed by using command line option
\verb|--explain| or \verb|-e|.


\begin{minted}[linenos=true,label=Example,frame=single,fontsize=\footnotesize]{sh}
  pkgcheck --explain e0012
\end{minted}



\subsection{Duplicate files}

By default, \pkgcheck detects duplicate files in a package. This could be
disabled by using command line switch \verb|--ignore dupes| or shorter \verb|-I dupes|.

\subsection{Same named files}

By default, \pkgcheck detects same named files in a package. This could be
disabled by using command line switch \verb|--ignore same-named| or shorter \verb|-I same-named|.

\subsection{Temporary files}

By default, \pkgcheck detects temporary files in a package. This could be
disabled by using command line switch \verb|--ignore tmpfiles| or shorter \verb|-I tmpfiles|.

\subsection{Permissions}

\pkgcheck offers the option \verb|--correct-le| or shorter \verb|-L| to
correct wrong permissions in a package.


\subsection{CRLF line endings}

\pkgcheck detects CRLF line endings in text files as good as it can.
It reads up to 1 MB to check for CRLF line endings.

Option \verb|--correct-crlf| or for short \verb|-L| can be used to convert a
file from CRLF to LF line endings.

\subsection{Help options}

This section describes specific help related options.

\begin{itemize}
\item \verb|-V|

  Outputs \pkgcheck's version number.

\item \verb|--help|

  Shows the available command line options.

\item  \verb|--explain <explain|

  This option explains an error message in more detail.

  Example:

\begin{minted}[linenos=true,frame=single,fontsize=\footnotesize]{sh}
  pkgcheck -e e0012
\end{minted}


\item  \verb|--explain-all|

Outputs a list of explanations of all messages.

\item \verb|--show-temp-endings|

  Outputs a list of all file name endings which \pkgcheck uses to detect
  temporary files.
\end{itemize}

\section{About checking file types}

\pkgcheck determines, similar to the UNIX \verb|file| command, the type of file.
This is required before for example checking permissions or complaining that a
text file has CRLF line endings.

It is very important to note that determining file types is not bullet proof.
So, it might happen in some cases that \pkgcheck makes mistakes when determining
a file type. This could lead to a subsequent mistake when complaining about an
x-bit, or complaining about CRF line ending.

\section{About permissions checking}

From an installation point of view the files and directories of a package
\begin{itemize}
\item must be at least world readable
\item must be writable by owner or group
\item must not have the x-bit on for the owner if the file isn't an executable,
  i.e. a script or binary
\end{itemize}

The reason for this minimal requirement is that the installation utility used by
the CTAN team (which by the way was written by Rainer Schöpf a long time ago)
sets permissions correctly if the owner permission is set correctly.

Examples:

\begin{itemize}
\item \verb|README.md| with \texttt{666} is ok because the installation utility converts
  the permission to 664
\item \verb|README.md| with \texttt{660} is wrong because the installation utility
  wouldn't have access to the file
\item \verb|some.pdf| with \texttt{744} would be wrong because a PDF document must not
  have the x-bit on for the owner
\end{itemize}

Because of the smartness of the installation utility \pkgcheck does check
minimal requirements only, i.e some weird looking permissions like the \texttt{666} above
are accepted.

\section{Different kind of messages}

\begin{description}
\item[Innnn] Informational messages

  These are message which usually announce \pkgcheck actions.

\item[Ennnn] Error messages

  Error messages report errors which must be fixed before installing a package.

\item[Wnnnn] Warning messages

  Warning messages denote possible errors depending upon the situation.

  For example, for a font package having many duplicate files might be ok. For
  another package it could be regarded as an error.

\item[Fatal messages]

  Fatal messages are related to environmental issues and not related to
  packages. They are usually unrecoverable errors, and \pkgcheck's only
  option is to terminate. Fatal messages are written to standard error.

  If for example, the package directory specified at
  the command line doesn't exist then the only option is to issue
  a message and to terminate.
\end{description}

\section{Environmental messages}

\subsection{Error: creating tempdir}

There was an error to create a temporary directory for unzipping the TDS zip archive.
The error message contains more detailed information what the cause is.

\subsection{Error: Config file could not be read}

There was an error reading the config file.

\subsection{Error: TDS archive is not a zip archive}

The TDS archive specified at the command line is not a zip archive.

\subsection{Specified TDS archive does not exist or is no file}


The TDS archive specified at the command does not exist or is no file.



\section{Informational messages}
\input{informationd}

\section{Warning messages}
\input{warningsd}

\section{Error messages}
\input{errorsd}

\end{document}


