-
-
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
Build: build.jobs.post_build
produces mysterious shell syntax errors
#10103
Comments
A literal copy of your own example produces a syntax error. I coped the text of the script from https://docs.readthedocs.io/en/stable/build-customization.html#id3 exactly in Ravenbrook/mps@b08bcf3 and it causes the syntax error seen at https://readthedocs.org/projects/mmref/builds/19671564/ |
build.jobs.post_build
produces mysterious shell syntax errors
Thanks for reporting this issue. We have been dealing with this already at pypi/warehouse#12953 and I wasn't able to find the cause of it at that time. We will need to dig deeper into the code to understand what's going on here. |
This split looks highly suspicious.
From a 10 minute scan of your code, it looks to me like there might be a confusion between executing a single command and executing a script. On a single command, where you want to split argv and do something like But a script is a single string that you want to pass complete to a shell, like
Again, I am in no way sure this is what's wrong, but your splits don't look right to me. |
@rptb1 I'm curious if it works if you put the script in a file, and just run that from the post-build step? Not ideal, but I don't think our indention with this feature was having full-length scripts here, but having commands or scripts that could be run. We can definitely change that design, but curious if it works that way. That said, if our docs examples aren't working, we should probably fix them :) |
That might be a workaround for now, thanks. The intention is clear from the documentation: currently the documented examples don't work. You'll need to carefully document the subset of shell language you do support. Why not just pass everything to the shell? Is there a reason not to? |
I'm not sure about _why_ we split the commands before sending it out our executor. The command is finally wrapper properly before being executed. I did some locally QA after removing the split of the command and it seems these scripts work fine. So, it seems safe to move forward with this, explanding the flexibility of our config file. Closes #10103
I opened a PR that removes the |
…#10119) * Build: pass shell commands directly (`build.jobs` / `build.commands)` I'm not sure about _why_ we split the commands before sending it out our executor. The command is finally wrapper properly before being executed. I did some locally QA after removing the split of the command and it seems these scripts work fine. So, it seems safe to move forward with this, explanding the flexibility of our config file. Closes #10103 * Test: match changes It compares to a full command instead of being split.
I'm re-opening this issue because the PR that was merged doesn't solve all the issues. That exact same code works properly in my local terminal. Even wrapping it in This requires more researching and testing. Suggestions and ideas welcomed! |
I think the main problem here is the It works without the prefix:
It fails with the prefix
This code is at readthedocs.org/readthedocs/doc_builder/environments.py Lines 356 to 384 in dd07a3e
|
Another simplified example that breaks because of the environment variable prefix:
|
Instead of prepending all the commands with the `PATH=` variable, we pass the environment variable directly to the Docker container. This allow us to run multi-line shell script without failing with weird syntax errors. Besides, the implementation is cleaner since all the environment variables are passed to the commands in the same way. I added some _default paths_ that I found by checking the local Docker container. I'm also passing the users' path, depending if we are working locally as root or in production. This is not 100% complete and there may be some other issues that I'm not seeing yet, but I think it's a first step to behave in a way our users are expecting. Closes #10103
I opened 2 PRs to solve this issue:
With these two, I think we will be solving most of our users' issues avoiding unexpected behaviors. |
@humitos Great work tracking this down! |
* Build: pass `PATH` environment variable to Docker container Instead of prepending all the commands with the `PATH=` variable, we pass the environment variable directly to the Docker container. This allow us to run multi-line shell script without failing with weird syntax errors. Besides, the implementation is cleaner since all the environment variables are passed to the commands in the same way. I added some _default paths_ that I found by checking the local Docker container. I'm also passing the users' path, depending if we are working locally as root or in production. This is not 100% complete and there may be some other issues that I'm not seeing yet, but I think it's a first step to behave in a way our users are expecting. Closes #10103 * Lint: for some reason fails at CircleCI otherwise Locally it tries to reverted back 🤷 * Update readthedocs/doc_builder/environments.py Co-authored-by: Santos Gallegos <[email protected]> * Increase code's readability by applying suggested changes --------- Co-authored-by: Santos Gallegos <[email protected]>
* Hosting: manual integrations via build contract * Use a single script to load everything * Include Read the Docs analytics to integrations * Initial work for hosting features * External version banner and doc-diff integration * Old version warning * Do not inject doc-diff on search page * Inject old version warning only for non-external versions * Comments! * More comments * Build: pass `PATH` environment variable to Docker container Instead of prepending all the commands with the `PATH=` variable, we pass the environment variable directly to the Docker container. This allow us to run multi-line shell script without failing with weird syntax errors. Besides, the implementation is cleaner since all the environment variables are passed to the commands in the same way. I added some _default paths_ that I found by checking the local Docker container. I'm also passing the users' path, depending if we are working locally as root or in production. This is not 100% complete and there may be some other issues that I'm not seeing yet, but I think it's a first step to behave in a way our users are expecting. Closes #10103 * Lint: for some reason fails at CircleCI otherwise Locally it tries to reverted back 🤷 * Feature flag for new hosting integrations X-RTD-Hosting-Integration: true/false This can be used from CloudFlare to decide whether or not inject a `<script>` into the resulting HTML or not. * Load `readthedocs-build.yaml` and generate `readthedocs-data.html` * Load READTHEDOCS_DATA async * Absolute proxied API path * Remove duplicated code * New approach using `readthedocs-client.js` and `/_/readthedocs-config.json` See https://github.com/humitos/readthedocs-client * Do not require `readthedocs-build.YAML` for now * Expand the JSON response with more data * Remove non-required files and rely on `readthedocs-client.js` only * Improve helper text * Builds: save `readthedocs-build.yaml` into database I added a `Version.build_data` field that may be used from `/_/readthedocs-config.json` to extend with data generated by the doctool at build time if necessary. * Use `Version.build_data` from the endpoint * Flyout: return data required to generate flyout dynamically * Updates to the API * Minor updates * Update the javascript client compiled version * doc-diff object returned * Build: check if the YAML file exists before trying to open it * Proxito: don't inject the header if the feature is turned off * Test: add hosting integrations tests * Remove JS This file will be deployed directly into S3. * Load the javascript from a local server for now * Update URL to remove .json from it * Remove non-required f-string * Allow saving `build_data` via API endpoint * Lint * Migrate nodejs installation to asdf * Change port to match `npm run dev` from readthedocs-client
We deployed a fix twice for this but we had other issues, so we had to roll them back. I'm re-opening this issue because the problem is not fixed in production. |
We attemped to fix this issue multiple times and we found problems when deploying those changes to production. This not perfect, but simple solution, could help us to support multi-line commands for now without manipulating "too much" the `PATH` variable, that was the one causing us issues. Closes #10103
So, I've run into this issue as well (Mbed-TLS/mbedtls#7538) - The workaround I settled on is to insert a newline before the
|
Using the simplified example from @humitos: $ sh -c 'FOO=bar if [ "1" ]; then echo 1; fi;'
sh: -c: line 1: syntax error near unexpected token 'then'
sh: -c: line 1: 'FOO=bar if [ "1" ]; then echo 1; fi;'
$ sh -c 'export FOO=bar
if [ "1" ]; then echo 1; fi;'
1 |
This is another attempt to fix this issue. It follows the suggestion posted by @bensze01 in #10103. It looks simple and I think it makes sense to give it a try since it doesn't seem to be harmful. I tested it locally with the branch https://github.com/readthedocs/test-builds/tree/build-commands-multiline and it worked fine. Note that without this PR the branch linked fails. Related #10133 Related #10119 Related #10206 External PRs that should be solved by this one: * pypi/warehouse#12953 * pypi/warehouse#12953 Closes #10103 Closes #10208
* Build: allow multi-line commands on `build.commands` This is another attempt to fix this issue. It follows the suggestion posted by @bensze01 in #10103. It looks simple and I think it makes sense to give it a try since it doesn't seem to be harmful. I tested it locally with the branch https://github.com/readthedocs/test-builds/tree/build-commands-multiline and it worked fine. Note that without this PR the branch linked fails. Related #10133 Related #10119 Related #10206 External PRs that should be solved by this one: * pypi/warehouse#12953 * pypi/warehouse#12953 Closes #10103 Closes #10208 * Build: use `;` to separate PREFIX from COMMAND
Details
Expected Result
A post_build script
if test -n "A"; then echo "B"; fi
should not produce a syntax error.A post_build script with
sh -c "foo"
in it should run the shell with the argument.Actual Result
/bin/sh: 1: Syntax error: "then" unexpected
sh: 0: -c requires an argument
I'm following the manual at "Extend the build process" and trying to insert a simple shell script at the post_build step.
A script that works locally (Ubuntu 22) is somehow mangled and causes syntax errors when inserted into the .readthedocs.yml at the post_build stage. I have tried many ways of writing the script and quoting it in YAML, to try to eliminate YAML as the culprit:
The last one is especially mysterious.
Is there some sort of mangling of the script going on, or am I just going blind?
None of these scripts produce syntax errors when I feed them to /bin/sh on my local Ubuntu. I have written similar scripts for multiple CI systems without coming across this problem before.
Thanks.
The text was updated successfully, but these errors were encountered: