1package releasedir
2
3import (
4	"path/filepath"
5
6	"code.cloudfoundry.org/clock"
7	boshblob "github.com/cloudfoundry/bosh-utils/blobstore"
8	bosherr "github.com/cloudfoundry/bosh-utils/errors"
9	boshlog "github.com/cloudfoundry/bosh-utils/logger"
10	boshsys "github.com/cloudfoundry/bosh-utils/system"
11	boshuuid "github.com/cloudfoundry/bosh-utils/uuid"
12
13	bicrypto "github.com/cloudfoundry/bosh-cli/crypto"
14	boshrel "github.com/cloudfoundry/bosh-cli/release"
15	boshidx "github.com/cloudfoundry/bosh-cli/releasedir/index"
16	boshcrypto "github.com/cloudfoundry/bosh-utils/crypto"
17)
18
19type Provider struct {
20	indexReporter        boshidx.Reporter
21	releaseIndexReporter ReleaseIndexReporter
22	blobsReporter        BlobsDirReporter
23	releaseProvider      boshrel.Provider
24	digestCalculator     bicrypto.DigestCalculator
25
26	cmdRunner              boshsys.CmdRunner
27	uuidGen                boshuuid.Generator
28	timeService            clock.Clock
29	fs                     boshsys.FileSystem
30	logger                 boshlog.Logger
31	digestCreateAlgorithms []boshcrypto.Algorithm
32}
33
34func NewProvider(
35	indexReporter boshidx.Reporter,
36	releaseIndexReporter ReleaseIndexReporter,
37	blobsReporter BlobsDirReporter,
38	releaseProvider boshrel.Provider,
39	digestCalculator bicrypto.DigestCalculator,
40	cmdRunner boshsys.CmdRunner,
41	uuidGen boshuuid.Generator,
42	timeService clock.Clock,
43	fs boshsys.FileSystem,
44	digestCreateAlgorithms []boshcrypto.Algorithm,
45	logger boshlog.Logger,
46) Provider {
47	return Provider{
48		indexReporter:          indexReporter,
49		releaseIndexReporter:   releaseIndexReporter,
50		blobsReporter:          blobsReporter,
51		releaseProvider:        releaseProvider,
52		digestCalculator:       digestCalculator,
53		cmdRunner:              cmdRunner,
54		uuidGen:                uuidGen,
55		timeService:            timeService,
56		fs:                     fs,
57		digestCreateAlgorithms: digestCreateAlgorithms,
58		logger:                 logger,
59	}
60}
61
62func (p Provider) NewFSReleaseDir(dirPath string, parallel int) FSReleaseDir {
63	gitRepo := NewFSGitRepo(dirPath, p.cmdRunner, p.fs)
64	blobsDir := p.NewFSBlobsDir(dirPath)
65	generator := NewFSGenerator(dirPath, p.fs)
66
67	devRelsPath := filepath.Join(dirPath, "dev_releases")
68	devReleases := NewFSReleaseIndex("dev", devRelsPath, p.releaseIndexReporter, p.uuidGen, p.fs)
69
70	finalRelsPath := filepath.Join(dirPath, "releases")
71	finalReleases := NewFSReleaseIndex("final", finalRelsPath, p.releaseIndexReporter, p.uuidGen, p.fs)
72
73	indiciesProvider := boshidx.NewProvider(p.indexReporter, p.newBlobstore(dirPath), p.fs)
74	_, finalIndex := indiciesProvider.DevAndFinalIndicies(dirPath)
75
76	releaseReader := p.NewReleaseReader(dirPath, parallel)
77
78	return NewFSReleaseDir(
79		dirPath,
80		p.newConfig(dirPath),
81		gitRepo,
82		blobsDir,
83		generator,
84		devReleases,
85		finalReleases,
86		finalIndex,
87		releaseReader,
88		p.timeService,
89		p.fs,
90		parallel,
91	)
92}
93
94func (p Provider) NewFSBlobsDir(dirPath string) FSBlobsDir {
95	return NewFSBlobsDir(dirPath, p.blobsReporter, p.newBlobstore(dirPath), p.digestCalculator, p.fs, p.logger)
96}
97
98func (p Provider) NewReleaseReader(dirPath string, parallel int) boshrel.BuiltReader {
99	multiReader := p.releaseProvider.NewMultiReader(dirPath)
100	indiciesProvider := boshidx.NewProvider(p.indexReporter, p.newBlobstore(dirPath), p.fs)
101	devIndex, finalIndex := indiciesProvider.DevAndFinalIndicies(dirPath)
102	return boshrel.NewBuiltReader(multiReader, devIndex, finalIndex, parallel)
103}
104
105func (p Provider) newBlobstore(dirPath string) boshblob.DigestBlobstore {
106	provider, options, err := p.newConfig(dirPath).Blobstore()
107	if err != nil {
108		return NewErrBlobstore(err)
109	}
110
111	var blobstore boshblob.Blobstore
112
113	switch provider {
114	case "local":
115		blobstore = boshblob.NewLocalBlobstore(p.fs, p.uuidGen, options)
116	case "s3":
117		blobstore = NewS3Blobstore(p.fs, p.uuidGen, options)
118	case "gcs":
119		blobstore = NewGCSBlobstore(p.fs, p.uuidGen, options)
120	default:
121		return NewErrBlobstore(bosherr.Error("Expected release blobstore to be configured"))
122	}
123
124	digestBlobstore := boshblob.NewDigestVerifiableBlobstore(blobstore, p.fs, p.digestCreateAlgorithms)
125	digestBlobstore = boshblob.NewRetryableBlobstore(digestBlobstore, 3, p.logger)
126
127	err = digestBlobstore.Validate()
128	if err != nil {
129		return NewErrBlobstore(err)
130	}
131
132	return digestBlobstore
133}
134
135func (p Provider) newConfig(dirPath string) FSConfig {
136	publicPath := filepath.Join(dirPath, "config", "final.yml")
137	privatePath := filepath.Join(dirPath, "config", "private.yml")
138	return NewFSConfig(publicPath, privatePath, p.fs)
139}
140