Skip to content
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

many: extract lifecycle ordering into own module #2159

Merged
merged 9 commits into from Jun 12, 2018

Conversation

kyrofa
Copy link
Contributor

@kyrofa kyrofa commented Jun 7, 2018

  • Have you followed the guidelines for contributing?
  • Have you signed the CLA?
  • If this is a bugfix. Have you checked that there is a bug report open for the issue you are trying to fix on bug reports?
  • If this is a new feature. Have you discussed the design on the forum?
  • Have you successfully run ./runtests.sh static?
  • Have you successfully run ./runtests.sh unit?

Currently the snapcraft CLI has step names and ordering hard-coded in a number of places, and those areas where it isn't hard-coded, a difficult-to-read index method is used. Simplify and extract this logic into a single module used by the others to determine lifecycle steps and ordering.

Currently the snapcraft CLI has step names and ordering hard-coded in a
number of places, and those areas where it isn't hard-coded, a
difficult-to-read index method is used. Simplify and extract this logic
into a single module used by the others to determine lifecycle steps and
ordering.

Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
SNAPCRAFT_INTERNAL_DIR = os.path.join('snap', '.snapcraft')
STEPS_TO_AUTOMATICALLY_CLEAN_IF_DIRTY = {'stage', 'prime'}
STEPS_TO_AUTOMATICALLY_CLEAN_IF_DIRTY = {steps.STAGE, steps.PRIME}
Copy link
Collaborator

Choose a reason for hiding this comment

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

would this look better if it were an attribute of the step?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, excellent idea!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

sources,
states,
steps,
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

this import style really drives me nuts for some reason I cannot explain 😛

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Haha, this one was long enough I had to split it, sorry!

Copy link
Collaborator

Choose a reason for hiding this comment

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

If you use autopep8 it will use the format I like :-P

next_step = step

return next_step
latest_step = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

if what we return is the next_step, should what we eval be the current_step instead of the latest_step? I am not sure why, but calling this latest_step confuses me, we had this conversation already as this is triggering things (I think we even opened a bug for this).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah, everything revolves around latest_step now it seems

Copy link
Contributor Author

@kyrofa kyrofa Jun 8, 2018

Choose a reason for hiding this comment

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

No logic has changed here, it was just called "last step" which never felt quite right, so I changed it to "latest". Everything naturally revolves around which step was run most recently, since they build on each other. Do you prefer another name?



class Step:
def __init__(self, name: str) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am just going to throw this out, but what if instead of keeping a tight coupling with STEPS and those index calls to know where it lives we create the Step instance with knowledge of the next step and the previous step, kind of like a linked list and create a map of step names to the instances?

Copy link
Contributor Author

@kyrofa kyrofa Jun 8, 2018

Choose a reason for hiding this comment

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

Yeah I thought about that, but ended up having two issues:

  1. Order needs to be provided somehow, whether that's by providing a list giving the order or by hard-coding it into each Step instance. The former seemed simpler to understand and modify than the latter (which also seems potentially error-prone).
  2. We need a way to know which step is first. The STEPS variable provides that knowledge (STEPS[0]).

Basically, I liked the idea of having order solidly maintained in a single, easy-to-understand place rather than spread through multiple classes and needing to know that PULL is the first step. It's an interesting idea, though. Let me try it real quick, I think it's a small change. Then we can see what we think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Alright, just pushed it up. Let me know what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We discussed offline, and I've moved it back to a list, but kept the same methods.

@codecov-io
Copy link

codecov-io commented Jun 8, 2018

Codecov Report

Merging #2159 into master will decrease coverage by 0.07%.
The diff coverage is 87.93%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2159      +/-   ##
==========================================
- Coverage   91.34%   91.26%   -0.08%     
==========================================
  Files         194      195       +1     
  Lines       12246    12317      +71     
  Branches     1820     1827       +7     
==========================================
+ Hits        11186    11241      +55     
- Misses        718      730      +12     
- Partials      342      346       +4
Impacted Files Coverage Δ
snapcraft/internal/common.py 97.1% <ø> (-0.03%) ⬇️
snapcraft/internal/lifecycle/constants.py 100% <ø> (ø) ⬆️
snapcraft/cli/lifecycle.py 93.75% <100%> (+0.16%) ⬆️
snapcraft/internal/errors.py 99.53% <100%> (+0.02%) ⬆️
snapcraft/internal/lxd/_project.py 92.06% <100%> (+4%) ⬆️
snapcraft/internal/lifecycle/_runner.py 90% <100%> (-0.16%) ⬇️
snapcraft/internal/meta/_manifest.py 100% <100%> (ø) ⬆️
snapcraft/internal/states/_state.py 88.23% <100%> (+0.23%) ⬆️
snapcraft/internal/lifecycle/_packer.py 85% <100%> (ø) ⬆️
snapcraft/internal/steps.py 72.05% <72.05%> (ø)
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 4cbe8c1...aa44ec3. Read the comment docs.

Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
@@ -112,10 +112,10 @@ def clean(self, parts: List[str], step: str):
print('Deleting {}'.format(self._container_name))
subprocess.check_call([
'lxc', 'delete', '-f', self._container_name])
step = 'pull'
step = steps.PULL.name
Copy link
Collaborator

Choose a reason for hiding this comment

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

I see two options here, but one thing first, we should rename the signature of this method to taking step_name instead of step or have it pass down an actual Step, where a possible value is None and move the DEPRECATED warning a level up when using strip passing it the appropriate step.

If using the former, I wouldn't get the name just to get the step again, but instead, only create the step for the case of strip

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, fixed by passing down a Step.

return hash(self.name)

def __repr__(self):
return 'snapcraft.internal.steps.Step({!r})'.format(self.name)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would of been nice to have some sort of __modpath__ to not hardcode this, closest I know of is __file__, but it will look too hacky. If we ever move this module, this change will most likely go unnoticed, so why not remove the leading qualifiers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, you're right. I'm mostly going off of python docs here that say:

[...] If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value

So I added the qualifiers. I agree that it's just asking to break though, and I question its usefulness anyway. This is really just to make test failures nice, so we can make it whatever we want. I'll remove the leading qualifiers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

PULL = Step('pull', False)
BUILD = Step('build', False)
STAGE = Step('stage', True)
PRIME = Step('prime', True)
Copy link
Collaborator

Choose a reason for hiding this comment

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

maybe add STRIP = PRIME with a comment about it being there for backwards compat?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That doesn't really help us since the step .name would still be prime. It's okay though, I think we can handle this a level above rather than pushing deprecation all the way down here.

Copy link
Collaborator

@sergiusens sergiusens left a comment

Choose a reason for hiding this comment

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

one last round of changes. Looking good.

Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
if build_environment.is_host:
step = step or steps.next_step(step).name

if step:
Copy link
Collaborator

Choose a reason for hiding this comment

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

it gets confusing a bit when step can be a step_name or an actual instance of Step.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed, fixed by using an identifier decl for click to make it use a different parameter name.

Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
Signed-off-by: Kyle Fazzari <kyrofa@ubuntu.com>
@kyrofa kyrofa merged commit 6a676f2 into canonical:master Jun 12, 2018
@kyrofa kyrofa deleted the feature/refactor_lifecycle_steps branch June 12, 2018 02:51
@sergiusens
Copy link
Collaborator

\o/

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.

None yet

3 participants