Add env and restore commands #11
8
CLI.md
8
CLI.md
|
@ -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
|
||||
|
|
7
DOCS.md
7
DOCS.md
|
@ -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.
|
|
@ -51,9 +51,11 @@ func NewApp() *cli.App {
|
|||
|
||||
app.Commands = []*cli.Command{
|
||||
Download,
|
||||
Env,
|
||||
Init,
|
||||
List,
|
||||
Remove,
|
||||
Restore,
|
||||
Save,
|
||||
Source,
|
||||
Test,
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 ®, tree.Unmarshal(®)
|
||||
|
||||
if err := tree.Unmarshal(®); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, tmpl := range reg.Templates {
|
||||
tmpl.reg = ®
|
||||
}
|
||||
|
||||
return ®, 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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue