Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ AWS_SERVICE=$(shell echo $(SERVICE) | tr '[:upper:]' '[:lower:]')
VERSION ?= "v0.0.0"
GITCOMMIT=$(shell git rev-parse HEAD)
BUILDDATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')
GO_LDFLAGS=-ldflags "-X main.version=$(VERSION) \
-X main.buildHash=$(GITCOMMIT) \
-X main.buildDate=$(BUILDDATE)"
IMPORT_PATH=github.com/aws-controllers-k8s/code-generator
GO_LDFLAGS=-ldflags "-X $(IMPORT_PATH)/pkg/version.Version=$(VERSION) \
-X $(IMPORT_PATH)/pkg/version.BuildHash=$(GITCOMMIT) \
-X $(IMPORT_PATH)/pkg/version.BuildDate=$(BUILDDATE)"

# We need to use the codegen tag when building and testing because the
# aws-sdk-go/private/model/api package is gated behind a build tag "codegen"...
Expand Down
20 changes: 17 additions & 3 deletions cmd/ack-generate/command/apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,10 @@ var (

// apiCmd is the command that generates service API types
var apisCmd = &cobra.Command{
Use: "apis <service>",
Short: "Generate Kubernetes API type definitions for an AWS service API",
RunE: generateAPIs,
Use: "apis <service>",
Short: "Generate Kubernetes API type definitions for an AWS service API",
RunE: generateAPIs,
PostRunE: saveGeneratedMetadata,
}

func init() {
Expand All @@ -54,6 +55,19 @@ func init() {
rootCmd.AddCommand(apisCmd)
}

// saveGeneratedMetadata saves the parameters used to generate APIs and checksum
// of the generated code.
func saveGeneratedMetadata(cmd *cobra.Command, args []string) error {
err := ackgenerate.CreateGenerationMetadata(
optGenVersion,
filepath.Join(optOutputPath, "apis"),
ackgenerate.UpdateReasonAPIGeneration,
optAWSSDKGoVersion,
optGeneratorConfigPath,
)
return err
}

// generateAPIs generates the Go files for each resource in the AWS service
// API.
func generateAPIs(cmd *cobra.Command, args []string) error {
Expand Down
9 changes: 1 addition & 8 deletions cmd/ack-generate/command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ A tool to generate AWS service controller code`
)

var (
version string
buildHash string
buildDate string
defaultCacheDir string
optCacheDir string
optRefreshCache bool
Expand Down Expand Up @@ -125,11 +122,7 @@ func init() {
// Execute adds all child commands to the root command and sets flags
// appropriately. This is called by main.main(). It only needs to happen once
// to the rootCmd.
func Execute(v string, bh string, bd string) {
version = v
buildHash = bh
buildDate = bd

func Execute() {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/ack-generate/command/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ package command

import (
"fmt"
"runtime"

"github.com/spf13/cobra"

"github.com/aws-controllers-k8s/code-generator/pkg/version"
)

const debugHeader = `Date: %s
Expand All @@ -31,8 +32,7 @@ var versionCmd = &cobra.Command{
Use: "version",
Short: "Display the version of " + appName,
Run: func(cmd *cobra.Command, args []string) {
goVersion := fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)
fmt.Printf(debugHeader, buildDate, goVersion, version, buildHash)
fmt.Printf(debugHeader, version.BuildDate, version.GoVersion, version.Version, version.BuildHash)
},
}

Expand Down
11 changes: 1 addition & 10 deletions cmd/ack-generate/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,6 @@ import (
"github.com/aws-controllers-k8s/code-generator/cmd/ack-generate/command"
)

var (
// version of application at compile time (-X 'main.version=$(VERSION)').
version = "(Unknown Version)"
// buildHash GIT hash of application at compile time (-X 'main.buildHash=$(GITCOMMIT)').
buildHash = "No Git-hash Provided."
// buildDate of application at compile time (-X 'main.buildDate=$(BUILDDATE)').
buildDate = "No Build Date Provided."
)

func main() {
command.Execute(version, buildHash, buildDate)
command.Execute()
}
195 changes: 195 additions & 0 deletions pkg/generate/ack/output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 ack

import (
"crypto/sha1"
"encoding/hex"
"io"
"io/ioutil"
"os"
"path/filepath"
"time"

"github.com/ghodss/yaml"

"github.com/aws-controllers-k8s/code-generator/pkg/version"
)

const (
outputFileName = "ack-generate-metadata.yaml"
)

// UpdateReason is the reason a package got modified.
type UpdateReason string

const (
// UpdateReasonAPIGeneration should be used when an API package
// is modified by the APIs generator (ack-generate apis).
UpdateReasonAPIGeneration UpdateReason = "API generation"

// UpdateReasonConversionFunctionsGeneration Should be used when
// an API package is modified by conversion functions generator.
// TODO(hilalymh) ack-generate conversion-functions
UpdateReasonConversionFunctionsGeneration UpdateReason = "Conversion functions generation"
)

// GenerationMetadata represents the parameters used to generate/update the
// API version directory.
//
// This type is public because soon it will be used by conversion generators
// to load APIs generation metadata.
// TODO(hilalymh) Add functions to load/edit metadata files.
type GenerationMetadata struct {
// The APIs version e.g v1alpha2
APIVersion string `json:"api_version"`
// The checksum of all the combined files generated within the APIs directory
APIDirectoryChecksum string `json:"api_directory_checksum"`
// Last modification reason
LastModification lastModificationInfo `json:"last_modification"`
// AWS SDK Go version used generate the APIs
AWSSDKGoVersion string `json:"aws_sdk_go_version"`
// Informatiom about the ack-generate binary used to generate the APIs
ACKGenerateInfo ackGenerateInfo `json:"ack_generate_info"`
// Information about the generator config file used to generate the APIs
GeneratorConfigInfo generatorConfigInfo `json:"generator_config_info"`
}

// ack-generate binary information
type ackGenerateInfo struct {
Version string `json:"version"`
GoVersion string `json:"go_version"`
BuildDate string `json:"build_date"`
BuildHash string `json:"build_hash"`
}

// generator.yaml information
type generatorConfigInfo struct {
OriginalFileName string `json:"original_file_name"`
FileChecksum string `json:"file_checksum"`
}

// last modification information
type lastModificationInfo struct {
// UTC Timestamp
Timestamp string `json:"timestamp"`
// Modification reason
Reason UpdateReason `json:"reason"`
}

// CreateGenerationMetadata gathers information about the generated code and save
// a yaml version in the API version directory
func CreateGenerationMetadata(
apiVersion string,
apisPath string,
modificationReason UpdateReason,
awsSDKGo string,
generatorFileName string,
) error {
filesDirectory := filepath.Join(apisPath, apiVersion)
hash, err := hashDirectoryContent(filesDirectory)
if err != nil {
return err
}

generatorFileHash, err := hashFile(generatorFileName)
if err != nil {
return err
}

generationMetadata := &GenerationMetadata{
APIVersion: apiVersion,
APIDirectoryChecksum: hash,
LastModification: lastModificationInfo{
Timestamp: time.Now().UTC().String(),
Reason: modificationReason,
},
AWSSDKGoVersion: awsSDKGo,
ACKGenerateInfo: ackGenerateInfo{
Version: version.Version,
BuildDate: version.BuildDate,
BuildHash: version.BuildHash,
GoVersion: version.GoVersion,
},
GeneratorConfigInfo: generatorConfigInfo{
OriginalFileName: filepath.Base(generatorFileName),
FileChecksum: generatorFileHash,
},
}

data, err := yaml.Marshal(generationMetadata)
if err != nil {
return err
}

outputFileName := filepath.Join(filesDirectory, outputFileName)
err = ioutil.WriteFile(
outputFileName,
data,
os.ModePerm,
)
if err != nil {
return err
}
return nil
}

// hashDirectoryContent returns the sha1 checksum of a given directory. It will walk
// the file tree of a directory and combine and the file contents before hashing it.
func hashDirectoryContent(directory string) (string, error) {
h := sha1.New()
err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !info.IsDir() {
// ignore yaml files (output.yaml and generator.yaml)
fileExtension := filepath.Ext(info.Name())
if fileExtension == ".yaml" {
return nil
}

fileReader, err := os.Open(path)
if err != nil {
return err
}
_, err = io.Copy(h, fileReader)
if err != nil {
return err
}
}
return nil
})
if err != nil {
return "", err
}

hash := hex.EncodeToString(h.Sum(nil))
return hash, nil
}

// hashFile returns the sha1 hash of a given file
func hashFile(filename string) (string, error) {
h := sha1.New()
fileReader, err := os.Open(filename)
if err != nil {
return "", err
}
_, err = io.Copy(h, fileReader)
if err != nil {
return "", err
}
hash := hex.EncodeToString(h.Sum(nil))
return hash, nil
}
34 changes: 34 additions & 0 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may
// not use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file 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 version

import (
"fmt"
"runtime"
)

var (
// BuildDate of application at compile time (-X 'main.buildDate=$(BUILDDATE)').
BuildDate string = "No Build Date Provided."
// Version of application at compile time (-X 'main.version=$(VERSION)').
Version string = "(Unknown Version)"
// BuildHash is the GIT hash of application at compile time (-X 'main.buildHash=$(GITCOMMIT)').
BuildHash string = "No Git-hash Provided."
// GoVersion is the Go compiler version used to compile this binary
GoVersion string
)

func init() {
GoVersion = fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)
}