blob: b820278fb6ca3147a16d7a0b861c928dd246f069 [file]
// Copyright 2020 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package plugsupport
import (
"context"
"infra/tools/migrator"
"sync"
"github.com/golang/protobuf/proto"
"go.chromium.org/luci/common/errors"
lucipb "go.chromium.org/luci/common/proto"
"go.chromium.org/luci/config/cfgclient"
)
// remoteProject implements the migrator.Project interface for a remote LUCI
// project (i.e. sourced via luci-config APIs).
type remoteProject struct {
id migrator.ReportID
ctx context.Context
configsOnce sync.Once
configsErr error
configs map[string]migrator.ConfigFile
}
// RemoteProject returns a new migrator.Project object for `projID`.
func RemoteProject(ctx context.Context, projID string) migrator.Project {
return &remoteProject{
id: migrator.ReportID{Project: projID},
ctx: ctx,
}
}
func (p *remoteProject) ID() string { return p.id.Project }
func (p *remoteProject) ConfigFiles() map[string]migrator.ConfigFile {
p.configsOnce.Do(func() {
var files []string
files, p.configsErr = cfgclient.Client(p.ctx).ListFiles(p.ctx, p.id.ConfigSet())
if p.configsErr == nil {
p.configs = make(map[string]migrator.ConfigFile, len(files))
for _, file := range files {
p.configs[file] = &remoteConfigFile{
id: migrator.ReportID{
Project: p.id.Project,
ConfigFile: file,
},
ctx: p.ctx,
}
}
}
})
if p.configsErr != nil {
panic(p.configsErr)
}
return p.configs
}
func (p *remoteProject) Report(tag, description string, opts ...migrator.ReportOption) {
getReportSink(p.ctx).add(p.id, tag, description, opts...)
}
// remoteConfigFile holds a single configuration file and its metadata.
type remoteConfigFile struct {
id migrator.ReportID
ctx context.Context
rawDataOnce sync.Once
rawDataErr error
rawData string
}
func (c *remoteConfigFile) Path() string { return c.id.ConfigFile }
func (c *remoteConfigFile) RawData() string {
c.rawDataOnce.Do(func() {
c.rawDataErr = cfgclient.Get(
c.ctx, c.id.ConfigSet(),
c.id.ConfigFile, cfgclient.String(&c.rawData), nil)
})
if c.rawDataErr != nil {
panic(c.rawDataErr)
}
return c.rawData
}
func (c *remoteConfigFile) TextPb(out proto.Message) {
if err := lucipb.UnmarshalTextML(c.RawData(), out); err != nil {
panic(errors.Annotate(err, "parsing TEXTPB: %s", c.id).Err())
}
}
func (c *remoteConfigFile) Report(tag, description string, opts ...migrator.ReportOption) {
getReportSink(c.ctx).add(c.id, tag, description, opts...)
}