Skip to content

Conversation

@GaryQian
Copy link
Contributor

@GaryQian GaryQian commented Feb 9, 2021

Split off from #63773

Part of series of PRs for #73345 and #57617

This PR contains the DeferredComponentsSetupValidator which implements various checks and tasks that are used to verify the developer has a properly configured app for deferred components.

Most checks will look for the existence or particular entries inside of the android directory and if the file is not satisfactory, it will output the correct/expected file in a temporary directory under build/android_deferred_components_setup_files. Due to regex based parsers being unreliable and difficult to maintain, I will be switching to a Xml packaged based system to generate new additions to the xml files.

Example usage:

final DeferredComponentSetupValidator validator = DeferredComponentSetupValidator(environment);

validator.checkBlah1(components);
validator.checkBlah2(loadingUnits);

validator.handleResults();

// ---------------------------------------------------------
// Calling the following instead of handleResults is also valid:
validator.displayResults();
validator.attemptToolExit();

The validator is used in an upcoming PR based off of #63773.

@flutter-dashboard flutter-dashboard bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Feb 9, 2021
@google-cla google-cla bot added the cla: yes label Feb 9, 2021
@GaryQian GaryQian changed the title flutter_tools: Deferred components setup validator and tests. flutter_tools: Deferred components setup validator Feb 10, 2021
Copy link
Contributor

@jonahwilliams jonahwilliams Feb 10, 2021

Choose a reason for hiding this comment

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

At a high level, having a single method that calls other methods based on a list of enums set in the object's constructor is confusing. Some of the checks aren't really checks either, like clear temp dir.

I would start by making each of these tasks performed by a public method, which documents what it is doing and named appropriately whether it is performing some cleanup or verification. I would also leave out this enum setup, at least for now, and we can discuss that more when you're further along the integration side of things.

Copy link
Contributor

Choose a reason for hiding this comment

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

(That would also remove a lot of the confusion about arguments that are only required conditionally)

Copy link
Contributor

Choose a reason for hiding this comment

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

In general RegExps should be hoisted into statics and extensively documented as to what they are intended to match.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need a specific diff format here, or is there a way to do this in Dart? In general, we need to be really careful about introducing new runtime dependencies.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer unidiff so that I can recommend a patch command to quickly apply all diffs, but if that is not possible the diff can still be displayed in other formats for developer reference. Overall, this step is not necessary for the function of this feature, but it provides helpful quality of life improvements.

I am not aware of any fully-dart ways to do this. The diff commands are more complex than it seems. For unix, diff should always be available. On windows however, fc is less powerful and doesn't generate the diffs I want. I am exploring using git diff instead. Since flutter requires git, git diff seems to be a relatively safe dependency.

In the worst case, if the commands for some reason cannot be run successfully, the diff step can be skipped without any material impact on the results of this validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm actually going to remove the diff task from this PR. I'll land a more fully developed version of it in the future. Meanwhile I'd like to get the rest of the PR moving along.

Copy link
Contributor

Choose a reason for hiding this comment

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

This would need to be done before this feature is landed

Copy link
Contributor

Choose a reason for hiding this comment

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

Prefer to inject globals into the constructor

Copy link
Contributor

Choose a reason for hiding this comment

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

If you use printError that will end up with error/red text. I would not spend too much time specifically formatting the errors

Copy link
Contributor

Choose a reason for hiding this comment

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

This is a dangerous pattern because forgetting to clear might lead to future tests passing inadvertently

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll use the setup method to avoid this.

Copy link
Contributor

Choose a reason for hiding this comment

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

out of date comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you link to an example/docs on what structure this is looking for in settings.gradle?

Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this a user-owned file? How can we be sure that it can be safely deleted, and that the parsing will work correctly on valid but differently formatted files?

Copy link
Contributor

Choose a reason for hiding this comment

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

ahh, misread settingsGradle and settingsGradleOutput

Copy link
Contributor

Choose a reason for hiding this comment

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

prefer to write the file all at once, since it is not particularly big and to prevent cases where the tool getting killed would leave a partial file.

Copy link
Contributor

Choose a reason for hiding this comment

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

This seems like a very fragile check. Can you document the structure that you are trying to parse here? Is there any guarantee that this logic will continue to be valid?

