Add env and restore commands #11

Merged
jolheiser merged 2 commits from refs/pull/11/head into main 2020-11-30 05:16:25 +00:00
10 changed files with 165 additions and 22 deletions

8
CLI.md
View File

@ -32,6 +32,10 @@ Download a template
**--branch, -b**="": Branch to clone (default: main)
## env
Show tmpl environment variables
## init
Initialize a template
@ -44,6 +48,10 @@ List templates in the registry
Remove a template
## restore
Restore missing templates
## save
Save a local template

View File

@ -109,3 +109,10 @@ I realize that many users will be using GitHub, and most will likely still be us
2. Set the env variable `TMPL_SOURCE` to `github`
2. Set the env variable `TMPL_BRANCH` to `master`
3. Happy templating! `tmpl download user/repo repo`
## Backup and Restore
1. The simplest solution is to make a copy of your `registry.toml` (default: `~/.tmpl/registry.toml`).
* Once in the new location, you will need to use `tmpl restore`.
2. Alternatively, you can copy/paste the entire registry (default: `~/.tmpl`) and skip the restore step.

View File

@ -51,9 +51,11 @@ func NewApp() *cli.App {
app.Commands = []*cli.Command{
Download,
Env,
Init,
List,
Remove,
Restore,
Save,
Source,
Test,

34
cmd/env.go 100644
View File

@ -0,0 +1,34 @@
package cmd
import (
"os"
"github.com/urfave/cli/v2"
"go.jolheiser.com/beaver"
"go.jolheiser.com/beaver/color"
)
var Env = &cli.Command{
Name: "env",
Usage: "Show tmpl environment variables",
Description: "Show tmpl environment variables and their configuration",
Action: runEnv,
}
func runEnv(_ *cli.Context) error {
// Source
beaver.Infof("TMPL_SOURCE: %s", getEnv("TMPL_SOURCE"))
// Registry Path
beaver.Infof("TMPL_REGISTRY: %s", getEnv("TMPL_REGISTRY"))
// Branch
beaver.Infof("TMPL_BRANCH: %s", getEnv("TMPL_BRANCH"))
return nil
}
func getEnv(key string) string {
return color.FgHiBlue.Format(os.Getenv(key))
}

View File

@ -25,7 +25,7 @@ func runList(_ *cli.Context) error {
}
wr := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
if _, err := fmt.Fprintf(wr, "NAME\tURL\tLOCAL\tUPDATED\n"); err != nil {
if _, err := fmt.Fprintf(wr, "NAME\tURL\tLOCAL\tLAST UPDATED\n"); err != nil {
return err
}
for _, t := range reg.Templates {
@ -35,7 +35,7 @@ func runList(_ *cli.Context) error {
u = t.Path
local = true
}
if _, err := fmt.Fprintf(wr, "%s\t%s\t%t\t%s\n", t.Name, u, local, t.Created.Format("01/02/2006")); err != nil {
if _, err := fmt.Fprintf(wr, "%s\t%s\t%t\t%s\n", t.Name, u, local, t.LastUpdate.Format("01/02/2006")); err != nil {
return err
}
}

39
cmd/restore.go 100644
View File

@ -0,0 +1,39 @@
package cmd
import (
"os"
"go.jolheiser.com/tmpl/cmd/flags"
"go.jolheiser.com/tmpl/registry"
"github.com/urfave/cli/v2"
"go.jolheiser.com/beaver"
)
var Restore = &cli.Command{
Name: "restore",
Usage: "Restore missing templates",
Description: "Restore templates that are listed in the registry, but are missing archives",
Action: runRestore,
}
func runRestore(_ *cli.Context) error {
reg, err := registry.Open(flags.Registry)
if err != nil {
return err
}
var num int
for _, tmpl := range reg.Templates {
if _, err := os.Lstat(tmpl.ArchivePath()); os.IsNotExist(err) {
beaver.Infof("Restoring %s...", tmpl.Name)
if err := reg.UpdateTemplate(tmpl.Name); err != nil {
return err
}
num++
}
}
beaver.Infof("Restored %d templates.", num)
return nil
}

View File

@ -31,16 +31,7 @@ func runUpdate(ctx *cli.Context) error {
return err
}
if err := reg.RemoveTemplate(tmpl.Name); err != nil {
return err
}
if tmpl.Path != "" {
_, err = reg.SaveTemplate(tmpl.Name, tmpl.Path)
} else {
_, err = reg.DownloadTemplate(tmpl.Name, tmpl.Repository, tmpl.Branch)
}
if err != nil {
if err := reg.UpdateTemplate(tmpl.Name); err != nil {
return err
}

View File

@ -2,6 +2,19 @@ package registry
import "fmt"
type ErrTemplateExists struct {
Name string
}
func (e ErrTemplateExists) Error() string {
return fmt.Sprintf("template %s already exists", e.Name)
}
func IsErrTemplateExists(err error) bool {
_, ok := err.(ErrTemplateExists)
return ok
}
type ErrTemplateNotFound struct {
Name string
}

View File

@ -50,12 +50,16 @@ func (r *Registry) GetTemplate(name string) (*Template, error) {
// DownloadTemplate downloads and adds a new Template to the Registry
func (r *Registry) DownloadTemplate(name, repo, branch string) (*Template, error) {
if _, err := r.GetTemplate(name); err == nil {
return nil, ErrTemplateExists{Name: name}
}
t := &Template{
reg: r,
Name: name,
Repository: repo,
Branch: branch,
Created: time.Now(),
LastUpdate: time.Now(),
}
r.Templates = append(r.Templates, t)
@ -68,11 +72,15 @@ func (r *Registry) DownloadTemplate(name, repo, branch string) (*Template, error
// SaveTemplate saves a local Template to the Registry
func (r *Registry) SaveTemplate(name, path string) (*Template, error) {
if _, err := r.GetTemplate(name); err == nil {
return nil, ErrTemplateExists{Name: name}
}
t := &Template{
reg: r,
Name: name,
Path: path,
Created: time.Now(),
LastUpdate: time.Now(),
}
r.Templates = append(r.Templates, t)
@ -89,16 +97,48 @@ func (r *Registry) RemoveTemplate(name string) error {
if err != nil {
return err
}
for idx, t := range r.Templates {
if strings.EqualFold(name, t.Name) {
r.Templates = append(r.Templates[:idx], r.Templates[idx+1:]...)
if err := os.Remove(t.ArchivePath()); err != nil {
return err
}
return r.save()
}
}
return r.save()
return nil
}
// RemoveTemplate updates the Template on disk and in meta
func (r *Registry) UpdateTemplate(name string) error {
_, err := r.GetTemplate(name)
if err != nil {
return err
}
for idx, t := range r.Templates {
if strings.EqualFold(name, t.Name) {
// If the path doesn't exist, we are replacing it regardless
if err := os.Remove(t.ArchivePath()); err != nil && !os.IsNotExist(err) {
return err
}
// Cut it out of the template list so we don't get a duplicate
r.Templates = append(r.Templates[:idx], r.Templates[idx+1:]...)
// If path exists, it is local
if t.Path != "" {
_, err = r.SaveTemplate(t.Name, t.Path)
} else {
_, err = r.DownloadTemplate(t.Name, t.Repository, t.Branch)
}
return err
}
}
return nil
}
// GetSource retrieves a Source from the Registry
@ -159,7 +199,16 @@ func Open(dir string) (*Registry, error) {
if err != nil {
return nil, err
}
return &reg, tree.Unmarshal(&reg)
if err := tree.Unmarshal(&reg); err != nil {
return nil, err
}
for _, tmpl := range reg.Templates {
tmpl.reg = &reg
}
return &reg, nil
}
func create(regFile string) error {
@ -191,7 +240,7 @@ func download(cloneURL, branch, dest string) error {
return err
}
// RemoveTemplate .git
// Remove .git
if err := os.RemoveAll(filepath.Join(tmp, ".git")); err != nil {
return err
}

View File

@ -20,7 +20,7 @@ type Template struct {
Path string `toml:"path"`
Repository string `toml:"repository"`
Branch string `toml:"branch"`
Created time.Time `toml:"created"`
LastUpdate time.Time `toml:"last_update"`
}
// ArchiveName is the name given to the archive for this Template