% gitVer
% 
% (c) Charles Baynham 2022
%
% License: LaTeX Project Public License 1.3c
%
% This package will get a description of the current git version of this
% document and store it in a command "\gitVer". If memoir is installed, it
% will also add this to the document headers unless the option "noheader" is
% passed.
% 
% It also defines a command "\versionBox{}" which outputs a box containing the
% version and date of compilation
%
% For this to work, you must have git installed and available on the command
% line, and latex must be running in "shell escape" mode.
%

\NeedsTeXFormat{LaTeX2e}
\def\@gitVerPkgName{gitver}
\ProvidesPackage{\@gitVerPkgName}
  [2022/07/16 v1.4 Access current git version and optionally add it to document headers]

\RequirePackage{hyperref}
\RequirePackage{catchfile}
\RequirePackage{pdftexcmds}
\RequirePackage{datetime2}
\RequirePackage{ifthen}
\RequirePackage{xparse}

% Define a command to get environmental variables
% Thanks to egreg at https://tex.stackexchange.com/questions/62010/can-i-access-system-environment-variables-from-latex-for-instance-home
\ExplSyntaxOn
\NewDocumentCommand{\getenv}{om}
 {
  \sys_get_shell:nnN { kpsewhich ~ --var-value ~ #2 } { } \l_tmpa_tl %
  \tl_trim_spaces:N \l_tmpa_tl %
  \IfNoValueTF { #1 } %
   {%
    \tl_use:N \l_tmpa_tl%
   }%
   {%
    \tl_set_eq:NN #1 \l_tmpa_tl%
   }%
 }
\ExplSyntaxOff

% Support lualatex by reinstating the \write18 command
\RequirePackage{ifluatex}
\ifluatex
	\RequirePackage{shellesc}
\fi

%%% Package options %%%

%% 'noheader' option
\newif\if@gitver@noheader
\@gitver@noheaderfalse
\DeclareOption{noheader}{
	\@gitver@noheadertrue
	\PackageInfo{\@gitVerPkgName}{Header info disabled}%
}
%
%% 'nopdfinfo' option
\newif\if@gitver@pdfsubect
\@gitver@pdfsubecttrue
\DeclareOption{nopdfinfo}{
	\@gitver@pdfsubectfalse
	\PackageInfo{\@gitVerPkgName}{Metadata info disabled}%
}
%
\ProcessOptions\relax

%%% End package options %%%

% Define some ifs
\newif\if@gitver@ready
\newif\if@gitver@success

% https://tex.stackexchange.com/questions/88614/how-do-you-detect-restricted-write18-support

\ifcase\pdf@shellescape
  \@gitver@readyfalse%
  \or
  \@gitver@readytrue%
  \or
  \@gitver@readyfalse%
 \fi

\if@gitver@ready
	\PackageInfo{\@gitVerPkgName}{Shell escape enabled}%
%
	% Get current git version
	% Note: this command requires (a) git installed and (b) shell escape in latex enabled
	\immediate\write18{ git describe --match nopenopenope --always --long --dirty --abbrev=6 > \jobname_desc.aux }
%
	% Extract this into a new variable, gitVer
	\@gitver@successfalse
	\IfFileExists{\jobname_desc.aux}{
		% Read the file into \gitVer
		\CatchFileDef{\gitVer}{\jobname_desc.aux}{\endlinechar=-1}

		% Check if the macro \gitVer is empty: this is its definition if the file had no contents
		\def\@gitver@emptyfile{}

		\ifx\gitVer\@gitver@emptyfile%
			\PackageWarning{\@gitVerPkgName}{Git output is empty: is this folder a git repo? Make sure that this directory has had "git init" called in it, has at least one commit, and that git is installed.}
		\else
			\@gitver@successtrue
		\fi
	}

	\if@gitver@success
	\else
	    % Look for "CLSI" environmental variable: this stands for Common Latex Service
        % Interface, and is set to "1" in web builders like Overleaf.com
        \getenv[\CLSI]{CLSI}
        % Check if CLSI == 1 (see https://tex.stackexchange.com/a/306500)
        \ifnum1=0\CLSI\relax 
            \PackageWarning{\@gitVerPkgName}{Running on a Common Latex Service %
                Interface without Git: writing version as "CLSI"}%
		    \def\gitVer{CLSI}
        \else 
            \PackageError{\@gitVerPkgName}{Git command failed: writing as "unknown"}{%
                Calling git failed, and your system did not identify itself as a 
                Common Latex Service Interface (e.g. overleaf.com). Make sure that git
                is installed and that this file is in a repository which has at least
                one commit. 
            }%
		    \def\gitVer{unknown}
        \fi
	\fi
%
	% Make a box containing the date and version
	\newcommand{\versionBox}{\fbox{Manuscript version: \textit{\#\gitVer} - \DTMnow{} }}
%
	% If we're using memoir, put the tag into into the header
%
	\@ifclassloaded{memoir}%
	  {%
	  	\PackageInfo{\@gitVerPkgName}{Memoir detected}%
	  	\if@gitver@noheader%
		\else%
			% Add the git version and the date/time to the header / footer
			\PackageInfo{\@gitVerPkgName}{Adding git info to header}%
			\makeoddfoot{Ruled}{\versionBox}{}{\thepage}
			\makeevenfoot{Ruled}{\thepage}{}{\versionBox}
			\makeevenhead {Ruled}{\scshape\leftmark}{}{\textit{\#\gitVer}}
			\makeoddhead {Ruled}{\textit{\#\gitVer}}{}{\rightmark}
		\fi%
	}{%
		% If we're not using memoir, but we are using fancyhdr, also add to the header
		\@ifpackageloaded{fancyhdr}
		{%
			\if@gitver@noheader%
			\else%
				\fancyfoot[L]{\versionBox}
				\fancyfoot[C]{}
				\fancyfoot[R]{\thepage}
			\fi
		}{%
			% No memoir or fancyhdr
			\if@gitver@noheader%
			\else%
				\PackageWarning{\@gitVerPkgName}{Not changing the document headers because you're not using "memoir" or "fancyhdr" package. Pass "noheader" to suppress this warning, or use one of these classes / packages.}
			\fi
		}
	}%

	\if@gitver@pdfsubect%
		\PackageInfo{\@gitVerPkgName}{Setting pdf subject metadata}%
		% Put it into the metadata too
		\hypersetup{
			pdfsubject={Version \#\gitVer{}}
		}%
	\fi%
\else
	\PackageError{\@gitVerPkgName}{Shell escape not enabled}{Latex failed to write a file. This is probably because shell-escape mode is disabled: you must turn this on!}

	\def\versionBox{???}
	\def\gitVer{unknown}
\fi