package main

import (
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"text/template"
	"time"
)

var (
	flPackageName  = flag.String("package", "version", "name for the generated golang package")
	flVariableName = flag.String("variable", "VERSION", "variable name in the generated golang package")
	flOutputFile   = flag.String("output", "", "output filename (default stdout)")
)

func main() {
	flag.Parse()
	dir := "."
	if flag.NArg() > 0 {
		dir = flag.Args()[0]
	}
	dir, err := filepath.Abs(dir)
	if err != nil {
		log.Fatal(err)
	}

	var output io.Writer
	if len(*flOutputFile) > 0 {
		fh, err := os.Create(*flOutputFile)
		if err != nil {
			log.Fatal(err)
		}
		defer fh.Close()
		output = fh
	} else {
		output = os.Stdout
	}

	vers, err := GitDescribe(dir)
	if err != nil {
		vers = ReadVersionFile(dir)
	}
	vp := VersionPackage{
		Name:     *flPackageName,
		Path:     dir,
		Date:     time.Now(),
		Variable: *flVariableName,
		Version:  vers,
	}

	packageTemplate.Execute(output, vp)
}

// VersionPackage is the needed information to template a version package
type VersionPackage struct {
	Name     string
	Path     string
	Date     time.Time
	Variable string
	Version  string
}

var packageTemplate = template.Must(template.New("default").Parse(packageLayout))
var packageLayout = `package {{.Name}}
// AUTO-GENERATED. DO NOT EDIT
// {{.Date}}

// {{.Variable}} is generated by git-describe or static version file from gen.go
var {{.Variable}} = "{{.Version}}"
 `

// GitDescribe calls `git describe` in the provided path
func GitDescribe(path string) (string, error) {
	cwd, err := os.Getwd()
	if err != nil {
		return "", err
	}
	// TODO check if this is a directory
	if err := os.Chdir(path); err != nil {
		return "", err
	}
	defer os.Chdir(cwd)

	buf, err := exec.Command("git", "describe").CombinedOutput()
	if err != nil {
		return "", err
	}

	return strings.TrimSpace(string(buf)), nil
}

func ReadVersionFile(path string) string {
	versionFile := filepath.Join(path, "../../../version")
	content, err := ioutil.ReadFile(versionFile)
	if err != nil {
		return "unknown"
	}
	return strings.Trim(string(content), "\n")
}
