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 #716 from jmank88/unexport_prune_project
Browse files Browse the repository at this point in the history
unexport and re-locate PruneProject and helpers
  • Loading branch information
darkowlzz authored Jul 13, 2017
2 parents 7b002ae + 1477ab9 commit fc00707
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 161 deletions.
130 changes: 129 additions & 1 deletion cmd/dep/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ package main
import (
"bytes"
"flag"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
"strings"

"github.com/golang/dep"
"github.com/golang/dep/internal/fs"
"github.com/golang/dep/internal/gps"
"github.com/golang/dep/internal/gps/pkgtree"
"github.com/pkg/errors"
Expand Down Expand Up @@ -80,5 +86,127 @@ func (cmd *pruneCommand) Run(ctx *dep.Ctx, args []string) error {
if ctx.Verbose {
pruneLogger = ctx.Err
}
return dep.PruneProject(p, sm, pruneLogger)
return pruneProject(p, sm, pruneLogger)
}

// pruneProject removes unused packages from a project.
func pruneProject(p *dep.Project, sm gps.SourceManager, logger *log.Logger) error {
td, err := ioutil.TempDir(os.TempDir(), "dep")
if err != nil {
return errors.Wrap(err, "error while creating temp dir for writing manifest/lock/vendor")
}
defer os.RemoveAll(td)

if err := gps.WriteDepTree(td, p.Lock, sm, true); err != nil {
return err
}

var toKeep []string
for _, project := range p.Lock.Projects() {
projectRoot := string(project.Ident().ProjectRoot)
for _, pkg := range project.Packages() {
toKeep = append(toKeep, filepath.Join(projectRoot, pkg))
}
}

toDelete, err := calculatePrune(td, toKeep, logger)
if err != nil {
return err
}

if logger != nil {
if len(toDelete) > 0 {
logger.Println("Calculated the following directories to prune:")
for _, d := range toDelete {
logger.Printf(" %s\n", d)
}
} else {
logger.Println("No directories found to prune")
}
}

if err := deleteDirs(toDelete); err != nil {
return err
}

vpath := filepath.Join(p.AbsRoot, "vendor")
vendorbak := vpath + ".orig"
var failerr error
if _, err := os.Stat(vpath); err == nil {
// Move out the old vendor dir. just do it into an adjacent dir, to
// try to mitigate the possibility of a pointless cross-filesystem
// move with a temp directory.
if _, err := os.Stat(vendorbak); err == nil {
// If the adjacent dir already exists, bite the bullet and move
// to a proper tempdir.
vendorbak = filepath.Join(td, "vendor.orig")
}
failerr = fs.RenameWithFallback(vpath, vendorbak)
if failerr != nil {
goto fail
}
}

// Move in the new one.
failerr = fs.RenameWithFallback(td, vpath)
if failerr != nil {
goto fail
}

os.RemoveAll(vendorbak)

return nil

fail:
fs.RenameWithFallback(vendorbak, vpath)
return failerr
}

func calculatePrune(vendorDir string, keep []string, logger *log.Logger) ([]string, error) {
if logger != nil {
logger.Println("Calculating prune. Checking the following packages:")
}
sort.Strings(keep)
toDelete := []string{}
err := filepath.Walk(vendorDir, func(path string, info os.FileInfo, err error) error {
if _, err := os.Lstat(path); err != nil {
return nil
}
if !info.IsDir() {
return nil
}
if path == vendorDir {
return nil
}

name := strings.TrimPrefix(path, vendorDir+string(filepath.Separator))
if logger != nil {
logger.Printf(" %s", name)
}
i := sort.Search(len(keep), func(i int) bool {
return name <= keep[i]
})
if i >= len(keep) || !strings.HasPrefix(keep[i], name) {
toDelete = append(toDelete, path)
}
return nil
})
return toDelete, err
}

func deleteDirs(toDelete []string) error {
// sort by length so we delete sub dirs first
sort.Sort(byLen(toDelete))
for _, path := range toDelete {
if err := os.RemoveAll(path); err != nil {
return err
}
}
return nil
}

type byLen []string

func (a byLen) Len() int { return len(a) }
func (a byLen) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byLen) Less(i, j int) bool { return len(a[i]) > len(a[j]) }
46 changes: 46 additions & 0 deletions cmd/dep/prune_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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 main

import (
"path/filepath"
"reflect"
"sort"
"testing"

"github.com/golang/dep/internal/test"
)

func TestCalculatePrune(t *testing.T) {
h := test.NewHelper(t)
defer h.Cleanup()

vendorDir := "vendor"
h.TempDir(vendorDir)
h.TempDir(filepath.Join(vendorDir, "github.com/keep/pkg/sub"))
h.TempDir(filepath.Join(vendorDir, "github.com/prune/pkg/sub"))

toKeep := []string{
filepath.FromSlash("github.com/keep/pkg"),
filepath.FromSlash("github.com/keep/pkg/sub"),
}

got, err := calculatePrune(h.Path(vendorDir), toKeep, nil)
if err != nil {
t.Fatal(err)
}

sort.Sort(byLen(got))

want := []string{
h.Path(filepath.Join(vendorDir, "github.com/prune/pkg/sub")),
h.Path(filepath.Join(vendorDir, "github.com/prune/pkg")),
h.Path(filepath.Join(vendorDir, "github.com/prune")),
}

if !reflect.DeepEqual(want, got) {
t.Fatalf("calculated prune paths are not as expected.\n(WNT) %s\n(GOT) %s", want, got)
}
}
125 changes: 0 additions & 125 deletions txn_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"log"
"os"
"path/filepath"
"sort"
"strings"

