-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Environment/depfile: fix bug with Git hash versions #36642
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
Changes from all commits
358ab0f
0ad9057
9cf4cfd
6cb04bf
91056bb
587ad08
6a7197a
aacd2c5
e14587f
136ea94
a4c2f3f
4c1cf6e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -6,6 +6,7 @@ | |||||||||
| import glob | ||||||||||
| import io | ||||||||||
| import os | ||||||||||
| import re | ||||||||||
| import shutil | ||||||||||
| import sys | ||||||||||
| from argparse import Namespace | ||||||||||
|
|
@@ -3119,6 +3120,46 @@ def test_environment_depfile_makefile(depfile_flags, expected_installs, tmpdir, | |||||||||
| assert len(specs_that_make_would_install) == len(expected_installs) | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def test_environment_depfile_spec_format_special_chars(tmpdir, mock_packages, monkeypatch): | ||||||||||
| env("create", "test") | ||||||||||
| makefile = str(tmpdir.join("Makefile")) | ||||||||||
| with ev.read("test"): | ||||||||||
| add("dttop") | ||||||||||
| concretize() | ||||||||||
|
|
||||||||||
| orig_format = spack.spec.Spec.format | ||||||||||
|
|
||||||||||
| def _contrived_spec_format(obj, format_str): | ||||||||||
| if obj.name == "dtlink1": | ||||||||||
| return "dtlink1-githash=version-spackhash" | ||||||||||
| else: | ||||||||||
| return orig_format(obj, format_str) | ||||||||||
|
|
||||||||||
| monkeypatch.setattr(spack.spec.Spec, "format", _contrived_spec_format) | ||||||||||
|
|
||||||||||
| # Disable jobserver so we can do a dry run. | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're not using dry run 🤔 tbh, dry run is the best way to validate the makefile, and this is an integration test already, so it might even be better than manually validating the generated output
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Dry run could be useful to do in addition to this, but I strongly feel that it is not enough: the problem I ran into involved a makefile which you could use (no syntax errors, and running
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I see now (commented in the wrong thread before, sorry) abc=def: prereq # ordinary definition of `abc`
target: abc=def # target-specific variable value for variable `abc` in target `target`Notice that a dry-run is more than "it runs", since it will print what it would do in order, which is better than parsing a Makefile. See other tests
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is https://github.com/spack/spack/pull/36642/files#r1160315876 an answer to this? It is to me. The use case I worked from is enormous so I can't post the full file here but:
That's why I think a dry run would not expose the error: you have to actually execute the task.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would need to check but I think the makefile generated by this test should successfully execute a dry run without the changes outside of the unit-tests (I didn't check that as part of this PR because (a) the special characters were the source of the problem in the larger example and (b) I removed those as part of the PR).
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I want to be clear that I strongly recommend against doing anything like what this diff suggests: ultimately it does not matter what properties inside of specs give rise to special characters, only that they could be generated as part of using Spec functionality to generate a makefile target. There is a better way to do what I did (and I'm happy to try to make that happen), but it is not this particular diff.
My initial interpretation of what you said is to examine something like I could test I could refactor the does that seem better?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you have an integration test for git versions, then this
is not a concern in the unit test. If I would write it I would just make a small class (the model) that has properties that are passed to
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At the same time, I also don't care too much at this point 😆 as long as the bug fix gets in
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think you're talking about taking the dictionary passed to Validating such an object would be complex: the targets in general can have several different special characters, and while I don't think I think my suggestion from #36642 (comment) would simplify the matter:
The
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow 🤔 I've implemented
in #36911, and it's not complex to do |
||||||||||
| with ev.read("test"): | ||||||||||
| env( | ||||||||||
| "depfile", | ||||||||||
| "-o", | ||||||||||
| makefile, | ||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can save a few lines by dropping |
||||||||||
| "--make-disable-jobserver", | ||||||||||
| "--make-prefix=prefix", | ||||||||||
| "--use-buildcache=never", | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| with open(makefile, "r") as f: | ||||||||||
| makefile_lines = f.readlines() | ||||||||||
|
|
||||||||||
| makefile_contents = "\n".join(makefile_lines) | ||||||||||
|
Comment on lines
+3151
to
+3154
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
see above |
||||||||||
|
|
||||||||||
| for line in makefile_lines: | ||||||||||
| if "githash=version" in line: | ||||||||||
| assert re.search("SPEC = dtlink1-githash=version-spackhash$", line) | ||||||||||
|
|
||||||||||
| assert "dtlink1-githash_version-spackhash" in makefile_contents | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def test_environment_depfile_out(tmpdir, mock_packages): | ||||||||||
| env("create", "test") | ||||||||||
| makefile_path = str(tmpdir.join("Makefile")) | ||||||||||
|
|
||||||||||
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.
Since you already have mock_packages, can't you actually use a normal git version with user specified spack version to the same effect? That would be less contrived
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.
I wanted to avoid patching the packages to achieve this condition: IMO the source of all errors like the one this PR aims to correct is specially-interpreted characters via
Spec.format; therefore I argue that this is the least-contrived way to test the outcome (changing things about the versions etc. would silently render this test useless ifspec.formathappened to behave differently in some scenarios vs. others).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.
Hm, it's a rule of thumb not to mock in integration tests, cause assumptions on the implementation make the test redundant on refactor. If you want an integration test for git versions, then just use a git version. If you want to test normalization of targets, then write a unit test. In both cases you don't need to use monkeypatch
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.
I don't want to normalize the entire target: the depfile uses special characters in targets for their intended effect. The issue is when those targets are partially defined using
Spec.format, which introduces unexpected special characters.I don't think git versions are the (real) problem. For a system that generates makefiles of spack installs and needs to create targets based on the Specs, each such target is composed of:
The latter is the only place that can surprise us. The current logic has no formalized abstraction for the latter and directly uses
.format. I considered it appropriate to just alterSpec.format, but it would be more-robust to mock the Spec object entirely.given the above, while I'd say it is strictly true that this mocking makes an assumption in the implementation, setting a git version is even more a violation of this rule (conditional changes to
str()of version could render this test useless: why not target the point where the depfile logic directly interfaces with the Spec API?).Uh oh!
There was an error while loading. Please reload this page.
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.
I'm sorry for being so insistent, but I'd rather see
monkeypatchdropped. The other point is thatSpec.formatis so commonly called, mocking it will likely break invariants elsewhere in the future.Please just add an integration/regression test with depfile and git versions which is the problem you're solving in the PR (you can just adapt the test above the one you've added), and if you don't like integration tests, refactor so that you can unit test the adjacency list