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 *.so
*.dylib *.dylib
homemaker homemaker
build
# Test binary, build with `go test -c` # Test binary, build with `go test -c`
*.test *.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 [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. configuring a new system for use.
![](img/demo.gif) ![](https://foosoft.net/projects/homemaker/img/demo.gif)
## Table of Contents ## 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: 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 ## Configuration

View File

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

12
go.mod
View File

@ -1,13 +1,7 @@
module foosoft.net/projects/homemaker module github.com/FooSoft/homemaker
go 1.18
require ( 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/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 h1:rCUeRUHjBjGTSHl0VC00jUPLz8/F9dDzYI70Hzifhks=
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= 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 h1:PT/lllxVVN0gzzSqSlHEmP8MJB4MY2U7STGxiouV4X8=
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= 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/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.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -27,8 +27,7 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath" "path"
"strings"
) )
const ( const (
@ -43,7 +42,7 @@ const (
) )
func usage() { 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, "https://foosoft.net/projects/homemaker/\n\n")
fmt.Fprintf(os.Stderr, "Parameters:\n") fmt.Fprintf(os.Stderr, "Parameters:\n")
flag.PrintDefaults() flag.PrintDefaults()
@ -51,7 +50,7 @@ func usage() {
func main() { func main() {
taskName := flag.String("task", "default", "name of task to execute") 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") force := flag.Bool("force", true, "create parent directories to target")
clobber := flag.Bool("clobber", false, "delete files and directories at target") clobber := flag.Bool("clobber", false, "delete files and directories at target")
verbose := flag.Bool("verbose", false, "verbose output") verbose := flag.Bool("verbose", false, "verbose output")
@ -95,10 +94,6 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
if strings.TrimSpace(*dstDir) == "" {
*dstDir, _ = os.UserHomeDir()
}
conf.srcDir = makeAbsPath(flag.Arg(1)) conf.srcDir = makeAbsPath(flag.Arg(1))
conf.dstDir = makeAbsPath(*dstDir) conf.dstDir = makeAbsPath(*dstDir)
conf.variant = *variant conf.variant = *variant

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

60
link.go
View File

@ -26,10 +26,51 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath" "path"
"strconv" "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) { func parseLink(params []string) (srcPath, dstPath string, mode os.FileMode, err error) {
length := len(params) length := len(params)
if length < 1 || length > 3 { if length < 1 || length > 3 {
@ -65,13 +106,13 @@ func processLink(params []string, conf *config) error {
} }
srcPathAbs := srcPath srcPathAbs := srcPath
if !filepath.IsAbs(srcPathAbs) { if !path.IsAbs(srcPathAbs) {
srcPathAbs = filepath.Join(conf.srcDir, srcPath) srcPathAbs = path.Join(conf.srcDir, srcPath)
} }
dstPathAbs := dstPath dstPathAbs := dstPath
if !filepath.IsAbs(dstPathAbs) { if !path.IsAbs(dstPathAbs) {
dstPathAbs = filepath.Join(conf.dstDir, dstPath) dstPathAbs = path.Join(conf.dstDir, dstPath)
} }
if conf.flags&flagUnlink != flagUnlink { if conf.flags&flagUnlink != flagUnlink {
@ -83,13 +124,9 @@ func processLink(params []string, conf *config) error {
return err return err
} }
pathCleaned, err := cleanPath(dstPathAbs, conf.flags) if err := try(func() error { return cleanPath(dstPathAbs, conf.flags) }); err != nil {
if err != nil {
return err return err
} }
if !pathCleaned {
return nil
}
if conf.flags&flagVerbose != 0 { if conf.flags&flagVerbose != 0 {
log.Printf("linking %s to %s", srcPathAbs, dstPathAbs) log.Printf("linking %s to %s", srcPathAbs, dstPathAbs)
@ -104,7 +141,6 @@ func processLink(params []string, conf *config) error {
return nil return nil
} }
_, err = cleanPath(dstPathAbs, conf.flags) return try(func() error { return cleanPath(dstPathAbs, conf.flags) })
return err
} }
} }

View File

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