diff --git a/pkg/command/command_diff.go b/pkg/command/command_diff.go index 0b5ad8b..8e689f3 100644 --- a/pkg/command/command_diff.go +++ b/pkg/command/command_diff.go @@ -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 "` Cached bool `name:"cached" help:"Compare the differences between the staging area and "` - 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 and HEAD instead"` Output string `name:"output" help:"Output to a specific file instead of stdout" placeholder:""` Histogram bool `name:"histogram" help:"Generate a diff using the \"Histogram diff\" algorithm"` @@ -33,8 +35,8 @@ 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:"-"` } @@ -42,12 +44,14 @@ const ( diffSummaryFormat = `%s zeta diff [] [] [--] [...] %s zeta diff [] --cached [] [--] [...] %s zeta diff [] [--] [...] -%s zeta diff [] ... [--] [...]` +%s zeta diff [] ... [--] [...] +%s zeta diff [] +%s zeta diff [] --no-index [--] ` ) 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 { @@ -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 { @@ -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, diff --git a/pkg/serve/repo/push.go b/pkg/serve/repo/push.go index b6e87bd..15ca8fd 100644 --- a/pkg/serve/repo/push.go +++ b/pkg/serve/repo/push.go @@ -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, diff --git a/pkg/tr/languages/zh-CN.toml b/pkg/tr/languages/zh-CN.toml index b69d02a..ebad9e1 100644 --- a/pkg/tr/languages/zh-CN.toml +++ b/pkg/tr/languages/zh-CN.toml @@ -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 而不是补丁" @@ -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 存储库" diff --git a/pkg/zeta/showdiff.go b/pkg/zeta/showdiff.go index a465b74..33cab06 100644 --- a/pkg/zeta/showdiff.go +++ b/pkg/zeta/showdiff.go @@ -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 { @@ -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 { @@ -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 { @@ -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: // |<+++/---> // 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 @@ -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) @@ -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 @@ -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) { diff --git a/pkg/zeta/worktree_diff.go b/pkg/zeta/worktree_diff.go index eca083c..86e0979 100644 --- a/pkg/zeta/worktree_diff.go +++ b/pkg/zeta/worktree_diff.go @@ -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 { @@ -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