Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add the stdlib_diff tool to compare gno and go standard libraries #2869

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
50fa8d0
Add Myers algorithm implementation and Algorithm interface
FloRichardAloeCorp Dec 7, 2023
aa3b468
Add objects to handle packages comparison
FloRichardAloeCorp Dec 7, 2023
df26bbf
Add report generation
FloRichardAloeCorp Dec 7, 2023
dadbdf4
Add README.md
FloRichardAloeCorp Dec 7, 2023
0d7850e
Indentation is now preserved in file preview
FloRichardAloeCorp Dec 8, 2023
adb9478
Reorganize functions order
FloRichardAloeCorp Dec 8, 2023
eb55d62
Add missing check on delete count
FloRichardAloeCorp Dec 8, 2023
89dc533
Add --src_is_gno flag to indicates which one of the source or destina…
FloRichardAloeCorp Dec 8, 2023
a4ec9ca
Rename template variables
FloRichardAloeCorp Dec 8, 2023
f56696b
Add code comment
FloRichardAloeCorp Dec 8, 2023
193e2df
Update README.md
FloRichardAloeCorp Dec 8, 2023
16e54a3
Update flag usage
FloRichardAloeCorp Dec 8, 2023
8e5bc5e
Fix diffstatus const case. Use iota for enum
FloRichardAloeCorp Dec 15, 2023
8a6ab0b
add go:embed to load templates
FloRichardAloeCorp Dec 15, 2023
4854614
Cleaning FileDiff.Differences()
FloRichardAloeCorp Dec 15, 2023
9efc2ef
Add named return values
FloRichardAloeCorp Dec 15, 2023
5edfd6c
Improving myers algorithm
FloRichardAloeCorp Dec 15, 2023
79f825e
Making LineDifference Operation field an actual operation. Cleaning o…
FloRichardAloeCorp Dec 15, 2023
8033330
getFileLines now returns error
FloRichardAloeCorp Dec 15, 2023
175c32d
Equal values on compared files are greyed
FloRichardAloeCorp Dec 15, 2023
219de73
Operation symbols (+/-) are handled by the template, and they are not…
FloRichardAloeCorp Dec 15, 2023
cfb11ac
Fix templates
FloRichardAloeCorp Dec 15, 2023
ef3bb3a
Solve comments on PR
Villaquiranm Sep 29, 2024
777a759
use gotextdiff
Villaquiranm Oct 5, 2024
0d563bc
mark directories as not found on index
Villaquiranm Oct 5, 2024
88c73f0
list all subdirectories on index
Villaquiranm Oct 5, 2024
44441cc
Handle paths with and without trailing /
Villaquiranm Oct 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions misc/stdlib_diff/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Stdlibs_diff

Stdlibs_diff is a tool that generates an html report indicating differences between gno standard libraries and go standrad libraries

## Usage

Compare the `go` standard libraries the `gno` standard libraries

```shell
./stdlibs_diff -src <path to go standard libraries> -dst <path to gno standard libraries> -out <output directory>
```

Compare the `gno` standard libraries the `go` standard libraries

```shell
./stdlibs_diff -src <path to gno standard libraries> -dst <path to go standard libraries> -out <output directory> -src_is_gno
```


## Parameters

| Flag | Description | Default value |
| ---------- | ------------------------------------------------------------------ | ------------- |
| src | Directory containing packages that will be compared to destination | None |
| dst | Directory containing packages; used to compare src packages | None |
| out | Directory where the report will be created | None |
| src_is_gno | Indicates if the src parameters is the gno standard library | false |

## Tips

An index.html is generated at the root of the report location. Utilize it to navigate easily through the report.
25 changes: 25 additions & 0 deletions misc/stdlib_diff/diffstatus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

type diffStatus uint

const (
missingInSrc diffStatus = iota
missingInDst
hasDiff
noDiff
)

func (status diffStatus) String() string {
switch status {
case missingInSrc:
return "missing in src"
case missingInDst:
return "missing in dst"
case hasDiff:
return "files differ"
case noDiff:
return "files are equal"
default:
return "Unknown"
}
}
146 changes: 146 additions & 0 deletions misc/stdlib_diff/filediff.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package main

import (
"fmt"
"os"
"strings"

"github.com/hexops/gotextdiff"
"github.com/hexops/gotextdiff/myers"
"github.com/hexops/gotextdiff/span"
)

// FileDiff is a struct for comparing differences between two files.
type FileDiff struct {
Src string // Name of the source file.
Dst string // Name of the destination file.
srcContent string // Content of the source file.
dstContent string // Content of the destination file.
srcLines []string // Lines of the source file.
dstLines []string // Lines of the destination file.

}

// LineDifferrence represents a difference in a line during file comparison.
type LineDifferrence struct {
Line string // The line content.
Operation operation // The operation performed on the line (e.g., "add", "delete", "equal").
Number int
}

// NewFileDiff creates a new FileDiff instance for comparing differences between
// the specified source and destination files. It initializes the source and
// destination file lines .
func NewFileDiff(srcPath, dstPath string) (*FileDiff, error) {
src, err := getFileContent(srcPath)
if err != nil {
return nil, fmt.Errorf("can't read src file: %w", err)
}

dst, err := getFileContent(dstPath)
if err != nil {
return nil, fmt.Errorf("can't read dst file: %w", err)
}

return &FileDiff{
srcContent: src,
dstContent: dst,
srcLines: strings.Split(src, "\n"),
dstLines: strings.Split(dst, "\n"),
Src: srcPath,
Dst: dstPath,
}, nil
}