@jonahwilliams
Copy link
Contributor

How much of the automation that this PR is doing (reading/writing strings.xml/settings.gradle) is strictly necessary for an initial version of this feature?

I'm concerned that there is actually no good way to parse a settings.gradle (that I am aware of) - writing to user owned files in general is a bit of a trap.

Copy link
Contributor

Choose a reason for hiding this comment

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

The tool should correctly throw errors for permissions into tool exits, so you might only hit a fse if the file is missing.

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you expand on this a little more, what string resources are required, what is the expected format, et cetera

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't the xml parser give you access to names/properties in a way that doesn't require looking at raw lines?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The idea is that I want to maintain the original formatting and comments in the file, and the xml parser consumes all of this and collapses it into a format-less xmldocument/xmlelement. This manual parsing is able to maintain any developer formatting/comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to xml package based system.

@GaryQian
Copy link
Contributor Author

https://gist.github.com/GaryQian/9786e287b3c00406fa3c12fa62a30d7b is a snapshot of the validator before switching away from the RegExp based system for future reference.

Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

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

High level comment to think about what happens when input files are malformed, and what happens when file system operations fail.

Copy link
Member

Choose a reason for hiding this comment

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

nit: Alphabetize.

Copy link
Member

Choose a reason for hiding this comment

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

Should this parameter be @required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This property can be null. If null, it will just use the default templates directory. I can document this.

Copy link
Member

Choose a reason for hiding this comment

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

Should there be a check here that this file exists, or is it already known to exist at this point?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added an _invalidFiles system to report errors like this.

Copy link
Member

Choose a reason for hiding this comment

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

See: ErrorHandlingFileSystem.deleteIfExists

Copy link
Member

Choose a reason for hiding this comment

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

Can these be testWithoutContext?

Copy link
Member

Choose a reason for hiding this comment

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

If this yaml can be provided by users by hand, then there should be tests that the tool does an appropriate throwToolExit when it is malformed.

Copy link
Member

Choose a reason for hiding this comment

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

Same idea here. If settings.gradle is under user control, then it should not crash the tool (from the new code in this PR) if it is malformed, and there should be unit tests of that.

@GaryQian GaryQian requested a review from zanderso February 16, 2021 20:29
@GaryQian
Copy link
Contributor Author

I added systems to track and report file i/o and validity checking. Since this is an optional validator, any errors of this sort are reported in the validation output and are treated as if the check had failed (triggers tool exit)

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

This PR is approaching the point where I don't think I could feasibly review it anymore. If each of the validations is fairly stand-alone - could you stage the PR so that each of them is added in a separate commit.

Copy link
Contributor

Choose a reason for hiding this comment

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

These methods can be made fairly standalone, by having each method individually return its inputs/outputs - then letting the caller be responsible for combining them.

Copy link
Contributor Author

@GaryQian GaryQian Feb 16, 2021

Choose a reason for hiding this comment

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

So I actually want the class to handle the check result internally. I don't really want the caller to be handling the results of the validation directly since there are specific behaviors that should happen based off of the results of each check, which is handled by displayResults. Letting the caller combine/handle the check results directly can easily miss a lot of nuance and result in incorrect recommendations to the developer.

These checks are not intended be run independently of the overall validator class. Making them dependent on the class discourages/prevents this unintended use.

@GaryQian GaryQian force-pushed the splittoolsvalidator branch from 2099347 to 8c25c7c Compare February 16, 2021 21:36
@GaryQian GaryQian force-pushed the splittoolsvalidator branch from 8c25c7c to b24b155 Compare February 16, 2021 21:58
@GaryQian
Copy link
Contributor Author

Restructured commits to have each check added as a separate commit.

Recursive delete directory
@GaryQian GaryQian changed the title flutter_tools: Deferred components setup validator [flutter_tools] Deferred components setup validator Feb 18, 2021
@jonahwilliams
Copy link
Contributor

I'm really concerned about the parsing of the gradle settings file. I would feel more comfortable if we had better parsing, or at least knew what some of the edge cases were?

@GaryQian
Copy link
Contributor Author

Ok, I'll just remove it for this version then. Consider it gone.

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

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

LGTM (if gradle.settings parsing is removed for now)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants