1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
package autorest
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/Azure/azure-sdk-for-go/eng/tools/generator/autorest/model"
"github.com/Azure/azure-sdk-for-go/eng/tools/internal/packages/track1"
)
// GenerationMetadata contains all the metadata that has been used when generating a track 1 package
type GenerationMetadata struct {
// AutorestVersion is the version of autorest.core
AutorestVersion string `json:"autorest,omitempty"`
// CommitHash is the commit hash of azure-rest-api-specs from which this SDK package is generated
CommitHash string `json:"commit,omitempty"`
// Readme is the normalized path of the readme file from which this SDK package is generated. It should be in this pattern: /_/azure-rest-api-specs/{relative_path}
Readme string `json:"readme,omitempty"`
// Tag is the tag from which this SDK package is generated
Tag string `json:"tag,omitempty"`
// CodeGenVersion is the version of autorest.go using when this package is generated
CodeGenVersion string `json:"use,omitempty"`
// RepositoryURL is the URL of the azure-rest-api-specs. This should always be a constant "https://github.com/Azure/azure-rest-api-specs.git"
RepositoryURL string `json:"repository_url,omitempty"`
// AutorestCommand is the full command that generates this package
AutorestCommand string `json:"autorest_command,omitempty"`
// AdditionalProperties is a map of addition information in this metadata
AdditionalProperties GenerationMetadataAdditionalProperties `json:"additional_properties,omitempty"`
}
// GenerationMetadataAdditionalProperties contains all the additional options other than go-sdk-foler, tag, multiapi, use or the readme path
type GenerationMetadataAdditionalProperties struct {
AdditionalOptions string `json:"additional_options,omitempty"`
}
// RelativeReadme returns the relative readme path
func (meta *GenerationMetadata) RelativeReadme() string {
return strings.TrimPrefix(meta.Readme, NormalizedSpecRoot)
}
// CollectGenerationMetadata iterates every track 1 go sdk package under root, and collect all the GenerationMetadata into a map
// using the absolute path of the package as keys
func CollectGenerationMetadata(root string) (map[string]GenerationMetadata, error) {
pkgs, err := track1.List(root)
if err != nil {
return nil, fmt.Errorf("failed to get track 1 package list under root '%s': %+v", root, err)
}
result := make(map[string]GenerationMetadata)
for _, pkg := range pkgs {
m, err := GetGenerationMetadata(pkg)
if err != nil {
return nil, err
}
if m != nil {
result[pkg.FullPath()] = *m
}
}
return result, nil
}
// GetGenerationMetadata gets the GenerationMetadata in one specific package
func GetGenerationMetadata(pkg track1.Package) (*GenerationMetadata, error) {
metadataFilepath := filepath.Join(pkg.FullPath(), MetadataFilename)
// some classical package might not have a changelog, therefore we need to identify whether the changelog file exist or not
if _, err := os.Stat(metadataFilepath); os.IsNotExist(err) {
log.Printf("package '%s' does not have a metadata file", pkg.Path())
return nil, nil
}
b, err := ioutil.ReadFile(metadataFilepath)
if err != nil {
return nil, fmt.Errorf("cannot read file %s: %+v", metadataFilepath, err)
}
var metadata GenerationMetadata
if err := json.Unmarshal(b, &metadata); err != nil {
return nil, fmt.Errorf("cannot unmarshal metadata: %+v", err)
}
return &metadata, nil
}
// AdditionalOptions removes flags that may change over scenarios
func AdditionalOptions(arguments []model.Option) []model.Option {
var transformed []model.Option
for _, argument := range arguments {
switch o := argument.(type) {
case model.ArgumentOption: // omit the readme path argument
continue
case model.FlagOption:
if o.Flag() == "multiapi" { // omit the multiapi flag or use
continue
}
case model.KeyValueOption:
// omit go-sdk-folder, use, tag and metadata-output-folder
if o.Key() == "go-sdk-folder" || o.Key() == "use" || o.Key() == "tag" || o.Key() == "metadata-output-folder" {
continue
}
}
transformed = append(transformed, argument)
}
return transformed
}
// AdditionalOptionsToString removes flags that may change over scenarios and cast them to strings
func AdditionalOptionsToString(arguments []model.Option) []string {
transformed := AdditionalOptions(arguments)
result := make([]string, len(transformed))
for i, o := range transformed {
result[i] = o.Format()
}
return result
}
const (
// NormalizedSpecRoot this is the prefix for readme
NormalizedSpecRoot = "/_/azure-rest-api-specs/"
// NormalizedSDKRoot this is the prefix for readme
NormalizedSDKRoot = "/_/azure-sdk-for-go/"
// MetadataFilename ...
MetadataFilename = "_meta.json"
)
|