if cli -f is a dir, then edit each file+clean each file+keep each as individual file
This commit is contained in:
@@ -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,21 +280,38 @@ 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 {
|
||||
reader, err := filePathReader(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func dump(dry bool, writer io.Writer, filepaths []string, tags []string, search, rootDisplay string) error {
|
||||
var root pttodo.Root
|
||||
if err := yaml.Unmarshal(b, &root); err != nil {
|
||||
return err
|
||||
|
||||
for _, filepath := range filepaths {
|
||||
reader, err := filePathReader(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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,21 +352,13 @@ 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)
|
||||
return nil
|
||||
}
|
||||
|
||||
func filePathReader(path string) (io.Reader, error) {
|
||||
@@ -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
|
||||
}
|
||||
|
||||
29
cmd/pttodo-cli/cli_test.go
Normal file
29
cmd/pttodo-cli/cli_test.go
Normal 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
4
cmd/pttodo-cli/testdata/1.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
todo:
|
||||
- "1"
|
||||
scheduled: []
|
||||
done: []
|
||||
4
cmd/pttodo-cli/testdata/2.yaml
vendored
Normal file
4
cmd/pttodo-cli/testdata/2.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
todo:
|
||||
- "2"
|
||||
scheduled: []
|
||||
done: []
|
||||
4
cmd/pttodo-cli/testdata/3.yaml
vendored
Normal file
4
cmd/pttodo-cli/testdata/3.yaml
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
todo:
|
||||
- "3"
|
||||
scheduled: []
|
||||
done: []
|
||||
Reference in New Issue
Block a user