Skip to content

Commit b90ca79

Browse files
authoredJun 23, 2023
Merge pull request #12 from metal3d/develop
Enhancements and refactorization
2 parents 0604630 + c342bb9 commit b90ca79

File tree

8 files changed

+772
-180
lines changed

8 files changed

+772
-180
lines changed
 

‎Makefile

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ SIGNER=metal3d@gmail.com
1616

1717
TARGETS=dist/goreorder-linux-amd64 dist/goreorder-darwin-amd64 dist/goreorder-windows-amd64.exe dist/goreorder-freebsd-amd64
1818

19+
# TEST selection
20+
# e.g. TEST="TestFoo TestBar"
21+
TEST=
22+
1923
install:
2024
go install -v $(CC_OPTS) $(PACKAGE)
2125

@@ -80,8 +84,12 @@ clean-dist:
8084
clean: clean-dist
8185
rm -f ./goreorder
8286

83-
test:
87+
test:
88+
ifeq ($(strip $(TEST)),)
8489
go test -v -race -cover -short ./...
90+
else
91+
go test -v -race -run $(TEST) ./...
92+
endif
8593

8694
test-cover-html:
8795
go test -cover -coverprofile=coverage.out ./...

‎README.md

+45-3
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ This tool will "reorder" your sources:
1212

1313
There are several possibilities:
1414

