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

List out of date deps #1553

Merged
merged 5 commits into from
Mar 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 192 additions & 4 deletions cmd/dep/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package main

import (
"bytes"
"context"
"encoding/json"
"flag"
"fmt"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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)
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.
}
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 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.


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() {
Copy link
Collaborator

Choose a reason for hiding this comment

The 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.

Copy link
Collaborator

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Expand Down
10 changes: 10 additions & 0 deletions cmd/dep/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,16 @@ func TestValidateFlags(t *testing.T) {
cmd: statusCommand{missing: true, old: true},
wantErr: errors.Wrapf(errors.New("cannot pass multiple operating mode flags"), "[-old -missing]"),
},
{
name: "old with -dot",
cmd: statusCommand{dot: true, old: true},
wantErr: errors.New("-dot generates dependency graph; cannot pass other flags"),
},
{
name: "old with template",
cmd: statusCommand{old: true, template: "foo"},
wantErr: nil,
},
}

for _, tc := range testCases {
Expand Down

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"
]
}