article-cli 1.1.0__tar.gz → 1.2.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-1.1.0 → article_cli-1.2.0}/PKG-INFO +1 -1
- {article_cli-1.1.0 → article_cli-1.2.0}/pyproject.toml +1 -1
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/__init__.py +10 -3
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/cli.py +37 -38
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/latex_compiler.py +31 -22
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/repository_setup.py +138 -34
- {article_cli-1.1.0 → article_cli-1.2.0}/.gitignore +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/LICENSE +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/README.md +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/__main__.py +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/config.py +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/git_manager.py +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/src/article_cli/zotero.py +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/tests/__init__.py +0 -0
- {article_cli-1.1.0 → article_cli-1.2.0}/tests/test_config.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: article-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.0
|
|
4
4
|
Summary: CLI tool for managing LaTeX articles 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
|
|
@@ -5,10 +5,10 @@ This package provides tools for:
|
|
|
5
5
|
- Git release management with gitinfo2 support
|
|
6
6
|
- Zotero bibliography synchronization
|
|
7
7
|
- LaTeX build file cleanup
|
|
8
|
-
- Git hooks setup
|
|
8
|
+
- Git hooks setup
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
__version__ = "1.
|
|
11
|
+
__version__ = "1.2.0"
|
|
12
12
|
__author__ = "Christophe Prud'homme"
|
|
13
13
|
__email__ = "prudhomm@cemosis.fr"
|
|
14
14
|
|
|
@@ -19,4 +19,11 @@ from .git_manager import GitManager
|
|
|
19
19
|
from .repository_setup import RepositorySetup
|
|
20
20
|
from .latex_compiler import LaTeXCompiler
|
|
21
21
|
|
|
22
|
-
__all__ = [
|
|
22
|
+
__all__ = [
|
|
23
|
+
"main",
|
|
24
|
+
"Config",
|
|
25
|
+
"ZoteroBibTexUpdater",
|
|
26
|
+
"GitManager",
|
|
27
|
+
"RepositorySetup",
|
|
28
|
+
"LaTeXCompiler",
|
|
29
|
+
]
|
|
@@ -56,9 +56,7 @@ Environment variables:
|
|
|
56
56
|
init_parser = subparsers.add_parser(
|
|
57
57
|
"init", help="Initialize repository with workflows and configuration"
|
|
58
58
|
)
|
|
59
|
-
init_parser.add_argument(
|
|
60
|
-
"--title", required=True, help="Article title"
|
|
61
|
-
)
|
|
59
|
+
init_parser.add_argument("--title", required=True, help="Article title")
|
|
62
60
|
init_parser.add_argument(
|
|
63
61
|
"--authors",
|
|
64
62
|
required=True,
|
|
@@ -86,41 +84,40 @@ Environment variables:
|
|
|
86
84
|
subparsers.add_parser("clean", help="Clean LaTeX build files")
|
|
87
85
|
|
|
88
86
|
# Compile command
|
|
89
|
-
compile_parser = subparsers.add_parser(
|
|
87
|
+
compile_parser = subparsers.add_parser(
|
|
88
|
+
"compile", help="Compile LaTeX document using latexmk"
|
|
89
|
+
)
|
|
90
90
|
compile_parser.add_argument(
|
|
91
|
-
"tex_file",
|
|
92
|
-
nargs="?",
|
|
93
|
-
help="LaTeX file to compile (auto-detected if not specified)"
|
|
91
|
+
"tex_file",
|
|
92
|
+
nargs="?",
|
|
93
|
+
help="LaTeX file to compile (auto-detected if not specified)",
|
|
94
94
|
)
|
|
95
95
|
compile_parser.add_argument(
|
|
96
|
-
"--engine",
|
|
97
|
-
choices=["latexmk", "pdflatex"],
|
|
96
|
+
"--engine",
|
|
97
|
+
choices=["latexmk", "pdflatex"],
|
|
98
98
|
default="latexmk",
|
|
99
|
-
help="LaTeX engine to use (default: latexmk)"
|
|
99
|
+
help="LaTeX engine to use (default: latexmk)",
|
|
100
100
|
)
|
|
101
101
|
compile_parser.add_argument(
|
|
102
|
-
"--shell-escape",
|
|
103
|
-
action="store_true",
|
|
104
|
-
help="Enable shell escape (for code highlighting, etc.)"
|
|
102
|
+
"--shell-escape",
|
|
103
|
+
action="store_true",
|
|
104
|
+
help="Enable shell escape (for code highlighting, etc.)",
|
|
105
105
|
)
|
|
106
106
|
compile_parser.add_argument(
|
|
107
|
-
"--clean-first",
|
|
108
|
-
action="store_true",
|
|
109
|
-
help="Clean build files before compilation"
|
|
107
|
+
"--clean-first",
|
|
108
|
+
action="store_true",
|
|
109
|
+
help="Clean build files before compilation",
|
|
110
110
|
)
|
|
111
111
|
compile_parser.add_argument(
|
|
112
|
-
"--clean-after",
|
|
113
|
-
action="store_true",
|
|
114
|
-
help="Clean build files after compilation"
|
|
112
|
+
"--clean-after", action="store_true", help="Clean build files after compilation"
|
|
115
113
|
)
|
|
116
114
|
compile_parser.add_argument(
|
|
117
|
-
"--watch",
|
|
118
|
-
action="store_true",
|
|
119
|
-
help="Watch for changes and recompile automatically"
|
|
115
|
+
"--watch",
|
|
116
|
+
action="store_true",
|
|
117
|
+
help="Watch for changes and recompile automatically",
|
|
120
118
|
)
|
|
121
119
|
compile_parser.add_argument(
|
|
122
|
-
"--output-dir",
|
|
123
|
-
help="Output directory for compiled files"
|
|
120
|
+
"--output-dir", help="Output directory for compiled files"
|
|
124
121
|
)
|
|
125
122
|
|
|
126
123
|
# Create command
|
|
@@ -223,48 +220,50 @@ def handle_compile_command(args: argparse.Namespace, config: Config) -> int:
|
|
|
223
220
|
"""Handle the compile command"""
|
|
224
221
|
try:
|
|
225
222
|
from .latex_compiler import LaTeXCompiler
|
|
226
|
-
|
|
223
|
+
|
|
227
224
|
# Auto-detect tex file if not provided
|
|
228
225
|
tex_file = args.tex_file
|
|
229
226
|
if not tex_file:
|
|
230
227
|
tex_file = _auto_detect_tex_file()
|
|
231
228
|
if not tex_file:
|
|
232
|
-
print_error(
|
|
229
|
+
print_error(
|
|
230
|
+
"No .tex file specified and none found in current directory"
|
|
231
|
+
)
|
|
233
232
|
return 1
|
|
234
|
-
|
|
233
|
+
|
|
235
234
|
# Validate tex file exists
|
|
236
235
|
tex_path = Path(tex_file)
|
|
237
236
|
if not tex_path.exists():
|
|
238
237
|
print_error(f"LaTeX file not found: {tex_file}")
|
|
239
238
|
return 1
|
|
240
|
-
|
|
239
|
+
|
|
241
240
|
compiler = LaTeXCompiler(config)
|
|
242
|
-
|
|
241
|
+
|
|
243
242
|
# Clean before compilation if requested
|
|
244
243
|
if args.clean_first:
|
|
245
244
|
print_info("Cleaning build files before compilation...")
|
|
246
245
|
git_manager = GitManager()
|
|
247
246
|
latex_config = config.get_latex_config()
|
|
248
247
|
git_manager.clean_latex_files(latex_config["clean_extensions"])
|
|
249
|
-
|
|
248
|
+
|
|
250
249
|
# Compile the document
|
|
251
250
|
success = compiler.compile(
|
|
252
251
|
tex_file=tex_file,
|
|
253
252
|
engine=args.engine,
|
|
254
253
|
shell_escape=args.shell_escape,
|
|
255
254
|
output_dir=args.output_dir,
|
|
256
|
-
watch=args.watch
|
|
255
|
+
watch=args.watch,
|
|
257
256
|
)
|
|
258
|
-
|
|
257
|
+
|
|
259
258
|
# Clean after compilation if requested
|
|
260
259
|
if args.clean_after and success:
|
|
261
260
|
print_info("Cleaning build files after compilation...")
|
|
262
261
|
git_manager = GitManager()
|
|
263
262
|
latex_config = config.get_latex_config()
|
|
264
263
|
git_manager.clean_latex_files(latex_config["clean_extensions"])
|
|
265
|
-
|
|
264
|
+
|
|
266
265
|
return 0 if success else 1
|
|
267
|
-
|
|
266
|
+
|
|
268
267
|
except Exception as e:
|
|
269
268
|
print_error(f"Compilation failed: {e}")
|
|
270
269
|
return 1
|
|
@@ -274,18 +273,18 @@ def _auto_detect_tex_file() -> Optional[str]:
|
|
|
274
273
|
"""Auto-detect main .tex file in current directory"""
|
|
275
274
|
current_dir = Path.cwd()
|
|
276
275
|
tex_files = list(current_dir.glob("*.tex"))
|
|
277
|
-
|
|
276
|
+
|
|
278
277
|
if not tex_files:
|
|
279
278
|
return None
|
|
280
|
-
|
|
279
|
+
|
|
281
280
|
if len(tex_files) == 1:
|
|
282
281
|
return tex_files[0].name
|
|
283
|
-
|
|
282
|
+
|
|
284
283
|
# Multiple .tex files - prefer common patterns
|
|
285
284
|
for pattern in ["main.tex", "article.tex", f"{current_dir.name}.tex"]:
|
|
286
285
|
if (current_dir / pattern).exists():
|
|
287
286
|
return pattern
|
|
288
|
-
|
|
287
|
+
|
|
289
288
|
# Return first .tex file found
|
|
290
289
|
print_info(f"Multiple .tex files found, using: {tex_files[0].name}")
|
|
291
290
|
return tex_files[0].name
|
|
@@ -5,9 +5,7 @@ Provides compilation functionality that mimics LaTeX Workshop configuration
|
|
|
5
5
|
with support for latexmk and pdflatex engines.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
-
import os
|
|
9
8
|
import subprocess
|
|
10
|
-
import sys
|
|
11
9
|
import time
|
|
12
10
|
from pathlib import Path
|
|
13
11
|
from typing import Dict, List, Optional
|
|
@@ -103,6 +101,8 @@ class LaTeXCompiler:
|
|
|
103
101
|
# Stream output in real time
|
|
104
102
|
try:
|
|
105
103
|
while True:
|
|
104
|
+
if process.stdout is None:
|
|
105
|
+
break
|
|
106
106
|
output = process.stdout.readline()
|
|
107
107
|
if output == "" and process.poll() is not None:
|
|
108
108
|
break
|
|
@@ -178,7 +178,7 @@ class LaTeXCompiler:
|
|
|
178
178
|
try:
|
|
179
179
|
# Run multiple passes for cross-references, bibliography, etc.
|
|
180
180
|
passes = ["First pass", "Second pass", "Third pass"]
|
|
181
|
-
|
|
181
|
+
|
|
182
182
|
for i, pass_name in enumerate(passes):
|
|
183
183
|
print_info(f"{pass_name}...")
|
|
184
184
|
result = subprocess.run(
|
|
@@ -237,12 +237,14 @@ class LaTeXCompiler:
|
|
|
237
237
|
# Core options (from LaTeX Workshop)
|
|
238
238
|
if shell_escape:
|
|
239
239
|
cmd.append("--shell-escape")
|
|
240
|
-
|
|
241
|
-
cmd.extend(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
240
|
+
|
|
241
|
+
cmd.extend(
|
|
242
|
+
[
|
|
243
|
+
"-pdf",
|
|
244
|
+
"-interaction=nonstopmode",
|
|
245
|
+
"-synctex=1",
|
|
246
|
+
]
|
|
247
|
+
)
|
|
246
248
|
|
|
247
249
|
if output_dir:
|
|
248
250
|
cmd.extend(["-outdir", output_dir])
|
|
@@ -264,11 +266,13 @@ class LaTeXCompiler:
|
|
|
264
266
|
if shell_escape:
|
|
265
267
|
cmd.append("--shell-escape")
|
|
266
268
|
|
|
267
|
-
cmd.extend(
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
269
|
+
cmd.extend(
|
|
270
|
+
[
|
|
271
|
+
"-synctex=1",
|
|
272
|
+
"-interaction=nonstopmode",
|
|
273
|
+
"-file-line-error",
|
|
274
|
+
]
|
|
275
|
+
)
|
|
272
276
|
|
|
273
277
|
if output_dir:
|
|
274
278
|
cmd.extend(["-output-directory", output_dir])
|
|
@@ -282,7 +286,10 @@ class LaTeXCompiler:
|
|
|
282
286
|
base_name = tex_path.stem
|
|
283
287
|
|
|
284
288
|
# Check if bibliography is needed
|
|
285
|
-
if
|
|
289
|
+
if (
|
|
290
|
+
"citation undefined" in latex_output.lower()
|
|
291
|
+
or "rerun" in latex_output.lower()
|
|
292
|
+
):
|
|
286
293
|
# Check for .aux file to determine if we need bibtex
|
|
287
294
|
aux_file = tex_path.with_suffix(".aux")
|
|
288
295
|
if aux_file.exists():
|
|
@@ -306,12 +313,12 @@ class LaTeXCompiler:
|
|
|
306
313
|
size = pdf_path.stat().st_size
|
|
307
314
|
size_mb = size / (1024 * 1024)
|
|
308
315
|
print_info(f"PDF size: {size_mb:.2f} MB")
|
|
309
|
-
|
|
316
|
+
|
|
310
317
|
# Show modification time
|
|
311
318
|
mtime = pdf_path.stat().st_mtime
|
|
312
319
|
mtime_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(mtime))
|
|
313
320
|
print_info(f"Generated: {mtime_str}")
|
|
314
|
-
|
|
321
|
+
|
|
315
322
|
except Exception:
|
|
316
323
|
pass # Silently ignore errors getting file info
|
|
317
324
|
|
|
@@ -346,14 +353,16 @@ class LaTeXCompiler:
|
|
|
346
353
|
def print_dependency_status(self) -> None:
|
|
347
354
|
"""Print status of LaTeX dependencies"""
|
|
348
355
|
print_info("Checking LaTeX dependencies...")
|
|
349
|
-
|
|
356
|
+
|
|
350
357
|
deps = self.check_dependencies()
|
|
351
|
-
|
|
358
|
+
|
|
352
359
|
for tool, available in deps.items():
|
|
353
360
|
status = "✅ Available" if available else "❌ Not found"
|
|
354
361
|
print(f" {tool}: {status}")
|
|
355
|
-
|
|
362
|
+
|
|
356
363
|
if not all(deps.values()):
|
|
357
|
-
print_info(
|
|
364
|
+
print_info(
|
|
365
|
+
"\nSome LaTeX tools are missing. Install a LaTeX distribution like TeX Live."
|
|
366
|
+
)
|
|
358
367
|
print_info("On macOS: brew install --cask mactex")
|
|
359
|
-
print_info("On Ubuntu: sudo apt-get install texlive-full")
|
|
368
|
+
print_info("On Ubuntu: sudo apt-get install texlive-full")
|
|
@@ -8,10 +8,8 @@ Provides functionality to initialize LaTeX article repositories with:
|
|
|
8
8
|
- Git hooks and configuration
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
-
import os
|
|
12
|
-
import shutil
|
|
13
11
|
from pathlib import Path
|
|
14
|
-
from typing import
|
|
12
|
+
from typing import List, Optional
|
|
15
13
|
|
|
16
14
|
from .zotero import print_error, print_info, print_success
|
|
17
15
|
|
|
@@ -47,23 +45,24 @@ class RepositorySetup:
|
|
|
47
45
|
- .vscode/settings.json with LaTeX Workshop configuration
|
|
48
46
|
- LTeX dictionary files for spell checking
|
|
49
47
|
- hooks/post-commit for gitinfo2 integration
|
|
48
|
+
- main.tex if no .tex file exists
|
|
50
49
|
|
|
51
50
|
Args:
|
|
52
51
|
title: Article title
|
|
53
52
|
authors: List of author names
|
|
54
53
|
group_id: Zotero group ID
|
|
55
54
|
force: Overwrite existing files if True
|
|
56
|
-
main_tex_file: Main .tex filename (auto-detected if None)
|
|
55
|
+
main_tex_file: Main .tex filename (auto-detected if None, created if missing)
|
|
57
56
|
|
|
58
57
|
Returns:
|
|
59
58
|
True if successful, False otherwise
|
|
60
59
|
"""
|
|
61
60
|
print_info(f"Initializing repository at: {self.repo_path}")
|
|
62
61
|
|
|
63
|
-
# Detect or validate main .tex file
|
|
64
|
-
tex_file = self.
|
|
62
|
+
# Detect or validate main .tex file, create if missing
|
|
63
|
+
tex_file = self._detect_or_create_tex_file(main_tex_file, title, authors, force)
|
|
65
64
|
if not tex_file:
|
|
66
|
-
print_error("
|
|
65
|
+
print_error("Failed to detect or create main .tex file")
|
|
67
66
|
return False
|
|
68
67
|
|
|
69
68
|
project_name = self.repo_path.name
|
|
@@ -113,27 +112,39 @@ class RepositorySetup:
|
|
|
113
112
|
print_error(f"Failed to initialize repository: {e}")
|
|
114
113
|
return False
|
|
115
114
|
|
|
116
|
-
def
|
|
115
|
+
def _detect_or_create_tex_file(
|
|
116
|
+
self, specified: Optional[str], title: str, authors: List[str], force: bool
|
|
117
|
+
) -> Optional[str]:
|
|
117
118
|
"""
|
|
118
|
-
Detect main .tex file in repository
|
|
119
|
+
Detect main .tex file in repository or create one if missing
|
|
119
120
|
|
|
120
121
|
Args:
|
|
121
122
|
specified: User-specified filename (takes priority)
|
|
123
|
+
title: Article title (for creating new .tex file)
|
|
124
|
+
authors: List of author names (for creating new .tex file)
|
|
125
|
+
force: Overwrite existing file if True
|
|
122
126
|
|
|
123
127
|
Returns:
|
|
124
|
-
Main .tex filename or None
|
|
128
|
+
Main .tex filename or None on failure
|
|
125
129
|
"""
|
|
126
130
|
if specified:
|
|
127
131
|
tex_path = self.repo_path / specified
|
|
128
132
|
if tex_path.exists():
|
|
129
133
|
return specified
|
|
130
|
-
|
|
134
|
+
# Specified file doesn't exist - create it
|
|
135
|
+
if self._create_tex_file(specified, title, authors, force):
|
|
136
|
+
return specified
|
|
131
137
|
return None
|
|
132
138
|
|
|
133
139
|
# Auto-detect .tex files
|
|
134
140
|
tex_files = list(self.repo_path.glob("*.tex"))
|
|
135
141
|
|
|
136
142
|
if not tex_files:
|
|
143
|
+
# No .tex files found - create main.tex
|
|
144
|
+
default_name = "main.tex"
|
|
145
|
+
print_info(f"No .tex file found, creating {default_name}")
|
|
146
|
+
if self._create_tex_file(default_name, title, authors, force):
|
|
147
|
+
return default_name
|
|
137
148
|
return None
|
|
138
149
|
|
|
139
150
|
if len(tex_files) == 1:
|
|
@@ -151,6 +162,94 @@ class RepositorySetup:
|
|
|
151
162
|
)
|
|
152
163
|
return tex_files[0].name
|
|
153
164
|
|
|
165
|
+
def _create_tex_file(
|
|
166
|
+
self, filename: str, title: str, authors: List[str], force: bool
|
|
167
|
+
) -> bool:
|
|
168
|
+
"""
|
|
169
|
+
Create a basic LaTeX article file
|
|
170
|
+
|
|
171
|
+
Args:
|
|
172
|
+
filename: Name of the .tex file to create
|
|
173
|
+
title: Article title
|
|
174
|
+
authors: List of author names
|
|
175
|
+
force: Overwrite if exists
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
True if successful
|
|
179
|
+
"""
|
|
180
|
+
tex_path = self.repo_path / filename
|
|
181
|
+
|
|
182
|
+
if tex_path.exists() and not force:
|
|
183
|
+
print_info(f"{filename} already exists (use --force to overwrite)")
|
|
184
|
+
return True
|
|
185
|
+
|
|
186
|
+
# Format authors for LaTeX
|
|
187
|
+
authors_latex = " \\and ".join(authors)
|
|
188
|
+
|
|
189
|
+
tex_content = f"""\\documentclass[a4paper,11pt]{{article}}
|
|
190
|
+
|
|
191
|
+
% Essential packages
|
|
192
|
+
\\usepackage[utf8]{{inputenc}}
|
|
193
|
+
\\usepackage[T1]{{fontenc}}
|
|
194
|
+
\\usepackage{{lmodern}}
|
|
195
|
+
\\usepackage{{amsmath,amssymb,amsthm}}
|
|
196
|
+
\\usepackage{{graphicx}}
|
|
197
|
+
\\usepackage{{hyperref}}
|
|
198
|
+
\\usepackage[margin=1in]{{geometry}}
|
|
199
|
+
|
|
200
|
+
% Bibliography
|
|
201
|
+
\\usepackage[style=numeric,sorting=none]{{biblatex}}
|
|
202
|
+
\\addbibresource{{references.bib}}
|
|
203
|
+
|
|
204
|
+
% Git version information
|
|
205
|
+
\\usepackage{{gitinfo2}}
|
|
206
|
+
|
|
207
|
+
% Title and authors
|
|
208
|
+
\\title{{{title}}}
|
|
209
|
+
\\author{{{authors_latex}}}
|
|
210
|
+
\\date{{\\today}}
|
|
211
|
+
|
|
212
|
+
\\begin{{document}}
|
|
213
|
+
|
|
214
|
+
\\maketitle
|
|
215
|
+
|
|
216
|
+
\\begin{{abstract}}
|
|
217
|
+
Your abstract goes here.
|
|
218
|
+
\\end{{abstract}}
|
|
219
|
+
|
|
220
|
+
\\section{{Introduction}}
|
|
221
|
+
|
|
222
|
+
Your introduction goes here.
|
|
223
|
+
|
|
224
|
+
\\section{{Methodology}}
|
|
225
|
+
|
|
226
|
+
Your methodology goes here.
|
|
227
|
+
|
|
228
|
+
\\section{{Results}}
|
|
229
|
+
|
|
230
|
+
Your results go here.
|
|
231
|
+
|
|
232
|
+
\\section{{Conclusion}}
|
|
233
|
+
|
|
234
|
+
Your conclusion goes here.
|
|
235
|
+
|
|
236
|
+
% Print bibliography
|
|
237
|
+
\\printbibliography
|
|
238
|
+
|
|
239
|
+
% Git information (optional - appears in footer)
|
|
240
|
+
\\vfill
|
|
241
|
+
\\hrule
|
|
242
|
+
\\small
|
|
243
|
+
\\noindent Git version: \\gitAbbrevHash{{}} (\\gitAuthorIsoDate) \\\\
|
|
244
|
+
Branch: \\gitBranch
|
|
245
|
+
|
|
246
|
+
\\end{{document}}
|
|
247
|
+
"""
|
|
248
|
+
|
|
249
|
+
tex_path.write_text(tex_content)
|
|
250
|
+
print_success(f"Created: {tex_path.relative_to(self.repo_path)}")
|
|
251
|
+
return True
|
|
252
|
+
|
|
154
253
|
def _create_directories(self) -> None:
|
|
155
254
|
"""Create necessary directory structure"""
|
|
156
255
|
directories = [
|
|
@@ -163,9 +262,7 @@ class RepositorySetup:
|
|
|
163
262
|
directory.mkdir(parents=True, exist_ok=True)
|
|
164
263
|
print_info(f"Created directory: {directory.relative_to(self.repo_path)}")
|
|
165
264
|
|
|
166
|
-
def _create_workflow(
|
|
167
|
-
self, project_name: str, tex_file: str, force: bool
|
|
168
|
-
) -> bool:
|
|
265
|
+
def _create_workflow(self, project_name: str, tex_file: str, force: bool) -> bool:
|
|
169
266
|
"""
|
|
170
267
|
Create GitHub Actions workflow file
|
|
171
268
|
|
|
@@ -180,7 +277,9 @@ class RepositorySetup:
|
|
|
180
277
|
workflow_path = self.repo_path / ".github" / "workflows" / "latex.yml"
|
|
181
278
|
|
|
182
279
|
if workflow_path.exists() and not force:
|
|
183
|
-
print_info(
|
|
280
|
+
print_info(
|
|
281
|
+
f"Workflow already exists: {workflow_path.name} (use --force to overwrite)"
|
|
282
|
+
)
|
|
184
283
|
return True
|
|
185
284
|
|
|
186
285
|
# Extract base name (without .tex extension)
|
|
@@ -203,7 +302,7 @@ class RepositorySetup:
|
|
|
203
302
|
Returns:
|
|
204
303
|
Workflow YAML content
|
|
205
304
|
"""
|
|
206
|
-
return f
|
|
305
|
+
return f"""name: Compile LaTeX and Release PDF
|
|
207
306
|
|
|
208
307
|
# This workflow uses article-cli for:
|
|
209
308
|
# - Git hooks setup (article-cli setup)
|
|
@@ -639,7 +738,7 @@ jobs:
|
|
|
639
738
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
640
739
|
echo "Please check the workflow logs for details." >> $GITHUB_STEP_SUMMARY
|
|
641
740
|
fi
|
|
642
|
-
|
|
741
|
+
"""
|
|
643
742
|
|
|
644
743
|
def _create_pyproject(
|
|
645
744
|
self,
|
|
@@ -665,15 +764,13 @@ jobs:
|
|
|
665
764
|
pyproject_path = self.repo_path / "pyproject.toml"
|
|
666
765
|
|
|
667
766
|
if pyproject_path.exists() and not force:
|
|
668
|
-
print_info(
|
|
669
|
-
f"pyproject.toml already exists (use --force to overwrite)"
|
|
670
|
-
)
|
|
767
|
+
print_info(f"pyproject.toml already exists (use --force to overwrite)")
|
|
671
768
|
return True
|
|
672
769
|
|
|
673
770
|
# Format authors for TOML
|
|
674
771
|
authors_toml = ",\n ".join([f'{{name = "{author}"}}' for author in authors])
|
|
675
772
|
|
|
676
|
-
pyproject_content = f
|
|
773
|
+
pyproject_content = f"""# Article Repository Dependency Management
|
|
677
774
|
# This file manages dependencies for the LaTeX article project
|
|
678
775
|
|
|
679
776
|
[project]
|
|
@@ -709,7 +806,7 @@ clean_extensions = [
|
|
|
709
806
|
".fls", ".synctex.gz", ".toc", ".fdb_latexmk",
|
|
710
807
|
".idx", ".ilg", ".ind", ".lof", ".lot"
|
|
711
808
|
]
|
|
712
|
-
|
|
809
|
+
"""
|
|
713
810
|
|
|
714
811
|
pyproject_path.write_text(pyproject_content)
|
|
715
812
|
print_success(f"Created: {pyproject_path.relative_to(self.repo_path)}")
|
|
@@ -744,7 +841,7 @@ clean_extensions = [
|
|
|
744
841
|
|
|
745
842
|
authors_list = "\n".join([f"- {author}" for author in authors])
|
|
746
843
|
|
|
747
|
-
readme_content = f
|
|
844
|
+
readme_content = f"""# {title}
|
|
748
845
|
|
|
749
846
|
## Authors
|
|
750
847
|
|
|
@@ -867,7 +964,7 @@ article-cli config show
|
|
|
867
964
|
url = {{https://github.com/feelpp/{project_name}}}
|
|
868
965
|
}}
|
|
869
966
|
```
|
|
870
|
-
|
|
967
|
+
"""
|
|
871
968
|
|
|
872
969
|
readme_path.write_text(readme_content)
|
|
873
970
|
print_success(f"Created: {readme_path.relative_to(self.repo_path)}")
|
|
@@ -958,10 +1055,12 @@ references.bib.backup
|
|
|
958
1055
|
vscode_settings_path = self.repo_path / ".vscode" / "settings.json"
|
|
959
1056
|
|
|
960
1057
|
if vscode_settings_path.exists() and not force:
|
|
961
|
-
print_info(
|
|
1058
|
+
print_info(
|
|
1059
|
+
".vscode/settings.json already exists (use --force to overwrite)"
|
|
1060
|
+
)
|
|
962
1061
|
return True
|
|
963
1062
|
|
|
964
|
-
settings_content =
|
|
1063
|
+
settings_content = """{
|
|
965
1064
|
"latex-workshop.latex.recipes": [
|
|
966
1065
|
{
|
|
967
1066
|
"name": "latexmk-pdf",
|
|
@@ -1023,7 +1122,7 @@ references.bib.backup
|
|
|
1023
1122
|
"ltex.enabled": true,
|
|
1024
1123
|
"ltex.language": "en-US"
|
|
1025
1124
|
}
|
|
1026
|
-
|
|
1125
|
+
"""
|
|
1027
1126
|
|
|
1028
1127
|
vscode_settings_path.write_text(settings_content)
|
|
1029
1128
|
print_success(f"Created: {vscode_settings_path.relative_to(self.repo_path)}")
|
|
@@ -1059,7 +1158,9 @@ parametrical
|
|
|
1059
1158
|
print_info(f"Created: {dictionary_path.relative_to(self.repo_path)}")
|
|
1060
1159
|
|
|
1061
1160
|
# Hidden false positives file (empty initially)
|
|
1062
|
-
false_positives_path =
|
|
1161
|
+
false_positives_path = (
|
|
1162
|
+
self.repo_path / ".vscode" / "ltex.hiddenFalsePositives.en-US.txt"
|
|
1163
|
+
)
|
|
1063
1164
|
if not false_positives_path.exists() or force:
|
|
1064
1165
|
false_positives_path.write_text("")
|
|
1065
1166
|
print_info(f"Created: {false_positives_path.relative_to(self.repo_path)}")
|
|
@@ -1083,7 +1184,7 @@ parametrical
|
|
|
1083
1184
|
return True
|
|
1084
1185
|
|
|
1085
1186
|
# gitinfo2 post-commit hook
|
|
1086
|
-
post_commit_content =
|
|
1187
|
+
post_commit_content = """#!/bin/sh
|
|
1087
1188
|
# Copyright 2015 Brent Longborough
|
|
1088
1189
|
# Part of gitinfo2 package Version 2
|
|
1089
1190
|
# Release 2.0.7 2015-11-22
|
|
@@ -1114,15 +1215,18 @@ git --no-pager log -1 --date=short --decorate=short \\
|
|
|
1114
1215
|
firsttagdescribe={$FIRSTTAG},
|
|
1115
1216
|
reltag={$RELTAG}
|
|
1116
1217
|
]{gitexinfo}" HEAD > .git/gitHeadInfo.gin
|
|
1117
|
-
|
|
1218
|
+
"""
|
|
1118
1219
|
|
|
1119
1220
|
post_commit_path.write_text(post_commit_content)
|
|
1120
|
-
|
|
1221
|
+
|
|
1121
1222
|
# Make the hook executable
|
|
1122
1223
|
import stat
|
|
1123
|
-
|
|
1124
|
-
|
|
1224
|
+
|
|
1225
|
+
post_commit_path.chmod(
|
|
1226
|
+
post_commit_path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
|
|
1227
|
+
)
|
|
1228
|
+
|
|
1125
1229
|
print_success(f"Created: {post_commit_path.relative_to(self.repo_path)}")
|
|
1126
1230
|
print_info("Made post-commit hook executable")
|
|
1127
|
-
|
|
1231
|
+
|
|
1128
1232
|
return True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|