blob: 26a1dade8989e7e9d7b13b0ab0173b23088c2065 [file] [log] [blame]
// Copyright 2023 The Fuchsia 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 proto
import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"os/exec"
"path/filepath"
"strings"
"go.fuchsia.dev/infra/cmd/roller-configurator/jiri"
)
func (s *GitSubmodule) url(ctx context.Context, repoRoot string) (string, error) {
gitmodules := filepath.Join(repoRoot, ".gitmodules")
if _, err := os.Stat(gitmodules); err != nil {
return "", fmt.Errorf("no .gitmodules file in repository root")
}
// TODO(olivernewman): Run `git config --list` once to get all submodule
// info and cache the result instead of running a subprocess for every
// submodule.
cmd := exec.CommandContext(ctx, "git", "config", "--list", "--file", gitmodules)
var stdout, stderr strings.Builder
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
var suffix string
if stderr.Len() > 0 {
suffix = fmt.Sprintf(": %s", stderr.String())
}
return "", fmt.Errorf("%w%s", err, suffix)
}
for _, line := range strings.Split(strings.TrimSpace(stdout.String()), "\n") {
key, val, ok := strings.Cut(line, "=")
if !ok {
return "", fmt.Errorf("invalid `git config --list --file .gitmodules` line: %q", line)
}
// Assumes the submodule's path is the same as its name.
if key == fmt.Sprintf("submodule.%s.url", s.GetPath()) {
return val, nil
}
}
return "", fmt.Errorf("no such submodule %q listed in .gitmodules", s.GetPath())
}
func (s *GitSubmodule) Validate(ctx context.Context, repoRoot string) error {
_, err := s.url(ctx, repoRoot)
return err
}
func (c *CIPDEnsureFile) Validate(ctx context.Context, repoRoot string) error {
if _, err := os.Stat(filepath.Join(repoRoot, c.Path)); err != nil {
return fmt.Errorf("no such file: %s", c.Path)
}
return nil
}
func (p *JiriProject) Validate(ctx context.Context, repoRoot string) error {
_, err := p.manifestEntry(repoRoot)
return err
}
func (p *JiriProject) manifestEntry(repoRoot string) (jiri.Project, error) {
manifest, err := jiri.LoadManifest(filepath.Join(repoRoot, p.Manifest))
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
err = fmt.Errorf("no such file: %s", p.Manifest)
}
return jiri.Project{}, err
}
for _, proj := range manifest.Projects {
if proj.Name == p.Project {
return proj, nil
}
}
return jiri.Project{}, fmt.Errorf("no project %q in manifest %q", p.Project, p.Manifest)
}
func (p *JiriPackages) Validate(ctx context.Context, repoRoot string) error {
_, err := p.manifestEntries(repoRoot)
return err
}
func (p *JiriPackages) manifestEntries(repoRoot string) ([]jiri.Package, error) {
var entries []jiri.Package
for _, m := range p.Manifests {
manifest, err := jiri.LoadManifest(filepath.Join(repoRoot, m.Path))
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
err = fmt.Errorf("no such file: %s", m.Path)
}
return nil, err
}
for _, pkg := range m.Packages {
var found bool
for _, entry := range manifest.Packages {
if entry.Name == pkg {
entries = append(entries, entry)
found = true
}
}
if !found {
return nil, fmt.Errorf("no package %q in manifest %q", pkg, m.Path)
}
}
}
return entries, nil
}