Skip to content

Commit

Permalink
release-ready
Browse files Browse the repository at this point in the history
  • Loading branch information
TarasKuzyo committed Aug 26, 2021
1 parent 89b680d commit 0fd6a08
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 43 deletions.
65 changes: 47 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# LaTeXpkges
This is a LaTeX package cleanup utility. Use it to find packages that are included in your LaTeX document but are not actually used.
# LaTeXpkges3

**NEW:** You may now run it directly against your original sources! The utility **will not changes** the sources while working.
This is a LaTeX package cleanup utility. You can use it to find packages that are included in your LaTeX document but are not actually used.

You may run it directly against your original sources. The utility operates on a copy of the original .tex file and **will not modify** any source files while working.

**Note**: it may delete your other LaTeX-related files with the following extensions: `.log`, `.aux`, `.dvi`, `.ps`, `.pdf`, `.xdv`, `.bcf`, `.bbl`, `.blg`.

Current version is based on `python >= 3.6`. If you need a version working for `python < 3.0`, please use the python 2 compatible [release](https://github.com/TarasKuzyo/LaTeXpkges/releases/tag/v0.2).
## How it Works

### Hash-based algorithm

The utility follows the following algorithm:

1. Find all package imports in the LaTeX document
Expand All @@ -15,39 +22,61 @@ The idea is that if after you excluded the package, the PDF did not change, then

PDFs are compared using MD5 hash after being stripped of ID's and dates. XDV files are compared with diff.

### Visual algorithm

Alternatively, you may use the flag `--visual` to convert the files (DVX or PDF) into images and compare them one-by-one instead.

Usually, this method is slower than the MD5-based algorithm but can sometimes provide more accurate results. Also, you can speed it up with the multiprocessing enabled.

**Note:** `pdflatex` yields some erratic results for MD5 comparison, so it is better to use it only in the visual mode.

## General Assumptions

This utility runs on Linux and Windows platforms.

You may use any of the LaTeX engines: `latex`, `pdflatex`,`xelatex` or `lualatex` as a processor and either `bibtex` or `biber` for bibliography.

In order to use the visual comparison, you need to have [ghostscript](https://www.ghostscript.com/) installed.

## Usage

To use the utility, go to the location of your LaTeX project. Assuming your main `.tex` file is `main.tex` and it is in that folder, run the script from the command line:

LaTeXpkges.py --latex pdflatex --bibtex biber main.tex
```
latexpkges3 --latex pdflatex --bibtex biber main.tex
```
### Command-line arguments

`LaTeXpkges3` accepts a single positional argument - the name of the .tex file to analyze and a number of optional arguments listed in the table below:

Let it finish, and in the end it will inform you what packages it considers as unused in your project. The flag `--visual` will convert the files (DVX or PDF) into images and compare them, the flag `--debug` will leave behind all temporary files use in the process.
| Argument | Description |
| -------------- | ----------------------------------------------------------- |
| --latex | The name of an engine to process .tex files (default: pdflatex). Supported engines: latex, pdflatex, xelatex, lualatex |
| --bibtex | The name of a reference engine for .tex files (default: None). Supported engines: bibtex, biber |
| --num_threads | The number of parallel processes (default: 1) |
| --visual | Do the visual comarison instead of checksum |
| --verbose | Enable extra verbosity |
| --debug | Do not delete build artifacts and .pdf files generated during processing |

You may run `LaTeXpkges -h` or `LaTeXpkges --help` for more info.
You may run `latexpkges3 -h` or `latexpkges3 --help` for more info.

## Development

This program was initially developed by Vasily Sidorov (@Bazzilic) and the development now continues under Taras Kuzyo with the support of Books in Bytes, Inc.

The program intentionaly handles ONLY packages that are inserted at top level, that is, that are inserted inside the main project
file and not by file called via ...

\input
\usepackage{}
\RequirePackage
file and not by file called via

```
\input
\usepackage{}
\RequirePackage
```
The reasons for this are:

A- The programming may not be so simple, the logic would be quite messy and it will make the program harder for people to contrib
- The programming may not be so simple, the logic would be quite messy and it will make the program harder for people to contrib
ute to the project!

B- Potential for creating a messy directory with many copies of many files spread in many subdirectories ...

C- Confusing logic (to the user) because we definitely do not want the program to follow a

\RequirePackage{amsmath}
- Potential for creating a messy directory with many copies of many files spread in many subdirectories

and start editing "amsmath" for exclusion of any of its subpackages, even if the user is able to edit it.
- Confusing logic (to the user) because we definitely do not want the program to follow a `\RequirePackage{amsmath}` and start editing "amsmath" for exclusion of any of its subpackages, even if the user is able to edit it.
41 changes: 24 additions & 17 deletions latexpkges3/latexpkges3.py → latexpkges3.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import os
import re
import sys
import filecmp
Expand Down Expand Up @@ -38,12 +37,12 @@ def setup_parser():
help='The name of a reference engine for .tex files (default: %(default)s)'
)
parser.add_argument(
'--visual', action='store_true',
help='Do the visual comarison instead of checksum'
'--num_threads', type=int, default=1,
help="The number of parallel processes (default: %(default)s)"
)
parser.add_argument(
'--num_threads', type=int, default=1,
help="Parallelize with multiple threads (default: %(default)s)"
'--visual', action='store_true',
help='Do the visual comarison instead of checksum'
)
parser.add_argument(
'--verbose', action='store_true',
Expand Down Expand Up @@ -96,7 +95,8 @@ def burst_jpeg(filename, latex_engine):
if latex_engine == 'latex':
command = ['dvips', filename.with_suffix('.dvi')]
subprocess.run(
command, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
command, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
cwd=filename.parent
)
input_name = filename.with_suffix('.ps')
else:
Expand All @@ -110,7 +110,8 @@ def burst_jpeg(filename, latex_engine):
f'-sOutputFile={jpg_prefix}-p%05d.jpg', '-r300x300', str(input_name)
]
subprocess.run(
command, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
command, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
cwd=filename.parent
)
return jpg_prefix.parent

Expand Down Expand Up @@ -219,25 +220,29 @@ def build(filename, latex='pdflatex', bibtex=None, visual=False, verbose=False):
if verbose:
print('Building the project ', end='')
response = subprocess.run(
compile_code, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
compile_code, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE,
cwd=filename.parent
)
if verbose:
print('.' if response.returncode == 0 else 'F', end='')

if bibtex:
response = subprocess.run(
[bibtex, str(filename.stem)], stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
[bibtex, str(filename.stem)], stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE, cwd=filename.parent
)
if verbose:
print('.' if response.returncode == 0 else 'F', end='')
response = subprocess.run(
compile_code, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
compile_code, stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE, cwd=filename.parent
)
if verbose:
print('.' if response.returncode == 0 else 'F', end='')

response = subprocess.run(
compile_code, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE
compile_code, stdout=subprocess.DEVNULL,
stderr=subprocess.PIPE, cwd=filename.parent
)
if verbose:
print('.' if response.returncode == 0 else 'F', end='')
Expand All @@ -261,16 +266,11 @@ def cleanup(filename, jpeg_dirname):
jpeg_dirname.rmdir()


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

if __name__ == '__main__':
def main():

parser = setup_parser()
args = parser.parse_args()

project_dir = args.filename.parent
os.chdir(project_dir)

# initial build
success = build(args.filename, args.latex, args.bibtex, args.visual, verbose=args.verbose)
if not success:
Expand Down Expand Up @@ -315,3 +315,10 @@ def cleanup(filename, jpeg_dirname):

if not args.debug:
cleanup(args.filename, original_jpeg)


# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #


if __name__ == '__main__':
main()
10 changes: 2 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from distutils.core import setup
import py2exe

setup(
name='latexpkges3',
Expand All @@ -20,14 +19,9 @@
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
'Programming Language :: Python :: 3.9'
],
package_dir={'': 'latexpkges3'},
options={
'py2exe': {'bundle_files': 1, 'compressed': True}
},
py_modules=['latexpkges3'],
entry_points={
'console_scripts': [
'latexpkges3=latexpkges3:main',
Expand Down

0 comments on commit 0fd6a08

Please sign in to comment.