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)
|
**--branch, -b**="": Branch to clone (default: main)
|
||||||
|
|
||||||
|
## env
|
||||||
|
|
||||||
|
Show tmpl environment variables
|
||||||
|
|
||||||
## init
|
## init
|
||||||
|
|
||||||
Initialize a template
|
Initialize a template
|
||||||
|
@ -44,6 +48,10 @@ List templates in the registry
|
||||||
|
|
||||||
Remove a template
|
Remove a template
|
||||||
|
|
||||||
|
## restore
|
||||||
|
|
||||||
|
Restore missing templates
|
||||||
|
|
||||||
## save
|
## save
|
||||||
|
|
||||||
Save a local template
|
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_SOURCE` to `github`
|
||||||
2. Set the env variable `TMPL_BRANCH` to `master`
|
2. Set the env variable `TMPL_BRANCH` to `master`
|
||||||
3. Happy templating! `tmpl download user/repo repo`
|
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{
|
app.Commands = []*cli.Command{
|
||||||
Download,
|
Download,
|
||||||
|
Env,
|
||||||
Init,
|
Init,
|
||||||
List,
|
List,
|
||||||
Remove,
|
Remove,
|
||||||
|
Restore,
|
||||||
Save,
|
Save,
|
||||||
Source,
|
Source,
|
||||||
Test,
|
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)
|
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
|
return err
|
||||||
}
|
}
|
||||||
for _, t := range reg.Templates {
|
for _, t := range reg.Templates {
|
||||||
|
@ -35,7 +35,7 @@ func runList(_ *cli.Context) error {
|
||||||
u = t.Path
|
u = t.Path
|
||||||
local = true
|
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
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := reg.RemoveTemplate(tmpl.Name); err != nil {
|
if err := reg.UpdateTemplate(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 {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,19 @@ package registry
|
||||||
|
|
||||||
import "fmt"
|
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 {
|
type ErrTemplateNotFound struct {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,16 @@ func (r *Registry) GetTemplate(name string) (*Template, error) {
|
||||||
|
|
||||||
// DownloadTemplate downloads and adds a new Template to the Registry
|
// DownloadTemplate downloads and adds a new Template to the Registry
|
||||||
func (r *Registry) DownloadTemplate(name, repo, branch string) (*Template, error) {
|
func (r *Registry) DownloadTemplate(name, repo, branch string) (*Template, error) {
|
||||||
|
if _, err := r.GetTemplate(name); err == nil {
|
||||||
|
return nil, ErrTemplateExists{Name: name}
|
||||||
|
}
|
||||||
|
|
||||||
t := &Template{
|
t := &Template{
|
||||||
reg: r,
|
reg: r,
|
||||||
Name: name,
|
Name: name,
|
||||||
Repository: repo,
|
Repository: repo,
|
||||||
Branch: branch,
|
Branch: branch,
|
||||||
Created: time.Now(),
|
LastUpdate: time.Now(),
|
||||||
}
|
}
|
||||||
r.Templates = append(r.Templates, t)
|
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
|
// SaveTemplate saves a local Template to the Registry
|
||||||
func (r *Registry) SaveTemplate(name, path string) (*Template, error) {
|
func (r *Registry) SaveTemplate(name, path string) (*Template, error) {
|
||||||
|
if _, err := r.GetTemplate(name); err == nil {
|
||||||
|
return nil, ErrTemplateExists{Name: name}
|
||||||
|
}
|
||||||
|
|
||||||
t := &Template{
|
t := &Template{
|
||||||
reg: r,
|
reg: r,
|
||||||
Name: name,
|
Name: name,
|
||||||
Path: path,
|
Path: path,
|
||||||
Created: time.Now(),
|
LastUpdate: time.Now(),
|
||||||
}
|
}
|
||||||
r.Templates = append(r.Templates, t)
|
r.Templates = append(r.Templates, t)
|
||||||
|
|
||||||
|
@ -89,16 +97,48 @@ func (r *Registry) RemoveTemplate(name string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, t := range r.Templates {
|
for idx, t := range r.Templates {
|
||||||
if strings.EqualFold(name, t.Name) {
|
if strings.EqualFold(name, t.Name) {
|
||||||
r.Templates = append(r.Templates[:idx], r.Templates[idx+1:]...)
|
r.Templates = append(r.Templates[:idx], r.Templates[idx+1:]...)
|
||||||
if err := os.Remove(t.ArchivePath()); err != nil {
|
if err := os.Remove(t.ArchivePath()); err != nil {
|
||||||
return err
|
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
|
// GetSource retrieves a Source from the Registry
|
||||||
|
@ -159,7 +199,16 @@ func Open(dir string) (*Registry, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
func create(regFile string) error {
|
||||||
|
@ -191,7 +240,7 @@ func download(cloneURL, branch, dest string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTemplate .git
|
// Remove .git
|
||||||
if err := os.RemoveAll(filepath.Join(tmp, ".git")); err != nil {
|
if err := os.RemoveAll(filepath.Join(tmp, ".git")); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ type Template struct {
|
||||||
Path string `toml:"path"`
|
Path string `toml:"path"`
|
||||||
Repository string `toml:"repository"`
|
Repository string `toml:"repository"`
|
||||||
Branch string `toml:"branch"`
|
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
|
// ArchiveName is the name given to the archive for this Template
|
||||||
|
|
Loading…
Reference in New Issue