Skip to content
This repository was archived by the owner on Sep 9, 2020. It is now read-only.

[WIP] Report Ineffectual Rules #1494

Closed

Conversation

JackyChiu
Copy link
Contributor

@JackyChiu JackyChiu commented Dec 29, 2017

What does this do / why do we need it?

Report ineffectual rules found in the manifest. This happens on dep ensure.

Did this by:

  • Refactoring the getDirectDependinces method to be a part of the Project struct
  • Adding a validation method that reports for ineffectual constraints and ignored packages
  • Calling the validation in ensure and status commands

Would like some intermediate feedback before I start writing the tests and fixing a bunch of tests

What should your reviewer look out for in this PR?

  • Implementation
  • Am I reporting in the right place?
  • Am I reporting the right ineffectual rules?
  • Is the error message clear?

Do you need help or clarification on anything?

Which issue(s) does this PR fix?

fixes #302

@darkowlzz
Copy link
Collaborator

[NOT A REVIEW]
Please add this to the changelog.

And also, I think we would like to have this warning in ensure only, not in status. Could make status annoying. We had some discussion about it sometime back.

Copy link
Collaborator

@darkowlzz darkowlzz left a comment

Choose a reason for hiding this comment

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

Looks to be in the right direction.
We would also need integration tests for this.

manifest.go Outdated
@@ -33,6 +33,7 @@ var (
errInvalidMetadata = errors.New("metadata should be a TOML table")

errInvalidProjectRoot = errors.New("ProjectRoot name validation failed")
errInefficientRules = errors.New("Inefficient rules found in the manifest")
Copy link
Collaborator

Choose a reason for hiding this comment

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

errors should start with lowercase, unless they are some special term, like ProjectRoot.

manifest.go Outdated
@@ -324,6 +325,78 @@ func ValidateProjectRoots(c *Ctx, m *Manifest, sm gps.SourceManager) error {
return valErr
}

// ValidatePackageRules ensure that there are no ineffectual package declarations
// in the constraints, overrides, required, and ignored rules in the manifest.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't think we should do this with required and ignored, because they can be used to include and ignore packages that are not part of root project code or not directly reachable by the root project.

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 reread the spec for required and I agree it shouldn't/ be applied in this case.

But for ignored I can see value in letting you know that one of the packages in that rule isn't being imported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let me know where we'd like to go with this when you get a chance!

manifest.go Outdated
}
}

// Check overrides as well
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's have proper sentences with a period at the end for all the comments :) We are doing it as much as possible for all the new code.

- casing in error message
- whole sentences in comments
- remove merging or required packages
- omit underscore values in ranges
@JackyChiu JackyChiu force-pushed the warn_for_ignored_constraints branch from ee72b5f to 29857b2 Compare January 4, 2018 02:38
@JackyChiu
Copy link
Contributor Author

I'd like one more persons feedback before I get started on the tests please 😄

manifest.go Outdated
@@ -324,6 +325,71 @@ func ValidateProjectRoots(c *Ctx, m *Manifest, sm gps.SourceManager) error {
return valErr
}

// ValidatePackageRules ensure that there are no ineffectual package declarations
// in the constraints, overrides, and ignored rules in the manifest.
func ValidatePackageRules(c *Ctx, proj *Project, sm gps.SourceManager) (err error) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

What about separating responsibilities here by dropping the c *Ctx argument and instead returning an extended errInefficientRules error that knows how to print itself the same way?

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 like the idea, of dropping Ctx, but to clarify do you mean appending more lines to the errInefficentRules before returning it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was thinking expand var errInefficentRules error from a single static error instance to something like type errInefficentRules struct{constraints, ignores []gps.ProjectRoot} with an Error() string method (which e.g. builds a string via bytes.Buffer rather than logging). So, essentially the same result as adding lines to errInefficentRules before returning, but underneath it would actually be deferred until the error is printed.

Copy link
Collaborator

Choose a reason for hiding this comment

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

^ This would also set us up to potentially export errInefficentRules and its fields later on, giving callers even more flexibility when interpreting and handling the error.

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 that sounds pretty good to me, will do

manifest.go Outdated

