-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Modifying multiple files per update in fine-grained incremental mode #4282
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
Conversation
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 found time to go over this after all. Feel free to either merge unchanged, merge after addressing feedback, or build more changes on top of this and resubmit.
assert len(changed_modules) == 1, changed_modules | ||
changed_modules = get_all_changed_modules(module, path, old_graph, graph) | ||
# If there are multiple modules to process, only process one of them and return the | ||
# remaining ones to the caller. |
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.
Maybe note that you process the last one in the list first? This is significant, because the first one in the list is guaranteed (by the implementation of get_all_changed_modules()
) to be the original module.
for id, _ in remaining_modules: | ||
del manager.modules[id] | ||
del graph[id] | ||
module, path = changed_modules[-1] |
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.
Somehow this came as a small surprise to me -- I would chop off the designated item first. (Maybe using pop()
so the slice on line 262 is unnecessary.)
# TODO: state.fix_suppressed_dependencies()? | ||
|
||
# Run remaining passes of semantic analysis. | ||
try: | ||
state.semantic_analysis() | ||
except CompileError as err: | ||
# TODO: What if there are multiple changed modules? |
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.
That TODO is currently irrelevant.
for st in new_graph.values(): | ||
if st.id not in old_graph and st.id not in changed_set: | ||
changed_set.add(st.id) | ||
assert st.path |
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.
The assert looks odd in the middle of updating the two parallel data structures -- I'd put it at the top of the block.
I'll add suggested improvements to my next PR if they are still relevant. |
The approach is to split multiple file updates into multiple single-file
updates, and only report errors for the final update. If a modified file
brings in additional files through an import, we'll process one of the
imported files instead, changing the target file as we go. The
motivation is that this should result in less redundant work than
postponing the imported file, as a missing imported file will result
in a lot of stale targets which would need to processed again on the
next update.
This still doesn't handle blockers well. I'll fix these issues separately.
This is inefficient as some files can be parsed multiple times, with
O(n**2) worst case behavior (n is the number of changed files). It
should be fine when a small number of files need to be processed.