Skip to content

Commit

Permalink
diff: support --no-index
Browse files Browse the repository at this point in the history
  • Loading branch information
fcharlie committed Dec 19, 2024
1 parent 5336141 commit 8e2b276
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 41 deletions.
131 changes: 119 additions & 12 deletions pkg/command/command_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,21 @@ import (
"strings"

"github.com/antgroup/hugescm/modules/diferenco"
"github.com/antgroup/hugescm/modules/zeta/object"
"github.com/antgroup/hugescm/pkg/zeta"
)

type Diff struct {
NoIndex bool `name:"no-index" help:"Compares two given paths on the filesystem"`
NameOnly bool `name:"name-only" help:"Show only names of changed files"`
NameStatus bool `name:"name-status" help:"Show names and status of changed files"`
Numstat bool `name:"numstat" help:"Show numeric diffstat instead of patch"`
Stat bool `name:"stat" help:"Show diffstat instead of patch"`
ShortStat bool `name:"shortstat" help:"Output only the last line of --stat format"`
Shortstat bool `name:"shortstat" help:"Output only the last line of --stat format"`
Z bool `name:":z" short:"z" help:"Output diff-raw with lines terminated with NUL"`
Staged bool `name:"staged" help:"Compare the differences between the staging area and <revision>"`
Cached bool `name:"cached" help:"Compare the differences between the staging area and <revision>"`
Textconv bool `name:"textconv" help:"Convert text to Unicode and compare differences"`
TextConv bool `name:"textconv" help:"Convert text to Unicode and compare differences"`
MergeBase string `name:"merge-base" help:"If --merge-base is given, use the common ancestor of <commit> and HEAD instead"`
Output string `name:"output" help:"Output to a specific file instead of stdout" placeholder:"<file>"`
Histogram bool `name:"histogram" help:"Generate a diff using the \"Histogram diff\" algorithm"`
Expand All @@ -33,21 +35,23 @@ type Diff struct {
Patience bool `name:"patience" help:"Generate a diff using the \"Patience diff\" algorithm"`
Minimal bool `name:"minimal" help:"Spend extra time to make sure the smallest possible diff is produced"`
DiffAlgorithm string `name:"diff-algorithm" help:"Choose a diff algorithm, supported: histogram|onp|myers|patience|minimal"`
From string `arg:"" optional:"" name:"from" help:"Revision from"`
To string `arg:"" optional:"" name:"to" help:"Revision to"`
From string `arg:"" optional:"" name:"from" help:"From"`
To string `arg:"" optional:"" name:"to" help:"To"`
passthroughArgs []string `kong:"-"`
}

const (
diffSummaryFormat = `%s zeta diff [<options>] [<commit>] [--] [<path>...]
%s zeta diff [<options>] --cached [<commit>] [--] [<path>...]
%s zeta diff [<options>] <commit> <commit> [--] [<path>...]
%s zeta diff [<options>] <commit>...<commit> [--] [<path>...]`
%s zeta diff [<options>] <commit>...<commit> [--] [<path>...]
%s zeta diff [<options>] <blob> <blob>
%s zeta diff [<options>] --no-index [--] <path> <path>`
)

func (c *Diff) Summary() string {
or := W(" or: ")
return fmt.Sprintf(diffSummaryFormat, W("Usage: "), or, or, or)
return fmt.Sprintf(diffSummaryFormat, W("Usage: "), or, or, or, or, or)
}

func (c *Diff) NewLine() byte {
Expand Down Expand Up @@ -91,24 +95,24 @@ func (c *Diff) NewOptions() (*zeta.DiffOptions, error) {
opts := &zeta.DiffOptions{
NameOnly: c.NameOnly,
NameStatus: c.NameStatus,
NumStat: c.Numstat,
Numstat: c.Numstat,
Stat: c.Stat,
ShortStat: c.ShortStat,
Staged: c.Staged || c.Cached,
Shortstat: c.Shortstat,
NewLine: c.NewLine(),
NewOutput: c.NewOutput,
PathSpec: slashPaths(c.passthroughArgs),
From: c.From,
To: c.To,
Staged: c.Staged || c.Cached,
MergeBase: c.MergeBase,
Textconv: c.Textconv,
TextConv: c.TextConv,
Algorithm: a,
NewOutput: c.NewOutput,
}
if len(c.To) == 0 {
if from, to, ok := strings.Cut(c.From, "..."); ok {
opts.From = from
opts.To = to
opts.W3 = true
opts.Way3 = true
return opts, nil
}
if from, to, ok := strings.Cut(c.From, ".."); ok {
Expand All @@ -132,7 +136,110 @@ func (c *Diff) NewOutput(ctx context.Context) (io.WriteCloser, bool, error) {
return printer, printer.UseColor(), nil
}

func (c *Diff) render(u *diferenco.Unified) error {
opts := &zeta.DiffOptions{
NameOnly: c.NameOnly,
NameStatus: c.NameStatus,
Numstat: c.Numstat,
Stat: c.Stat,
Shortstat: c.Shortstat,
NewLine: c.NewLine(),
NewOutput: c.NewOutput,
}
switch {
case c.Numstat, c.Stat, c.Shortstat:
s := u.Stat()
name := c.From
if c.From != c.To {
name = fmt.Sprintf("%s => %s", c.From, c.To)
}
opts.ShowStats(context.Background(), object.FileStats{
object.FileStat{
Name: name,
Addition: s.Addition,
Deletion: s.Deletion,
},
})
default:
opts.ShowPatch(context.Background(), []*diferenco.Unified{u})
}
return nil
}

func (c *Diff) nameStatus() error {
w, _, err := c.NewOutput(context.Background())
if err != nil {
return err
}
defer w.Close()
if c.NameOnly {
fmt.Fprintf(w, "%s%c", c.From, c.NewLine())
return nil
}
fmt.Fprintf(w, "%c %s%c", 'M', c.To, c.NewLine())
return nil
}

func (c *Diff) diffNoIndex(g *Globals) error {
if len(c.From) == 0 || len(c.To) == 0 {
die("missing arg, example: zeta diff --no-index from to")
return ErrArgRequired
}
if c.NameOnly || c.NameStatus {
return c.nameStatus()
}

a, err := c.checkAlgorithm()
if err != nil {
fmt.Fprintf(os.Stderr, "zeta diff --no-index: parse options error: %v\n", err)
return err
}
g.DbgPrint("from %s to %s", c.From, c.To)
var isBinary bool
from, err := readText(c.From, c.TextConv)
if err != nil && err != diferenco.ErrNonTextContent {
diev("zeta diff --no-index read text error: %v", err)
return err
}
if err == diferenco.ErrNonTextContent {
isBinary = true
}
to, err := readText(c.To, c.TextConv)
if err != nil && err != diferenco.ErrNonTextContent {
diev("zeta diff --no-index read text error: %v", err)
return err
}
if err == diferenco.ErrNonTextContent {
isBinary = true
}
if isBinary {
return c.render(&diferenco.Unified{
From: &diferenco.File{Name: c.From},
To: &diferenco.File{Name: c.To},
IsBinary: true,
})
}
u, err := diferenco.DoUnified(context.Background(), &diferenco.Options{
From: &diferenco.File{Name: c.From},
To: &diferenco.File{Name: c.To},
S1: from,
S2: to,
A: a,
})
if err != nil {
diev("zeta diff --no-index error: %v", err)
return err
}
return c.render(u)
}

func (c *Diff) Run(g *Globals) error {
if c.NoIndex {
return c.diffNoIndex(g)
}
if _, _, err := zeta.FindZetaDir(g.CWD); err != nil {
return c.diffNoIndex(g)
}
r, err := zeta.Open(context.Background(), &zeta.OpenOptions{
Worktree: g.CWD,
Values: g.Values,
Expand Down
2 changes: 1 addition & 1 deletion pkg/serve/repo/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ func (r *repository) DoPush(ctx context.Context, cmd *Command, reader io.Reader,
_ = ro.ng(cmd, "store object error: %v", err)
return ErrReportStarted
}
_ = ro.status(cmd.W("objects verified")) //nolint:govet
_ = ro.status("%s", cmd.W("objects verified")) //nolint:govet
change := &database.Command{
ReferenceName: cmd.ReferenceName,
NewRev: cmd.NewRev,
Expand Down
2 changes: 1 addition & 1 deletion pkg/tr/languages/zh-CN.toml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
"Given paths, show as match patterns; else, use root as sole argument" = "有路径时,显示为匹配模式;否则,使用根目录作为唯一路径参数"
# Diff
"Show changes between commits, commit and working tree, etc" = "显示提交之间的更改、提交和工作树等"
"Compares two given paths on the filesystem" = "比较文件系统上给定的两个路径"
"Show only names of changed files" = "仅显示已更改文件的名称"
"Show names and status of changed files" = "显示已更改文件的名称和状态"
"Show numeric diffstat instead of patch" = "显示数字 diffstat 而不是补丁"
Expand Down Expand Up @@ -387,7 +388,6 @@
"Use a diff3 based merge" = "使用基于 diff3 的合并"
"Use a zealous diff3 based merge" = "使用基于狂热 diff3(zealous diff3)的合并"
"Set labels for file1/orig-file/file2" = "为 文件1/初始文件/文件2 设置标签"

# Others
"WARNING" = "警告"
"not zeta repository" = "不是 zeta 存储库"
Expand Down
44 changes: 23 additions & 21 deletions pkg/zeta/showdiff.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,26 @@ import (
type DiffOptions struct {
NameOnly bool
NameStatus bool // name status
NumStat bool
Numstat bool
Stat bool
ShortStat bool
Shortstat bool
Staged bool
NewLine byte
MergeBase string
From string
To string
PathSpec []string
Textconv bool
UseColor bool
W3 bool
Algorithm diferenco.Algorithm
NewOutput func(context.Context) (io.WriteCloser, bool, error) // new writer func
// index value
MergeBase string
From string
To string
PathSpec []string
TextConv bool
UseColor bool
Way3 bool
Algorithm diferenco.Algorithm
}

func (opts *DiffOptions) po() *object.PatchOptions {
m := NewMatcher(opts.PathSpec)
return &object.PatchOptions{Textconv: opts.Textconv, Algorithm: opts.Algorithm, Match: m.Match}
return &object.PatchOptions{Textconv: opts.TextConv, Algorithm: opts.Algorithm, Match: m.Match}
}

func (opts *DiffOptions) ShowChanges(ctx context.Context, changes object.Changes) error {
Expand All @@ -45,18 +46,18 @@ func (opts *DiffOptions) ShowChanges(ctx context.Context, changes object.Changes
if opts.NameStatus {
return opts.showNameStatus(ctx, changes)
}
if opts.showStatsOnly() {
if opts.showStatOnly() {
fileStats, err := changes.Stats(ctx, opts.po())
if err != nil {
return err
}
return opts.showStats(ctx, fileStats)
return opts.ShowStats(ctx, fileStats)
}
patch, err := changes.Patch(ctx, opts.po())
if err != nil {
return err
}
return opts.showPatch(ctx, patch)
return opts.ShowPatch(ctx, patch)
}

func (opts *DiffOptions) showNameOnly(ctx context.Context, changes object.Changes) error {
Expand Down Expand Up @@ -112,8 +113,8 @@ func (opts *DiffOptions) showNameStatus(ctx context.Context, changes object.Chan
return nil
}

func (opts *DiffOptions) showStatsOnly() bool {
return opts.NameStatus || opts.NumStat || opts.ShortStat || opts.Stat
func (opts *DiffOptions) showStatOnly() bool {
return opts.Numstat || opts.Stat || opts.Shortstat
}

func numPadding(i int, padding int) string {
Expand All @@ -132,19 +133,19 @@ func numPaddingLeft(i int, padding int) string {
return strings.Repeat(" ", padding-len(s)) + s
}

// showStats: show stats
// ShowStats: show stats
//
// Original implementation: https://github.com/git/git/blob/1a87c842ece327d03d08096395969aca5e0a6996/diff.c#L2615
// Parts of the output:
// <pad><filename><pad>|<pad><changeNumber><pad><+++/---><newline>
// example: " main.go | 10 +++++++--- "
func (opts *DiffOptions) showStats(ctx context.Context, fileStats object.FileStats) error {
func (opts *DiffOptions) ShowStats(ctx context.Context, fileStats object.FileStats) error {
w, useColor, err := opts.NewOutput(ctx)
if err != nil {
return err
}
defer w.Close()
if opts.ShortStat {
if opts.Shortstat {
var added, deleted int
for _, s := range fileStats {
added += s.Addition
Expand All @@ -153,7 +154,7 @@ func (opts *DiffOptions) showStats(ctx context.Context, fileStats object.FileSta
fmt.Fprintf(w, " %d files changed, %d insertions(+), %d deletions(-)%c", len(fileStats), added, deleted, opts.NewLine)
return nil
}
if opts.NumStat {
if opts.Numstat {
var ma, md int
for _, s := range fileStats {
ma = max(ma, s.Addition)
Expand Down Expand Up @@ -199,7 +200,7 @@ func (opts *DiffOptions) showStats(ctx context.Context, fileStats object.FileSta
return nil
}

func (opts *DiffOptions) showPatch(ctx context.Context, patch []*diferenco.Unified) error {
func (opts *DiffOptions) ShowPatch(ctx context.Context, patch []*diferenco.Unified) error {
w, useColor, err := opts.NewOutput(ctx)
if err != nil {
return err
Expand Down Expand Up @@ -230,6 +231,7 @@ func (opts *DiffOptions) showChangesStatus(ctx context.Context, changes merkletr
}
return nil
}
// name-status
for _, c := range changes {
name := nameFromAction(&c)
if !m.Match(name) {
Expand Down
12 changes: 6 additions & 6 deletions pkg/zeta/worktree_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,19 +201,19 @@ func (w *Worktree) showChanges(ctx context.Context, opts *DiffOptions, changes m
return opts.showChangesStatus(ctx, changes)
}
m := NewMatcher(opts.PathSpec)
if opts.showStatsOnly() {
fileStats, err := w.getStatsContext(ctx, changes, m, opts.Textconv)
if opts.showStatOnly() {
fileStats, err := w.getStatsContext(ctx, changes, m, opts.TextConv)
if err != nil {
return err
}
return opts.showStats(ctx, fileStats)
return opts.ShowStats(ctx, fileStats)
}

filePatchs, err := w.getPatchContext(ctx, changes, m, opts.Textconv)
filePatchs, err := w.getPatchContext(ctx, changes, m, opts.TextConv)
if err != nil {
return err
}
return opts.showPatch(ctx, filePatchs)
return opts.ShowPatch(ctx, filePatchs)
}

func (w *Worktree) diffWorktree(ctx context.Context, opts *DiffOptions) error {
Expand Down Expand Up @@ -272,7 +272,7 @@ func (w *Worktree) DiffTreeWithWorktree(ctx context.Context, oid plumbing.Hash,
}

func (w *Worktree) resolveBetweenTree(ctx context.Context, opts *DiffOptions) (oldTree *object.Tree, newTree *object.Tree, err error) {
if !opts.W3 {
if !opts.Way3 {
if oldTree, err = w.parseTreeExhaustive(ctx, opts.From, ""); err != nil {
fmt.Fprintf(os.Stderr, "resolve tree: %s error: %v\n", opts.From, err)
return
Expand Down

0 comments on commit 8e2b276

Please sign in to comment.