"github.com/golang/dep/internal/fs"
"github.com/golang/dep/internal/gps"
Expand Down Expand Up @@ -457,132 +455,9 @@ func (sw *SafeWriter) PrintPreparedActions(output *log.Logger) error {
return nil
}

// PruneProject removes unused packages from a project.
func PruneProject(p *Project, sm gps.SourceManager, logger *log.Logger) error {
td, err := ioutil.TempDir(os.TempDir(), "dep")
if err != nil {
return errors.Wrap(err, "error while creating temp dir for writing manifest/lock/vendor")
}
defer os.RemoveAll(td)

if err := gps.WriteDepTree(td, p.Lock, sm, true); err != nil {
return err
}

var toKeep []string
for _, project := range p.Lock.Projects() {
projectRoot := string(project.Ident().ProjectRoot)
for _, pkg := range project.Packages() {
toKeep = append(toKeep, filepath.Join(projectRoot, pkg))
}
}

toDelete, err := calculatePrune(td, toKeep, logger)
if err != nil {
return err
}

if logger != nil {
if len(toDelete) > 0 {
logger.Println("Calculated the following directories to prune:")
for _, d := range toDelete {
logger.Printf(" %s\n", d)
}
} else {
logger.Println("No directories found to prune")
}
}

if err := deleteDirs(toDelete); err != nil {
return err
}

vpath := filepath.Join(p.AbsRoot, "vendor")
vendorbak := vpath + ".orig"
var failerr error
if _, err := os.Stat(vpath); err == nil {
// Move out the old vendor dir. just do it into an adjacent dir, to
// try to mitigate the possibility of a pointless cross-filesystem
// move with a temp directory.
if _, err := os.Stat(vendorbak); err == nil {
// If the adjacent dir already exists, bite the bullet and move
// to a proper tempdir.
vendorbak = filepath.Join(td, "vendor.orig")
}
failerr = fs.RenameWithFallback(vpath, vendorbak)
if failerr != nil {
goto fail
}
}

// Move in the new one.
failerr = fs.RenameWithFallback(td, vpath)
if failerr != nil {
goto fail
}

os.RemoveAll(vendorbak)

return nil

fail:
fs.RenameWithFallback(vendorbak, vpath)
return failerr
}

// calculatePrune returns the paths of the packages to be deleted from vendorDir.
func calculatePrune(vendorDir string, keep []string, logger *log.Logger) ([]string, error) {
if logger != nil {
logger.Println("Calculating prune. Checking the following packages:")
}
sort.Strings(keep)
toDelete := []string{}
err := filepath.Walk(vendorDir, func(path string, info os.FileInfo, err error) error {
if _, err := os.Lstat(path); err != nil {
return nil
}
if !info.IsDir() {
return nil
}
if path == vendorDir {
return nil
}

name := strings.TrimPrefix(path, vendorDir+string(filepath.Separator))
if logger != nil {
logger.Printf(" %s", name)
}
i := sort.Search(len(keep), func(i int) bool {
return name <= keep[i]
})
if i >= len(keep) || !strings.HasPrefix(keep[i], name) {
toDelete = append(toDelete, path)
}
return nil
})
return toDelete, err
}

func deleteDirs(toDelete []string) error {
// sort by length so we delete sub dirs first
sort.Sort(byLen(toDelete))
for _, path := range toDelete {
if err := os.RemoveAll(path); err != nil {
return err
}
}
return nil
}

// hasDotGit checks if a given path has .git file or directory in it.
func hasDotGit(path string) bool {
gitfilepath := filepath.Join(path, ".git")
_, err := os.Stat(gitfilepath)
return err == nil
}

type byLen []string

func (a byLen) Len() int { return len(a) }
func (a byLen) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byLen) Less(i, j int) bool { return len(a[i]) > len(a[j]) }
35 changes: 0 additions & 35 deletions txn_writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,9 @@ import (
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"testing"

"reflect"

"github.com/golang/dep/internal/test"
"github.com/pkg/errors"
)
Expand Down Expand Up @@ -570,35 +567,3 @@ func TestSafeWriter_VendorDotGitPreservedWithForceVendor(t *testing.T) {
t.Fatal(err)
}
}

func TestCalculatePrune(t *testing.T) {
h := test.NewHelper(t)
defer h.Cleanup()

vendorDir := "vendor"
h.TempDir(vendorDir)
h.TempDir(filepath.Join(vendorDir, "github.com/keep/pkg/sub"))
h.TempDir(filepath.Join(vendorDir, "github.com/prune/pkg/sub"))

toKeep := []string{
filepath.FromSlash("github.com/keep/pkg"),
filepath.FromSlash("github.com/keep/pkg/sub"),
}

got, err := calculatePrune(h.Path(vendorDir), toKeep, nil)
if err != nil {
t.Fatal(err)
}

sort.Sort(byLen(got))

want := []string{
h.Path(filepath.Join(vendorDir, "github.com/prune/pkg/sub")),
h.Path(filepath.Join(vendorDir, "github.com/prune/pkg")),
h.Path(filepath.Join(vendorDir, "github.com/prune")),
}

if !reflect.DeepEqual(want, got) {
t.Fatalf("calculated prune paths are not as expected.\n(WNT) %s\n(GOT) %s", want, got)
}
}

0 comments on commit fc00707

Please sign in to comment.