15-
- If you have "go" on your machine, simply install using `go install github.com/metal3d/goreorder@latest` (you can replace "latest" by a known version)
16-
- Visit the [release page](https://github.com/metal3d/goreorder/releases) to download the latest version (to place un you `$PATH`)
15+
- If you have "go" on your machine, simply install using (you can replace "latest" by a known tag):
16+
```bash
17+
go install github.com/metal3d/goreorder/cmd/goreorder@latest`
18+
```
19+
- Visit the [release page](https://github.com/metal3d/goreorder/releases) to download the desired version (to place un you `$PATH`)
1720
- Use the installer:
1821
```bash
1922
curl -sSL https://raw.githubusercontent.com/metal3d/goreorder/main/repo-tools/install.sh | bash -s
@@ -32,7 +35,7 @@ cd goreorder
3235
make install
3336
```
3437

35-
## Basic Usage
38+
# Basic Usage
3639

3740
```
3841
goreorder reorders the structs (optional), methods and constructors in a Go
@@ -78,8 +81,47 @@ patch -p1 < ./reorder.patch
7881
patch -p1 -R < ./reorder.patch
7982
```
8083

84+
# Releases are GPG signed
85+
86+
The released binaries are signed with GPG. If you want to verify that the release comes from this repository and was built by the author:
87+
88+
```bash
89+
90+
## Optional, you can get and trust the owner GPG key
91+
# this is the repo owner key:
92+
_KEY="F3702E3FAD8F76DC"
93+
# You can get it with this command:
94+
_KEY=$(curl -s https://api.github.com/users/metal3d/gpg_keys | \
95+
awk -F'"' '/"key_id"/{print $4; exit}')
96+
echo ${_KEY}
97+
98+
# you can import the repository owner key from keyserver
99+
gpg --keyserver hkps://keys.openpgp.org/ --recv-keys ${_KEY}
100+
101+
# optoinal, trust owner key
102+
_FPR=$(gpg -k --with-colons --fingerprint "${_KEY}" | awk -F: '/fpr/{print $10; exit}')
103+
echo ${_FPR}:6: | gpg --import-ownertrust
104+
unset _KEY _FPR
105+
106+
## Verification
107+
# get the signature of the right binary
108+
_REL="goreorder-linux-amd64"
109+
_SIGNURL=https://github.com/metal3d/goreorder/releases/download/${_REL}.asc
110+
curl ${_SIGNURL} -o /tmp/goreorder.asc
111+
unset _SIGNURL _REL
112+
113+
# get or set the path to the binary file you downloaded / installed
114+
# _GOREORDERBIN=/path/to/the/binary
115+
_GOREORDERBIN=$(command -v goreorder)
116+
117+
# check the signature
118+
gpg --verify /tmp/goreorder.asc $_GOREORDERBIN
119+
rm /tmp/goreorder.asc
120+
```
121+
81122
# Contribute
82123

83124
Please fill an issue to create a bug report.
84125

85126
If you want to participate, please fork the repository and propose a pull request **on the "develop" branch**.
127+

‎cmd/goreorder/main.go

+14-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,13 @@ func processFile(fileOrDirectoryName string, formatToolName string, reorderStruc
178178

179179
if input != nil && len(input) != 0 {
180180
// process stdin
181-
content, err := ordering.ReorderSource(fileOrDirectoryName, formatToolName, reorderStructs, input, diff)
181+
content, err := ordering.ReorderSource(ordering.ReorderConfig{
182+
Filename: fileOrDirectoryName,
183+
FormatCommand: formatToolName,
184+
ReorderStructs: reorderStructs,
185+
Src: input,
186+
Diff: diff,
187+
})
182188
if err != nil {
183189
log.Fatal(err)
184190
}
@@ -213,7 +219,13 @@ func processFile(fileOrDirectoryName string, formatToolName string, reorderStruc
213219
}
214220

215221
log.Println("Processing file: " + fileOrDirectoryName)
216-
output, err := ordering.ReorderSource(fileOrDirectoryName, formatToolName, reorderStructs, input, diff)
222+
output, err := ordering.ReorderSource(ordering.ReorderConfig{
223+
Filename: fileOrDirectoryName,
224+
FormatCommand: formatToolName,
225+
ReorderStructs: reorderStructs,
226+
Src: input,
227+
Diff: diff,
228+
})
217229
if err != nil {
218230
log.Println("ERR: Ordering error:", err)
219231
return

‎ordering/main.go

+109-46
Original file line numberDiff line numberDiff line change
@@ -4,60 +4,74 @@ import (
44
"crypto/sha256"
55
"errors"
66
"fmt"
7+
"go/format"
78
"io/ioutil"
89
"os"
910
"os/exec"
1011
"sort"
1112
"strings"
1213
)
1314

14-
// ReorderSource reorders the source code in the given filename. It will be helped by the formatCommand (gofmt or goimports). The method is to
15-
// use the Parse() function to extract types, methods and constructors. Then we replace the original source code with a comment containing the
16-
// sha256 of the source. This is made to not lose the original source code "lenght" while we reinject the ordered source code. Then, we finally
15+
type ReorderConfig struct {
16+
Filename string
17+
FormatCommand string
18+
ReorderStructs bool
19+
Diff bool
20+
Src interface{}
21+
}
22+
23+
// ReorderSource reorders the source code in the given filename.
24+
// It will be helped by the formatCommand (gofmt or goimports).
25+
// If gofmt is used, the source code will be formatted with the go/fmt package in memory.
26+
//
27+
// This function calls the Parse() function to extract types, methods, vars, consts and constructors.
28+
// Then it replaces the original source code with a comment containing the
29+
// sha256 of the source. This is made to not lose the original source code "lenght"
30+
// while we reinject the ordered source code. Then, we finally
1731
// remove thses lines from the source code.
18-
func ReorderSource(filename, formatCommand string, reorderStructs bool, src interface{}, diff bool) (string, error) {
19-
// in all cases, we must return the original source code if an error occurs
20-
// get the content of the file
32+
func ReorderSource(opt ReorderConfig) (string, error) {
2133
var content []byte
2234
var err error
23-
if src == nil || len(src.([]byte)) == 0 {
24-
content, err = ioutil.ReadFile(filename)
35+
if opt.Src == nil || len(opt.Src.([]byte)) == 0 {
36+
content, err = ioutil.ReadFile(opt.Filename)
2537
if err != nil {
2638
return "", err
2739
}
2840
} else {
29-
content = src.([]byte)
41+
content = opt.Src.([]byte)
3042
}
3143

32-
methods, constructors, structs, err := Parse(filename, formatCommand, content)
44+
info, err := Parse(opt.Filename, content)
3345

3446
if err != nil {
3547
return string(content), errors.New("Error parsing source: " + err.Error())
3648
}
3749

38-
if len(structs) == 0 {
39-
return string(content), errors.New("No structs found in " + filename + ", cannot reorder")
50+
if len(info.Structs) == 0 {
51+
return string(content), errors.New("No structs found in " + opt.Filename + ", cannot reorder")
4052
}
4153

4254
// sort methods by name
43-
for _, method := range methods {
55+
for _, method := range info.Methods {
4456
sort.Slice(method, func(i, j int) bool {
4557
return method[i].Name < method[j].Name
4658
})
4759
}
4860

49-
for _, method := range constructors {
50-
sort.Slice(method, func(i, j int) bool {
51-
return method[i].Name < method[j].Name
61+
for _, constructor := range info.Constructors {
62+
sort.Slice(constructor, func(i, j int) bool {
63+
return constructor[i].Name < constructor[j].Name
5264
})
5365
}
5466

55-
structNames := make([]string, 0, len(methods))
56-
for _, s := range structs {
57-
structNames = append(structNames, s.Name)
67+
functionNames := make([]string, 0, len(info.Functions))
68+
for functionName := range info.Functions {
69+
functionNames = append(functionNames, functionName)
5870
}
59-
if reorderStructs {
60-
sort.Strings(structNames)
71+
sort.Strings(functionNames)
72+
73+
if opt.ReorderStructs {
74+
info.StructNames.Sort()
6175
}
6276

6377
// Get the source code signature - we will use this to mark the lines to remove later
@@ -71,37 +85,68 @@ func ReorderSource(filename, formatCommand string, reorderStructs bool, src inte
7185

7286
lineNumberWhereInject := 0
7387
removedLines := 0
74-
for _, typename := range structNames {
88+
for i, sourceCode := range info.Constants {
7589
if removedLines == 0 {
76-
lineNumberWhereInject = structs[typename].OpeningLine
90+
lineNumberWhereInject = info.Constants[i].OpeningLine
91+
}
92+
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
93+
originalContent[ln] = "// -- " + sign
94+
}
95+
source = append(source, "\n"+sourceCode.SourceCode)
96+
removedLines += len(info.Constants)
97+
}
98+
for i, sourceCode := range info.Variables {
99+
if removedLines == 0 {
100+
lineNumberWhereInject = info.Variables[i].OpeningLine
101+
}
102+
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
103+
originalContent[ln] = "// -- " + sign
104+
}
105+
source = append(source, "\n"+sourceCode.SourceCode)
106+
removedLines += len(info.Variables)
107+
}
108+
for _, typename := range *info.StructNames {
109+
if removedLines == 0 {
110+
lineNumberWhereInject = info.Structs[typename].OpeningLine
77111
}
78112
// replace the definitions by "// -- line to remove
79-
for ln := structs[typename].OpeningLine - 1; ln < structs[typename].ClosingLine; ln++ {
113+
for ln := info.Structs[typename].OpeningLine - 1; ln < info.Structs[typename].ClosingLine; ln++ {
80114
originalContent[ln] = "// -- " + sign
81115
}
82-
removedLines += structs[typename].ClosingLine - structs[typename].OpeningLine
116+
removedLines += info.Structs[typename].ClosingLine - info.Structs[typename].OpeningLine
83117
// add the struct definition to "source"
84-
source = append(source, "\n\n"+structs[typename].SourceCode)
118+
source = append(source, "\n\n"+info.Structs[typename].SourceCode)
85119

86120
// same for constructors
87-
for _, constructor := range constructors[typename] {
121+
for _, constructor := range info.Constructors[typename] {
88122
for ln := constructor.OpeningLine - 1; ln < constructor.ClosingLine; ln++ {
89123
originalContent[ln] = "// -- " + sign
90124
}
91125
// add the constructor to "source"
92126
source = append(source, "\n"+constructor.SourceCode)
93127
}
94-
removedLines += len(constructors[typename])
128+
removedLines += len(info.Constructors[typename])
95129

96130
// same for methods
97-
for _, method := range methods[typename] {
131+
for _, method := range info.Methods[typename] {
98132
for ln := method.OpeningLine - 1; ln < method.ClosingLine; ln++ {
99133
originalContent[ln] = "// -- " + sign
100134
}
101135
// add the method to "source"
102136
source = append(source, "\n"+method.SourceCode)
103137
}
104-
removedLines += len(methods[typename])
138+
removedLines += len(info.Methods[typename])
139+
}
140+
for _, name := range functionNames {
141+
sourceCode := info.Functions[name]
142+
if removedLines == 0 {
143+
lineNumberWhereInject = info.Functions[name].OpeningLine
144+
}
145+
for ln := sourceCode.OpeningLine - 1; ln < sourceCode.ClosingLine; ln++ {
146+
originalContent[ln] = "// -- " + sign
147+
}
148+
source = append(source, "\n"+sourceCode.SourceCode)
149+
removedLines += len(info.Functions)
105150
}
106151

107152
// add the "source" at the found lineNumberWhereInject
@@ -118,32 +163,50 @@ func ReorderSource(filename, formatCommand string, reorderStructs bool, src inte
118163
output := strings.Join(originalContent, "\n")
119164

120165
// write in a temporary file and use "gofmt" to format it
166+
newcontent := []byte(output)
167+
switch opt.FormatCommand {
168+
case "gofmt":
169+
// format the temporary file
170+
newcontent, err = format.Source([]byte(output))
171+
if err != nil {
172+
return string(content), errors.New("Failed to format source: " + err.Error())
173+
}
174+
default:
175+
if newcontent, err = formatWithCommand(content, output, opt); err != nil {
176+
return string(content), errors.New("Failed to format source: " + err.Error())
177+
}
178+
}
179+
180+
if opt.Diff {
181+
return doDiff(content, newcontent, opt.Filename)
182+
}
183+
return string(newcontent), nil
184+
}
185+
186+
func formatWithCommand(content []byte, output string, opt ReorderConfig) (newcontent []byte, err error) {
187+
// we use the format command given by the user
188+
// on a temporary file we need to create and remove
121189
tmpfile, err := ioutil.TempFile("", "")
122190
if err != nil {
123-
return string(content), errors.New("Failed to create temp file: " + err.Error())
191+
return content, errors.New("Failed to create temp file: " + err.Error())
124192
}
125-
defer func() {
126-
os.Remove(tmpfile.Name()) // clean up
127-
tmpfile.Close()
128-
}()
193+
defer os.Remove(tmpfile.Name())
129194

195+
// write the temporary file
130196
if _, err := tmpfile.Write([]byte(output)); err != nil {
131-
return string(content), errors.New("Failed to write to temporary file: " + err.Error())
197+
return content, errors.New("Failed to write temp file: " + err.Error())
132198
}
199+
tmpfile.Close()
133200

134-
cmd := exec.Command(formatCommand, "-w", tmpfile.Name())
201+
// format the temporary file
202+
cmd := exec.Command(opt.FormatCommand, "-w", tmpfile.Name())
135203
if err := cmd.Run(); err != nil {
136-
return string(content), err
204+
return content, err
137205
}
138-
139206
// read the temporary file
140-
newcontent, err := ioutil.ReadFile(tmpfile.Name())
207+
newcontent, err = ioutil.ReadFile(tmpfile.Name())
141208
if err != nil {
142-
return string(content), errors.New("Read Temporary File error: " + err.Error())
143-
}
144-
145-
if diff {
146-
return doDiff(content, newcontent, filename)
209+
return content, errors.New("Read Temporary File error: " + err.Error())
147210
}
148-
return string(newcontent), nil
211+
return newcontent, nil
149212
}

0 commit comments

Comments
 (0)
Failed to load comments.