article-cli 2.0.0__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {article_cli-2.0.0 → article_cli-2.1.0}/PKG-INFO +113 -9
- {article_cli-2.0.0 → article_cli-2.1.0}/README.md +109 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/pyproject.toml +6 -9
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/__init__.py +1 -1
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/cli.py +1 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/__init__.py +2 -0
- article_cli-2.1.0/src/article_cli/commands/bundle.py +93 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/version.py +1 -1
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/config.py +20 -14
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/git_hooks.py +2 -1
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/git_manager.py +2 -1
- article_cli-2.1.0/src/article_cli/paper_version.py +108 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/repository_setup.py +6 -1
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/__init__.py +8 -0
- article_cli-2.1.0/src/article_cli/services/bundle.py +335 -0
- article_cli-2.1.0/src/article_cli/services/bundle_backends.py +337 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/compiler.py +11 -4
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/gitinfo.py +45 -5
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/release.py +33 -12
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/article/ieee.tex.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/article/lncs.tex.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/article/lncs.typ.j2 +3 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/article/main.tex.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/article/main.typ.j2 +3 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/poster/poster.tex.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/poster/poster.typ.j2 +3 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/presentation/beamer.tex.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/presentation/typst.typ.j2 +3 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/project/README.md.j2 +2 -2
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/project/pyproject.toml.j2 +1 -1
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/typst_compiler.py +9 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/zotero.py +81 -51
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/golden/article_main.tex +2 -2
- article_cli-2.1.0/tests/test_bundle.py +311 -0
- article_cli-2.1.0/tests/test_bundle_typst.py +332 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_cli.py +6 -5
- article_cli-2.1.0/tests/test_paper_version.py +231 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_release_service.py +24 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_repository_setup.py +3 -6
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_services.py +3 -3
- article_cli-2.1.0/tests/test_version_consistency.py +40 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_workflow_ci.py +1 -4
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_zotero_bibliography.py +80 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/.gitignore +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/LICENSE +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/__main__.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/command_runner.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/bibtex.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/clean.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/compile.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/config.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/doctor.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/fonts.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/init.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/release.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/setup.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/commands/themes.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/doctor.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/fonts.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/latex_compiler.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/project_context.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/reporting.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/bibliography.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/git.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/services/workflow.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/template_renderer.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/__init__.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/github/latex.yml.j2 +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/project/gitignore.j2 +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/templates/project/vscode-settings.json.j2 +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/src/article_cli/themes.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/__init__.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/golden/__init__.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_config.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_doctor.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_fonts.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_latex_compiler.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_project_context.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_template_renderer.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_themes.py +0 -0
- {article_cli-2.0.0 → article_cli-2.1.0}/tests/test_typst_compiler.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: article-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.0
|
|
4
4
|
Summary: CLI tool for managing LaTeX and Typst documents with git integration and Zotero bibliography
|
|
5
5
|
Project-URL: Homepage, https://github.com/feelpp/article.cli
|
|
6
6
|
Project-URL: Documentation, https://github.com/feelpp/article.cli#readme
|
|
@@ -35,18 +35,15 @@ Classifier: Intended Audience :: Science/Research
|
|
|
35
35
|
Classifier: License :: OSI Approved :: MIT License
|
|
36
36
|
Classifier: Operating System :: OS Independent
|
|
37
37
|
Classifier: Programming Language :: Python :: 3
|
|
38
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
39
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
40
38
|
Classifier: Programming Language :: Python :: 3.11
|
|
41
39
|
Classifier: Programming Language :: Python :: 3.12
|
|
42
40
|
Classifier: Programming Language :: Python :: 3.13
|
|
43
41
|
Classifier: Topic :: Scientific/Engineering
|
|
44
42
|
Classifier: Topic :: Text Processing :: Markup :: LaTeX
|
|
45
|
-
Requires-Python: >=3.
|
|
43
|
+
Requires-Python: >=3.11
|
|
46
44
|
Requires-Dist: jinja2>=3.1
|
|
47
45
|
Requires-Dist: pyyaml>=6.0
|
|
48
46
|
Requires-Dist: requests>=2.28.0
|
|
49
|
-
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
50
47
|
Provides-Extra: dev
|
|
51
48
|
Requires-Dist: black==25.11.0; extra == 'dev'
|
|
52
49
|
Requires-Dist: build>=1.2.0; extra == 'dev'
|
|
@@ -54,7 +51,7 @@ Requires-Dist: flake8>=6.0; extra == 'dev'
|
|
|
54
51
|
Requires-Dist: mypy<2.0,>=1.0; extra == 'dev'
|
|
55
52
|
Requires-Dist: pytest-cov; extra == 'dev'
|
|
56
53
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
57
|
-
Requires-Dist: twine>=
|
|
54
|
+
Requires-Dist: twine>=7.0.0; extra == 'dev'
|
|
58
55
|
Requires-Dist: types-requests; extra == 'dev'
|
|
59
56
|
Description-Content-Type: text/markdown
|
|
60
57
|
|
|
@@ -292,7 +289,7 @@ The `init` command sets up:
|
|
|
292
289
|
### Git Release Management
|
|
293
290
|
|
|
294
291
|
```bash
|
|
295
|
-
# Refresh
|
|
292
|
+
# Refresh paper version metadata (LaTeX or Typst)
|
|
296
293
|
article-cli version
|
|
297
294
|
|
|
298
295
|
# Refresh metadata, compile, and check the PDF version text
|
|
@@ -367,6 +364,97 @@ article-cli compile --clean-first --clean-after
|
|
|
367
364
|
article-cli compile --output-dir build/
|
|
368
365
|
```
|
|
369
366
|
|
|
367
|
+
### Paper Version Metadata
|
|
368
|
+
|
|
369
|
+
`article-cli version` writes LaTeX's `gitHeadLocal.gin` for `gitinfo2`, or a
|
|
370
|
+
portable `gitHeadLocal.json` snapshot beside a Typst main document. The Typst
|
|
371
|
+
snapshot contains the commit, short hash, branch, description, nearest tag,
|
|
372
|
+
commit date, and dirty flag. Generated metadata is excluded from dirty detection;
|
|
373
|
+
tracked source changes count as dirty, matching the existing LaTeX behavior.
|
|
374
|
+
`--dry-run` reports planned changes without writing files.
|
|
375
|
+
|
|
376
|
+
```latex
|
|
377
|
+
\usepackage[local]{gitinfo2}
|
|
378
|
+
% In the document body:
|
|
379
|
+
Version: \gitDescribe{} / \gitAbbrevHash{}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
```typst
|
|
383
|
+
#let git = json("gitHeadLocal.json")
|
|
384
|
+
#set page(footer: align(center)[Version: #git.description])
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
New built-in templates include a version stamp. Typst compilation refreshes its
|
|
388
|
+
snapshot when Git is available; extracted source archives keep their frozen
|
|
389
|
+
snapshot. Typst reads JSON directly, so no extra Typst package is needed.
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
article-cli version --document main.typ --compile --check-pdf --checksum
|
|
393
|
+
article-cli version --document main.tex --compile --check-pdf
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Submission Source Bundles (LaTeX and Typst)
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Build and package the main document and its recorded dependencies
|
|
400
|
+
article-cli bundle main.tex --verify
|
|
401
|
+
article-cli bundle main.typ --verify
|
|
402
|
+
|
|
403
|
+
# Preview an existing build without changing any files
|
|
404
|
+
article-cli bundle main.tex --dry-run
|
|
405
|
+
|
|
406
|
+
# Extend project policy for one archive
|
|
407
|
+
article-cli bundle main.tex --include 'supplement/**' --exclude 'reviews/**' -o dist/preprint.zip
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`bundle` automatically selects a LaTeX or Typst backend. LaTeX uses `latexmk`
|
|
411
|
+
and TeX recorder data; Typst 0.14+ uses native JSON dependency reporting, including
|
|
412
|
+
dynamically loaded data, imports, figures, and bibliography styles. The command
|
|
413
|
+
writes a reproducible ZIP and an adjacent JSON manifest with file hashes.
|
|
414
|
+
`--verify` recompiles only the selected files in a temporary directory before
|
|
415
|
+
publishing the archive. Both formats share the same selection and output policy.
|
|
416
|
+
|
|
417
|
+
```toml
|
|
418
|
+
[tool.article-cli.bundle]
|
|
419
|
+
output = "dist/preprint.zip"
|
|
420
|
+
include = ["supplement/**"]
|
|
421
|
+
exclude = ["reviews/**", "local-only/**"]
|
|
422
|
+
include_pdf = false
|
|
423
|
+
verify = true
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Paths and globs are relative to the main document's directory, which becomes the
|
|
427
|
+
ZIP root. Include patterns add files to detected dependencies; CLI patterns extend
|
|
428
|
+
those in configuration. Exclusions take precedence, and excluding a required
|
|
429
|
+
source fails with an explanation. `**` matches any number of directories.
|
|
430
|
+
|
|
431
|
+
Git repository internals, virtual environments, `local-only`, `.env` files, and build logs are
|
|
432
|
+
excluded by default. The main PDF is excluded unless `--include-pdf` is set; figure
|
|
433
|
+
PDFs remain included. Keep all local dependencies and the build directory under
|
|
434
|
+
the main document's directory. System TeX packages are supplied by the receiving
|
|
435
|
+
service. LaTeX shell escape is disabled.
|
|
436
|
+
|
|
437
|
+
Typst imports from external versioned packages are copied, with their manifests
|
|
438
|
+
and license files, under `.article-cli/typst-packages`. Configured local
|
|
439
|
+
`[tool.article-cli.typst].font_paths` must be under the document directory; font
|
|
440
|
+
files are included and their relative search paths recorded in the manifest.
|
|
441
|
+
System fonts remain environment dependencies. To compile an extracted Typst bundle:
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
typst compile --root . --package-path .article-cli/typst-packages main.typ
|
|
445
|
+
# Add --font-path fonts when the bundle uses a configured local font directory.
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Use `--build-dir build --no-build` to reuse existing LaTeX `.fls`/`.aux`/`.bbl`
|
|
449
|
+
data or Typst `<document>.typst-deps.json` metadata, or `--force` to replace an
|
|
450
|
+
existing ZIP and manifest. Typst dependency metadata is generated by `bundle`;
|
|
451
|
+
a previous plain `compile` does not create it. Dry runs require existing metadata. `--no-verify` and `--no-include-pdf` override project policy.
|
|
452
|
+
Verification checks local compilability; HAL/arXiv still apply their own submission
|
|
453
|
+
and supported-format requirements. This command prepares files without uploading them.
|
|
454
|
+
|
|
455
|
+
Run `article-cli version` before bundling when you need an up-to-date provenance
|
|
456
|
+
stamp. Bundling preserves the selected snapshot during compilation and verification.
|
|
457
|
+
|
|
370
458
|
### Typst Compilation
|
|
371
459
|
|
|
372
460
|
```bash
|
|
@@ -502,7 +590,7 @@ Use `[tool.article-cli.release] tag_policy = "semver"` when a repository must re
|
|
|
502
590
|
|
|
503
591
|
## Requirements
|
|
504
592
|
|
|
505
|
-
- Python 3.
|
|
593
|
+
- Python 3.11+
|
|
506
594
|
- Git repository with gitinfo2 package (for LaTeX integration)
|
|
507
595
|
- Zotero account with API access (for bibliography features)
|
|
508
596
|
- Typst CLI (for Typst compilation) - install from https://typst.app/
|
|
@@ -522,6 +610,22 @@ MIT License - see LICENSE file for details.
|
|
|
522
610
|
|
|
523
611
|
## Changelog
|
|
524
612
|
|
|
613
|
+
### v2.1.0
|
|
614
|
+
- Require Python 3.11+ and use its built-in TOML parser
|
|
615
|
+
- Add LaTeX and Typst submission bundles and portable paper version metadata
|
|
616
|
+
|
|
617
|
+
### v2.0.1
|
|
618
|
+
- Keep Python package, generated-template minimum version, Antora component version, docs package version, and lockfiles synchronized
|
|
619
|
+
- Add a release-version bump script and CI test to prevent stale documentation version labels
|
|
620
|
+
|
|
621
|
+
### v2.0.0
|
|
622
|
+
- Treat the paper lifecycle as explicit commands: `init`, `setup`, `doctor`, `bib update`, `compile`, `version`, and `release`
|
|
623
|
+
- Add safe `doctor --fix` repairs for output directories, managed git hooks, and `gitHeadLocal.gin`
|
|
624
|
+
- Make `release` the checked paper release workflow and keep `create` as a deprecated compatibility alias
|
|
625
|
+
- Drop Python 3.8 support; test Python 3.9 through 3.13
|
|
626
|
+
- Move generated templates and workflows to package Jinja2 resources
|
|
627
|
+
- Add Antora documentation with Feel++ Antora UI
|
|
628
|
+
|
|
525
629
|
### v1.5.0
|
|
526
630
|
- Add `doctor` diagnostics with JSON output and safe `--fix` repairs
|
|
527
631
|
- Split CLI implementation into command modules
|
|
@@ -232,7 +232,7 @@ The `init` command sets up:
|
|
|
232
232
|
### Git Release Management
|
|
233
233
|
|
|
234
234
|
```bash
|
|
235
|
-
# Refresh
|
|
235
|
+
# Refresh paper version metadata (LaTeX or Typst)
|
|
236
236
|
article-cli version
|
|
237
237
|
|
|
238
238
|
# Refresh metadata, compile, and check the PDF version text
|
|
@@ -307,6 +307,97 @@ article-cli compile --clean-first --clean-after
|
|
|
307
307
|
article-cli compile --output-dir build/
|
|
308
308
|
```
|
|
309
309
|
|
|
310
|
+
### Paper Version Metadata
|
|
311
|
+
|
|
312
|
+
`article-cli version` writes LaTeX's `gitHeadLocal.gin` for `gitinfo2`, or a
|
|
313
|
+
portable `gitHeadLocal.json` snapshot beside a Typst main document. The Typst
|
|
314
|
+
snapshot contains the commit, short hash, branch, description, nearest tag,
|
|
315
|
+
commit date, and dirty flag. Generated metadata is excluded from dirty detection;
|
|
316
|
+
tracked source changes count as dirty, matching the existing LaTeX behavior.
|
|
317
|
+
`--dry-run` reports planned changes without writing files.
|
|
318
|
+
|
|
319
|
+
```latex
|
|
320
|
+
\usepackage[local]{gitinfo2}
|
|
321
|
+
% In the document body:
|
|
322
|
+
Version: \gitDescribe{} / \gitAbbrevHash{}
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
```typst
|
|
326
|
+
#let git = json("gitHeadLocal.json")
|
|
327
|
+
#set page(footer: align(center)[Version: #git.description])
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
New built-in templates include a version stamp. Typst compilation refreshes its
|
|
331
|
+
snapshot when Git is available; extracted source archives keep their frozen
|
|
332
|
+
snapshot. Typst reads JSON directly, so no extra Typst package is needed.
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
article-cli version --document main.typ --compile --check-pdf --checksum
|
|
336
|
+
article-cli version --document main.tex --compile --check-pdf
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Submission Source Bundles (LaTeX and Typst)
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
# Build and package the main document and its recorded dependencies
|
|
343
|
+
article-cli bundle main.tex --verify
|
|
344
|
+
article-cli bundle main.typ --verify
|
|
345
|
+
|
|
346
|
+
# Preview an existing build without changing any files
|
|
347
|
+
article-cli bundle main.tex --dry-run
|
|
348
|
+
|
|
349
|
+
# Extend project policy for one archive
|
|
350
|
+
article-cli bundle main.tex --include 'supplement/**' --exclude 'reviews/**' -o dist/preprint.zip
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
`bundle` automatically selects a LaTeX or Typst backend. LaTeX uses `latexmk`
|
|
354
|
+
and TeX recorder data; Typst 0.14+ uses native JSON dependency reporting, including
|
|
355
|
+
dynamically loaded data, imports, figures, and bibliography styles. The command
|
|
356
|
+
writes a reproducible ZIP and an adjacent JSON manifest with file hashes.
|
|
357
|
+
`--verify` recompiles only the selected files in a temporary directory before
|
|
358
|
+
publishing the archive. Both formats share the same selection and output policy.
|
|
359
|
+
|
|
360
|
+
```toml
|
|
361
|
+
[tool.article-cli.bundle]
|
|
362
|
+
output = "dist/preprint.zip"
|
|
363
|
+
include = ["supplement/**"]
|
|
364
|
+
exclude = ["reviews/**", "local-only/**"]
|
|
365
|
+
include_pdf = false
|
|
366
|
+
verify = true
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Paths and globs are relative to the main document's directory, which becomes the
|
|
370
|
+
ZIP root. Include patterns add files to detected dependencies; CLI patterns extend
|
|
371
|
+
those in configuration. Exclusions take precedence, and excluding a required
|
|
372
|
+
source fails with an explanation. `**` matches any number of directories.
|
|
373
|
+
|
|
374
|
+
Git repository internals, virtual environments, `local-only`, `.env` files, and build logs are
|
|
375
|
+
excluded by default. The main PDF is excluded unless `--include-pdf` is set; figure
|
|
376
|
+
PDFs remain included. Keep all local dependencies and the build directory under
|
|
377
|
+
the main document's directory. System TeX packages are supplied by the receiving
|
|
378
|
+
service. LaTeX shell escape is disabled.
|
|
379
|
+
|
|
380
|
+
Typst imports from external versioned packages are copied, with their manifests
|
|
381
|
+
and license files, under `.article-cli/typst-packages`. Configured local
|
|
382
|
+
`[tool.article-cli.typst].font_paths` must be under the document directory; font
|
|
383
|
+
files are included and their relative search paths recorded in the manifest.
|
|
384
|
+
System fonts remain environment dependencies. To compile an extracted Typst bundle:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
typst compile --root . --package-path .article-cli/typst-packages main.typ
|
|
388
|
+
# Add --font-path fonts when the bundle uses a configured local font directory.
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
Use `--build-dir build --no-build` to reuse existing LaTeX `.fls`/`.aux`/`.bbl`
|
|
392
|
+
data or Typst `<document>.typst-deps.json` metadata, or `--force` to replace an
|
|
393
|
+
existing ZIP and manifest. Typst dependency metadata is generated by `bundle`;
|
|
394
|
+
a previous plain `compile` does not create it. Dry runs require existing metadata. `--no-verify` and `--no-include-pdf` override project policy.
|
|
395
|
+
Verification checks local compilability; HAL/arXiv still apply their own submission
|
|
396
|
+
and supported-format requirements. This command prepares files without uploading them.
|
|
397
|
+
|
|
398
|
+
Run `article-cli version` before bundling when you need an up-to-date provenance
|
|
399
|
+
stamp. Bundling preserves the selected snapshot during compilation and verification.
|
|
400
|
+
|
|
310
401
|
### Typst Compilation
|
|
311
402
|
|
|
312
403
|
```bash
|
|
@@ -442,7 +533,7 @@ Use `[tool.article-cli.release] tag_policy = "semver"` when a repository must re
|
|
|
442
533
|
|
|
443
534
|
## Requirements
|
|
444
535
|
|
|
445
|
-
- Python 3.
|
|
536
|
+
- Python 3.11+
|
|
446
537
|
- Git repository with gitinfo2 package (for LaTeX integration)
|
|
447
538
|
- Zotero account with API access (for bibliography features)
|
|
448
539
|
- Typst CLI (for Typst compilation) - install from https://typst.app/
|
|
@@ -462,6 +553,22 @@ MIT License - see LICENSE file for details.
|
|
|
462
553
|
|
|
463
554
|
## Changelog
|
|
464
555
|
|
|
556
|
+
### v2.1.0
|
|
557
|
+
- Require Python 3.11+ and use its built-in TOML parser
|
|
558
|
+
- Add LaTeX and Typst submission bundles and portable paper version metadata
|
|
559
|
+
|
|
560
|
+
### v2.0.1
|
|
561
|
+
- Keep Python package, generated-template minimum version, Antora component version, docs package version, and lockfiles synchronized
|
|
562
|
+
- Add a release-version bump script and CI test to prevent stale documentation version labels
|
|
563
|
+
|
|
564
|
+
### v2.0.0
|
|
565
|
+
- Treat the paper lifecycle as explicit commands: `init`, `setup`, `doctor`, `bib update`, `compile`, `version`, and `release`
|
|
566
|
+
- Add safe `doctor --fix` repairs for output directories, managed git hooks, and `gitHeadLocal.gin`
|
|
567
|
+
- Make `release` the checked paper release workflow and keep `create` as a deprecated compatibility alias
|
|
568
|
+
- Drop Python 3.8 support; test Python 3.9 through 3.13
|
|
569
|
+
- Move generated templates and workflows to package Jinja2 resources
|
|
570
|
+
- Add Antora documentation with Feel++ Antora UI
|
|
571
|
+
|
|
465
572
|
### v1.5.0
|
|
466
573
|
- Add `doctor` diagnostics with JSON output and safe `--fix` repairs
|
|
467
574
|
- Split CLI implementation into command modules
|
|
@@ -4,22 +4,20 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "article-cli"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.1.0"
|
|
8
8
|
authors = [
|
|
9
9
|
{name = "Christophe Prud'homme", email = "prudhomm@cemosis.fr"},
|
|
10
10
|
]
|
|
11
11
|
description = "CLI tool for managing LaTeX and Typst documents with git integration and Zotero bibliography"
|
|
12
12
|
readme = "README.md"
|
|
13
13
|
license = {file = "LICENSE"}
|
|
14
|
-
requires-python = ">=3.
|
|
14
|
+
requires-python = ">=3.11"
|
|
15
15
|
classifiers = [
|
|
16
16
|
"Development Status :: 4 - Beta",
|
|
17
17
|
"Intended Audience :: Science/Research",
|
|
18
18
|
"License :: OSI Approved :: MIT License",
|
|
19
19
|
"Operating System :: OS Independent",
|
|
20
20
|
"Programming Language :: Python :: 3",
|
|
21
|
-
"Programming Language :: Python :: 3.9",
|
|
22
|
-
"Programming Language :: Python :: 3.10",
|
|
23
21
|
"Programming Language :: Python :: 3.11",
|
|
24
22
|
"Programming Language :: Python :: 3.12",
|
|
25
23
|
"Programming Language :: Python :: 3.13",
|
|
@@ -31,7 +29,6 @@ dependencies = [
|
|
|
31
29
|
"requests>=2.28.0",
|
|
32
30
|
"PyYAML>=6.0",
|
|
33
31
|
"Jinja2>=3.1",
|
|
34
|
-
"tomli>=2.0.0; python_version < '3.11'",
|
|
35
32
|
]
|
|
36
33
|
|
|
37
34
|
[project.optional-dependencies]
|
|
@@ -42,7 +39,7 @@ dev = [
|
|
|
42
39
|
"flake8>=6.0",
|
|
43
40
|
"mypy>=1.0,<2.0",
|
|
44
41
|
"build>=1.2.0",
|
|
45
|
-
"twine>=
|
|
42
|
+
"twine>=7.0.0",
|
|
46
43
|
"types-requests",
|
|
47
44
|
]
|
|
48
45
|
|
|
@@ -54,7 +51,7 @@ dev = [
|
|
|
54
51
|
"flake8>=6.0",
|
|
55
52
|
"mypy>=1.0,<2.0",
|
|
56
53
|
"build>=1.2.0",
|
|
57
|
-
"twine>=
|
|
54
|
+
"twine>=7.0.0",
|
|
58
55
|
"types-requests",
|
|
59
56
|
]
|
|
60
57
|
|
|
@@ -80,7 +77,7 @@ include = [
|
|
|
80
77
|
|
|
81
78
|
[tool.black]
|
|
82
79
|
line-length = 88
|
|
83
|
-
target-version = ['
|
|
80
|
+
target-version = ['py311']
|
|
84
81
|
include = '\.pyi?$'
|
|
85
82
|
extend-exclude = '''
|
|
86
83
|
/(
|
|
@@ -97,7 +94,7 @@ extend-exclude = '''
|
|
|
97
94
|
'''
|
|
98
95
|
|
|
99
96
|
[tool.mypy]
|
|
100
|
-
python_version = "3.
|
|
97
|
+
python_version = "3.11"
|
|
101
98
|
warn_return_any = true
|
|
102
99
|
warn_unused_configs = true
|
|
103
100
|
disallow_untyped_defs = false # Relax for now to avoid breaking changes
|
|
@@ -44,6 +44,7 @@ Examples:
|
|
|
44
44
|
%(prog)s bib update --check # Check checked-in bibliography freshness
|
|
45
45
|
%(prog)s bib update # Update references from Zotero
|
|
46
46
|
%(prog)s compile # Compile configured main document
|
|
47
|
+
%(prog)s bundle --verify # Prepare a submission source ZIP
|
|
47
48
|
%(prog)s version # Refresh and report git metadata
|
|
48
49
|
%(prog)s version --compile --check-pdf # Refresh, compile, and inspect PDF text
|
|
49
50
|
%(prog)s release v1 --dry-run # Preview release tag creation
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Source archive command for HAL, arXiv, and other submission systems."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
6
|
+
from ..config import Config
|
|
7
|
+
from ..reporting import print_error, print_info, print_success
|
|
8
|
+
from ..services.bundle import BundleOptions, BundleService
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def add_parser(subparsers):
|
|
12
|
+
parser = subparsers.add_parser("bundle", help="Create a LaTeX or Typst source ZIP")
|
|
13
|
+
parser.add_argument(
|
|
14
|
+
"document", nargs="?", help="Main .tex or .typ file (or configured document)"
|
|
15
|
+
)
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
"-o", "--output", help="ZIP path, relative to document directory"
|
|
18
|
+
)
|
|
19
|
+
parser.add_argument(
|
|
20
|
+
"--build-dir", help="Build directory containing compiler dependency metadata"
|
|
21
|
+
)
|
|
22
|
+
parser.add_argument(
|
|
23
|
+
"--include",
|
|
24
|
+
action="append",
|
|
25
|
+
default=[],
|
|
26
|
+
help="Add document-relative glob (repeatable)",
|
|
27
|
+
)
|
|
28
|
+
parser.add_argument(
|
|
29
|
+
"--exclude",
|
|
30
|
+
action="append",
|
|
31
|
+
default=[],
|
|
32
|
+
help="Exclude document-relative glob (repeatable)",
|
|
33
|
+
)
|
|
34
|
+
for key, help_text in [
|
|
35
|
+
("verify", "Recompile selected files in a clean directory"),
|
|
36
|
+
("include-pdf", "Include the generated main PDF in the ZIP"),
|
|
37
|
+
]:
|
|
38
|
+
group = parser.add_mutually_exclusive_group()
|
|
39
|
+
group.add_argument(
|
|
40
|
+
"--" + key,
|
|
41
|
+
dest=key.replace("-", "_"),
|
|
42
|
+
action="store_true",
|
|
43
|
+
default=None,
|
|
44
|
+
help=help_text,
|
|
45
|
+
)
|
|
46
|
+
group.add_argument(
|
|
47
|
+
"--no-" + key, dest=key.replace("-", "_"), action="store_false"
|
|
48
|
+
)
|
|
49
|
+
parser.add_argument(
|
|
50
|
+
"--no-build",
|
|
51
|
+
action="store_true",
|
|
52
|
+
help="Use existing compiler dependency metadata and PDF",
|
|
53
|
+
)
|
|
54
|
+
parser.add_argument(
|
|
55
|
+
"--dry-run",
|
|
56
|
+
action="store_true",
|
|
57
|
+
help="List files from existing build data; write nothing",
|
|
58
|
+
)
|
|
59
|
+
parser.add_argument(
|
|
60
|
+
"--force", action="store_true", help="Replace an existing ZIP and manifest"
|
|
61
|
+
)
|
|
62
|
+
parser.set_defaults(handler=run)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def run(args: argparse.Namespace, config: Config) -> int:
|
|
66
|
+
try:
|
|
67
|
+
service = BundleService(config)
|
|
68
|
+
plan = service.plan(
|
|
69
|
+
BundleOptions(
|
|
70
|
+
document=args.document,
|
|
71
|
+
output=args.output,
|
|
72
|
+
build_dir=args.build_dir,
|
|
73
|
+
include=tuple(args.include),
|
|
74
|
+
exclude=tuple(args.exclude),
|
|
75
|
+
include_pdf=args.include_pdf,
|
|
76
|
+
verify=args.verify,
|
|
77
|
+
no_build=args.no_build,
|
|
78
|
+
dry_run=args.dry_run,
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
print_info(f"Bundle files ({len(plan.files)}):")
|
|
82
|
+
for name in sorted(plan.files):
|
|
83
|
+
print(f" {name}")
|
|
84
|
+
if args.dry_run:
|
|
85
|
+
print_info(f"Would write: {plan.output}")
|
|
86
|
+
else:
|
|
87
|
+
output = service.write(plan, force=args.force)
|
|
88
|
+
print_success(f"Created source bundle: {output}")
|
|
89
|
+
print_info(f'Manifest: {output.with_suffix(".manifest.json")}')
|
|
90
|
+
return 0
|
|
91
|
+
except (ValueError, OSError, subprocess.TimeoutExpired) as error:
|
|
92
|
+
print_error(str(error))
|
|
93
|
+
return 1
|
|
@@ -17,7 +17,7 @@ def add_parser(subparsers: Any) -> None:
|
|
|
17
17
|
"version",
|
|
18
18
|
help="Refresh and report git version metadata",
|
|
19
19
|
description=(
|
|
20
|
-
"Refresh gitinfo2 metadata and report
|
|
20
|
+
"Refresh LaTeX gitinfo2 or Typst JSON metadata and report Git state "
|
|
21
21
|
"without creating a tag."
|
|
22
22
|
),
|
|
23
23
|
)
|
|
@@ -9,13 +9,7 @@ from pathlib import Path
|
|
|
9
9
|
from typing import Dict, Any, Optional, Union
|
|
10
10
|
import argparse
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
import tomllib # Python 3.11+
|
|
14
|
-
except ImportError:
|
|
15
|
-
try:
|
|
16
|
-
import tomli as tomllib # fallback for older Python versions
|
|
17
|
-
except ImportError:
|
|
18
|
-
tomllib = None
|
|
12
|
+
import tomllib
|
|
19
13
|
|
|
20
14
|
|
|
21
15
|
class Config:
|
|
@@ -67,7 +61,7 @@ class Config:
|
|
|
67
61
|
config_path = self._find_config_file()
|
|
68
62
|
self.loaded_config_file = config_path.resolve() if config_path else None
|
|
69
63
|
|
|
70
|
-
if config_path
|
|
64
|
+
if config_path:
|
|
71
65
|
try:
|
|
72
66
|
with open(config_path, "rb") as f:
|
|
73
67
|
full_config = tomllib.load(f)
|
|
@@ -104,12 +98,6 @@ class Config:
|
|
|
104
98
|
if not self.quiet:
|
|
105
99
|
print(f"Warning: Could not load config file {config_path}: {e}")
|
|
106
100
|
self._config_data = {}
|
|
107
|
-
elif config_path and not tomllib:
|
|
108
|
-
if not self.quiet:
|
|
109
|
-
print(
|
|
110
|
-
"Warning: TOML support not available. Install dependencies with: uv sync"
|
|
111
|
-
)
|
|
112
|
-
self._config_data = {}
|
|
113
101
|
else:
|
|
114
102
|
self._config_data = {}
|
|
115
103
|
|
|
@@ -205,6 +193,16 @@ class Config:
|
|
|
205
193
|
"timeout": self.get("latex", "timeout", 300),
|
|
206
194
|
}
|
|
207
195
|
|
|
196
|
+
def get_bundle_config(self) -> Dict[str, Any]:
|
|
197
|
+
"""Get source archive policy; patterns are document-directory relative."""
|
|
198
|
+
return {
|
|
199
|
+
"output": self.get("bundle", "output", ""),
|
|
200
|
+
"include": self.get("bundle", "include", []),
|
|
201
|
+
"exclude": self.get("bundle", "exclude", []),
|
|
202
|
+
"include_pdf": self.get("bundle", "include_pdf", False),
|
|
203
|
+
"verify": self.get("bundle", "verify", False),
|
|
204
|
+
}
|
|
205
|
+
|
|
208
206
|
def get_project_config(self) -> Dict[str, Any]:
|
|
209
207
|
"""Get project-level configuration"""
|
|
210
208
|
return {
|
|
@@ -426,6 +424,14 @@ shell_escape = false
|
|
|
426
424
|
# Compilation timeout in seconds
|
|
427
425
|
timeout = 300
|
|
428
426
|
|
|
427
|
+
[bundle]
|
|
428
|
+
# Submission ZIP; paths and globs are relative to the main document directory.
|
|
429
|
+
# output = "dist/paper-sources.zip"
|
|
430
|
+
include = []
|
|
431
|
+
exclude = ["local-only/**", "reviews/**"]
|
|
432
|
+
include_pdf = false
|
|
433
|
+
verify = false
|
|
434
|
+
|
|
429
435
|
[project]
|
|
430
436
|
# Project type: "article", "typst-article", "presentation", "typst-presentation",
|
|
431
437
|
# "poster", or "typst-poster"
|
|
@@ -10,6 +10,7 @@ import subprocess
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import List, Optional
|
|
12
12
|
|
|
13
|
+
from .paper_version import METADATA_EXCLUDES
|
|
13
14
|
from .reporting import print_info, print_success, print_warning
|
|
14
15
|
|
|
15
16
|
MANAGED_HOOK_START = "# >>> article-cli gitinfo2 hook >>>"
|
|
@@ -279,7 +280,7 @@ def _is_dirty_for_gitinfo2(repo_path: Path) -> bool:
|
|
|
279
280
|
"--untracked-files=no",
|
|
280
281
|
"--",
|
|
281
282
|
".",
|
|
282
|
-
|
|
283
|
+
*METADATA_EXCLUDES,
|
|
283
284
|
],
|
|
284
285
|
)
|
|
285
286
|
return bool(result and result.stdout.strip())
|
|
@@ -16,6 +16,7 @@ from .git_hooks import (
|
|
|
16
16
|
install_managed_gitinfo2_hook,
|
|
17
17
|
refresh_gitinfo2_metadata,
|
|
18
18
|
)
|
|
19
|
+
from .paper_version import METADATA_EXCLUDES
|
|
19
20
|
from .reporting import Colors, print_error, print_info, print_success, print_warning
|
|
20
21
|
|
|
21
22
|
|
|
@@ -294,7 +295,7 @@ class GitManager:
|
|
|
294
295
|
"""Return dirty tracked/untracked files, optionally ignoring gitHeadLocal.gin."""
|
|
295
296
|
pathspec = ["--", "."]
|
|
296
297
|
if ignore_gitinfo:
|
|
297
|
-
pathspec.
|
|
298
|
+
pathspec.extend(METADATA_EXCLUDES)
|
|
298
299
|
result = self.git(["status", "--porcelain", *pathspec])
|
|
299
300
|
if result.returncode != 0:
|
|
300
301
|
return ["<could not inspect git status>"]
|