Compare commits

..

No commits in common. "0682a0d24931a9ba4f96a460e6122e1e0b3fbd6d" and "0066db548728068cb761084a0bb8f255e9525837" have entirely different histories.

11 changed files with 75 additions and 146 deletions

1
.gitignore vendored
View File

@ -4,7 +4,6 @@
*.so
*.dylib
homemaker
build
# Test binary, build with `go test -c`
*.test

View File

@ -1,50 +0,0 @@
appname := homemaker
sources := $(wildcard *.go)
build = GOOS=$(1) GOARCH=$(2) go build -o build/$(appname)$(3)
tar = cd build && tar -cvzf $(appname)_$(1)_$(2).tar.gz $(appname)$(3) && rm $(appname)$(3)
zip = cd build && zip $(appname)_$(1)_$(2).zip $(appname)$(3) && rm $(appname)$(3)
.PHONY: all windows darwin linux clean
all: windows darwin linux
clean:
rm -rf build/
# linux builds
linux: build/$(appname)_linux_arm.tar.gz build/$(appname)_linux_arm64.tar.gz build/$(appname)_linux_386.tar.gz build/$(appname)_linux_amd64.tar.gz
build/$(appname)_linux_386.tar.gz: $(sources)
$(call build,linux,386,)
$(call tar,linux,386)
build/$(appname)_linux_amd64.tar.gz: $(sources)
$(call build,linux,amd64,)
$(call tar,linux,amd64)
build/$(appname)_linux_arm.tar.gz: $(sources)
$(call build,linux,arm,)
$(call tar,linux,arm)
build/$(appname)_linux_arm64.tar.gz: $(sources)
$(call build,linux,arm64,)
$(call tar,linux,arm64)
# darwin builds
darwin: build/$(appname)_darwin_amd64.tar.gz
build/$(appname)_darwin_amd64.tar.gz: $(sources)
$(call build,darwin,amd64,)
$(call tar,darwin,amd64)
# windows builds
windows: build/$(appname)_windows_386.zip build/$(appname)_windows_amd64.zip
build/$(appname)_windows_386.zip: $(sources)
$(call build,windows,386,.exe)
$(call zip,windows,386,.exe)
build/$(appname)_windows_amd64.zip: $(sources)
$(call build,windows,amd64,.exe)
$(call zip,windows,amd64,.exe)

View File

