-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlatex.py
108 lines (91 loc) · 3.54 KB
/
latex.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import asyncio
import mimetypes
import shutil
import yaml
from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile
from .config import Settings, get_settings
from .log import get_logger
logger = get_logger()
router = APIRouter()
def validate_file(file: UploadFile):
mime_type, _ = mimetypes.guess_type(file.filename)
if mime_type is None:
raise HTTPException(
status_code=400, detail='Could not determine mime type of file'
)
if mime_type != 'application/zip':
raise HTTPException(
status_code=400,
detail=f'Invalid file type: {mime_type} for LaTeX source: {file.filename}. Must be a ZIP archive',
)
@router.post('/latex/upload-file')
async def upload_file(
request: Request,
preprint_id: str,
file: UploadFile = File(...),
settings: Settings = Depends(get_settings),
):
logger.info('Uploading file')
validate_file(file)
file_path = settings.LATEX_SOURCE_DIRECTORY / preprint_id / file.filename
file_path.parent.mkdir(parents=True, exist_ok=True)
with file_path.open('wb') as buffer:
shutil.copyfileobj(file.file, buffer)
# unzip the file
logger.info(f'Unzipping file: {file_path}')
shutil.unpack_archive(file_path, file_path.parent)
# get the path to the unzipped directory
unzipped_directory = file_path.parent / file.filename.replace('.zip', '')
# write a yaml file (myst.ym) in the same directory. This file will contain the metadata for the preprint as following
myst_file = unzipped_directory / 'myst.yml'
with myst_file.open('w') as buffer:
yaml.dump(
{
'version': 1,
'project': {
'id': preprint_id,
'title': '',
'description': '',
'keywords': [],
'authors': [],
'subject': 'Article',
'open_access': True,
'license': '',
},
'site': {'template': 'article-theme'},
},
buffer,
)
myst_executable = shutil.which('myst')
if myst_executable is None:
raise HTTPException(status_code=500, detail='myst executable not found in PATH')
# run myst to convert the latex source to html
logger.info(f'Converting LaTeX source to HTML: {unzipped_directory}')
myst_command = [myst_executable, 'build', '--site', '--ci']
logger.info(f'Running myst command: {myst_command}')
process = await asyncio.create_subprocess_exec(
*myst_command,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=str(unzipped_directory),
)
stdout, stderr = await process.communicate()
logger.info(f'myst stdout: {stdout.decode()}')
logger.info(f'myst stderr: {stderr.decode()}')
if process.returncode != 0:
raise HTTPException(
status_code=500,
detail=f'myst command failed with return code: {process.returncode}',
)
build_directory = unzipped_directory / '_build' / 'site'
parent_directory = unzipped_directory.parent / 'site'
parent_directory.mkdir(parents=True, exist_ok=True)
# Now we need to move the contents of the _build directory to the parent directory
for item in build_directory.iterdir():
logger.info(f'Moving item: {item} to {parent_directory}')
shutil.move(item, parent_directory)
return {
'status': 'ok',
'filename': file.filename,
'path': parent_directory,
}