Add jinja templating, payload as tar, tests#2
Add jinja templating, payload as tar, tests#2lrandersson wants to merge 10 commits intodev-ra-798from
Conversation
constructor/briefcase.py
Outdated
|
|
||
| archive_path = dst / self.archive_name | ||
|
|
||
| with tarfile.open(archive_path, mode="w:gz", compresslevel=1) as tar: |
There was a problem hiding this comment.
I chose tar.gz here over tar.bz2, the reason is that MSI already compresses the contents, therefor the format of the compression does not do much of a difference in terms of disk space. However, .tar.gz is in general a little bit faster over .tar.bz2, so I have intentionally chose speed here over disk space.
There was a problem hiding this comment.
Could you add some benchmarks to this?
| set "PAYLOAD_TAR=%INSTDIR%\{{ archive_name }}" | ||
|
|
||
| "%INSTDIR%\_conda.exe" constructor --prefix "%BASE_PATH%" --extract-conda-pkgs | ||
| tar -xzf "%PAYLOAD_TAR%" -C "%INSTDIR%" |
There was a problem hiding this comment.
This will be updated in the future to instead use conda-standalone instead of built-in tar ...
There was a problem hiding this comment.
There's no time like the present!
|
|
||
| # Create a Briefcase configuration file. Using a full TOML writer rather than a Jinja | ||
| # template allows us to avoid escaping strings everywhere. | ||
| def write_pyproject_toml(tmp_dir, info): |
There was a problem hiding this comment.
This was not deleted, but moved into class Payload
constructor/template_file.py
Outdated
| from .jinja import render_template | ||
|
|
||
|
|
||
| @dataclass(frozen=True) |
There was a problem hiding this comment.
We can utilize this later also for the other installers.
There was a problem hiding this comment.
This seems to overly abstract. The name property appears to be too tailor-made (which other format needs it besides MSI) and then we just have a source and destination path. With all my other comments, I'm not sure we need this class.
The render_template_files function could then just handle one file and deal with all the file handling operations (which I think is nice).
marcoesters
left a comment
There was a problem hiding this comment.
My initial thoughts on this. Overall, I think we could do with a little less abstraction here.
| set "PAYLOAD_TAR=%INSTDIR%\{{ archive_name }}" | ||
|
|
||
| "%INSTDIR%\_conda.exe" constructor --prefix "%BASE_PATH%" --extract-conda-pkgs | ||
| tar -xzf "%PAYLOAD_TAR%" -C "%INSTDIR%" |
There was a problem hiding this comment.
There's no time like the present!
|
|
||
| rem Truncates the payload to 0 bytes | ||
| type nul > "%PAYLOAD_TAR%" |
There was a problem hiding this comment.
Why not delete it? That zero-byte file doesn't need to be there until the uninstallation.
There should probably also be a comment about why this is needed.
constructor/briefcase.py
Outdated
|
|
||
| archive_path = dst / self.archive_name | ||
|
|
||
| with tarfile.open(archive_path, mode="w:gz", compresslevel=1) as tar: |
There was a problem hiding this comment.
Could you add some benchmarks to this?
tests/test_briefcase.py
Outdated
| def test_payload_templates_are_rendered(): | ||
| """Test that templates are rendered when the payload is prepared.""" | ||
|
|
||
| def assert_no_jinja_markers(path: Path) -> None: |
There was a problem hiding this comment.
That function looks simple enough to be inlined.
constructor/briefcase.py
Outdated
| root: Path | None = None | ||
| archive_name: str = "payload.tar.gz" | ||
| conda_exe_name: str = "_conda.exe" | ||
| rendered_templates: list[TemplateFile] | None = None |
There was a problem hiding this comment.
I don't know if we want to make that distinction. Rendered templates are like any other file we add to the installer payload.
constructor/briefcase.py
Outdated
|
|
||
| return archive_path | ||
|
|
||
| def _convert_into_archive(self, src: Path, dst: Path) -> Path: |
There was a problem hiding this comment.
That function could be folded into make_tar_gz or vice versa
constructor/briefcase.py
Outdated
| """Render all configured Jinja templates into the payload root directory. | ||
| The set of successfully rendered templates is recorded on the instance and returned to the caller. | ||
| """ | ||
| root = self._ensure_root() |
There was a problem hiding this comment.
This is what I meant about either using __init__ to create the directory or not allowing a None value/non-existing directory. We have to manually add self._ensure_root() in all appropriate places.
constructor/briefcase.py
Outdated
| }, | ||
| } | ||
| # Render the template files and add them to the necessary config field | ||
| rendered_templates = self.render_templates() |
There was a problem hiding this comment.
I think this should go into prepare like with any other payload preparation. Since we will always have pre_uninstall and pre_install scripts for our installers, we can add those hard-coded into the config object above.
constructor/template_file.py
Outdated
| @@ -0,0 +1,26 @@ | |||
| from collections.abc import Mapping | |||
There was a problem hiding this comment.
Let's merge the two template functions into one. There doesn't seem to be enough here to justify a separate module.
constructor/template_file.py
Outdated
| from .jinja import render_template | ||
|
|
||
|
|
||
| @dataclass(frozen=True) |
There was a problem hiding this comment.
This seems to overly abstract. The name property appears to be too tailor-made (which other format needs it besides MSI) and then we just have a source and destination path. With all my other comments, I'm not sure we need this class.
The render_template_files function could then just handle one file and deal with all the file handling operations (which I think is nice).
|
@marcoesters To answer above comments. I just pushed a bunch of commits that did change a lot based on the review, I hope to summarize it:
|
marcoesters
left a comment
There was a problem hiding this comment.
Thank you! I think it's much closer to being ready now.
constructor/briefcase.py
Outdated
| "post_install_script": str(self.rendered_templates["post_install_script"].dst), | ||
| "pre_uninstall_script": str(self.rendered_templates["pre_uninstall_script"].dst), |
There was a problem hiding this comment.
| "post_install_script": str(self.rendered_templates["post_install_script"].dst), | |
| "pre_uninstall_script": str(self.rendered_templates["pre_uninstall_script"].dst), | |
| "post_install_script": layout.root / "post_install.bat", | |
| "pre_uninstall_script": layout.root / "pre_uninstall.bat", |
We know where these files go and that location is not configurable, so we might as well hard-code them here. That also gives layout even more of a purpose and makes the TemplateParameter dataclass obsolete and you don't need to store the template files in the class (the fact that they are templates isn't that important, I think).
| def make_tar_gz(self, src: Path, dst: Path) -> Path: | ||
| """Create a .tar.gz of the directory 'src'. |
There was a problem hiding this comment.
I think it would overall be good see a benchmark of tar.gz vs. tar.bz2 in terms of space and extraction speed, especially compared to the native MSI compression. While registry handling becomes much easier with one file, it would be good to say what the cost is.
There was a problem hiding this comment.
Agree, will do that separately.
| "%INSTDIR%\_conda.exe" install --offline --file "%BASE_PATH%\conda-meta\initial-state.explicit.txt" -yp "%BASE_PATH%" | ||
| "%CONDA_EXE%" install --offline --file "%BASE_PATH%\conda-meta\initial-state.explicit.txt" -yp "%BASE_PATH%" | ||
|
|
||
| rem Delete the payload to save disk space, a truncated placeholder of 0 bytes is recreated during uninstall |
There was a problem hiding this comment.
| rem Delete the payload to save disk space, a truncated placeholder of 0 bytes is recreated during uninstall | |
| rem Delete the payload to save disk space. | |
| rem A truncated placeholder of 0 bytes is recreated during uninstall | |
| rem because MSI expects the file to be there to clean the registry. |
|
@marcoesters Applied the fixes here 3327439 |
Description
This PR is a continuation of conda#1164, but split into a separate PR to hopefully simplify review, summarizing the changes:
post_install.batandpre_uninstall.bat(although this file is currently empty).write_pyproject_tomlinto classPayloadTemplateFileto better organize files that are templated using jinja.Checklist - did you ...
newsdirectory (using the template) for the next release's release notes?