Skip to content

Directive inheritance: laziness for the win#2623

Merged
tgamblin merged 5 commits intospack:developfrom
epfl-scitas:features/inheritance_of_directives
Dec 28, 2016
Merged

Directive inheritance: laziness for the win#2623
tgamblin merged 5 commits intospack:developfrom
epfl-scitas:features/inheritance_of_directives

Conversation

@alalazo
Copy link
Copy Markdown
Member

@alalazo alalazo commented Dec 18, 2016

This PR should fix #2466 and without touching a lot of code. The basic ideas:

  • directives now are lazy, and used just to capture the values passed to them
  • a list of commands stemming from directives gets stored in the class being created
  • these commands are executed at Meta.__init__ time if the class being created comes from a package repository (if not it's just code that has been factored into a common base)

This also means that DictWrapper and inspect.stack are not used anymore, as we defer code execution to a later time where pkg is already available. Currently this PR supports only single inheritance

Modifications
  • directives can be inherited
  • multiple inheritance of base classes containing directives is supported
  • tests that stress the new functionality

@davydden
Copy link
Copy Markdown
Member

is there a way to specify which cmake is needed? Maybe a given package depends on [email protected]:, can we do this somehow?

@tgamblin
Copy link
Copy Markdown
Member

tgamblin commented Dec 18, 2016

@davydden: if the parent says depends_on('cmake'), the subclass should be able to refine that to [email protected]: by just writing depends_on('[email protected]:') explicitly. I believe @alalazo just wants this PR to allow CMakePackages to have an implicit depends_on('cmake').

@tgamblin
Copy link
Copy Markdown
Member

@alalazo is on a roll here.

when = kwargs.get('when', pkg.name)
destination = kwargs.get('destination', "")
placement = kwargs.get('placement', None)
# Check if the path is relative
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalazo: is there some chance that I can convince you to use blank lines before sub-parts of long sections of code?

'can\'t be an absolute path.\n'
message += "\tdestination : '{dest}\n'".format(dest=destination)
raise RuntimeError(message)
# Check if the path falls within the main package stage area
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^ like here

normalized_destination = os.path.normpath(
join_path(test_path, destination)
) # Normalized absolute path
if test_path not in normalized_destination:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^^ or here

@davydden
Copy link
Copy Markdown
Member

the subclass should be able to refine that to [email protected]: by just writing depends_on('[email protected]:') explicitly.

i see. As long as it's un-conditional (does not depend on a variant), then the union of depends_on('cmake') in parent and depends_on('[email protected]:)` in child should indeed work without a problem, whereas in general there could be some issues with conretizer, like this one #1781

I believe @alalazo just wants this PR to allow CMakePackages to have an implicit depends_on('cmake').

i like the idea for sure.

@alalazo
Copy link
Copy Markdown
Member Author

alalazo commented Dec 18, 2016

@tgamblin This PR was one of the best code-puzzle so far in Spack! 😄

@tgamblin
Copy link
Copy Markdown
Member

@alalazo: It's a really good idea. I bet this actually makes loading package modules quite a bit faster. The original version relied on walking up the call stack to find the package scope, but this won't need to do that work. I'm a little sad because this was actually one of the original code puzzles in Spack -- how to make the DSL. But I think the lazy DSL is better 😄

@tgamblin
Copy link
Copy Markdown
Member

@alalazo: it might also make it easier to implement conditional directive groupings -- something I had thought of a while ago but that @TomasPuverle recently suggested. e.g.:

    with satisfies('@3.6:'):
        depends_on('foo')
        depends_on('bar')

    with satisfies('@3.8:'):
        depends_on('baz')

basically a way to factor out common when= clauses.

version('2.0', 'cdf266530fee8af87454f15feb619609')
version('1.5.2', '545f98923430369a6b046ef3632ef95c')
version('1.5.1', 'd774e4b5a0db5f0f171c4fc0aabfa14e')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we just take a step back and think about it, it's insane how many packages we can install with almost no code. There are probably hundreds of would be Autotools and CMake packages that no longer need any special install method. #1186 might just go down as the biggest line saving PR in Spack history. I'm looking at this empty package and it's hard to think of anything else we could remove. Now if we could just get rid of that stupid license and from spack import *...

Copy link
Copy Markdown
Member

@tgamblin tgamblin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alalazo: a few minor requests, but otherwise LGTM!

Do you want to merge this first or #2502 first? I would think #2502 first, then this can be rebased on the new test infrastructure.


import llnl.util.tty as tty
import spack.build_environment
import spack.directives
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just from spack import * like regular Packages?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to track what we are importing from where. As we are in core I tried to avoid:

from XXX import *

but if you think it's more readable, I have no objection changing it.

# build-system class we are using
build_system_class = 'CMakePackage'

spack.directives.depends_on('cmake', type='build')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no just regular old depends_on? Seems more readable.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely want thing to be readable so that other users can write their own Package subclasses or understand what is already present.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comes with the comment above. Let me know if you want this changed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the narrow import is good but can you do from spack.directives import depends_on so this is readable?

)
_directives_to_be_executed = []

return super(DirectiveMetaMixin, meta).__new__(meta, name, bases, attr_dict) # NOQA: ignore=E501
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just wrap it after __new__(.

pkg.versions[Version(ver)] = kwargs
# Store kwargs for the package to later with a fetch_strategy.
pkg.versions[Version(ver)] = kwargs
_directives_to_be_executed.append(_execute)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the directive decorator either:

  1. Pass this list in as a parameter (kind of like how pkg was passed in before)? or
  2. Make directives return either something callable on a Package or a list of them?

Either of these would make it so that not all directives have to refer to a global, and they'd consolidate any use of globals to the directive definition. It would also make it clearer to potential contributors how they might write their own directive (as the interface would be clear from the structure).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went for solution number 2 and moved all the global variables into the meta-class, see 30ae175 . Let me know if you want further modifications here.

Do you want to merge this first or #2502 first?

I think this one is ready, while #2502 needs some work to fix the coverage. That said, I have no preference on the order and no hurry in having any of the two merged immediately.

…ming from directives into packages + lazy directives

* _dep_types -> dependency_types
* using a meta-class to inject directives into packages
* directives are lazy

fixes spack#2466
CMakePackage: importing names from spack.directives
directives: wrap __new__ to respect pep8
directives: removed global variables in favor of class variables. Simplified the interface for directives (they return a callable on a package or a list of them).
@alalazo alalazo force-pushed the features/inheritance_of_directives branch from ac4aaba to 30ae175 Compare December 28, 2016 16:25
@tgamblin
Copy link
Copy Markdown
Member

Ok this LGTM. Thanks! I'll merge this one then #2502 when it's ready. Basically I want to get #2502 in so that @citibeth can write tests for her PR and so that I can rebase #2681 on the new test framework.

@alalazo: can you take a quick look at #2681? It actually reworks Spec significantly.

@tgamblin tgamblin merged commit 17b13b1 into spack:develop Dec 28, 2016
@alalazo alalazo deleted the features/inheritance_of_directives branch December 29, 2016 01:02
@adamjstewart adamjstewart mentioned this pull request Jan 14, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

All CMakePackages depend on CMake

4 participants