tooling/pipeline-documentation/cmd/overview/options.go (83 lines of code) (raw):
// Copyright 2025 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package overview
import (
"fmt"
"io"
"os"
"path/filepath"
"github.com/Azure/ARO-Tools/pkg/topology"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
"github.com/Azure/ARO-HCP/tooling/pipeline-documentation/pkg/generator"
)
func DefaultGenerationOptions() *RawGenerationOptions {
return &RawGenerationOptions{}
}
func BindGenerationOptions(opts *RawGenerationOptions, cmd *cobra.Command) error {
cmd.Flags().StringVar(&opts.Input, "topology", opts.Input, "file holding topology configuration")
cmd.Flags().StringVar(&opts.Output, "output", opts.Output, "output file path for overview")
for _, flag := range []string{"topology", "output"} {
if err := cmd.MarkFlagFilename(flag); err != nil {
return fmt.Errorf("failed to mark flag %q as a file: %w", flag, err)
}
}
return nil
}
// RawGenerationOptions holds input values.
type RawGenerationOptions struct {
Input string
Output string
}
// validatedGenerationOptions is a private wrapper that enforces a call of Validate() before Complete() can be invoked.
type validatedGenerationOptions struct {
*RawGenerationOptions
}
type ValidatedGenerationOptions struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*validatedGenerationOptions
}
// completedGenerationOptions is a private wrapper that enforces a call of Complete() before config generation can be invoked.
type completedGenerationOptions struct {
Topology topology.Topology
OutputFile io.WriteCloser
}
type GenerationOptions struct {
// Embed a private pointer that cannot be instantiated outside of this package.
*completedGenerationOptions
}
func (o *RawGenerationOptions) Validate() (*ValidatedGenerationOptions, error) {
if o.Input == "" {
return nil, fmt.Errorf("topology configuration file is required")
}
if o.Output == "" {
return nil, fmt.Errorf("output markdown file is required")
}
if _, err := os.Stat(o.Input); os.IsNotExist(err) {
return nil, fmt.Errorf("input file %s does not exist", o.Input)
}
return &ValidatedGenerationOptions{
validatedGenerationOptions: &validatedGenerationOptions{
RawGenerationOptions: o,
},
}, nil
}
func (o *ValidatedGenerationOptions) Complete() (*GenerationOptions, error) {
rawInput, err := os.ReadFile(o.Input)
if err != nil {
return nil, fmt.Errorf("failed to read input file %s: %w", o.Input, err)
}
var t topology.Topology
if err := yaml.Unmarshal(rawInput, &t); err != nil {
return nil, fmt.Errorf("failed to unmarshal topology: %w", err)
}
if err := os.MkdirAll(filepath.Dir(o.Output), os.ModePerm); err != nil {
return nil, fmt.Errorf("failed to create output directory %s: %w", o.Output, err)
}
outputFile, err := os.Create(o.Output)
if err != nil {
return nil, fmt.Errorf("failed to create output file %s: %w", o.Input, err)
}
return &GenerationOptions{
completedGenerationOptions: &completedGenerationOptions{
Topology: t,
OutputFile: outputFile,
},
}, nil
}
func (opts *GenerationOptions) GenerateOverview() error {
return generator.Markdown(opts.Topology, opts.OutputFile)
}