| // Copyright 2017 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package gps |
| |
| import "github.com/golang/dep/gps/pkgtree" |
| |
| // Manifest represents manifest-type data for a project at a particular version. |
| // The constraints expressed in a manifest determine the set of versions that |
| // are acceptable to try for a given project. |
| // |
| // Expressing a constraint in a manifest does not guarantee that a particular |
| // dependency will be present. It only guarantees that if packages in the |
| // project specified by the dependency are discovered through static analysis of |
| // the (transitive) import graph, then they will conform to the constraint. |
| // |
| // This does entail that manifests can express constraints on projects they do |
| // not themselves import. This is by design, but its implications are complex. |
| // See the gps docs for more information: https://github.com/sdboyer/gps/wiki |
| type Manifest interface { |
| // Returns a list of project-level constraints. |
| DependencyConstraints() ProjectConstraints |
| } |
| |
| // RootManifest extends Manifest to add special controls over solving that are |
| // only afforded to the root project. |
| type RootManifest interface { |
| Manifest |
| |
| // Overrides returns a list of ProjectConstraints that will unconditionally |
| // supersede any ProjectConstraint declarations made in either the root |
| // manifest, or in any dependency's manifest. |
| // |
| // Overrides are a special control afforded only to root manifests. Tool |
| // users should be encouraged to use them only as a last resort; they do not |
| // "play well with others" (that is their express goal), and overreliance on |
| // them can harm the ecosystem as a whole. |
| Overrides() ProjectConstraints |
| |
| // IgnoredPackages returns a pkgtree.IgnoredRuleset, which comprises a set |
| // of import paths, or import path patterns, that are to be ignored during |
| // solving. These ignored import paths can be within the root project, or |
| // part of other projects. Ignoring a package means that both it and its |
| // (unique) imports will be disregarded by all relevant solver operations. |
| // |
| // It is an error to include a package in both the ignored and required |
| // sets. |
| IgnoredPackages() *pkgtree.IgnoredRuleset |
| |
| // RequiredPackages returns a set of import paths to require. These packages |
| // are required to be present in any solution. The list can include main |
| // packages. |
| // |
| // It is meaningless to specify packages that are within the |
| // PackageTree of the ProjectRoot (though not an error, because the |
| // RootManifest itself does not report a ProjectRoot). |
| // |
| // It is an error to include a package in both the ignored and required |
| // sets. |
| RequiredPackages() map[string]bool |
| } |
| |
| // SimpleManifest is a helper for tools to enumerate manifest data. It's |
| // generally intended for ephemeral manifests, such as those Analyzers create on |
| // the fly for projects with no manifest metadata, or metadata through a foreign |
| // tool's idioms. |
| type SimpleManifest struct { |
| Deps ProjectConstraints |
| } |
| |
| var _ Manifest = SimpleManifest{} |
| |
| // DependencyConstraints returns the project's dependencies. |
| func (m SimpleManifest) DependencyConstraints() ProjectConstraints { |
| return m.Deps |
| } |
| |
| // simpleRootManifest exists so that we have a safe value to swap into solver |
| // params when a nil Manifest is provided. |
| type simpleRootManifest struct { |
| c, ovr ProjectConstraints |
| ig *pkgtree.IgnoredRuleset |
| req map[string]bool |
| } |
| |
| func (m simpleRootManifest) DependencyConstraints() ProjectConstraints { |
| return m.c |
| } |
| func (m simpleRootManifest) Overrides() ProjectConstraints { |
| return m.ovr |
| } |
| func (m simpleRootManifest) IgnoredPackages() *pkgtree.IgnoredRuleset { |
| return m.ig |
| } |
| func (m simpleRootManifest) RequiredPackages() map[string]bool { |
| return m.req |
| } |
| |
| // prepManifest ensures a manifest is prepared and safe for use by the solver. |
| // This is mostly about ensuring that no outside routine can modify the manifest |
| // while the solver is in-flight, but it also filters out any empty |
| // ProjectProperties. |
| // |
| // This is achieved by copying the manifest's data into a new SimpleManifest. |
| func prepManifest(m Manifest) SimpleManifest { |
| if m == nil { |
| return SimpleManifest{} |
| } |
| |
| deps := m.DependencyConstraints() |
| |
| rm := SimpleManifest{ |
| Deps: make(ProjectConstraints, len(deps)), |
| } |
| |
| for k, d := range deps { |
| // A zero-value ProjectProperties is equivalent to one with an |
| // anyConstraint{} in terms of how the solver will treat it. However, we |
| // normalize between these two by omitting such instances entirely, as |
| // it negates some possibility for false mismatches in input hashing. |
| if d.Constraint == nil { |
| if d.Source == "" { |
| continue |
| } |
| d.Constraint = anyConstraint{} |
| } |
| |
| rm.Deps[k] = d |
| } |
| |
| return rm |
| } |