X-Git-Url: https://ruderich.org/simon/gitweb/?p=nsscash%2Fnsscash.git;a=blobdiff_plain;f=main.go;h=5455dfe0b367cc8bf92f2ba20979273a97dce086;hp=50263877f2a71380b1b774e40f3984498324a8c6;hb=d946c291618d93e4ab4ad898c1ae317fbe2256e3;hpb=92afde4e875a96e1ab865e29b9f0d11b08d7db1c diff --git a/main.go b/main.go index 5026387..5455dfe 100644 --- a/main.go +++ b/main.go @@ -18,32 +18,141 @@ package main import ( + "bytes" + "flag" + "fmt" + "io/ioutil" "log" "os" + "path/filepath" ) func main() { - if len(os.Args) != 2 { - log.SetFlags(0) - log.Fatalf("usage: %s \n", os.Args[0]) + flag.Usage = func() { + fmt.Fprintf(os.Stderr, + "usage: %[1]s [options] fetch \n"+ + "usage: %[1]s [options] convert \n"+ + "", + os.Args[0]) + flag.PrintDefaults() } + flag.Parse() - cfg, err := LoadConfig(os.Args[1]) + args := flag.Args() + if len(args) == 0 { + flag.Usage() + os.Exit(1) + } + + switch args[0] { + case "fetch": + if len(args) != 2 { + break + } + + err := mainFetch(args[1]) + if err != nil { + log.Fatal(err) + } + return + + case "convert": + if len(args) != 4 { + break + } + + err := mainConvert(args[1], args[2], args[3]) + if err != nil { + log.Fatal(err) + } + return + } + + flag.Usage() + os.Exit(1) +} + +func mainFetch(cfgPath string) error { + cfg, err := LoadConfig(cfgPath) if err != nil { - log.Fatal(err) + return err } state, err := LoadState(cfg.StatePath) if err != nil { - log.Fatal(err) + return err } - err = handleFiles(cfg, state) if err != nil { - log.Fatal(err) + return err } + // NOTE: Make sure to call WriteState() only if there were no + // errors (see WriteState() and README) + err = WriteState(cfg.StatePath, state) + if err != nil { + return err + } + return nil +} - err = WriteStateIfChanged(cfg.StatePath, state) +func mainConvert(typ, srcPath, dstPath string) error { + var t FileType + err := t.UnmarshalText([]byte(typ)) if err != nil { - log.Fatal(err) + return err } + + src, err := ioutil.ReadFile(srcPath) + if err != nil { + return err + } + var x bytes.Buffer + if t == FileTypePlain { + x.Write(src) + } else if t == FileTypePasswd { + pws, err := ParsePasswds(bytes.NewReader(src)) + if err != nil { + return err + } + err = SerializePasswds(&x, pws) + if err != nil { + return err + } + } else if t == FileTypeGroup { + grs, err := ParseGroups(bytes.NewReader(src)) + if err != nil { + return err + } + err = SerializeGroups(&x, grs) + if err != nil { + return err + } + } else { + return fmt.Errorf("unsupported file type %v", t) + } + + dstDir := filepath.Dir(dstPath) + dstName := filepath.Base(dstPath) + + // We must create the file first or deployFile() will abort; this is + // ugly because deployFile() already performs an atomic replacement + // but the simplest solution with the least duplicate code + f, err := ioutil.TempFile(dstDir, "tmp-"+dstName+"-") + if err != nil { + return err + } + tmpPath := f.Name() + defer os.Remove(tmpPath) + f.Close() + + err = deployFile(&File{ + Type: t, + Url: srcPath, + Path: tmpPath, + body: x.Bytes(), + }) + if err != nil { + return err + } + + return os.Rename(tmpPath, dstPath) }