metadata.go (162 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package alzlib
import (
"context"
"fmt"
"io/fs"
"strings"
"github.com/Azure/alzlib/internal/processor"
)
// Metadata is a struct that represents the metadata of a library member.
type Metadata struct {
name string // name of the library member
displayName string // display name of the library member
description string // description of the library member
dependencies LibraryReferences // dependencies of the library member in the form of []LibraryReference
path string // path of the library member within the ALZ Library
ref LibraryReference // reference used to instantiate the library member
}
// LibraryReferences is a slice of LibraryReference.
// This type has methods for convenience.
type LibraryReferences []LibraryReference
// FSs returns the filesystems of the library references, can be used with Alzlib.Init().
func (m LibraryReferences) FSs() []fs.FS {
fss := make([]fs.FS, len(m))
for i, l := range m {
fss[i] = l.FS()
}
return fss
}
// FetchWithDependencies recursively fetches all the library references and their dependencies.
// The destination directory a hash value that will be appended to the `.alzlib` directory in the current working directory unless overridden by the `ALZLIB_DIR` environment variable.
func (m LibraryReferences) FetchWithDependencies(ctx context.Context) (LibraryReferences, error) {
processed := make(map[string]bool)
result := make(LibraryReferences, 0, 5)
for _, lib := range m {
err := fetchLibraryWithDependencies(ctx, processed, lib, &result)
if err != nil {
return nil, err
}
}
return result, nil
}
// LibraryReference is an interface that represents a dependency of a library member.
// It can be fetched form either a custom go-getter URL or from the ALZ Library.
type LibraryReference interface {
fmt.Stringer
Fetch(ctx context.Context, desinationDirectory string) (fs.FS, error) // Fetch fetches the library member to the `.alzlib/destinationDirectory`. Override the base dir using `ALZLIB_DIR` env var.
FetchWithDependencies(ctx context.Context) (LibraryReferences, error) // FetchWithDependencies fetches the library member and its dependencies.
FS() fs.FS // FS returns the filesystem of the library member, can be used in Alzlib.Init()
}
var _ LibraryReference = (*AlzLibraryReference)(nil)
var _ LibraryReference = (*CustomLibraryReference)(nil)
// AlzLibraryReference is a struct that represents a dependency of a library member that is fetched from the ALZ Library.
type AlzLibraryReference struct {
path string
ref string
filesystem fs.FS
}
func NewAlzLibraryReference(path, ref string) *AlzLibraryReference {
return &AlzLibraryReference{
path: path,
ref: ref,
filesystem: nil,
}
}
// Fetch fetches the library member from the ALZ Library.
func (m *AlzLibraryReference) Fetch(ctx context.Context, destinationDirectory string) (fs.FS, error) {
if m.filesystem != nil {
return m.filesystem, nil
}
f, err := FetchAzureLandingZonesLibraryMember(ctx, m.path, m.ref, destinationDirectory)
if err != nil {
return nil, fmt.Errorf("AlzLibraryReference.Fetch: could not fetch library member: %w", err)
}
m.filesystem = f
return f, nil
}
// FS returns the filesystem of the library member.
func (m *AlzLibraryReference) FS() fs.FS {
return m.filesystem
}
// String returns the formatted path and the tag of the library member.
func (m *AlzLibraryReference) String() string {
return strings.Join([]string{m.path, m.ref}, "@")
}
func (m *AlzLibraryReference) Path() string {
return m.path
}
func (m *AlzLibraryReference) Ref() string {
return m.ref
}
// FetchWithDependencies fetches the library member and its dependencies.
// If you have more than one LibraryReference in a LibraryReferences slice, use LibraryReferences.FetchWithDependencies() instead.
func (m *AlzLibraryReference) FetchWithDependencies(ctx context.Context) (LibraryReferences, error) {
processed := make(map[string]bool)
result := make(LibraryReferences, 0, 5)
return result, fetchLibraryWithDependencies(ctx, processed, m, &result)
}
// CustomLibraryReference is a struct that represents a dependency of a library member that is fetched from a custom go-getter URL.
type CustomLibraryReference struct {
url string
filesystem fs.FS
}
func NewCustomLibraryReference(url string) *CustomLibraryReference {
return &CustomLibraryReference{
url: url,
filesystem: nil,
}
}
// Fetch fetches the library member from the custom go-getter URL.
func (m *CustomLibraryReference) Fetch(ctx context.Context, destinationDirectory string) (fs.FS, error) {
if m.filesystem != nil {
return m.filesystem, nil
}
f, err := FetchLibraryByGetterString(ctx, m.url, destinationDirectory)
if err != nil {
return nil, fmt.Errorf("CustomLibraryReference.Fetch: could not fetch library member: %w", err)
}
m.filesystem = f
return f, nil
}
// FS returns the filesystem of the library member.
func (m *CustomLibraryReference) FS() fs.FS {
return m.filesystem
}
// String returns the URL of the custom go-getter.
func (m *CustomLibraryReference) String() string {
return m.url
}
// FetchWithDependencies fetches the library member and its dependencies.
// If you have more than one LibraryReference in a LibraryReferences slice, use LibraryReferences.FetchWithDependencies() instead.
func (m *CustomLibraryReference) FetchWithDependencies(ctx context.Context) (LibraryReferences, error) {
processed := make(map[string]bool)
result := make(LibraryReferences, 0, 5)
return result, fetchLibraryWithDependencies(ctx, processed, m, &result)
}
func NewMetadata(in *processor.LibMetadata, ref LibraryReference) *Metadata {
dependencies := make([]LibraryReference, len(in.Dependencies))
for i, dep := range in.Dependencies {
dependencies[i] = NewMetadataDependencyFromProcessor(dep)
}
return &Metadata{
name: in.Name,
displayName: in.DisplayName,
description: in.Description,
dependencies: dependencies,
path: in.Path,
ref: ref,
}
}
func NewMetadataDependencyFromProcessor(in processor.LibMetadataDependency) LibraryReference {
if in.CustomUrl != "" {
return &CustomLibraryReference{
url: in.CustomUrl,
}
}
return &AlzLibraryReference{
path: in.Path,
ref: in.Ref,
}
}
func (m *Metadata) Name() string {
return m.name
}
func (m *Metadata) DisplayName() string {
return m.displayName
}
func (m *Metadata) Description() string {
return m.description
}
func (m *Metadata) Dependencies() LibraryReferences {
return m.dependencies
}
func (m *Metadata) Path() string {
return m.path
}
func (m *Metadata) IsAlzLibraryRef() bool {
_, ok := m.ref.(*AlzLibraryReference)
return ok
}
func (m *Metadata) Ref() LibraryReference {
return m.ref
}