-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use latexmk if Sphinx > 1.6 #5656
Conversation
Running the command manually from inside the Docker image I get the output that I want:
I don't understand why it does not work when calling it from Python. |
I found the issue: our
Note that I'm removing all the unneeded |
We do that to prevent command injection. But if the code is entirely called from our code, we could add an option |
Yes! I pushed some changes adding a |
e58cb78
to
fbdfa96
Compare
bc6ecce
to
3de6972
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not going to work when using outside docker. Not sure how important it is to make it work outside docker anyway... Also, maybe it's easy to make it work in both 🤷♂️
""" | ||
self.escape_command = escape_command |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like something that can be moved to the parent class. I think (not sure) that the same behavior for this in local command is shell=True
https://docs.python.org/3.6/library/subprocess.html
On POSIX with shell=True, the shell defaults to /bin/sh. If args is a string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed at the shell prompt. This includes, for example, quoting or backslash escaping filenames with spaces in them. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional arguments to the shell itself...
|
||
command = [ | ||
self.python_env.venv_bin(filename='python'), | ||
'-c' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are missing a comma here
command = [ | ||
self.python_env.venv_bin(filename='python'), | ||
'-c' | ||
'"import sphinx; print(sphinx.__version__)"', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when DOCKER_ENABLED
is false, this will break. Because of the double quotes
>>> proc = subprocess.Popen(['python3', '-c', 'import sphinx; print(sphinx.__version__)'], stdou
t=subprocess.PIPE)
>>> proc.communicate()
(b'1.8.5\n', None)
>>> proc = subprocess.Popen(['python3', '-c', '"import sphinx; print(sphinx.__version__)"'], std
out=subprocess.PIPE)
>>> proc.communicate()
(b'', None)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for raising this.
I made it work by using shell=True
and flattening the command when shell=True
using the helper that we had there.
I like how the ended now. On BuildCommand
it uses the shell=True
attribute and flatten the command to be compatible. On DockerBuildCommand
it uses escape_command=False
to not escape the command.
It works in both builder backends.
I'd vote that we shouldn't be relying on command output in our build process. No-op commands like this are already awkward, doing a text comparison against the command output seems pretty fragile. Is there a reason we shouldn't use normal sh operators to chain? Something like:
This might be slightly annoying as it probably needs to be further wrapped in a This does make it more clear why we're executing latexmk or pdflatex to the user, rather than just having a version number in the output, and it works regardless of the builder type. |
@agjohnson I don't see this as a problem. The output of the command that we are relying here is a command that we control and users can't modify. I don't see any potential problem with it. Also, we are not comparing text directly, but using
Using operators chain has some problems. We need execute ~5 different commands depending on which pdf builder we use, so we would need to add the same check on each of those commands which is repeated code in the end.
Also, I don't want to log this to users in the build output. It's hard to read and confusing to users in my opinion. This should be transparent to users, similar to what happen locally --they don't care about this, Sphinx makes the decisions. Just to be clear, the Sphinx version is not logged in the build output. That was just a test locally to see what was happening and debug it properly. The command is executed with On the other hand, from a developer perspective, I find the code easy to read by having the different chunk of commands wrapped up into different methods. |
On local builder the command is flattern when `shell=True` is passed.
@humitos If it's too much to wrap the commands with a shell and use shell pipes to execute the command we want, I still think string parsing is the wrong approach, as it is more fragile than it needs to be. A more robust version of your implementation would use the exit code instead of coercing the Sphinx version multiple times. The command would be similar to the one i posted, but we don't use pipes and would instead use the exit code as a boolean for our decision on whether to run latexmk or not. If there are problems running the current PR outside docker, this avoids those issues as well, as we can expect an exit code from either execution strategy. I agree that in this case, the command is a noop command that is not helpful to users and should be hidden. |
The problem is not running the command inside or outside docker. The issue is because the command string is sanitized in a way that breaks depending how that string is used internally to run the command. Although, this problem is fixed using |
I updated the PR to use the exit code instead. |
# When using ``shell=True`` the command should be flatten | ||
command = self.command | ||
if self.shell: | ||
command = self.get_command() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note that this would make some problems to people using paths with spaces and reserved bash symbols (not our case). Flatten commands are not escaped by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach seems good. We do need to be very careful about using shell=True
, as not escaping correctly and allowing user input in our shell=True
command could lead to a remote execution attack. It's probably fine for these kind of applications though.
import zipfile | ||
from glob import glob | ||
from pathlib import Path | ||
|
||
from django.conf import settings | ||
from django.template import loader as template_loader | ||
from django.template.loader import render_to_string | ||
from packaging.version import Version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks unused now.
Co-Authored-By: Santos Gallegos <[email protected]>
@agjohnson @stsewd both commented about the same, and both are right. I didn't added the |
I'll merge the PR once the tests pass. |
latexmk
orpdflatex
should be called to build the PDF.Closes #5655