This commit is contained in:
Alex Yatskov 2015-09-04 12:15:57 +09:00
parent e9fa1bd8fb
commit c29b8b8200
6 changed files with 83 additions and 73 deletions

View File

@ -35,7 +35,7 @@ type macro struct {
Suffix []string
}
func processCmd(params []string, dir string, conf *config, flags int) error {
func processCmd(params []string, conf *config) error {
args := appendExpEnv(nil, params)
if len(args) == 0 {
return fmt.Errorf("invalid command statement")
@ -56,11 +56,11 @@ func processCmd(params []string, dir string, conf *config, flags int) error {
}
margs = appendExpEnv(margs, m.Suffix)
if flags&flagVerbose != 0 {
if conf.flags&flagVerbose != 0 {
log.Printf("using macro: %s", macroName)
}
return processCmd(margs, dir, conf, flags)
return processCmd(margs, conf)
}
var cmdArgs []string
@ -68,13 +68,13 @@ func processCmd(params []string, dir string, conf *config, flags int) error {
cmdArgs = args[1:]
}
if flags&flagVerbose != 0 {
if conf.flags&flagVerbose != 0 {
log.Printf("executing command: %s %s", cmdName, strings.Join(cmdArgs, " "))
}
return try(func() error {
cmd := exec.Command(cmdName, cmdArgs...)
cmd.Dir = dir
cmd.Dir = conf.dstDir
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
cmd.Stdin = os.Stdin

View File

@ -22,13 +22,50 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"github.com/naoina/toml"
"gopkg.in/yaml.v2"
)
type config struct {
Tasks map[string]task
Macros map[string]macro
tasksHandled map[string]bool
handled map[string]bool
srcDir string
dstDir string
variant string
flags int
}
func (c *config) process(srcDir, dstDir, taskName string, flags int) error {
c.tasksHandled = make(map[string]bool)
return processTask(taskName, srcDir, dstDir, c, flags)
func newConfig(filename string) (*config, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
conf := &config{handled: make(map[string]bool)}
switch path.Ext(filename) {
case ".json":
if err := json.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
case ".toml", ".tml":
if err := toml.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
case ".yaml", ".yml":
if err := yaml.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported configuration file format")
}
return conf, nil
}

View File

@ -29,7 +29,7 @@ import (
"strings"
)
func processEnv(env []string, flags int) error {
func processEnv(env []string, conf *config) error {
args := appendExpEnv(nil, env)
var value string
@ -37,7 +37,7 @@ func processEnv(env []string, flags int) error {
case len(args) == 0:
return fmt.Errorf("invalid environment statement")
case len(args) == 1:
if flags&flagVerbose != 0 {
if conf.flags&flagVerbose != 0 {
log.Printf("unsetting variable: %s", args[0])
}
os.Unsetenv(args[0])
@ -48,7 +48,7 @@ func processEnv(env []string, flags int) error {
value = strings.Join(args[1:], ",")
}
if flags&flagVerbose != 0 {
if conf.flags&flagVerbose != 0 {
log.Printf("setting variable %s to %s", args[0], value)
}

View File

@ -23,17 +23,12 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/user"
"path"
"github.com/BurntSushi/toml"
"gopkg.in/yaml.v2"
)
const (
@ -45,33 +40,6 @@ const (
flagNoMacro
)
func parseCfg(filename string) (*config, error) {
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
conf := &config{}
switch path.Ext(filename) {
case ".json":
if err := json.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
case ".toml", ".tml":
if err := toml.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
case ".yaml", ".yml":
if err := yaml.Unmarshal(bytes, &conf); err != nil {
return nil, err
}
default:
return nil, fmt.Errorf("unsupported configuration file format")
}
return conf, nil
}
func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [options] conf src\n", path.Base(os.Args[0]))
fmt.Fprintf(os.Stderr, "http://foosoft.net/projects/homemaker/\n\n")
@ -92,6 +60,7 @@ func main() {
verbose := flag.Bool("verbose", false, "verbose output")
nocmd := flag.Bool("nocmd", false, "don't execute commands")
nolink := flag.Bool("nolink", false, "don't create links")
variant := flag.String("variant", "", "execution variant")
flag.Usage = usage
flag.Parse()
@ -114,21 +83,25 @@ func main() {
}
if flag.NArg() == 2 {
confDirAbs := makeAbsPath(flag.Arg(0))
srcDirAbs := makeAbsPath(flag.Arg(1))
dstDirAbs := makeAbsPath(*dstDir)
confFile := makeAbsPath(flag.Arg(0))
os.Setenv("HM_CONFIG", confDirAbs)
os.Setenv("HM_TASK", *taskName)
os.Setenv("HM_SRC", srcDirAbs)
os.Setenv("HM_DEST", dstDirAbs)
conf, err := parseCfg(confDirAbs)
conf, err := newConfig(confFile)
if err != nil {
log.Fatal(err)
}
if err := conf.process(srcDirAbs, dstDirAbs, *taskName, flags); err != nil {
conf.srcDir = makeAbsPath(flag.Arg(1))
conf.dstDir = makeAbsPath(*dstDir)
conf.variant = *variant
conf.flags = flags
os.Setenv("HM_CONFIG", confFile)
os.Setenv("HM_TASK", *taskName)
os.Setenv("HM_SRC", conf.srcDir)
os.Setenv("HM_DEST", conf.dstDir)
os.Setenv("HM_VARIANT", conf.variant)
if err := processTask(*taskName, conf); err != nil {
log.Fatal(err)
}
} else {

12
link.go
View File

@ -99,7 +99,7 @@ func parseLink(params []string) (srcPath, dstPath string, mode os.FileMode, err
return
}
func processLink(params []string, srcDir, dstDir string, flags int) error {
func processLink(params []string, conf *config) error {
srcPath, dstPath, mode, err := parseLink(params)
if err != nil {
return err
@ -107,27 +107,27 @@ func processLink(params []string, srcDir, dstDir string, flags int) error {
srcPathAbs := srcPath
if !path.IsAbs(srcPathAbs) {
srcPathAbs = path.Join(srcDir, srcPath)
srcPathAbs = path.Join(conf.srcDir, srcPath)
}
dstPathAbs := dstPath
if !path.IsAbs(dstPathAbs) {
dstPathAbs = path.Join(dstDir, dstPath)
dstPathAbs = path.Join(conf.dstDir, dstPath)
}
if _, err := os.Stat(srcPathAbs); os.IsNotExist(err) {
return fmt.Errorf("source path %s does not exist in filesystem", srcPathAbs)
}
if err := try(func() error { return createPath(dstPathAbs, flags, mode) }); err != nil {
if err := try(func() error { return createPath(dstPathAbs, conf.flags, mode) }); err != nil {
return err
}
if err := try(func() error { return cleanPath(dstPathAbs, flags) }); err != nil {
if err := try(func() error { return cleanPath(dstPathAbs, conf.flags) }); err != nil {
return err
}
if flags&flagVerbose != 0 {
if conf.flags&flagVerbose != 0 {
log.Printf("linking %s to %s", srcPathAbs, dstPathAbs)
}

22
task.go
View File

@ -31,30 +31,30 @@ type task struct {
Envs [][]string
}
func (t *task) process(srcDir, dstDir string, conf *config, flags int) error {
func (t *task) process(conf *config) error {
for _, currTask := range t.Deps {
if err := processTask(currTask, srcDir, dstDir, conf, flags); err != nil {
if err := processTask(currTask, conf); err != nil {
return err
}
}
for _, currEnv := range t.Envs {
if err := processEnv(currEnv, flags); err != nil {
if err := processEnv(currEnv, conf); err != nil {
return err
}
}
if flags&flagNoCmd == 0 {
if conf.flags&flagNoCmd == 0 {
for _, currCmd := range t.Cmds {
if err := processCmd(currCmd, dstDir, conf, flags); err != nil {
if err := processCmd(currCmd, conf); err != nil {
return err
}
}
}
if flags&flagNoLink == 0 {
if conf.flags&flagNoLink == 0 {
for _, currLink := range t.Links {
if err := processLink(currLink, srcDir, dstDir, flags); err != nil {
if err := processLink(currLink, conf); err != nil {
return err
}
}
@ -63,18 +63,18 @@ func (t *task) process(srcDir, dstDir string, conf *config, flags int) error {
return nil
}
func processTask(taskName, srcDir, dstDir string, conf *config, flags int) error {
handled, ok := conf.tasksHandled[taskName]
func processTask(taskName string, conf *config) error {
handled, ok := conf.handled[taskName]
if ok && handled {
return nil
}
conf.tasksHandled[taskName] = true
conf.handled[taskName] = true
t, ok := conf.Tasks[taskName]
if !ok {
return fmt.Errorf("task not found: %s", taskName)
}
return t.process(srcDir, dstDir, conf, flags)
return t.process(conf)
}