// 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 main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
)

const versiongoTemplate = `// This is an autogenerated file and should not be edited.

// 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 contains constants to indicate the current version of the
// agent. It is autogenerated
package version

// Please DO NOT commit any changes to this file (specifically the hash) except
// for those created by running ./scripts/update-version at the root of the
// repository. Only the 'Version' const should change in checked-in source code

// Version is the version of the Agent
const Version = "{{.Version}}"

// GitDirty indicates the cleanliness of the git repo when this agent was built
const GitDirty = {{.Dirty}}

// GitShortHash is the short hash of this agent build
const GitShortHash = "{{.Hash}}"
`

type versionInfo struct {
	Version string
	Dirty   bool
	Hash    string
}

func gitDirty() bool {
	cmd := exec.Command("git", "status", "--porcelain")
	err := cmd.Run()
	return err != nil
}

func gitHash() string {
	cmd := exec.Command("git", "rev-parse", "--short=8", "HEAD")
	hash, err := cmd.Output()
	if err != nil {
		log.Printf("failed to execute git rev-parse --short=8 HEAD, err: %v", err)
		return "UNKNOWN"
	}
	hashStr := strings.TrimSpace(string(hash))
	log.Printf("Successfully retrieved short hash value from git rev-parse --short=8 HEAD, hashStr: %s",
		hashStr)
	return hashStr
}

func releaseCommitGitHash() (string, error) {
	fullHash, err := os.ReadFile(filepath.Join("..", "..", "RELEASE_COMMIT"))
	if err != nil {
		return "", fmt.Errorf("unable to read RELEASE_COMMIT file, err: %v", err)
	}
	fullHashStr := strings.TrimSpace(string(fullHash))
	if fullHashStr == "" || len(fullHashStr) < 8 {
		log.Fatalf("Invalid hash value obtained from RELEASE_COMMIT file (empty or length <8), fullHashStr: %s",
			fullHashStr)
	}
	log.Printf("Successfully retrieved full hash value from RELEASE_COMMIT file, fullHashStr: %s", fullHashStr)
	// return short hash (first 8 characters) instead of full hash
	return fullHashStr[0:8], nil
}

func selectGitHash() string {
	hash, err := releaseCommitGitHash()
	if err != nil {
		return gitHash()
	}
	return hash
}

// version-gen is a simple program that generates the agent's version file,
// containing information about the agent's version, commit hash, and repository
// cleanliness.
func main() {

	versionStr, _ := os.ReadFile(filepath.Join("..", "..", "VERSION"))

	// default values
	info := versionInfo{
		Version: strings.TrimSpace(string(versionStr)),
		Dirty:   true,
		Hash:    "UNKNOWN",
	}

	if strings.TrimSpace(os.Getenv("ECS_RELEASE")) == "cleanbuild" {
		// 'clean' release; all other releases assumed dirty
		info.Dirty = gitDirty()
	}
	if os.Getenv("ECS_UNKNOWN_VERSION") == "" {
		// When the version file is updated, the above is set
		// Setting UNKNOWN version allows the version committed in git to never
		// have a commit hash so that it does not churn with every commit. This
		// env var should not be set when building, and go generate should be
		// run before any build, such that the commithash will be set correctly.
		info.Hash = selectGitHash()
	}

	outFile, err := os.Create("version.go")
	if err != nil {
		log.Fatalf("Unable to create output version file: %v", err)
	}
	t := template.Must(template.New("version").Parse(versiongoTemplate))

	err = t.Execute(outFile, info)
	if err != nil {
		log.Fatalf("Error applying template: %v", err)
	}
}
