Compare commits

...

5 Commits

9 changed files with 116 additions and 39 deletions

View File

@ -1,7 +1,8 @@
from PyTeX.default_formatters import ClassFormatter, PackageFormatter, DictionaryFormatter from PyTeX.default_formatters import ClassFormatter, PackageFormatter, DictionaryFormatter, DocstripFormatter
__all__ = [ __all__ = [
"ClassFormatter", "ClassFormatter",
"PackageFormatter", "PackageFormatter",
"DictionaryFormatter" "DictionaryFormatter",
'DocstripFormatter'
] ]

View File

@ -15,20 +15,20 @@ def build(
build_dir: Optional[Path] = None, build_dir: Optional[Path] = None,
input_file: Optional[Path] = None, input_file: Optional[Path] = None,
author: Optional[str] = None, author: Optional[str] = None,
latex_name: str = 'prepend-author', # name handling latex_name: str = 'prepend-author', # name handling
recursive: bool = False, # input control recursive: bool = False, # input control
include_timestamp: bool = False, # header include_timestamp: bool = False, # header
include_pytex_version: bool = False, # header include_pytex_version: bool = False, # header
include_license: bool = False, # header include_license: bool = False, # header
include_git_version: bool = False, # header include_git_version: bool = False, # header
include_pytex_info_text: bool = False, # header include_pytex_info_text: bool = False, # header
extra_header: Optional[Path] = None, extra_header: Optional[Path] = None,
allow_dirty: bool = False, # versioning allow_dirty: bool = False, # versioning
overwrite_existing_files: bool = False, # output control overwrite_existing_files: bool = False, # output control
build_all: bool = False, # output control / versioning build_all: bool = False, # output control / versioning
write_build_information: bool = True, # meta write_build_information: bool = True, # meta
clean_old_files: bool = False clean_old_files: bool = False
): ):
pytex_msg('Getting git repository information...') pytex_msg('Getting git repository information...')
if extra_header: if extra_header:
if extra_header.exists(): if extra_header.exists():
@ -76,6 +76,8 @@ def build(
files.append(file) files.append(file)
for file in src_dir.rglob('*.pycls3'): for file in src_dir.rglob('*.pycls3'):
files.append(file) files.append(file)
for file in src_dir.rglob('*.dtx'):
files.append(file)
else: else:
for file in src_dir.glob('*.pysty'): for file in src_dir.glob('*.pysty'):
files.append(file) files.append(file)
@ -87,12 +89,15 @@ def build(
files.append(file) files.append(file)
for file in src_dir.glob('*.pycls3'): for file in src_dir.glob('*.pycls3'):
files.append(file) files.append(file)
for file in src_dir.glob('*.dtx'):
files.append(file)
sources_to_build = [] sources_to_build = []
for file in files: for file in files:
if last_build_info: if last_build_info:
last_build_info_for_this_file =\ last_build_info_for_this_file = \
list(filter(lambda i: i['source file'] == str(file.relative_to(src_dir)), last_build_info['tex_sources'])) list(filter(lambda i: i['source file'] == str(file.relative_to(src_dir)),
last_build_info['tex_sources']))
else: else:
last_build_info_for_this_file = [] last_build_info_for_this_file = []
sources_to_build.append( sources_to_build.append(
@ -143,8 +148,9 @@ def build(
file.unlink() file.unlink()
elif not str(file.relative_to(output_dir)) in built_files: elif not str(file.relative_to(output_dir)) in built_files:
if not file.is_dir() and not str(file.relative_to(output_dir)) == 'build_info.json': if not file.is_dir() and not str(file.relative_to(output_dir)) == 'build_info.json':
# PyTeX does not at all know something about this file if '.git' not in str(file) and 'documentation/' not in str(file):
raise UnknownFileInBuildDirectory(file.relative_to(output_dir)) # PyTeX does not at all know something about this file
raise UnknownFileInBuildDirectoryError(file.relative_to(output_dir))
if write_build_information: if write_build_information:
with open(output_dir / 'build_info.json', 'w') as f: with open(output_dir / 'build_info.json', 'w') as f:

View File

@ -77,7 +77,7 @@ def parse_and_build(arglist: [str]):
) )
parser.add_argument( parser.add_argument(
'-l', '--license', '-l', '--license',
help='Insert MIT license into package header', help='Insert LPPL and GPLv3 license into package header',
action='store_true', action='store_true',
dest='include_license' dest='include_license'
) )

View File

@ -2,7 +2,7 @@ from pathlib import Path
from typing import Optional, List from typing import Optional, List
from PyTeX.build.git_hook import is_recent, get_latest_commit from PyTeX.build.git_hook import is_recent, get_latest_commit
from PyTeX import PackageFormatter, ClassFormatter, DictionaryFormatter from PyTeX import PackageFormatter, ClassFormatter, DictionaryFormatter, DocstripFormatter
from PyTeX.errors import * from PyTeX.errors import *
from .pytex_msg import pytex_msg from .pytex_msg import pytex_msg
from PyTeX.utils import md5 from PyTeX.utils import md5
@ -79,6 +79,8 @@ class TexFileToFormat:
latex_file_type = 'class' latex_file_type = 'class'
elif '.pydict' in self.src_path.name: elif '.pydict' in self.src_path.name:
latex_file_type = 'dictionary' latex_file_type = 'dictionary'
elif '.dtx' in self.src_path.name:
latex_file_type = 'ERROR'
else: else:
raise ProgrammingError raise ProgrammingError
new_header.append(line.format( new_header.append(line.format(
@ -126,6 +128,8 @@ class TexFileToFormat:
author=self.current_build_info.author, author=self.current_build_info.author,
header=self._header header=self._header
) )
elif self.src_path.name.endswith('.dtx'):
formatter = DocstripFormatter(name=self.src_path.with_suffix('').name)
else: else:
raise ProgrammingError raise ProgrammingError
formatter.make_default_macros() formatter.make_default_macros()

View File

@ -1,22 +1,27 @@
LICENSE = [ LICENSE = [
'Copyright © {year} {copyright_holders}', 'Copyright © {year} {copyright_holders}',
'', '',
'Permission is hereby granted, free of charge, to any person obtaining a copy', 'This work may be distributed and/or modified',
'of this software and associated documentation files (the “Software”), to deal',
'in the Software without restriction, including without limitation the rights',
'to use, copy, modify, merge, publish, distribute, sublicense, and/or sell',
'copies of the Software, and to permit persons to whom the Software is',
'furnished to do so, subject to the following conditions:',
'The above copyright notice and this permission notice shall be included in all',
'copies or substantial portions of the Software.',
'', '',
'THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR', '1. under the LaTeX Project Public License and/or',
'IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,', '2. under the GNU General Public License'
'FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE', '',
'AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER', '',
'LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,', 'Distribution under conditions of the LaTeX Project Public License,',
'OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE', 'requires either version 1.3 of this license or (at your option)',
'SOFTWARE.' 'any later version.',
'The latest version of this license is in',
' http://www.latex-project.org/lppl.txt',
'and version 1.3 or later is part of all distributions of LaTeX',
'version 2005/12/01 or later.',
'',
'This work has the LPPL maintenance status \`maintained\'.',
'',
'The Current Maintainer of this work is {copyright_holders}.',
'',
'',
'Distribution under the GNU General Public License requires either',
'version 3 or (at your opinion) any later version.'
] ]
PYTEX_INFO_TEXT = [ PYTEX_INFO_TEXT = [

View File

@ -1,9 +1,11 @@
from .class_formatter import ClassFormatter from .class_formatter import ClassFormatter
from .package_formatter import PackageFormatter from .package_formatter import PackageFormatter
from .dictionary_formatter import DictionaryFormatter from .dictionary_formatter import DictionaryFormatter
from .docstrip_formatter import DocstripFormatter
__all__ = [ __all__ = [
'PackageFormatter', 'PackageFormatter',
'ClassFormatter', 'ClassFormatter',
'DictionaryFormatter' 'DictionaryFormatter',
'DocstripFormatter'
] ]

View File

@ -0,0 +1,39 @@
from pathlib import Path
from typing import Dict, Optional, List
import subprocess
from PyTeX.formatter import Formatter
from PyTeX.utils import ensure_file_integrity
from PyTeX.errors import FileNotGeneratedFromDTXFileError, LatexMKError
class DocstripFormatter(Formatter):
def __init__(self, name: str):
self.name = name
self.filename = self.name + '.sty'
Formatter.__init__(self)
def expected_file_name(self) -> str:
return self.filename
def format_file(self, input_path: Path, output_dir: Path,
relative_name: Optional[str] = None,
last_build_info: Optional[List[Dict]] = None) -> List[str]:
ensure_file_integrity(output_dir / self.filename, str(Path(relative_name).parent / self.filename), last_build_info)
try:
result = subprocess.run(['latexmk', '-gg', '-output-directory=/tmp'], cwd=str(input_path.parent),
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
except subprocess.CalledProcessError:
raise LatexMKError(self.filename)
if not result:
pass
sty_file = (Path('/tmp') / input_path.with_suffix('.sty').name)
if sty_file.exists():
sty = sty_file.read_text()
else:
raise FileNotGeneratedFromDTXFileError(self.filename, 'style')
output_dir.mkdir(parents=True, exist_ok=True)
(output_dir / self.filename).write_text(sty)
return [self.filename]

View File

@ -1,6 +1,6 @@
from .errors import PyTexError, SubmoduleDirtyForbiddenError, ProgrammingError, ExtraHeaderFileNotFoundError, \ from .errors import PyTexError, SubmoduleDirtyForbiddenError, ProgrammingError, ExtraHeaderFileNotFoundError, \
UnknownTexVersionError, ModifiedFileInBuildDirectoryError, UnknownFileInBuildDirectoryNoOverwriteError, \ UnknownTexVersionError, ModifiedFileInBuildDirectoryError, UnknownFileInBuildDirectoryNoOverwriteError, \
UnknownFileInBuildDirectory UnknownFileInBuildDirectoryError, LatexMKError, FileNotGeneratedFromDTXFileError
__all__ = [ __all__ = [
'PyTexError', 'PyTexError',
@ -10,5 +10,7 @@ __all__ = [
'UnknownTexVersionError', 'UnknownTexVersionError',
'ModifiedFileInBuildDirectoryError', 'ModifiedFileInBuildDirectoryError',
'UnknownFileInBuildDirectoryNoOverwriteError', 'UnknownFileInBuildDirectoryNoOverwriteError',
'UnknownFileInBuildDirectory' 'UnknownFileInBuildDirectoryError',
'LatexMKError',
'FileNotGeneratedFromDTXFileError'
] ]

View File

@ -56,10 +56,28 @@ class UnknownFileInBuildDirectoryNoOverwriteError(PyTexError):
) )
class UnknownFileInBuildDirectory(PyTexError): class UnknownFileInBuildDirectoryError(PyTexError):
def __init__(self, filename): def __init__(self, filename):
super().__init__( super().__init__(
f"Detected unknown file {filename} in build directory." f"Detected unknown file {filename} in build directory."
f"PyTeX has no knowledge about this, you should probably" f"PyTeX has no knowledge about this, you should probably"
f"remove it." f"remove it."
) )
class LatexMKError(PyTexError):
def __init__(self, filename):
super().__init__(
f"Running latexmk on file {filename} resulted in an error. "
f"Make sure this file is well-formed and an appropriate "
f"'.latexmkrc' is present in its directory."
)
class FileNotGeneratedFromDTXFileError(PyTexError):
def __init__(self, filename, type):
super().__init__(
f"Running latexmk on {filename} did not produce a LaTeX "
f"{type} file as needed. I do not know how to build "
f"a {type} from this '.dtx' file."
)