// FindIneffectualConstraints looks for constraints decleared in the project
// manifest that aren't directly used in the project.
func FindIneffectualConstraints(m *Manifest, directDeps map[string]bool) []gps.ProjectRoot {
Copy link
Collaborator

Choose a reason for hiding this comment

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

It looks like the FindIneffectual* functions don't need to be exported, is there a compelling reason to export them?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They don't need to be, I'll fix that

- move display string logic in errInefficientRules.Error()
- remove Ctx from ValidatePackageRules
- unexport FindIneffectual* funcs
@JackyChiu
Copy link
Contributor Author

@darkowlzz @jmank88 should we get rid of checking for ignores as a part of the validation?

Also I'll have to open up a new PR to fix the current integration tests, many of them call ensure and have unimported constraints :/. Or is there a better way of doing this?

@darkowlzz
Copy link
Collaborator

Sorry for the delay. I have new thoughts now:

About ineffectual required, we can do it but it's not the same as ineffectual constraint. required and ignored are package based and constraint is project based. So your previous implementation would need some tweaking.

If a project is a transitive dependency, the project would have an entry in the lock file with all the subpackages of it that are needed for the main project to build. Adding a required for any package in this project would result in ineffectual required if the package already exists in the packages list in the lock. I'm talking about this packages list from lock, to make it clear

[[projects]]
  name = "github.com/golang/dep"
  packages = [
    ".",
    "cmd/dep",
    "internal/feedback",
    "internal/fs",
    "internal/gps",
    "internal/gps/internal/pb",
    "internal/gps/paths",
    "internal/gps/pkgtree",
    "internal/importers",
    "internal/importers/base",
    "internal/importers/glide",
    "internal/importers/godep",
    "internal/importers/govend",
    "internal/importers/gvt",
    "internal/importers/vndr"
  ]
  revision = "8ddfc8afb2d520d41997ebddd921b52152706c01"
  version = "v0.3.2"

Also, given a manifest and lock, it's difficult to tell if a given project is in the lock due to the required package in manifest or if it's a transitive dependency. I think a solve without applying required would help answer this. But as you can see, finding ineffectual for required is not as simple as for constraints with only reachability check.
So, I would recommend to keep this PR for ineffectual constrains only for now. We can work on ineffectual required later separately.

Addressing one of your old comments:

But for ignored I can see value in letting you know that one of the packages in that rule isn't being imported.

ignored isn't about the current project. ignored could be anything that's never imported in the main project. So, to answer your recent question

should we get rid of checking for ignores as a part of the validation?

yes, let's not do it and focus on ineffectual constraints only.

Also, let's change ValidatePackageRules to have "Project" or "Constraint" in the name. Package is only for required and ignored, constraint is project based.

Also I'll have to open up a new PR to fix the current integration tests, many of them call ensure and have unimported constraints :/. Or is there a better way of doing this?

I would recommend building clean sets of changes as multiple commits and squashing your existing commits to cleanup. Keeping new implementation, old test fixes and new test changes into cleanly separated commits would help while reviewing and avoid failing tests across PRs. I like commits that build stories :)

@darkowlzz
Copy link
Collaborator

Thoughts about ineffectual ignores:

ignored is very different from required or constraint. It defines what we want dep to not see in the dep graph, resulting in no static analysis of that package. An ignore would be ineffectual if an ignore is already covered by another ignore. Say we have github.com/foo/bar/pkgA* and github.com/foo/bar/pkgA/pkgAx in ignored. In this case, the first ignore covers the second ignore and that makes the second ignore ineffectual. This is one way in which we can find ineffectual ignores.

Another way in which an ignore would be ineffectual is if the ignored package is not part of root project, direct dependency or transitive dependency. A totally unrelated package would also be an ineffectual ignore.

Leaving the idea here, we can do it as a separate PR in the future.

@JackyChiu
Copy link
Contributor Author

@darkowlzz sounds good, thanks for explaining!

@sdboyer sdboyer added this to the v0.4.0 milestone Jan 16, 2018
Copy link
Member

@sdboyer sdboyer left a comment

Choose a reason for hiding this comment

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

sorry, there's a couple too many things here - in particular, getDirectDependencies is actually the wrong implementation to be using here - that should only be used by init, as-written.

i'm going to close this in favor of my PR, #1534

return nil
}

// findIneffectualConstraints looks for constraints decleared in the project
Copy link
Member

Choose a reason for hiding this comment

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

decleared

@@ -324,6 +324,90 @@ func ValidateProjectRoots(c *Ctx, m *Manifest, sm gps.SourceManager) error {
return valErr
}

type errInefficientRules struct {
Copy link
Member

Choose a reason for hiding this comment

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

ineffectual, not inefficient

return ineffectuals
}

// findIneffectualIgnores looks for ignored packages decleared in the project
Copy link
Member

Choose a reason for hiding this comment

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

declared


// findIneffectualIgnores looks for ignored packages decleared in the project
// manifest that aren't directly used in the project.
func findIneffectualIgnores(m *Manifest, directDeps map[string]bool) []gps.ProjectRoot {
Copy link
Member

Choose a reason for hiding this comment

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

not possible to determine if ignores are ineffectual at this point

@sdboyer sdboyer closed this Jan 16, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Report when manifests contain ineffectual constraints
5 participants