if cli -f is a dir, then edit each file+clean each file+keep each as individual file

Bel LaPointe 2022-01-08 23:42:05 -05:00
parent dd7ac8d786
commit c559c8eba6
5 changed files with 146 additions and 42 deletions

View File

@ -35,8 +35,8 @@ func _main() error {
if !ok {
defaultFilepath = "-"
}
filepath := flag.String("f", defaultFilepath, "($PTTODO_FILE) path to yaml file")
filepathToMergeIn := flag.String("g", "", "path to yaml file to merge into -f")
filepath := flag.String("f", defaultFilepath, "($PTTODO_FILE) path to yaml file or dir (starting with root then alphabetical for dir)")
filepathToMergeIn := flag.String("g", "", "path to yaml file to merge into -f (modifies f)")
root := flag.String("root", DUMP_TODO, "path to pretty print ("+fmt.Sprint([]string{DUMP_ALL, DUMP_TODO, DUMP_SCHEDULED, DUMP_DONE})+")")
tags := flag.String("tags", "", "csv of all tags to find, -tag to invert")
search := flag.String("search", "", "fts case insensitive")
@ -48,8 +48,17 @@ func _main() error {
return err
}
}
filepaths := []string{*filepath}
if stat, err := os.Stat(*filepath); err != nil && !os.IsNotExist(err) {
return err
} else if err == nil && stat.IsDir() {
filepaths, err = listDir(*filepath)
if err != nil {
return err
}
}
if *e {
if err := edit(*dry, *filepath); err != nil {
if err := edit(*dry, filepaths); err != nil {
return err
}
}
@ -57,7 +66,7 @@ func _main() error {
if *tags != "" {
tagslist = strings.Split(*tags, ",")
}
return dump(*dry, os.Stdout, *filepath, tagslist, *search, *root)
return dump(*dry, os.Stdout, filepaths, tagslist, *search, *root)
}
func verifyRoot(root pttodo.Root) error {
@ -79,16 +88,19 @@ func verifyRoot(root pttodo.Root) error {
}
func verifyFile(path string) error {
if err := dump(true, io.Discard, path, nil, "", DUMP_ALL); err != nil {
if err := dump(true, io.Discard, []string{path}, nil, "", DUMP_ALL); err != nil {
return fmt.Errorf("failed verifying file %s: %w", path, err)
}
return nil
}
func edit(dry bool, filepath string) error {
var tempFile string
cp := func() error {
f, err := ioutil.TempFile(os.TempDir(), path.Base(filepath))
func edit(dry bool, filepaths []string) error {
tempDir, err := ioutil.TempDir(os.TempDir(), "edit-pttodo")
if err != nil {
return err
}
cpOne := func(filepath string) error {
f, err := os.Create(path.Join(tempDir, path.Base(filepath)))
if err != nil {
return err
}
@ -103,14 +115,18 @@ func edit(dry bool, filepath string) error {
g.Close()
}
f.Close()
tempFile = f.Name() + ".yaml"
return os.Rename(f.Name(), tempFile)
return nil
}
cp := func() error {
for _, filepath := range filepaths {
if err := cpOne(filepath); err != nil {
return err
}
}
return nil
}
vi := func() error {
bin := "vim"
if editor := os.Getenv("EDITOR"); editor != "" {
bin = editor
}
editorbin, err := exec.LookPath(bin)
if err != nil {
editorbin, err = exec.LookPath("vi")
@ -118,12 +134,17 @@ func edit(dry bool, filepath string) error {
if err != nil {
return err
}
args := []string{editorbin, tempFile}
args := []string{editorbin, "-p"}
tempfiles, err := listDir(tempDir)
if err != nil {
return err
}
args = append(args, tempfiles...)
cpid, err := syscall.ForkExec(
editorbin,
args,
&syscall.ProcAttr{
Dir: "",
Dir: tempDir,
Env: os.Environ(),
Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()},
Sys: nil,
@ -145,7 +166,7 @@ func edit(dry bool, filepath string) error {
}
return nil
}
verify := func() error {
verifyOne := func(tempFile string) error {
for {
err := verifyFile(tempFile)
if err == nil {
@ -162,13 +183,31 @@ func edit(dry bool, filepath string) error {
}
return verifyFile(tempFile)
}
save := func() error {
verify := func() error {
for _, filepath := range filepaths {
tempFile := path.Join(tempDir, path.Base(filepath))
if err := verifyOne(tempFile); err != nil {
return err
}
}
return nil
}
saveOne := func(filepath string) error {
tempFile := path.Join(tempDir, path.Base(filepath))
if dry {
log.Printf("would've saved %s as %s", tempFile, filepath)
return nil
}
return os.Rename(tempFile, filepath)
}
save := func() error {
for _, filepath := range filepaths {
if err := saveOne(filepath); err != nil {
return err
}
}
return nil
}
for _, foo := range []func() error{cp, vi, verify, save} {
if err := foo(); err != nil {
@ -176,7 +215,7 @@ func edit(dry bool, filepath string) error {
}
}
if !dry {
os.Remove(tempFile)
os.RemoveAll(tempDir)
}
return nil
@ -241,7 +280,10 @@ func marshalRootToTempFile(root pttodo.Root) (string, error) {
return filepath, err
}
func dump(dry bool, writer io.Writer, filepath string, tags []string, search, rootDisplay string) error {
func dump(dry bool, writer io.Writer, filepaths []string, tags []string, search, rootDisplay string) error {
var root pttodo.Root
for _, filepath := range filepaths {
reader, err := filePathReader(filepath)
if err != nil {
return err
@ -252,10 +294,24 @@ func dump(dry bool, writer io.Writer, filepath string, tags []string, search, ro
return err
}
var root pttodo.Root
if err := yaml.Unmarshal(b, &root); err != nil {
var root2 pttodo.Root
if err := yaml.Unmarshal(b, &root2); err != nil {
return err
}
root2.MoveScheduledToTodo()
root.MergeIn(root2)
if !dry {
b3, err := yaml.Marshal(root2)
if err != nil {
return err
}
if err := os.WriteFile(filepath, b3, os.ModePerm); err != nil {
return err
}
}
}
root.MoveScheduledToTodo()
var v interface{} = root
@ -296,23 +352,15 @@ func dump(dry bool, writer io.Writer, filepath string, tags []string, search, ro
}
v = todos
}
b2, err := yaml.Marshal(v)
if err != nil {
return err
}
fmt.Fprintf(writer, "%s\n", b2)
if dry {
return nil
}
b3, err := yaml.Marshal(root)
if err != nil {
return err
}
return os.WriteFile(filepath, b3, os.ModePerm)
}
func filePathReader(path string) (io.Reader, error) {
var reader io.Reader
if path == "-" {
@ -326,3 +374,18 @@ func filePathReader(path string) (io.Reader, error) {
}
return reader, nil
}
func listDir(dname string) ([]string, error) {
entries, err := os.ReadDir(dname)
if err != nil {
return nil, err
}
paths := make([]string, 0, len(entries))
for i := range entries {
if entries[i].IsDir() {
continue
}
paths = append(paths, path.Join(dname, entries[i].Name()))
}
return paths, nil
}

View File

@ -0,0 +1,29 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"path"
"strconv"
"testing"
)
func TestListDir(t *testing.T) {
d := t.TempDir()
want := []string{}
for i := 0; i < 3; i++ {
p := path.Join(d, strconv.Itoa(i))
ioutil.WriteFile(p, []byte{}, os.ModePerm)
want = append(want, p)
}
os.Mkdir(path.Join(d, "d"), os.ModePerm)
got, err := listDir(d)
if err != nil {
t.Fatal(err)
}
if fmt.Sprint(want) != fmt.Sprint(got) {
t.Fatal(want, got)
}
}

4
cmd/pttodo-cli/testdata/1.yaml vendored Normal file
View File

@ -0,0 +1,4 @@
todo:
- "1"
scheduled: []
done: []

4
cmd/pttodo-cli/testdata/2.yaml vendored Normal file
View File

@ -0,0 +1,4 @@
todo:
- "2"
scheduled: []
done: []

4
cmd/pttodo-cli/testdata/3.yaml vendored Normal file
View File

@ -0,0 +1,4 @@
todo:
- "3"
scheduled: []
done: []