Remove ls and cat commands

This commit is contained in:
Sung 2025-11-07 23:00:23 -08:00
commit 04091f7ddf
13 changed files with 425 additions and 197 deletions

View file

@ -131,7 +131,7 @@ func newRun(ctx context.DnoteCtx) infra.RunEFunc {
return err
}
output.NoteInfo(info)
output.NoteInfo(os.Stdout, info)
if err := upgrade.Check(ctx); err != nil {
log.Error(errors.Wrap(err, "automatically checking updates").Error())

View file

@ -1,95 +0,0 @@
/* Copyright 2025 Dnote Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cat
import (
"strconv"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/database"
"github.com/dnote/dnote/pkg/cli/infra"
"github.com/dnote/dnote/pkg/cli/log"
"github.com/dnote/dnote/pkg/cli/output"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
var example = `
* See the notes with index 2 from a book 'javascript'
dnote cat javascript 2
`
var deprecationWarning = `and "view" will replace it in the future version.
Run "dnote view --help" for more information.
`
func preRun(cmd *cobra.Command, args []string) error {
if len(args) != 2 {
return errors.New("Incorrect number of arguments")
}
return nil
}
// NewCmd returns a new cat command
func NewCmd(ctx context.DnoteCtx) *cobra.Command {
cmd := &cobra.Command{
Use: "cat <book name> <note index>",
Aliases: []string{"c"},
Short: "See a note",
Example: example,
RunE: NewRun(ctx, false),
PreRunE: preRun,
Deprecated: deprecationWarning,
}
return cmd
}
// NewRun returns a new run function
func NewRun(ctx context.DnoteCtx, contentOnly bool) infra.RunEFunc {
return func(cmd *cobra.Command, args []string) error {
var noteRowIDArg string
if len(args) == 2 {
log.Plain(log.ColorYellow.Sprintf("DEPRECATED: you no longer need to pass book name to the view command. e.g. `dnote view 123`.\n\n"))
noteRowIDArg = args[1]
} else {
noteRowIDArg = args[0]
}
noteRowID, err := strconv.Atoi(noteRowIDArg)
if err != nil {
return errors.Wrap(err, "invalid rowid")
}
db := ctx.DB
info, err := database.GetNoteInfo(db, noteRowID)
if err != nil {
return err
}
if contentOnly {
output.NoteContent(info)
} else {
output.NoteInfo(info)
}
return nil
}
}

View file

@ -166,7 +166,7 @@ func runNote(ctx context.DnoteCtx, rowIDArg string) error {
}
log.Success("edited the note\n")
output.NoteInfo(noteInfo)
output.NoteInfo(os.Stdout, noteInfo)
return nil
}

View file

@ -17,6 +17,7 @@ package remove
import (
"fmt"
"os"
"strconv"
"github.com/dnote/dnote/pkg/cli/context"
@ -129,7 +130,7 @@ func runNote(ctx context.DnoteCtx, rowIDArg string) error {
return err
}
output.NoteInfo(noteInfo)
output.NoteInfo(os.Stdout, noteInfo)
ok, err := maybeConfirm("remove this note?", false)
if err != nil {

View file

@ -13,76 +13,19 @@
* limitations under the License.
*/
package ls
package view
import (
"database/sql"
"fmt"
"io"
"strings"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/infra"
"github.com/dnote/dnote/pkg/cli/log"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
var example = `
* List all books
dnote ls
* List notes in a book
dnote ls javascript
`
var deprecationWarning = `and "view" will replace it in the future version.
Run "dnote view --help" for more information.
`
func preRun(cmd *cobra.Command, args []string) error {
if len(args) > 1 {
return errors.New("Incorrect number of argument")
}
return nil
}
// NewCmd returns a new ls command
func NewCmd(ctx context.DnoteCtx) *cobra.Command {
cmd := &cobra.Command{
Use: "ls <book name?>",
Aliases: []string{"l", "notes"},
Short: "List all notes",
Example: example,
RunE: NewRun(ctx, false),
PreRunE: preRun,
Deprecated: deprecationWarning,
}
return cmd
}
// NewRun returns a new run function for ls
func NewRun(ctx context.DnoteCtx, nameOnly bool) infra.RunEFunc {
return func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
if err := printBooks(ctx, nameOnly); err != nil {
return errors.Wrap(err, "viewing books")
}
return nil
}
bookName := args[0]
if err := printNotes(ctx, bookName); err != nil {
return errors.Wrapf(err, "viewing book '%s'", bookName)
}
return nil
}
}
// bookInfo is an information about the book to be printed on screen
type bookInfo struct {
BookLabel string
@ -97,15 +40,13 @@ type noteInfo struct {
// getNewlineIdx returns the index of newline character in a string
func getNewlineIdx(str string) int {
var ret int
ret = strings.Index(str, "\n")
if ret == -1 {
ret = strings.Index(str, "\r\n")
// Check for \r\n first
if idx := strings.Index(str, "\r\n"); idx != -1 {
return idx
}
return ret
// Then check for \n
return strings.Index(str, "\n")
}
// formatBody returns an excerpt of the given raw note content and a boolean
@ -123,15 +64,15 @@ func formatBody(noteBody string) (string, bool) {
return strings.Trim(trimmed, " "), false
}
func printBookLine(info bookInfo, nameOnly bool) {
func printBookLine(w io.Writer, info bookInfo, nameOnly bool) {
if nameOnly {
fmt.Println(info.BookLabel)
fmt.Fprintln(w, info.BookLabel)
} else {
log.Printf("%s %s\n", info.BookLabel, log.ColorYellow.Sprintf("(%d)", info.NoteCount))
fmt.Fprintf(w, "%s %s\n", info.BookLabel, log.ColorYellow.Sprintf("(%d)", info.NoteCount))
}
}
func printBooks(ctx context.DnoteCtx, nameOnly bool) error {
func listBooks(ctx context.DnoteCtx, w io.Writer, nameOnly bool) error {
db := ctx.DB
rows, err := db.Query(`SELECT books.label, count(notes.uuid) note_count
@ -157,13 +98,13 @@ func printBooks(ctx context.DnoteCtx, nameOnly bool) error {
}
for _, info := range infos {
printBookLine(info, nameOnly)
printBookLine(w, info, nameOnly)
}
return nil
}
func printNotes(ctx context.DnoteCtx, bookName string) error {
func listNotes(ctx context.DnoteCtx, w io.Writer, bookName string) error {
db := ctx.DB
var bookUUID string
@ -191,7 +132,7 @@ func printNotes(ctx context.DnoteCtx, bookName string) error {
infos = append(infos, info)
}
log.Infof("on book %s\n", bookName)
fmt.Fprintf(w, "on book %s\n", bookName)
for _, info := range infos {
body, isExcerpt := formatBody(info.Body)
@ -201,7 +142,7 @@ func printNotes(ctx context.DnoteCtx, bookName string) error {
body = fmt.Sprintf("%s %s", body, log.ColorYellow.Sprintf("[---More---]"))
}
log.Plainf("%s %s\n", rowid, body)
fmt.Fprintf(w, "%s %s\n", rowid, body)
}
return nil

View file

@ -0,0 +1,184 @@
/* Copyright 2025 Dnote Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package view
import (
"bytes"
"fmt"
"strings"
"testing"
"github.com/dnote/dnote/pkg/assert"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/database"
)
func TestGetNewlineIdx(t *testing.T) {
testCases := []struct {
input string
expected int
}{
{
input: "hello\nworld",
expected: 5,
},
{
input: "hello\r\nworld",
expected: 5,
},
{
input: "no newline here",
expected: -1,
},
{
input: "",
expected: -1,
},
{
input: "\n",
expected: 0,
},
{
input: "\r\n",
expected: 0,
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("input: %q", tc.input), func(t *testing.T) {
got := getNewlineIdx(tc.input)
assert.Equal(t, got, tc.expected, "newline index mismatch")
})
}
}
func TestFormatBody(t *testing.T) {
testCases := []struct {
input string
expectedBody string
expectedExcerpt bool
}{
{
input: "single line",
expectedBody: "single line",
expectedExcerpt: false,
},
{
input: "first line\nsecond line",
expectedBody: "first line",
expectedExcerpt: true,
},
{
input: "first line\r\nsecond line",
expectedBody: "first line",
expectedExcerpt: true,
},
{
input: " spaced line ",
expectedBody: "spaced line",
expectedExcerpt: false,
},
{
input: " first line \nsecond line",
expectedBody: "first line",
expectedExcerpt: true,
},
{
input: "",
expectedBody: "",
expectedExcerpt: false,
},
{
input: "line with trailing newline\n",
expectedBody: "line with trailing newline",
expectedExcerpt: false,
},
{
input: "line with trailing newlines\n\n",
expectedBody: "line with trailing newlines",
expectedExcerpt: false,
},
}
for _, tc := range testCases {
t.Run(fmt.Sprintf("input: %q", tc.input), func(t *testing.T) {
gotBody, gotExcerpt := formatBody(tc.input)
assert.Equal(t, gotBody, tc.expectedBody, "formatted body mismatch")
assert.Equal(t, gotExcerpt, tc.expectedExcerpt, "excerpt flag mismatch")
})
}
}
func TestListNotes(t *testing.T) {
// Setup
db := database.InitTestMemoryDB(t)
defer db.Close()
bookUUID := "js-book-uuid"
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", bookUUID, "javascript")
database.MustExec(t, "inserting note 1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "note-1", bookUUID, "first note", 1515199943)
database.MustExec(t, "inserting note 2", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "note-2", bookUUID, "multiline note\nwith second line", 1515199945)
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
// Execute
err := listNotes(ctx, &buf, "javascript")
if err != nil {
t.Fatal(err)
}
got := buf.String()
// Verify output
assert.Equal(t, strings.Contains(got, "on book javascript"), true, "should show book name")
assert.Equal(t, strings.Contains(got, "first note"), true, "should contain first note")
assert.Equal(t, strings.Contains(got, "multiline note"), true, "should show first line of multiline note")
assert.Equal(t, strings.Contains(got, "[---More---]"), true, "should show more indicator for multiline note")
assert.Equal(t, strings.Contains(got, "with second line"), false, "should not show second line of multiline note")
}
func TestListBooks(t *testing.T) {
// Setup
db := database.InitTestMemoryDB(t)
defer db.Close()
b1UUID := "js-book-uuid"
b2UUID := "linux-book-uuid"
database.MustExec(t, "inserting book 1", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b1UUID, "javascript")
database.MustExec(t, "inserting book 2", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", b2UUID, "linux")
// Add notes to test count
database.MustExec(t, "inserting note 1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "note-1", b1UUID, "note body 1", 1515199943)
database.MustExec(t, "inserting note 2", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)", "note-2", b1UUID, "note body 2", 1515199944)
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
// Execute
err := listBooks(ctx, &buf, false)
if err != nil {
t.Fatal(err)
}
got := buf.String()
// Verify output
assert.Equal(t, strings.Contains(got, "javascript"), true, "should contain javascript book")
assert.Equal(t, strings.Contains(got, "linux"), true, "should contain linux book")
assert.Equal(t, strings.Contains(got, "(2)"), true, "should show 2 notes for javascript")
}

47
pkg/cli/cmd/view/note.go Normal file
View file

@ -0,0 +1,47 @@
/* Copyright 2025 Dnote Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package view
import (
"io"
"strconv"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/database"
"github.com/dnote/dnote/pkg/cli/output"
"github.com/pkg/errors"
)
func viewNote(ctx context.DnoteCtx, w io.Writer, noteRowIDArg string, contentOnly bool) error {
noteRowID, err := strconv.Atoi(noteRowIDArg)
if err != nil {
return errors.Wrap(err, "invalid rowid")
}
db := ctx.DB
info, err := database.GetNoteInfo(db, noteRowID)
if err != nil {
return err
}
if contentOnly {
output.NoteContent(w, info)
} else {
output.NoteInfo(w, info)
}
return nil
}

View file

@ -0,0 +1,90 @@
/* Copyright 2025 Dnote Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package view
import (
"bytes"
"strings"
"testing"
"github.com/dnote/dnote/pkg/assert"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/database"
)
func TestViewNote(t *testing.T) {
db := database.InitTestMemoryDB(t)
defer db.Close()
bookUUID := "test-book-uuid"
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", bookUUID, "golang")
database.MustExec(t, "inserting note", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)",
"note-uuid", bookUUID, "test note content", 1515199943000000000)
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
err := viewNote(ctx, &buf, "1", false)
if err != nil {
t.Fatal(err)
}
got := buf.String()
assert.Equal(t, strings.Contains(got, "test note content"), true, "should contain note content")
}
func TestViewNoteContentOnly(t *testing.T) {
db := database.InitTestMemoryDB(t)
defer db.Close()
bookUUID := "test-book-uuid"
database.MustExec(t, "inserting book", db, "INSERT INTO books (uuid, label) VALUES (?, ?)", bookUUID, "golang")
database.MustExec(t, "inserting note", db, "INSERT INTO notes (uuid, book_uuid, body, added_on) VALUES (?, ?, ?, ?)",
"note-uuid", bookUUID, "test note content", 1515199943000000000)
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
err := viewNote(ctx, &buf, "1", true)
if err != nil {
t.Fatal(err)
}
got := buf.String()
assert.Equal(t, got, "test note content", "should contain only note content")
}
func TestViewNoteInvalidRowID(t *testing.T) {
db := database.InitTestMemoryDB(t)
defer db.Close()
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
err := viewNote(ctx, &buf, "not-a-number", false)
assert.NotEqual(t, err, nil, "should return error for invalid rowid")
}
func TestViewNoteNotFound(t *testing.T) {
db := database.InitTestMemoryDB(t)
defer db.Close()
ctx := context.DnoteCtx{DB: db}
var buf bytes.Buffer
err := viewNote(ctx, &buf, "999", false)
assert.NotEqual(t, err, nil, "should return error for non-existent note")
}

View file

@ -16,14 +16,13 @@
package view
import (
"os"
"github.com/dnote/dnote/pkg/cli/context"
"github.com/dnote/dnote/pkg/cli/infra"
"github.com/dnote/dnote/pkg/cli/utils"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/dnote/dnote/pkg/cli/cmd/cat"
"github.com/dnote/dnote/pkg/cli/cmd/ls"
"github.com/dnote/dnote/pkg/cli/utils"
)
var example = `
@ -68,27 +67,26 @@ func NewCmd(ctx context.DnoteCtx) *cobra.Command {
func newRun(ctx context.DnoteCtx) infra.RunEFunc {
return func(cmd *cobra.Command, args []string) error {
var run infra.RunEFunc
if len(args) == 0 {
run = ls.NewRun(ctx, nameOnly)
// List all books
return listBooks(ctx, os.Stdout, nameOnly)
} else if len(args) == 1 {
if nameOnly {
return errors.New("--name-only flag is only valid when viewing books")
}
if utils.IsNumber(args[0]) {
run = cat.NewRun(ctx, contentOnly)
// View a note by index
return viewNote(ctx, os.Stdout, args[0], contentOnly)
} else {
run = ls.NewRun(ctx, false)
// List notes in a book
return listNotes(ctx, os.Stdout, args[0])
}
} else if len(args) == 2 {
// DEPRECATED: passing book name to view command is deprecated
run = cat.NewRun(ctx, false)
} else {
return errors.New("Incorrect number of arguments")
// View a note in a book (book name + note index)
return viewNote(ctx, os.Stdout, args[1], contentOnly)
}
return run(cmd, args)
return errors.New("Incorrect number of arguments")
}
}

View file

@ -26,12 +26,10 @@ import (
// commands
"github.com/dnote/dnote/pkg/cli/cmd/add"
"github.com/dnote/dnote/pkg/cli/cmd/cat"
"github.com/dnote/dnote/pkg/cli/cmd/edit"
"github.com/dnote/dnote/pkg/cli/cmd/find"
"github.com/dnote/dnote/pkg/cli/cmd/login"
"github.com/dnote/dnote/pkg/cli/cmd/logout"
"github.com/dnote/dnote/pkg/cli/cmd/ls"
"github.com/dnote/dnote/pkg/cli/cmd/remove"
"github.com/dnote/dnote/pkg/cli/cmd/root"
"github.com/dnote/dnote/pkg/cli/cmd/sync"
@ -79,10 +77,8 @@ func main() {
root.Register(login.NewCmd(*ctx))
root.Register(logout.NewCmd(*ctx))
root.Register(add.NewCmd(*ctx))
root.Register(ls.NewCmd(*ctx))
root.Register(sync.NewCmd(*ctx))
root.Register(version.NewCmd(*ctx))
root.Register(cat.NewCmd(*ctx))
root.Register(view.NewCmd(*ctx))
root.Register(find.NewCmd(*ctx))

View file

@ -20,6 +20,7 @@ import (
"log"
"os"
"os/exec"
"strings"
"testing"
"github.com/dnote/dnote/pkg/assert"
@ -568,3 +569,65 @@ func TestDBPathFlag(t *testing.T) {
db2.QueryRow("SELECT count(*) FROM books WHERE label = ?", "db1-book").Scan(&db2HasDB1Book)
assert.Equal(t, db2HasDB1Book, 0, "db2 should not have db1's book")
}
func TestView(t *testing.T) {
t.Run("view note by rowid", func(t *testing.T) {
_, opts := setupTestEnv(t)
db, dbPath := database.InitTestFileDB(t)
testutils.Setup4(t, db)
output := testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "view", "1")
assert.Equal(t, strings.Contains(output, "Booleans have toString()"), true, "should contain note content")
assert.Equal(t, strings.Contains(output, "book name"), true, "should show metadata")
})
t.Run("view note content only", func(t *testing.T) {
_, opts := setupTestEnv(t)
db, dbPath := database.InitTestFileDB(t)
testutils.Setup4(t, db)
output := testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "view", "1", "--content-only")
assert.Equal(t, strings.Contains(output, "Booleans have toString()"), true, "should contain note content")
assert.Equal(t, strings.Contains(output, "book name"), false, "should not show metadata")
})
t.Run("list books", func(t *testing.T) {
_, opts := setupTestEnv(t)
db, dbPath := database.InitTestFileDB(t)
testutils.Setup1(t, db)
output := testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "view")
assert.Equal(t, strings.Contains(output, "js"), true, "should list js book")
assert.Equal(t, strings.Contains(output, "linux"), true, "should list linux book")
})
t.Run("list notes in book", func(t *testing.T) {
_, opts := setupTestEnv(t)
db, dbPath := database.InitTestFileDB(t)
testutils.Setup2(t, db)
output := testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "view", "js")
assert.Equal(t, strings.Contains(output, "n1 body"), true, "should list note 1")
assert.Equal(t, strings.Contains(output, "n2 body"), true, "should list note 2")
})
t.Run("view note by book name and rowid", func(t *testing.T) {
_, opts := setupTestEnv(t)
db, dbPath := database.InitTestFileDB(t)
testutils.Setup4(t, db)
output := testutils.RunDnoteCmd(t, opts, binaryName, "--dbPath", dbPath, "view", "js", "2")
assert.Equal(t, strings.Contains(output, "Date object implements mathematical comparisons"), true, "should contain note content")
assert.Equal(t, strings.Contains(output, "book name"), true, "should show metadata")
})
}

View file

@ -19,6 +19,7 @@ package output
import (
"fmt"
"io"
"time"
"github.com/dnote/dnote/pkg/cli/database"
@ -26,7 +27,7 @@ import (
)
// NoteInfo prints a note information
func NoteInfo(info database.NoteInfo) {
func NoteInfo(w io.Writer, info database.NoteInfo) {
log.Infof("book name: %s\n", info.BookLabel)
log.Infof("created at: %s\n", time.Unix(0, info.AddedOn).Format("Jan 2, 2006 3:04pm (MST)"))
if info.EditedOn != 0 {
@ -35,13 +36,13 @@ func NoteInfo(info database.NoteInfo) {
log.Infof("note id: %d\n", info.RowID)
log.Infof("note uuid: %s\n", info.UUID)
fmt.Printf("\n------------------------content------------------------\n")
fmt.Printf("%s", info.Content)
fmt.Printf("\n-------------------------------------------------------\n")
fmt.Fprintf(w, "\n------------------------content------------------------\n")
fmt.Fprintf(w, "%s", info.Content)
fmt.Fprintf(w, "\n-------------------------------------------------------\n")
}
func NoteContent(info database.NoteInfo) {
fmt.Printf("%s", info.Content)
func NoteContent(w io.Writer, info database.NoteInfo) {
fmt.Fprintf(w, "%s", info.Content)
}
// BookInfo prints a note information

View file

@ -144,7 +144,7 @@ type RunDnoteCmdOptions struct {
}
// RunDnoteCmd runs a dnote command
func RunDnoteCmd(t *testing.T, opts RunDnoteCmdOptions, binaryName string, arg ...string) {
func RunDnoteCmd(t *testing.T, opts RunDnoteCmdOptions, binaryName string, arg ...string) string {
t.Logf("running: %s %s", binaryName, strings.Join(arg, " "))
cmd, stderr, stdout, err := NewDnoteCmd(opts, binaryName, arg...)
@ -162,6 +162,8 @@ func RunDnoteCmd(t *testing.T, opts RunDnoteCmdOptions, binaryName string, arg .
// Print stdout if and only if test fails later
t.Logf("\n%s", stdout)
return stdout.String()
}
// WaitDnoteCmd runs a dnote command and passes stdout to the callback.