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

Commit

Permalink
Merge pull request #1553 from zkry/list-out-of-date-deps
Browse files Browse the repository at this point in the history
List out of date deps
  • Loading branch information
darkowlzz authored Mar 25, 2018
2 parents 89bca42 + 2935827 commit dbbe73b
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 4 deletions.
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.
}

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() {
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"
]
}

0 comments on commit dbbe73b

Please sign in to comment.