@ -7,7 +7,7 @@ installation, has no dependencies and makes use of simple configuration file str
[make](https://en.wikipedia.org/wiki/Make_%28software%29) to generate symlinks and execute system commands to aid in
configuring a new system for use.
![](img/demo.gif)
![](https://foosoft.net/projects/homemaker/img/demo.gif)
## Table of Contents
@ -68,10 +68,18 @@ your needs.
If you already have the Go environment and toolchain set up, you can get the latest version by running:
```
go install foosoft.net/projects/homemaker@latest
$ go get github.com/FooSoft/homemaker
```
Otherwise, you can use the [pre-built binaries](https://github.com/FooSoft/homemaker/releases) from the project page.
Otherwise, you can use the pre-built binaries for the platforms below:
* [homemaker\_darwin\_386.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_darwin_386.tar.gz)
* [homemaker\_darwin\_amd64.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_darwin_amd64.tar.gz)
* [homemaker\_linux\_386.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_linux_386.tar.gz)
* [homemaker\_linux\_amd64.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_linux_amd64.tar.gz)
* [homemaker\_linux\_arm.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_linux_arm.tar.gz)
* [homemaker\_windows\_386.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_windows_386.tar.gz)
* [homemaker\_windows\_amd64.tar.gz](https://foosoft.net/projects/homemaker/dl/homemaker_windows_amd64.tar.gz)
## Configuration

View File

@ -26,7 +26,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"path"
"github.com/naoina/toml"
"gopkg.in/yaml.v2"
@ -50,7 +50,7 @@ func newConfig(filename string) (*config, error) {
}
conf := &config{handled: make(map[string]bool)}
switch filepath.Ext(filename) {
switch path.Ext(filename) {
case ".json":
if err := json.Unmarshal(bytes, &conf); err != nil {
return nil, err

12
go.mod
View File

@ -1,13 +1,7 @@
module foosoft.net/projects/homemaker
go 1.18
module github.com/FooSoft/homemaker
require (
github.com/naoina/toml v0.1.1
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/naoina/go-stringutil v0.1.0 // indirect
github.com/naoina/toml v0.1.1
gopkg.in/yaml.v2 v2.2.2
)

7
go.sum
View File

@ -1,10 +1,7 @@
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/naoina/go-stringutil v0.1.0 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
github.com/naoina/toml v0.1.1 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -27,8 +27,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"strings"
"path"
)
const (
@ -43,7 +42,7 @@ const (
)
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [options] conf src\n", filepath.Base(os.Args[0]))
fmt.Fprintf(os.Stderr, "Usage: %s [options] conf src\n", path.Base(os.Args[0]))
fmt.Fprintf(os.Stderr, "https://foosoft.net/projects/homemaker/\n\n")
fmt.Fprintf(os.Stderr, "Parameters:\n")
flag.PrintDefaults()
@ -51,7 +50,7 @@ func usage() {
func main() {
taskName := flag.String("task", "default", "name of task to execute")
dstDir := flag.String("dest", "", "target directory for tasks")
dstDir := flag.String("dest", os.Getenv("HOME"), "target directory for tasks")
force := flag.Bool("force", true, "create parent directories to target")
clobber := flag.Bool("clobber", false, "delete files and directories at target")
verbose := flag.Bool("verbose", false, "verbose output")
@ -95,10 +94,6 @@ func main() {
log.Fatal(err)
}
if strings.TrimSpace(*dstDir) == "" {
*dstDir, _ = os.UserHomeDir()
}
conf.srcDir = makeAbsPath(flag.Arg(1))
conf.dstDir = makeAbsPath(*dstDir)
conf.variant = *variant

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

60
link.go
View File

@ -26,10 +26,51 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"path"
"strconv"
)
func cleanPath(loc string, flags int) error {
if info, _ := os.Lstat(loc); info != nil {
if info.Mode()&os.ModeSymlink == 0 {
if flags&flagClobber != 0 || prompt("clobber path", loc) {
if flags&flagVerbose != 0 {
log.Printf("clobbering path: %s", loc)
}
if err := os.RemoveAll(loc); err != nil {
return err
}
}
} else {
if flags&flagVerbose != 0 {
log.Printf("removing symlink: %s", loc)
}
if err := os.Remove(loc); err != nil {
return err
}
}
}
return nil
}
func createPath(loc string, flags int, mode os.FileMode) error {
parentDir := path.Dir(loc)
if _, err := os.Stat(parentDir); os.IsNotExist(err) {
if flags&flagForce != 0 || prompt("force create path", parentDir) {
if flags&flagVerbose != 0 {
log.Printf("force creating path: %s", parentDir)
}
if err := os.MkdirAll(parentDir, mode); err != nil {
return err
}
}
}
return nil
}
func parseLink(params []string) (srcPath, dstPath string, mode os.FileMode, err error) {
length := len(params)
if length < 1 || length > 3 {
@ -65,13 +106,13 @@ func processLink(params []string, conf *config) error {
}
srcPathAbs := srcPath
if !filepath.IsAbs(srcPathAbs) {
srcPathAbs = filepath.Join(conf.srcDir, srcPath)
if !path.IsAbs(srcPathAbs) {
srcPathAbs = path.Join(conf.srcDir, srcPath)
}
dstPathAbs := dstPath
if !filepath.IsAbs(dstPathAbs) {
dstPathAbs = filepath.Join(conf.dstDir, dstPath)
if !path.IsAbs(dstPathAbs) {
dstPathAbs = path.Join(conf.dstDir, dstPath)
}
if conf.flags&flagUnlink != flagUnlink {
@ -83,13 +124,9 @@ func processLink(params []string, conf *config) error {
return err
}
pathCleaned, err := cleanPath(dstPathAbs, conf.flags)
if err != nil {
if err := try(func() error { return cleanPath(dstPathAbs, conf.flags) }); err != nil {
return err
}
if !pathCleaned {
return nil
}
if conf.flags&flagVerbose != 0 {
log.Printf("linking %s to %s", srcPathAbs, dstPathAbs)
@ -104,7 +141,6 @@ func processLink(params []string, conf *config) error {
return nil
}
_, err = cleanPath(dstPathAbs, conf.flags)
return err
return try(func() error { return cleanPath(dstPathAbs, conf.flags) })
}
}

View File

@ -26,7 +26,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"path"
"strconv"
"strings"
"text/template"
@ -79,13 +79,13 @@ func processTemplate(params []string, conf *config) (err error) {
}
srcPathAbs := srcPath
if !filepath.IsAbs(srcPathAbs) {
srcPathAbs = filepath.Join(conf.srcDir, srcPath)
if !path.IsAbs(srcPathAbs) {
srcPathAbs = path.Join(conf.srcDir, srcPath)
}
dstPathAbs := dstPath
if !filepath.IsAbs(dstPathAbs) {
dstPathAbs = filepath.Join(conf.dstDir, dstPath)
if !path.IsAbs(dstPathAbs) {
dstPathAbs = path.Join(conf.dstDir, dstPath)
}
if _, err = os.Stat(srcPathAbs); os.IsNotExist(err) {
@ -96,13 +96,9 @@ func processTemplate(params []string, conf *config) (err error) {
return err
}
pathCleaned, err := cleanPath(dstPathAbs, conf.flags)
if err != nil {
if err = try(func() error { return cleanPath(dstPathAbs, conf.flags) }); err != nil {
return err
}
if !pathCleaned {
return nil
}
if conf.flags&flagVerbose != 0 {
log.Printf("process template %s to %s", srcPathAbs, dstPathAbs)

46
util.go
View File

@ -47,52 +47,6 @@ func makeAbsPath(path string) string {
return path
}
func cleanPath(loc string, flags int) (bool, error) {
if info, _ := os.Lstat(loc); info != nil {
if info.Mode()&os.ModeSymlink == 0 {
shouldContinue := false
if flags&flagClobber == 0 {
shouldContinue = prompt("clobber path", loc)
}
if flags&flagClobber != 0 || shouldContinue {
if flags&flagVerbose != 0 {
log.Printf("clobbering path: %s", loc)
}
if err := try(func() error { return os.RemoveAll(loc) }) ; err != nil {
return false, err
}
} else {
return false, nil
}
} else {
if flags&flagVerbose != 0 {
log.Printf("removing symlink: %s", loc)
}
if err := try(func() error { return os.Remove(loc) }); err != nil {
return false, err
}
}
}
return true, nil
}
func createPath(loc string, flags int, mode os.FileMode) error {
parentDir := filepath.Dir(loc)
if _, err := os.Stat(parentDir); os.IsNotExist(err) {
if flags&flagForce != 0 || prompt("force create path", parentDir) {
if flags&flagVerbose != 0 {
log.Printf("force creating path: %s", parentDir)
}
if err := os.MkdirAll(parentDir, mode); err != nil {
return err
}
}
}
return nil
}
func makeVariantNames(name, variant string) []string {
if nameParts := strings.Split(name, "__"); len(nameParts) > 1 {
variant = nameParts[len(nameParts)-1]