// Differences returns the differences in lines between the source and
// destination files using the configured diff algorithm.
func (f *FileDiff) Differences() (src, dst []LineDifferrence) {
var (
srcIndex, dstIndex int
insertCount, deleteCount int
dstDiff, srcDiff []LineDifferrence
)

if len(f.dstContent) == 0 {
return f.destEmpty()
}

if len(f.srcContent) == 0 {
return f.srcEmpty()
}

/* printUntil prints all the lines than do not appear on the computed edits from gotextdiff
so we need to add them manually looping always from the current value of
srcIndex until the line before the start of the hunk computed diff, hunk.FromLine-1

We need to print all the lines before each hunk and then ensure the end of the file is printed too
*/
printUntil := func(until int) {
for i := srcIndex; i < until; i++ {
dstDiff = append(dstDiff, LineDifferrence{Line: f.srcLines[srcIndex], Operation: equal, Number: dstIndex + 1})
srcDiff = append(srcDiff, LineDifferrence{Line: f.srcLines[srcIndex], Operation: equal, Number: srcIndex + 1})
srcIndex++
dstIndex++
}
}

edits := myers.ComputeEdits(span.URIFromPath(f.Src), f.srcContent, f.dstContent)
unified := gotextdiff.ToUnified(f.Src, f.Dst, f.srcContent, edits)
for _, hunk := range unified.Hunks {
printUntil(hunk.FromLine - 1)

for _, line := range hunk.Lines {
switch line.Kind {
case gotextdiff.Insert:
insertCount++
dstIndex++
dstDiff = append(dstDiff, LineDifferrence{Line: line.Content, Operation: insert, Number: dstIndex})

case gotextdiff.Equal:
srcIndex++
dstIndex++
dstDiff = append(dstDiff, LineDifferrence{Line: line.Content, Operation: equal, Number: dstIndex})
srcDiff = append(srcDiff, LineDifferrence{Line: line.Content, Operation: equal, Number: srcIndex})

case gotextdiff.Delete:
srcIndex++
deleteCount++
srcDiff = append(srcDiff, LineDifferrence{Line: line.Content, Operation: delete, Number: srcIndex})
}
}
}

printUntil(len(f.srcLines))

return srcDiff, dstDiff
}

func (f *FileDiff) destEmpty() ([]LineDifferrence, []LineDifferrence) {
srcDiff := []LineDifferrence{}
for index, line := range f.srcLines {
srcDiff = append(srcDiff, LineDifferrence{Line: line, Operation: delete, Number: index + 1})
}

return srcDiff, make([]LineDifferrence, 0)
}

func (f *FileDiff) srcEmpty() ([]LineDifferrence, []LineDifferrence) {
destDiff := []LineDifferrence{}
for index, line := range f.dstLines {
destDiff = append(destDiff, LineDifferrence{Line: line, Operation: insert, Number: index + 1})
}

return make([]LineDifferrence, 0), destDiff
}

// getFileContent reads and returns the lines of a file given its path.
func getFileContent(p string) (string, error) {
data, err := os.ReadFile(p)
if err != nil {
if os.IsNotExist(err) {
return "", nil
}
return "", err
}
return strings.ReplaceAll(string(data), "\t", " "), nil
}
5 changes: 5 additions & 0 deletions misc/stdlib_diff/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/gnolang/gno/misc/stdlib_diff

go 1.21.0

require github.com/hexops/gotextdiff v1.0.3
2 changes: 2 additions & 0 deletions misc/stdlib_diff/go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions misc/stdlib_diff/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

import (
"flag"
"log"
)

func main() {
var srcPath string
var dstPath string
var outDirectory string
var srcIsGno bool

flag.StringVar(&srcPath, "src", "", "Directory containing packages that will be compared to destination")
flag.StringVar(&dstPath, "dst", "", "Directory containing packages; used to compare src packages")
flag.StringVar(&outDirectory, "out", "", "Directory where the report will be created")
flag.BoolVar(&srcIsGno, "src_is_gno", false, "If true, indicates that the src parameter corresponds to the gno standard libraries")
flag.Parse()

reportBuilder, err := NewReportBuilder(srcPath, dstPath, outDirectory, srcIsGno)
if err != nil {
log.Fatal("can't build report builder: ", err.Error())
}

log.Println("Building report...")
if err := reportBuilder.Build(); err != nil {
log.Fatalln("can't build report: ", err.Error())
}
log.Println("Report generation done!")
}
28 changes: 28 additions & 0 deletions misc/stdlib_diff/operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

// operation is an enumeration type representing different types of operations. Used in diff algorithm
// to indicates differences between files.
type operation uint

const (
// insert represents an insertion operation.
insert operation = iota + 1
// delete represents a deletion operation.
delete
// equal represents an equal operation.
equal
)

// String returns a string representation of the operation.
func (op operation) String() string {
switch op {
case insert:
return "INS"
case delete:
return "DEL"
case equal:
return "EQ"
default:
return "UNKNOWN"
}
}
Loading
Loading