Skip to content

Commit

Permalink
cli: add --output-overwrite
Browse files Browse the repository at this point in the history
  • Loading branch information
JohannesKaufmann committed Jan 20, 2025
1 parent 12115d5 commit 9242e7b
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 6 deletions.
5 changes: 4 additions & 1 deletion cli/html2markdown/cmd/cmd_help.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Use a HTML sanitizer before displaying the HTML in the browser!
--output PATH
Output file or directory (instead of stdout)
--output-overwrite
Replace existing files
If --input is a directory or glob pattern, --output must be a directory.
Expand Down Expand Up @@ -95,7 +98,7 @@ func tmpl(w io.Writer, text string, data interface{}) error {
func (cli *CLI) initUsageText() error {
var flags []*flag.Flag
cli.flags.VisitAll(func(f *flag.Flag) {
if f.Name == "v" || f.Name == "version" || f.Name == "input" || f.Name == "output" {
if f.Name == "v" || f.Name == "version" || f.Name == "input" || f.Name == "output" || f.Name == "output-overwrite" {
// We manually mention these in the usage
return
}
Expand Down
5 changes: 3 additions & 2 deletions cli/html2markdown/cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ type Config struct {
// args are the positional (non-flag) command-line arguments.
args []string

inputFilepath string
outputFilepath string
inputFilepath string
outputFilepath string
outputOverwrite bool

// - - - - - General - - - - - //
version bool
Expand Down
106 changes: 105 additions & 1 deletion cli/html2markdown/cmd/files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,63 @@ func TestExecute_DirectoryOutput(t *testing.T) {
`)
}

func TestExecute_NotOverwrite(t *testing.T) {
directoryPath := newTestDir(t)
defer os.RemoveAll(directoryPath)

outputPath := filepath.Join(directoryPath, "output.md")

t.Run("the first run", func(t *testing.T) {
args := []string{"html2markdown", "--output", outputPath}

stdin := &FakeFile{mode: modePipe}
stdout := &FakeFile{mode: modePipe}
stderr := &FakeFile{mode: modePipe}
stdin.WriteString("<strong>file content A</strong>")

Run(stdin, stdout, stderr, args, testRelease)

stderrBytes := stderr.Bytes()
if len(stderrBytes) != 0 {
t.Fatalf("got error: %q", string(stderrBytes))
}
if len(stdout.Bytes()) != 0 {
t.Fatalf("expected no stdout content")
}

expectRepresentation(t, directoryPath, `
.
├─output.md "**file content A**"
`)
})

t.Run("the second run", func(t *testing.T) {
args := []string{"html2markdown", "--output", outputPath}

stdin := &FakeFile{mode: modePipe}
stdout := &FakeFile{mode: modePipe}
stderr := &FakeFile{mode: modePipe}
stdin.WriteString("<strong>file content B</strong>")

Run(stdin, stdout, stderr, args, testRelease)

actualStderr := stderr.String()
expectedStderr := fmt.Sprintf("\nerror: output path %q already exists. Use --output-overwrite to replace existing files\n\n", outputPath)
if actualStderr != expectedStderr {
t.Errorf("expected stderr %q but got %q", expectedStderr, actualStderr)
}
if len(stdout.Bytes()) != 0 {
t.Fatalf("expected no stdout content")
}

// The content should still be the same:
expectRepresentation(t, directoryPath, `
.
├─output.md "**file content A**"
`)
})
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

func TestExecute_FilePattern(t *testing.T) {
Expand Down Expand Up @@ -307,7 +364,7 @@ func TestExecute_FilePattern(t *testing.T) {
input := filepath.Join(dir, "input", "website_a.html")
output := filepath.Join(dir, "input", "website_a.html")

return []string{"html2markdown", "--input", input, "--output", output}
return []string{"html2markdown", "--input", input, "--output", output, "--output-overwrite"}
},
// Note: The file content of "website_a.html" changed
expected: `
Expand Down Expand Up @@ -487,3 +544,50 @@ func TestExecute_FilePattern(t *testing.T) {
})
}
}

func TestWriteFile_OverrideFalse(t *testing.T) {
directoryPath := newTestDir(t)
defer os.RemoveAll(directoryPath)

filePath := filepath.Join(directoryPath, "test.txt")
override := false

expectRepresentation(t, directoryPath, ".")

// - - - file does not exist yet - - - //
err := WriteFile(filePath, []byte("A"), override)
if err != nil {
t.Error(err)
}
expectRepresentation(t, directoryPath, ".\n"+`├─test.txt "A"`)

// - - - file exists already - - - //
err = WriteFile(filePath, []byte("B"), override)
if err == nil {
t.Error("expected there to be an error but got nil")
}
expectRepresentation(t, directoryPath, ".\n"+`├─test.txt "A"`) // <-- still the old content
}
func TestWriteFile_OverrideTrue(t *testing.T) {
directoryPath := newTestDir(t)
defer os.RemoveAll(directoryPath)

filePath := filepath.Join(directoryPath, "test.txt")
override := true

expectRepresentation(t, directoryPath, ".")

// - - - file does not exist yet - - - //
err := WriteFile(filePath, []byte("A"), override)
if err != nil {
t.Error(err)
}
expectRepresentation(t, directoryPath, ".\n"+`├─test.txt "A"`)

// - - - file exists already - - - //
err = WriteFile(filePath, []byte("B"), override)
if err != nil {
t.Error(err)
}
expectRepresentation(t, directoryPath, ".\n"+`├─test.txt "B"`) // <-- the new content
}
1 change: 1 addition & 0 deletions cli/html2markdown/cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ func (cli *CLI) initFlags(progname string) {
"output",
"Write output to FILE instead of stdout",
)
cli.flags.BoolVar(&cli.config.outputOverwrite, "output-overwrite", false, "replace existing files")

// TODO: --tag-type-block=script,style (and check that it is not a selector)
// TODO: --tag-type-inline=script,style (and check that it is not a selector)
Expand Down
43 changes: 41 additions & 2 deletions cli/html2markdown/cmd/io_output.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -92,17 +93,25 @@ func (cli *CLI) writeOutput(outputType outputType, filename string, markdown []b
switch outputType {
case outputTypeDirectory:
{
err := os.WriteFile(filepath.Join(cli.config.outputFilepath, filename), markdown, 0644)
err := WriteFile(filepath.Join(cli.config.outputFilepath, filename), markdown, cli.config.outputOverwrite)
if err != nil {
if errors.Is(err, os.ErrExist) {
return fmt.Errorf("output path %q already exists. Use --output-overwrite to replace existing files", cli.config.outputFilepath)
}

return fmt.Errorf("error while writing the file into the directory: %w", err)
}

return nil
}
case outputTypeFile:
{
err := os.WriteFile(cli.config.outputFilepath, markdown, 0644)
err := WriteFile(cli.config.outputFilepath, markdown, cli.config.outputOverwrite)
if err != nil {
if errors.Is(err, os.ErrExist) {
return fmt.Errorf("output path %q already exists. Use --output-overwrite to replace existing files", cli.config.outputFilepath)
}

return fmt.Errorf("error while writing the file: %w", err)
}

Expand All @@ -116,3 +125,33 @@ func (cli *CLI) writeOutput(outputType outputType, filename string, markdown []b
}
}
}

// WriteFile writes data to a file with override control
// If override is false and file exists, returns an error
// If override is true, truncates existing file or creates new one
func WriteFile(filename string, data []byte, override bool) error {
// As the base flags we have:
// O_WRONLY = write to the file, not read
// O_CREATE = create the file if it doesn't exist
flag := os.O_WRONLY | os.O_CREATE

if override {
// We add this flag:
// O_TRUNC = the existing contents are truncated to zero length
flag |= os.O_TRUNC
} else {
// We add this flag:
// O_EXCL = if used with O_CREATE, causes error if file already exists
flag |= os.O_EXCL
}

f, err := os.OpenFile(filename, flag, 0644)
if err != nil {
return err
}
_, err = f.Write(data)
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Use a HTML sanitizer before displaying the HTML in the browser!
--output PATH
Output file or directory (instead of stdout)

--output-overwrite
Replace existing files

If --input is a directory or glob pattern, --output must be a directory.


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ Use a HTML sanitizer before displaying the HTML in the browser!
--output PATH
Output file or directory (instead of stdout)

--output-overwrite
Replace existing files

If --input is a directory or glob pattern, --output must be a directory.


Expand Down

0 comments on commit 9242e7b

Please sign in to comment.