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

View File

@ -22,13 +22,50 @@
package main package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"path"
"github.com/naoina/toml"
"gopkg.in/yaml.v2"
)
type config struct { type config struct {
Tasks map[string]task Tasks map[string]task
Macros map[string]macro 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 { func newConfig(filename string) (*config, error) {
c.tasksHandled = make(map[string]bool) bytes, err := ioutil.ReadFile(filename)
return processTask(taskName, srcDir, dstDir, c, flags) 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" "strings"
) )
func processEnv(env []string, flags int) error { func processEnv(env []string, conf *config) error {
args := appendExpEnv(nil, env) args := appendExpEnv(nil, env)
var value string var value string
@ -37,7 +37,7 @@ func processEnv(env []string, flags int) error {
case len(args) == 0: case len(args) == 0:
return fmt.Errorf("invalid environment statement") return fmt.Errorf("invalid environment statement")
case len(args) == 1: case len(args) == 1:
if flags&flagVerbose != 0 { if conf.flags&flagVerbose != 0 {
log.Printf("unsetting variable: %s", args[0]) log.Printf("unsetting variable: %s", args[0])
} }
os.Unsetenv(args[0]) os.Unsetenv(args[0])
@ -48,7 +48,7 @@ func processEnv(env []string, flags int) error {
value = strings.Join(args[1:], ",") value = strings.Join(args[1:], ",")
} }
if flags&flagVerbose != 0 { if conf.flags&flagVerbose != 0 {
log.Printf("setting variable %s to %s", args[0], value) log.Printf("setting variable %s to %s", args[0], value)
} }

View File

@ -23,17 +23,12 @@
package main package main
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"log" "log"
"os" "os"
"os/user" "os/user"
"path" "path"
"github.com/BurntSushi/toml"
"gopkg.in/yaml.v2"
) )
const ( const (
@ -45,33 +40,6 @@ const (
flagNoMacro 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() { func usage() {
fmt.Fprintf(os.Stderr, "Usage: %s [options] conf src\n", path.Base(os.Args[0])) 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") fmt.Fprintf(os.Stderr, "http://foosoft.net/projects/homemaker/\n\n")
@ -92,6 +60,7 @@ func main() {
verbose := flag.Bool("verbose", false, "verbose output") verbose := flag.Bool("verbose", false, "verbose output")
nocmd := flag.Bool("nocmd", false, "don't execute commands") nocmd := flag.Bool("nocmd", false, "don't execute commands")
nolink := flag.Bool("nolink", false, "don't create links") nolink := flag.Bool("nolink", false, "don't create links")
variant := flag.String("variant", "", "execution variant")
flag.Usage = usage flag.Usage = usage
flag.Parse() flag.Parse()
@ -114,21 +83,25 @@ func main() {
} }
if flag.NArg() == 2 { if flag.NArg() == 2 {
confDirAbs := makeAbsPath(flag.Arg(0)) confFile := makeAbsPath(flag.Arg(0))
srcDirAbs := makeAbsPath(flag.Arg(1))
dstDirAbs := makeAbsPath(*dstDir)
os.Setenv("HM_CONFIG", confDirAbs) conf, err := newConfig(confFile)
os.Setenv("HM_TASK", *taskName)
os.Setenv("HM_SRC", srcDirAbs)
os.Setenv("HM_DEST", dstDirAbs)
conf, err := parseCfg(confDirAbs)
if err != nil { if err != nil {
log.Fatal(err) 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) log.Fatal(err)
} }
} else { } else {

12
link.go
View File

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

22
task.go
View File

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