experimental/repositories.go (133 lines of code) (raw):
package experimental
import (
"fmt"
"io"
"os"
"strings"
"sync"
"github.com/Sirupsen/logrus"
)
type repositoriesData map[string]*repositoryData
var repositoriesLock sync.Mutex
func (r repositoriesData) get(path []string) *repositoryData {
repositoryName := strings.Join(path, "/")
repositoriesLock.Lock()
defer repositoriesLock.Unlock()
repository := r[repositoryName]
if repository == nil {
repository = newRepositoryData(repositoryName)
r[repositoryName] = repository
}
return repository
}
func (r repositoriesData) process(segments []string, info fileInfo) error {
for idx := 0; idx < len(segments)-1; idx++ {
repository := segments[0:idx]
args := segments[idx+1:]
switch segments[idx] {
case "_layers":
return r.get(repository).addLayer(args, info)
case "_manifests":
return r.get(repository).addManifest(args, info)
case "_uploads":
return r.get(repository).addUpload(args, info)
}
}
return fmt.Errorf("unparseable path: %v", segments)
}
func (r repositoriesData) walkPath(walkPath string, jg *jobGroup) error {
logrus.Infoln("REPOSITORIES DIR:", walkPath)
return currentStorage.Walk(walkPath, "repositories", func(path string, info fileInfo, err error) error {
jg.dispatch(func() error {
err = r.process(strings.Split(path, "/"), info)
if err != nil {
if err != nil {
logrus.Errorln("REPOSITORY:", path, ":", err)
if *softErrors {
return nil
}
} else {
logrus.Infoln("REPOSITORY:", path, ":", err)
}
return err
}
return nil
})
return nil
})
}
func (r repositoriesData) walk(parallel bool) error {
logrus.Infoln("Walking REPOSITORIES...")
jg := jobsRunner.group()
if parallel {
err := parallelWalk("repositories", func(listPath string) error {
return r.walkPath(listPath, jg)
})
if err != nil {
return err
}
} else {
err := r.walkPath("repositories", jg)
if err != nil {
return err
}
}
return jg.finish()
}
func (r repositoriesData) mark(blobs blobsData) error {
jg := jobsRunner.group()
for _, repository_ := range r {
repository := repository_
jg.dispatch(func() error {
return repository.mark(blobs)
})
}
err := jg.finish()
if err != nil {
return err
}
return nil
}
func (r repositoriesData) sweep() error {
jg := jobsRunner.group()
for _, repository_ := range r {
repository := repository_
jg.dispatch(func() error {
return repository.sweep()
})
}
err := jg.finish()
if err != nil {
return err
}
return nil
}
func (r repositoriesData) info(blobs blobsData, csvOutput string) {
var stream io.WriteCloser
if csvOutput != "" {
var err error
stream, err = os.Create(csvOutput)
if err == nil {
defer stream.Close()
labels := []string{
"Repository",
"Tags",
"TagVersions",
"Manifests",
"ManifestsUnused",
"Layers",
"LayersUnused",
"Data",
"DataUnused",
"Data-MB",
"DataUnused-MB",
}
fmt.Fprintln(stream, strings.Join(labels, ","))
} else {
logrus.Warningln(err)
}
}
for _, repository := range r {
repository.info(blobs, stream)
}
}