Skip to content

Commit

Permalink
fix: skip writting when no fixes were found
Browse files Browse the repository at this point in the history
  • Loading branch information
greut committed Oct 10, 2023
1 parent 921a461 commit 14d15ac
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 40 deletions.
96 changes: 68 additions & 28 deletions fix.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,17 @@ func FixWithDefinition(ctx context.Context, d *editorconfig.Definition, filename
fileSize := stat.Size()
mode := stat.Mode()

r, err := fixWithFilename(ctx, def, filename, fileSize)
r, fixed, err := fixWithFilename(ctx, def, filename, fileSize)
if err != nil {
return fmt.Errorf("cannot fix %s: %w", filename, err)
}

if !fixed {
log.V(1).Info("no fixes to apply", "filename", filename)

return nil
}

if r == nil {
return nil
}
Expand All @@ -56,15 +62,15 @@ func FixWithDefinition(ctx context.Context, d *editorconfig.Definition, filename
return fmt.Errorf("error copying file: %w", err)
}

log.V(1).Info("bytes written", "total", n)
log.V(1).Info("bytes written", "filename", filename, "total", n)

return nil
}

func fixWithFilename(ctx context.Context, def *definition, filename string, fileSize int64) (io.Reader, error) {
func fixWithFilename(ctx context.Context, def *definition, filename string, fileSize int64) (io.Reader, bool, error) {
fp, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("cannot open %s. %w", filename, err)
return nil, false, fmt.Errorf("cannot open %s. %w", filename, err)
}

defer fp.Close()
Expand All @@ -73,26 +79,26 @@ func fixWithFilename(ctx context.Context, def *definition, filename string, file

ok, err := probeReadable(fp, r)
if err != nil {
return nil, fmt.Errorf("cannot read %s. %w", filename, err)
return nil, false, fmt.Errorf("cannot read %s. %w", filename, err)
}

log := logr.FromContextOrDiscard(ctx)

if !ok {
log.V(2).Info("skipped unreadable or empty file")

return nil, nil
return nil, false, nil
}

charset, isBinary, err := ProbeCharsetOrBinary(ctx, r, def.Charset)
if err != nil {
return nil, err
return nil, false, err
}

if isBinary {
log.V(2).Info("binary file detected and skipped")

return nil, nil
return nil, false, nil
}

log.V(2).Info("charset probed", "charset", charset)
Expand All @@ -101,12 +107,14 @@ func fixWithFilename(ctx context.Context, def *definition, filename string, file
}

func fix( //nolint:funlen,cyclop
_ context.Context,
ctx context.Context,
r io.Reader,
fileSize int64,
_ string,
def *definition,
) (io.Reader, error) {
) (io.Reader, bool, error) {
log := logr.FromContextOrDiscard(ctx)

buf := bytes.NewBuffer([]byte{})

size := def.IndentSize
Expand All @@ -133,7 +141,7 @@ func fix( //nolint:funlen,cyclop
case "", UnsetValue:
size = 0
default:
return nil, fmt.Errorf(
return nil, false, fmt.Errorf(
"%w: %q is an invalid value of indent_style, want tab or space",
ErrConfiguration,
def.IndentStyle,
Expand All @@ -142,52 +150,73 @@ func fix( //nolint:funlen,cyclop

eol, err := def.EOL()
if err != nil {
return nil, fmt.Errorf("cannot get EOL: %w", err)
return nil, false, fmt.Errorf("cannot get EOL: %w", err)
}

trimTrailingWhitespace := false
if def.TrimTrailingWhitespace != nil {
trimTrailingWhitespace = *def.TrimTrailingWhitespace
}

fixed := false
errs := ReadLines(r, fileSize, func(index int, data []byte, isEOF bool) error {
var f bool
if size != 0 {
data = fixTabAndSpacePrefix(data, c, x)
data, f = fixTabAndSpacePrefix(data, c, x)
fixed = fixed || f
}

if trimTrailingWhitespace {
data = fixTrailingWhitespace(data)
data, f = fixTrailingWhitespace(data)
fixed = fixed || f
}

if def.EndOfLine != "" && !isEOF {
data = bytes.TrimRight(data, "\r\n")

data = append(data, eol...)
data, f = fixEndOfLine(data, eol)
fixed = fixed || f
}

_, err := buf.Write(data)
if err != nil {
return fmt.Errorf("error writing into buffer: %w", err)
}

log.V(2).Info("fix line", "index", index, "fixed", fixed)

return nil
})

if len(errs) != 0 {
return nil, errs[0]
return nil, false, errs[0]
}

if def.InsertFinalNewline != nil {
fixInsertFinalNewline(buf, *def.InsertFinalNewline, eol)
f := fixInsertFinalNewline(buf, *def.InsertFinalNewline, eol)
fixed = fixed || f
}

return buf, fixed, nil
}

// fixEndOfLine replaces any non eol suffix by the given one.
func fixEndOfLine(data []byte, eol []byte) ([]byte, bool) {
fixed := false

if !bytes.HasSuffix(data, eol) {
fixed = true
data = bytes.TrimRight(data, "\r\n")
data = append(data, eol...)
}

return buf, nil
return data, fixed
}

// fixTabAndSpacePrefix replaces any `x` by `c` in the given `data`.
func fixTabAndSpacePrefix(data []byte, c []byte, x []byte) []byte {
func fixTabAndSpacePrefix(data []byte, c []byte, x []byte) ([]byte, bool) {
newData := make([]byte, 0, len(data))

fixed := false

i := 0
for i < len(data) {
if bytes.HasPrefix(data[i:], c) {
Expand All @@ -203,17 +232,19 @@ func fixTabAndSpacePrefix(data []byte, c []byte, x []byte) []byte {

newData = append(newData, c...)

fixed = true

continue
}

return append(newData, data[i:]...)
return append(newData, data[i:]...), fixed
}

return data
return data, fixed
}

// fixTrailingWhitespace replaces any whitespace or tab from the end of the line.
func fixTrailingWhitespace(data []byte) []byte {
func fixTrailingWhitespace(data []byte) ([]byte, bool) {
i := len(data) - 1

// u -> v is the range to clean
Expand All @@ -236,28 +267,37 @@ outer:
}
}

if u != v {
// If u != v then the line has been fixed.
fixed := u != v
if fixed {
data = append(data[:u], data[v:]...)
}

return data
return data, fixed
}

// fixInsertFinalNewline modifies buf to fix the existence of a final newline.
// Line endings are assumed to already be consistent within the buffer.
// A nil buffer or an empty buffer is returned as is.
func fixInsertFinalNewline(buf *bytes.Buffer, insertFinalNewline bool, endOfLine []byte) {
func fixInsertFinalNewline(buf *bytes.Buffer, insertFinalNewline bool, endOfLine []byte) bool {
fixed := false

if buf == nil || buf.Len() == 0 {
return
return fixed
}

if insertFinalNewline {
if !bytes.HasSuffix(buf.Bytes(), endOfLine) {
fixed = true

buf.Write(endOfLine)
}
} else {
for bytes.HasSuffix(buf.Bytes(), endOfLine) {
fixed = true
buf.Truncate(buf.Len() - len(endOfLine))
}
}

return fixed
}
20 changes: 14 additions & 6 deletions fix_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/google/go-cmp/cmp"
)

func TestFixEndOfLine(t *testing.T) {
func TestFixEndOfLine(t *testing.T) { //nolint:gocognit
tests := []struct {
Name string
Lines [][]byte
Expand Down Expand Up @@ -46,18 +46,22 @@ func TestFixEndOfLine(t *testing.T) {
t.Parallel()

def, err := newDefinition(&editorconfig.Definition{
EndOfLine: "lf",
EndOfLine: editorconfig.EndOfLineLf,
})
if err != nil {
t.Fatal(err)
}

r := bytes.NewReader(file)
out, err := fix(ctx, r, fileSize, "utf-8", def)
out, fixed, err := fix(ctx, r, fileSize, "utf-8", def)
if err != nil {
t.Fatalf("no errors where expected, got %s", err)
}

if fixed {
t.Errorf("file should not have been fixed")
}

result, err := io.ReadAll(out)
if err != nil {
t.Fatalf("cannot read result %s", err)
Expand All @@ -80,11 +84,15 @@ func TestFixEndOfLine(t *testing.T) {
}

r := bytes.NewReader(file)
out, err := fix(ctx, r, fileSize, "utf-8", def)
out, fixed, err := fix(ctx, r, fileSize, "utf-8", def)
if err != nil {
t.Fatalf("no errors where expected, got %s", err)
}

if !fixed {
t.Errorf("file should have been fixed")
}

result, err := io.ReadAll(out)
if err != nil {
t.Fatalf("cannot read result %s", err)
Expand Down Expand Up @@ -142,7 +150,7 @@ func TestFixIndentStyle(t *testing.T) {
}

r := bytes.NewReader(tc.File)
out, err := fix(ctx, r, fileSize, "utf-8", def)
out, _, err := fix(ctx, r, fileSize, "utf-8", def)
if err != nil {
t.Fatalf("no errors where expected, got %s", err)
}
Expand Down Expand Up @@ -204,7 +212,7 @@ func TestFixTrimTrailingWhitespace(t *testing.T) {
t.Parallel()

for _, l := range tc.Lines {
m := fixTrailingWhitespace(l)
m, _ := fixTrailingWhitespace(l)

err := checkTrimTrailingWhitespace(m)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/google/go-cmp v0.5.9
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-colorable v0.1.13
golang.org/x/term v0.12.0
golang.org/x/term v0.13.0
golang.org/x/text v0.13.0
k8s.io/klog/v2 v2.100.1
)
Expand All @@ -19,7 +19,7 @@ require (
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/sys v0.13.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.12.0 h1:/ZfYdc3zq+q02Rv9vGqTeSItdzZTSNDmfTi0mBAuidU=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down

0 comments on commit 14d15ac

Please sign in to comment.