-
Notifications
You must be signed in to change notification settings - Fork 1k
List out of date deps #1553
List out of date deps #1553
Changes from all commits
9faf04b
3596a82
55c928d
7fc577b
2935827
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,7 @@ package main | |
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/json" | ||
"flag" | ||
"fmt" | ||
|
@@ -120,6 +121,13 @@ type outputter interface { | |
MissingFooter() error | ||
} | ||
|
||
// Only a subset of the outputters should be able to output old statuses. | ||
type oldOutputter interface { | ||
OldHeader() error | ||
OldLine(*OldStatus) error | ||
OldFooter() error | ||
} | ||
|
||
type tableOutput struct{ w *tabwriter.Writer } | ||
|
||
func (out *tableOutput) BasicHeader() error { | ||
|
@@ -162,10 +170,31 @@ func (out *tableOutput) MissingFooter() error { | |
return out.w.Flush() | ||
} | ||
|
||
func (out *tableOutput) OldHeader() error { | ||
_, err := fmt.Fprintf(out.w, "PROJECT\tCONSTRAINT\tREVISION\tLATEST\n") | ||
return err | ||
} | ||
|
||
func (out *tableOutput) OldLine(os *OldStatus) error { | ||
_, err := fmt.Fprintf(out.w, | ||
"%s\t%s\t%s\t%s\t\n", | ||
os.ProjectRoot, | ||
os.getConsolidatedConstraint(), | ||
formatVersion(os.Revision), | ||
os.getConsolidatedLatest(shortRev), | ||
) | ||
return err | ||
} | ||
|
||
func (out *tableOutput) OldFooter() error { | ||
return out.w.Flush() | ||
} | ||
|
||
type jsonOutput struct { | ||
w io.Writer | ||
basic []*rawStatus | ||
missing []*MissingStatus | ||
old []*rawOldStatus | ||
} | ||
|
||
func (out *jsonOutput) BasicHeader() error { | ||
|
@@ -196,6 +225,20 @@ func (out *jsonOutput) MissingFooter() error { | |
return json.NewEncoder(out.w).Encode(out.missing) | ||
} | ||
|
||
func (out *jsonOutput) OldHeader() error { | ||
out.old = []*rawOldStatus{} | ||
return nil | ||
} | ||
|
||
func (out *jsonOutput) OldLine(os *OldStatus) error { | ||
out.old = append(out.old, os.marshalJSON()) | ||
return nil | ||
} | ||
|
||
func (out *jsonOutput) OldFooter() error { | ||
return json.NewEncoder(out.w).Encode(out.old) | ||
} | ||
|
||
type dotOutput struct { | ||
w io.Writer | ||
o string | ||
|
@@ -237,7 +280,6 @@ type templateOutput struct { | |
|
||
func (out *templateOutput) BasicHeader() error { return nil } | ||
func (out *templateOutput) BasicFooter() error { return nil } | ||
|
||
func (out *templateOutput) BasicLine(bs *BasicStatus) error { | ||
data := rawStatus{ | ||
ProjectRoot: bs.ProjectRoot, | ||
|
@@ -250,9 +292,14 @@ func (out *templateOutput) BasicLine(bs *BasicStatus) error { | |
return out.tmpl.Execute(out.w, data) | ||
} | ||
|
||
func (out *templateOutput) OldHeader() error { return nil } | ||
func (out *templateOutput) OldFooter() error { return nil } | ||
func (out *templateOutput) OldLine(os *OldStatus) error { | ||
return out.tmpl.Execute(out.w, os) | ||
} | ||
|
||
func (out *templateOutput) MissingHeader() error { return nil } | ||
func (out *templateOutput) MissingFooter() error { return nil } | ||
|
||
func (out *templateOutput) MissingLine(ms *MissingStatus) error { | ||
return out.tmpl.Execute(out.w, ms) | ||
} | ||
|
@@ -288,8 +335,6 @@ func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error { | |
switch { | ||
case cmd.missing: | ||
return errors.Errorf("not implemented") | ||
case cmd.old: | ||
return errors.Errorf("not implemented") | ||
case cmd.json: | ||
out = &jsonOutput{ | ||
w: &buf, | ||
|
@@ -320,6 +365,15 @@ func (cmd *statusCommand) Run(ctx *dep.Ctx, args []string) error { | |
return errors.Errorf("no Gopkg.lock found. Run `dep ensure` to generate lock file") | ||
} | ||
|
||
if cmd.old { | ||
if _, ok := out.(oldOutputter); !ok { | ||
return errors.Errorf("invalid output format used") | ||
} | ||
err = cmd.runOld(ctx, out.(oldOutputter), p, sm) | ||
ctx.Out.Print(buf.String()) | ||
return err | ||
} | ||
|
||
hasMissingPkgs, errCount, err := runStatusAll(ctx, out, p, sm) | ||
if err != nil { | ||
switch err { | ||
|
@@ -387,6 +441,140 @@ func (cmd *statusCommand) validateFlags() error { | |
return nil | ||
} | ||
|
||
// OldStatus contains information about all the out of date packages in a project. | ||
type OldStatus struct { | ||
ProjectRoot string | ||
Constraint gps.Constraint | ||
Revision gps.Revision | ||
Latest gps.Version | ||
} | ||
|
||
type rawOldStatus struct { | ||
ProjectRoot, Constraint, Revision, Latest string | ||
} | ||
|
||
func (os OldStatus) getConsolidatedConstraint() string { | ||
var constraint string | ||
if os.Constraint != nil { | ||
if v, ok := os.Constraint.(gps.Version); ok { | ||
constraint = formatVersion(v) | ||
} else { | ||
constraint = os.Constraint.String() | ||
} | ||
} | ||
return constraint | ||
} | ||
|
||
func (os OldStatus) getConsolidatedLatest(revSize uint8) string { | ||
latest := "" | ||
if os.Latest != nil { | ||
switch revSize { | ||
case shortRev: | ||
latest = formatVersion(os.Latest) | ||
case longRev: | ||
latest = os.Latest.String() | ||
} | ||
} | ||
return latest | ||
} | ||
|
||
func (os OldStatus) marshalJSON() *rawOldStatus { | ||
return &rawOldStatus{ | ||
ProjectRoot: os.ProjectRoot, | ||
Constraint: os.getConsolidatedConstraint(), | ||
Revision: string(os.Revision), | ||
Latest: os.getConsolidatedLatest(longRev), | ||
} | ||
} | ||
|
||
func (cmd *statusCommand) runOld(ctx *dep.Ctx, out oldOutputter, p *dep.Project, sm gps.SourceManager) error { | ||
// While the network churns on ListVersions() requests, statically analyze | ||
// code from the current project. | ||
ptree, err := p.ParseRootPackageTree() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Set up a solver in order to check the InputHash. | ||
params := gps.SolveParameters{ | ||
ProjectAnalyzer: dep.Analyzer{}, | ||
RootDir: p.AbsRoot, | ||
RootPackageTree: ptree, | ||
Manifest: p.Manifest, | ||
// Locks aren't a part of the input hash check, so we can omit it. | ||
} | ||
|
||
logger := ctx.Err | ||
if ctx.Verbose { | ||
params.TraceLogger = ctx.Err | ||
} else { | ||
logger = log.New(ioutil.Discard, "", 0) | ||
} | ||
|
||
// Check update for all the projects. | ||
params.ChangeAll = true | ||
|
||
solver, err := gps.Prepare(params, sm) | ||
if err != nil { | ||
return errors.Wrap(err, "fastpath solver prepare") | ||
} | ||
|
||
logger.Println("Solving dependency graph to determine which dependencies can be updated.") | ||
solution, err := solver.Solve(context.TODO()) | ||
if err != nil { | ||
return errors.Wrap(err, "runOld") | ||
} | ||
|
||
var oldStatuses []OldStatus | ||
solutionProjects := solution.Projects() | ||
|
||
for _, proj := range p.Lock.Projects() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think checking against manifest projects would make more sense, because constraints are defined in manifest. If a project has no constraint in manifest, we don't know the constraint at which to check for latest. Locked projects would contain transitive dependencies too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update: I just realized that this is fine. Below this, we should check if there's an entry in manifest for the solution project before comparing their lock and solution versions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so if there isn't an entry in it's manifest it shouldn't go to the -old output as well right? |
||
for _, sProj := range solutionProjects { | ||
// Look for the same project in solution and lock. | ||
if sProj.Ident().ProjectRoot != proj.Ident().ProjectRoot { | ||
continue | ||
} | ||
|
||
// If revisions are not the same then it is old and we should display it. | ||
latestRev, _, _ := gps.VersionComponentStrings(sProj.Version()) | ||
atRev, _, _ := gps.VersionComponentStrings(proj.Version()) | ||
if atRev == latestRev { | ||
continue | ||
} | ||
|
||
var constraint gps.Constraint | ||
// Getting Constraint. | ||
if pp, has := p.Manifest.Ovr[proj.Ident().ProjectRoot]; has && pp.Constraint != nil { | ||
// manifest has override for project. | ||
constraint = pp.Constraint | ||
} else if pp, has := p.Manifest.Constraints[proj.Ident().ProjectRoot]; has && pp.Constraint != nil { | ||
// manifest has normal constraint. | ||
constraint = pp.Constraint | ||
} else { | ||
// No constraint exists. No need to worry about displaying it. | ||
continue | ||
} | ||
|
||
// Generate the old status data and append it. | ||
os := OldStatus{ | ||
ProjectRoot: proj.Ident().String(), | ||
Revision: gps.Revision(atRev), | ||
Latest: gps.Revision(latestRev), | ||
Constraint: constraint, | ||
} | ||
oldStatuses = append(oldStatuses, os) | ||
} | ||
} | ||
|
||
out.OldHeader() | ||
for _, ostat := range oldStatuses { | ||
out.OldLine(&ostat) | ||
} | ||
out.OldFooter() | ||
|
||
return nil | ||
} | ||
|
||
type rawStatus struct { | ||
ProjectRoot string | ||
Constraint string | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[[constraint]] | ||
name = "github.com/sdboyer/deptestdos" | ||
version = "v2.0.0" | ||
|
||
[[constraint]] | ||
name = "github.com/sdboyer/deptest" | ||
version = "v1.0.0" | ||
|
||
[[constraint]] | ||
name = "github.com/carolynvs/go-dep-test" | ||
version = "v0.1.0" |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[[constraint]] | ||
name = "github.com/sdboyer/deptestdos" | ||
version = "v2.0.0" | ||
|
||
[[constraint]] | ||
name = "github.com/sdboyer/deptest" | ||
version = "v1.0.0" | ||
|
||
[[constraint]] | ||
name = "github.com/carolynvs/go-dep-test" | ||
version = "v0.1.0" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2018 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 main | ||
|
||
import ( | ||
_ "github.com/carolynvs/go-dep-test" | ||
_ "github.com/sdboyer/deptest" | ||
_ "github.com/sdboyer/deptestdos" | ||
) | ||
|
||
func main() { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
PROJECT CONSTRAINT REVISION LATEST | ||
github.com/carolynvs/go-dep-test ^0.1.0 b9c5511 4069198 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"commands": [ | ||
["ensure"], | ||
["status", "-old"] | ||
], | ||
"error-expected": "", | ||
"vendor-final": [ | ||
"github.com/carolynvs/go-dep-test", | ||
"github.com/sdboyer/deptest", | ||
"github.com/sdboyer/deptestdos" | ||
] | ||
} |
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.
Let's add support for log output when
-v
is passed, similar to https://github.com/golang/dep/blob/v0.4.1/cmd/dep/status.go#L445-L449 .Since the solving takes some time, a verbose mode would be good to have to see what's happening.
Also, I think we should add a line telling the user that's it's solving and checking for updates. Right now, there's no message and it waits for long, which could be confusing to the user.