Package.installed now checks both the presence of prefix and a DB entry#8038
Conversation
| # If the spec is in the DB, check the installed | ||
| # attribute of the record | ||
| rec = spack.store.db.get_record(self.spec) | ||
| db_says_installed = rec.installed |
There was a problem hiding this comment.
@scheibelp @tgamblin I was wondering what is a case that could leave us with a record in the DB that has rec.installed ==False. Do you have any in mind?
There was a problem hiding this comment.
When packages are uninstalled the corresponding record is not removed - instead it is marked as .installed = False
There was a problem hiding this comment.
It doesn't seem the case to me, that's why I was wondering if I missed some corner case where it could happen:
$ spack find
==> 0 installed packages.
$ cat opt/spack/.spack-db/index.json
{
"database": {
"installs": {},
"version": "0.9.3"
}
}
$ spack install zlib
==> Installing zlib
==> Fetching file:///home/mculpo/production/mirror/zlib/zlib-1.2.11.tar.gz
...
Fetch: 0.02s. Build: 4.33s. Total: 4.35s.
[+] /home/mculpo/PycharmProjects/spack/opt/spack/linux-ubuntu18.04-x86_64/gcc-8/zlib-1.2.11-ypfhlhjehavum42gl6uvax7o6kzhseoi
$ cat opt/spack/.spack-db/index.json
{
"database": {
"installs": {
"ypfhlhjehavum42gl6uvax7o6kzhseoi": {
"explicit": true,
"installation_time": 1526021395.450302,
"ref_count": 0,
"installed": true,
"path": "/home/mculpo/PycharmProjects/spack/opt/spack/linux-ubuntu18.04-x86_64/gcc-8/zlib-1.2.11-ypfhlhjehavum42gl6uvax7o6kzhseoi",
"spec": {
"zlib": {
...
}
$ spack uninstall -y zlib
==> Successfully uninstalled [email protected]%gcc@8+optimize+pic+shared arch=linux-ubuntu18.04-x86_64 /ypfhlhj
$ cat opt/spack/.spack-db/index.json
{
"database": {
"installs": {},
"version": "0.9.3"
}
}There was a problem hiding this comment.
@scheibelp Any comment on:
When packages are uninstalled the corresponding record is not removed - instead it is marked as .installed = False
and the post above? As far as I can tell it always worked like that (removing the entry from the DB).
There was a problem hiding this comment.
I'm not sure how that comes about, nevertheless it is safest to proceed by checking the .installed field of the DB record since that is there.
@becker33 do you have a notion of when the .installed field on a DB record is used?
| # above raises a Key error | ||
| db_says_installed = False | ||
|
|
||
| return has_prefix and db_says_installed |
There was a problem hiding this comment.
Here I did the simplest modification possible. Don't know if you want to raise, or log a message somewhere, in case we find something inconsistent, like has_prefix == False and db_says_installed == True.
|
This feels like a matter of interpretation: I don't normally have an issue with considering external packages as installed. Does something go wrong when external packages are considered installed? Would this also imply there needs to be consideration about when a user adds an external package but doesn't explicitly install it? In this case Also the unit test looks good although IMO instead of directly invoking |
Nothing super-severe, but if you consider external packages installed without being registered in the DB:
Probably a couple of lines in the doc that inform users of the discrepancies above? If you want I can try to add a sentence somewhere to show how installing an external package differs from installing a regular one.
That's how I hit this issue. I wrote a command to help scripting a deployment procedure (#7899) and noticed that external packages were always considered installed, even if they were not explicitly
👍 |
|
@scheibelp I just double checked this:
and the def _install(spec):
s = spack.spec.Spec(spec)
s.concretize()
pkg = spack.repo.get(s)
pkg.do_install(fake=True)on its |
It should be ok to invoke IMO there are two competing desires:
Would there be an issue with having
I'm worried this would be fairly common and it would be nice to handle things automatically if possible.
I don't think there's a test which confirms right now that invoking |
I see two valid reasons why not doing that:
By 1. I mean that, for instance, the configuration file in #8036: packages:
openssl:
buildable: False
paths:
openssl@system: /usr/libsays that whenever Regarding 2. I think I would really be surprised (not positively) by a behavior like: # Evaluating the condition might write module files to disk for external packages
# or modify spack DB
if openssl.installed:
# This will never be hit by external packages, even if they don't appear in `spack find`
passTLDR I would stay explicit, and let people install via |
There is, but is done indirectly via the spack/lib/spack/spack/test/database.py Lines 448 to 464 in cdefbd7 This was added as part of #1167 |
I think there should be a test to ensure that
I think we support that mainly because we don't want to necessarily force users to be specific about the details. Even though we weren't specific, the external
so I'm assuming perhaps this works out for
I agree that would be strange. I want to make sure that if we require users to explicitly install externals, that it's clear to users what is going wrong if an external is considered not-installed. Perhaps something close to that would be to print a warning message when a not-installed external spec is encountered. Actually wouldn't this be rare? If the external appears as a dependency in a spec DAG and that DAG is installed, the database should be updated with the external (or I think that's how it works from looking at In other words I'm asking: when do you encounter an external that hasn't been registered in the DB? It may also be strange to users to have to explicitly install the same external multiple times with different specs if they want Spack to treat it as installed in different contexts (DAGs). |
e5e3765 to
30cee13
Compare
This, I think, as been taken care of in the latest rebase - at least for the modifications that are part of the PR.
Agreed, but with the caveat that I don't see it as a problem. To explain better my point of view: I interpret the semantic of entries in
For At least in our case, these applications (like |
|
@scheibelp Pinging you as you told me to do 😄 |
|
ping |
scheibelp
left a comment
There was a problem hiding this comment.
Overall this seems fine, in fact as I think on it, it may be sensible to use the database exclusively to check for installation, e.g. to account for module-only externals (not that this needs to be considered in this PR).
The docstring of check_for_unfinished_installation needs to be updated (since it is no longer "more strict" than Package.installed).
lib/spack/spack/test/database.py
Outdated
|
|
||
|
|
||
| @pytest.mark.regression('8036') | ||
| def test_regression_issue_8036(mutable_database): |
There was a problem hiding this comment.
I wish this test didn't depend on the existence of a system path - would it be possible to just set Spec.prefix to some path you create with a pytest fixture?
There was a problem hiding this comment.
Seems legit. I patched os.path.isdir for this particular regression test.
fixes spack#8036 Before this PR Package.installed was returning True if the spec prefix existed, without checking the DB. This is wrong for external packages, whose prefix exists before being registered into the DB. Now the property checks for both the prefix and a DB entry.
Improved the docstring of two functions (``installed`` and ``check_for_unfinished_installation``). A new fixture has been added so that the regression test is platform independent, and does not rely on ``/usr`` being present in the system.
30cee13 to
91462b3
Compare
|
@scheibelp Should be done. Let me know if there's anything else you want changed. |
lib/spack/spack/test/database.py
Outdated
| @pytest.mark.regression('8036') | ||
| def test_regression_issue_8036(mutable_database, usr_folder_exists): | ||
| # This version should not be installed on entry, but it points to /usr | ||
| # which is a directory that most likely exists everywhere (see #8036) |
There was a problem hiding this comment.
@alalazo now that you have added usr_folder_exists, you can replace
... but it points to /usr which is a directory that most likely exists everywhere
with
... but the test arranges for the package prefix to exist
Or perhaps altogether:
The test ensures that the external package prefix is treated as existing. Even when the package prefix exists, the package should not be considered installed until it is added to the database with do_install
The initial comment in the regression test was outdated by the last change. Now it has been updated and is worded more clearly (thanks to Peter's suggestion).
|
Thanks! |
fixes #8036
Before this PR Package.installed was returning True if the spec prefix existed, without checking the DB. This is wrong for external packages, whose prefix exists before being registered into the DB.
Now the property checks for both the prefix and a DB entry.