-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from ldemailly/initial
Initial / start of implementation
- Loading branch information
Showing
11 changed files
with
365 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# To get started with Dependabot version updates, you'll need to specify which | ||
# package ecosystems to update and where the package manifests are located. | ||
# Please see the documentation for all configuration options: | ||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates | ||
|
||
version: 2 | ||
updates: | ||
- package-ecosystem: "gomod" | ||
directory: "/" # Location of package manifests | ||
schedule: | ||
interval: "daily" | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
# Check for updates to GitHub Actions every week | ||
interval: "weekly" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Remember to change/update `description` below when copying | ||
# this include | ||
name: "Shared cli/server fortio workflows" | ||
on: | ||
push: | ||
branches: [ main ] | ||
tags: | ||
# so a vX.Y.Z-test1 doesn't trigger build | ||
- 'v[0-9]+.[0-9]+.[0-9]+' | ||
- 'v[0-9]+.[0-9]+.[0-9]+-pre*' | ||
pull_request: | ||
branches: [ main ] | ||
|
||
jobs: | ||
call-gochecks: | ||
uses: fortio/workflows/.github/workflows/gochecks.yml@main | ||
call-codecov: | ||
uses: fortio/workflows/.github/workflows/codecov.yml@main | ||
call-codeql: | ||
uses: fortio/workflows/.github/workflows/codeql-analysis.yml@main | ||
permissions: | ||
actions: read | ||
contents: read | ||
security-events: write | ||
call-releaser: | ||
uses: fortio/workflows/.github/workflows/releaser.yml@main | ||
with: | ||
description: "Fix line too long lll linter errors" | ||
secrets: | ||
GH_PAT: ${{ secrets.GH_PAT }} | ||
DOCKER_TOKEN: ${{ secrets.DOCKER_TOKEN }} | ||
DOCKER_USER: ${{ secrets.DOCKER_USER }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
FROM scratch | ||
COPY lll-fixer /usr/bin/lll-fixer | ||
ENTRYPOINT ["/usr/bin/lll-fixer"] | ||
CMD ["help"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
manual-test: | ||
cp lll_fixer.go test.txt && go run . -loglevel debug test.txt ; colordiff -u lll_fixer.go test.txt | ||
|
||
|
||
.PHONY: manual-test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,41 @@ | ||
# lll-fixer | ||
Fix lll (line length limit) lines too long linter errors in go files | ||
|
||
## Installation | ||
|
||
From source | ||
``` | ||
go install github.com/ldemailly/lll-fixer@latest | ||
``` | ||
|
||
Or see the numerous binaries in https://github.com/ldemailly/lll-fixer/releases | ||
|
||
Or docker `fortio/lll-fixer:latest` | ||
|
||
Or brew `brew install fortio/tap/lll-fixer` | ||
|
||
(I manage the fortio org and usually put everything there but this one is a bit unrelated so for now it is hosted here in `ldemailly` yet uses fortio's org for docker and brew) | ||
|
||
## Example | ||
|
||
Test on itself: | ||
``` | ||
$ go run . lll_fixer.go | ||
``` | ||
|
||
```diff | ||
diff --git a/lll_fixer.go b/lll_fixer.go | ||
index c5edf97..30452c3 100644 | ||
--- a/lll_fixer.go | ||
+++ b/lll_fixer.go | ||
@@ -43,7 +43,8 @@ func main() { | ||
} | ||
} | ||
|
||
-// process modifies the file filename to split long comments at maxlen. making this line longer than 80 characters to test. | ||
+// process modifies the file filename to split long comments at maxlen. making | ||
+// this line longer than 80 characters to test. | ||
func process(fset *token.FileSet, filename string, maxlen int) string { | ||
log.Infof("Processing file %q", filename) | ||
// Parse the Go file | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"go/format" | ||
"go/parser" | ||
"go/token" | ||
"os" | ||
) | ||
|
||
/* | ||
* multi line comment. | ||
*/ | ||
func main() { | ||
code := `package main | ||
/* | ||
* multi line comment. | ||
*/ | ||
func main() { | ||
}` | ||
fmt.Println("---input---") | ||
fmt.Println(code) | ||
fmt.Println("---processing---") | ||
fset := token.NewFileSet() | ||
node, err := parser.ParseFile(fset, "bug.go", code, parser.ParseComments) | ||
if err != nil { | ||
panic(err) | ||
} | ||
for _, cg := range node.Comments { | ||
for _, c := range cg.List { | ||
fmt.Printf("Found comment %q\n", c.Text) | ||
if len(c.Text) > 11 { | ||
fmt.Printf("Splitting comment %q\n", c.Text) | ||
c.Text = c.Text[:11] + "\n *" + c.Text[11:] | ||
fmt.Printf("into -> %q\n", c.Text) | ||
} | ||
} | ||
} | ||
fmt.Println("---result---") | ||
if err := format.Node(os.Stdout, fset, node); err != nil { | ||
panic(err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module github.com/ldemailly/lll-fixer | ||
|
||
go 1.21 | ||
|
||
require ( | ||
fortio.org/cli v1.5.1 | ||
fortio.org/log v1.12.0 | ||
) | ||
|
||
require ( | ||
fortio.org/struct2env v0.4.0 // indirect | ||
fortio.org/version v1.0.3 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
fortio.org/cli v1.5.1 h1:lqPvkxRVSajsVwLfblaN62BPAICPp05Oab+yjRvI3DU= | ||
fortio.org/cli v1.5.1/go.mod h1:Tp7AypudP1mJomTUN/J/vlOTlZDWTMsok09MMyA99ow= | ||
fortio.org/log v1.12.0 h1:5Yg4pL9Pp0jcWeJYixm2xikMCldVaSDMgDFDmQJZfho= | ||
fortio.org/log v1.12.0/go.mod h1:1tMBG/Elr6YqjmJCWiejJp2FPvXg7/9UAN0Rfpkyt1o= | ||
fortio.org/struct2env v0.4.0 h1:k5alSOTf3YHiB3MuacjDHQ3YhVWvNZ95ZP/a6MqvyLo= | ||
fortio.org/struct2env v0.4.0/go.mod h1:lENUe70UwA1zDUCX+8AsO663QCFqYaprk5lnPhjD410= | ||
fortio.org/version v1.0.3 h1:5gJ3plj6isAOMq52cI5ifo4cC+QHmJF76Wevc5Cp4x0= | ||
fortio.org/version v1.0.3/go.mod h1:2JQp9Ax+tm6QKiGuzR5nJY63kFeANcgrZ0osoQFDVm0= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
package main | ||
|
||
import ( | ||
"flag" | ||
"go/ast" | ||
"go/format" | ||
"go/parser" | ||
"go/token" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
"fortio.org/cli" | ||
"fortio.org/log" | ||
) | ||
|
||
func main() { | ||
maxlen := flag.Int("len", 79, "max line length") | ||
funmpt := flag.Bool("fumpt", false, "run gofumpt on the modified file") | ||
cli.MinArgs = 1 | ||
cli.MaxArgs = -1 | ||
cli.ArgsHelp = "filenames..." | ||
if false { | ||
// just to test literal string split | ||
cli.ArgsHelp = "this is a very a long string literal to test the split of long strings inside code" | ||
} | ||
cli.Main() | ||
fset := token.NewFileSet() | ||
for _, filename := range flag.Args() { | ||
newname := process(fset, filename, *maxlen) | ||
// swap .lll to .go and .go to .bak | ||
backup := filename + ".bak" | ||
if err := os.Rename(filename, backup); err != nil { | ||
log.Fatalf("Error renaming file %q to %q: %v", filename, backup, err) | ||
} | ||
log.Infof("Renamed file %q to %q", filename, backup) | ||
if err := os.Rename(newname, filename); err != nil { | ||
log.Fatalf("Error renaming file %q to %q: %v", newname, filename, err) | ||
} | ||
log.Infof("Renamed file %q to %q", newname, filename) | ||
// Run gofumpt on the modified file | ||
if *funmpt { | ||
cmd := exec.Command("gofumpt", "-w", filename) | ||
if err := cmd.Run(); err != nil { | ||
log.Errf("Error running gofumpt: %v", err) | ||
return | ||
} | ||
log.Infof("Ran gofumpt on the now modified file %q", filename) | ||
} | ||
} | ||
} | ||
|
||
func lineLead(s string) string { | ||
i := strings.LastIndex(s, "\n") | ||
return s[i+1 : i+4] // will break with -len too low | ||
} | ||
|
||
/* | ||
* Multi line comment with one line longer than 80 characters to test the split of multi line comments. | ||
*/ | ||
func splitAtWord(s string, maxlen int) string { | ||
if len(s) <= maxlen { | ||
return s | ||
} | ||
// find the last space before maxlen | ||
i := strings.LastIndex(s[:maxlen], " ") | ||
nospace := (i == -1) | ||
if nospace { | ||
// no space found, split at maxlen | ||
log.Warnf("No word/space found in first %d characters for %q", maxlen, s) | ||
i = maxlen | ||
} | ||
start := s[:i] | ||
lead := lineLead(start) | ||
var mid string | ||
switch { | ||
case strings.HasPrefix(lead, "/* "): | ||
mid = "\n * " | ||
case strings.HasPrefix(lead, " * "): | ||
mid = "\n * " | ||
case strings.HasPrefix(lead, "// "): | ||
mid = "\n// " | ||
case strings.HasPrefix(lead, "\""): | ||
mid = "\" +\n\t\"" // for string literals splitting | ||
if !nospace { | ||
mid += " " | ||
} | ||
default: | ||
log.Warnf("Unexpected lead %q", lead) | ||
mid = "\n " | ||
} | ||
log.Debugf("Start lead is %q", lead) | ||
return strings.TrimSpace(s[:i]) + mid + strings.TrimLeft(s[i:], " ") | ||
} | ||
|
||
// TODO process other nodes (and also maybe split leftmost position in line vs length of comment/literal | ||
// which could be far to the right) | ||
|
||
func processNode(n ast.Node, maxlen int) bool { | ||
if false { | ||
log.Debugf("Found node: %+v to shrink to %d", n, maxlen) | ||
} | ||
// process string literals | ||
if lit, ok := n.(*ast.BasicLit); ok && lit.Kind == token.STRING { | ||
lit.Value = splitAtWord(lit.Value, maxlen) | ||
} | ||
// more nodes... | ||
return true | ||
} | ||
|
||
// process modifies the file filename to split long comments at maxlen. making this line longer than 80 characters to test. | ||
func process(fset *token.FileSet, filename string, maxlen int) string { | ||
log.Infof("Processing file %q", filename) | ||
// Parse the Go file and this is an indented comment to test the split past column 80. | ||
node, err := parser.ParseFile(fset, filename, nil, parser.ParseComments) | ||
if err != nil { | ||
log.Fatalf("Error parsing %q: %v", filename, err) | ||
return "error.lll" // unreachable | ||
} | ||
for _, cg := range node.Comments { | ||
for _, c := range cg.List { | ||
log.Debugf("Found comment %q", c.Text) | ||
if len(c.Text) > maxlen { | ||
log.LogVf("Splitting comment %q", c.Text) | ||
c.Text = splitAtWord(c.Text, maxlen) | ||
log.LogVf("into -> %q", c.Text) | ||
} | ||
} | ||
} | ||
// Traverse and modify the AST | ||
ast.Inspect(node, func(n ast.Node) bool { | ||
return processNode(n, maxlen) | ||
}) | ||
|
||
// Generate the modified code | ||
newname := filename + ".lll" | ||
f, err := os.Create(newname) | ||
if err != nil { | ||
log.Errf("Error creating modified file %q: %v", newname, err) | ||
} | ||
defer f.Close() | ||
if err := format.Node(f, fset, node); err != nil { | ||
log.Errf("Error outputting modified file: %v", err) | ||
} | ||
log.Infof("Modified file written to %q", newname) | ||
return newname | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestLineLead(t *testing.T) { | ||
// tests input vs actual struct: | ||
tests := []struct { | ||
input string | ||
expected string | ||
}{ | ||
{"Hello", "Hel"}, | ||
{"\nHello", "Hel"}, | ||
{"abc\nxyz\nTest", "Tes"}, | ||
} | ||
// loop through the tests | ||
for _, test := range tests { | ||
actual := lineLead(test.input) | ||
// compare the actual vs expected | ||
if actual != test.expected { | ||
t.Errorf("Test failed! Expected: %q, Actual: %q", test.expected, actual) | ||
} | ||
} | ||
} | ||
|
||
func TestSplitAtWord(t *testing.T) { | ||
tests := []struct { | ||
input string | ||
expected string | ||
}{ | ||
{"Hello", "Hello"}, | ||
{"123456789ABC", "123456789A\n BC"}, | ||
{"// abc 1234567890", "// abc\n// 1234567890"}, | ||
{"/* abc 1234567890 */", "/* abc\n * 1234567890 */"}, | ||
{"/*\n * abc 1234567890\n*/", "/*\n * abc\n * 1234567890\n*/"}, | ||
{`"abc 1234567890"`, `"abc" + | ||
" 1234567890"`}, | ||
{`"123456789ABC"`, `"123456789" + | ||
"ABC"`}, | ||
} | ||
// loop through the tests | ||
for _, test := range tests { | ||
actual := splitAtWord(test.input, 10) | ||
// compare the actual vs expected | ||
if actual != test.expected { | ||
t.Errorf("Test failed! Expected: %q, Actual: %q", test.expected, actual) | ||
} | ||
} | ||
} |