Skip to content

Commit

Permalink
feat: Change hunks and regex into a list (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
nieomylnieja authored Sep 21, 2024
1 parent a5e3c02 commit 65e3cc5
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 22 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,26 @@ The config file is a JSON file which describes the synchronization process.
"repositoryName": "go-libyear",
// Optional. Name of the file to which the ignore rule applies.
"fileName": "golangci linter config",
// Optional. Regular expression used to ignore matching hunks.
"regex": "^\\s*local-prefixes:"
// Optional. List of regular expressions used to ignore matching hunks.
// Note: This regular expression is passed to 'diff -I <regex>' and thus follows
// BRE (basic regular expression) rules, you may need to escape some characters, like '+'.
// Ref: https://www.gnu.org/software/grep/manual/html_node/Basic-vs-Extended.html.
"regex": ["^\\s\\+local-prefixes:"]
},
{
// Optional. Hunk to be ignored is represented with lines header and changes list.
// Optional. Hunks to be ignored are represented with lines header and changes list.
// Either enter it manually or use the 'i' option in the sync command prompt.
//
// Ref: https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html.
"hunk": {
"hunks": [{
// Optional. If lines are not provided the changes will be matched anywhere within the file.
"lines": "@@ -3,0 +4,2 @@",
// Required.
"changes": [
"+ skip-dirs:",
"+ - scripts"
]
}
}]
}
],
// Required. At least one repository must be provided.
Expand Down
11 changes: 6 additions & 5 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ type File struct {
}

type IgnoreRule struct {
RepositoryName *string `json:"repositoryName,omitempty"`
FileName *string `json:"fileName,omitempty"`
Regex *string `json:"regex,omitempty"`
Hunk *diff.Hunk `json:"hunk,omitempty"`
RepositoryName *string `json:"repositoryName,omitempty"`
FileName *string `json:"fileName,omitempty"`
Regex []string `json:"regex,omitempty"`
Hunks []diff.Hunk `json:"hunks,omitempty"`
}

func ReadConfig(configPath string) (*Config, error) {
Expand Down Expand Up @@ -94,6 +94,7 @@ func (c *Config) Save() error {
}
enc := json.NewEncoder(f)
enc.SetIndent("", " ")
enc.SetEscapeHTML(false)
if err = enc.Encode(c); err != nil {
return fmt.Errorf("failed to save config: %w", err)
}
Expand Down Expand Up @@ -181,7 +182,7 @@ func (f *File) validate() error {
}

func (i *IgnoreRule) validate() error {
if i.Regex == nil && i.Hunk == nil {
if i.Regex == nil && i.Hunks == nil {
return errors.New("either 'regex' or 'hunk' needs to be defined")
}
return nil
Expand Down
6 changes: 4 additions & 2 deletions internal/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (u UnifiedFormat) String(original bool) string {
// Hunk represents a single diff hunk in of [UnifiedFormat].
type Hunk struct {
// Lines is the '@@' header containing the line numbers.
Lines string `json:"lines"`
Lines string `json:"lines,omitempty"`
// Changes contains only the changed lines, without any context.
Changes []string `json:"changes"`
// Original is the original string representation of the hunk.
Expand All @@ -55,8 +55,10 @@ func (h Hunk) String() string {
return sb.String()
}

// Equal compares two [Hunk]s for equality.
// It ignores color codes and will not compare [Hunk.Lines] if the receiver [Hunk] has no lines defined.
func (h Hunk) Equal(other Hunk) bool {
if h.Lines != other.Lines || len(h.Changes) != len(other.Changes) {
if (h.Lines != "" && h.Lines != other.Lines) || len(h.Changes) != len(other.Changes) {
return false
}
for i := range h.Changes {
Expand Down
44 changes: 34 additions & 10 deletions internal/gitsync/gitsync.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ func syncRepoFile(
FileName: file.Name,
Regex: true,
}) {
regexes = append(regexes, *ignore.Regex)
regexes = append(regexes, ignore.Regex...)
}
args := []string{
"-U", "0",
"--ignore-all-space",
"--color=always",
"--label", fmt.Sprintf("%s (synced): %s (%s)", syncedRepo.Name, file.Path, file.Name),
"--label", fmt.Sprintf("%s (root): %s (%s)", conf.Root.Name, file.Path, file.Name),
Expand All @@ -129,7 +130,6 @@ func syncRepoFile(
if err != nil {
return false, err
}
scanner := bufio.NewScanner(os.Stdin)
resultHunks := make([]diff.Hunk, 0, len(unifiedFmt.Hunks))
prompt := command == CommandSync
hunkLoop:
Expand All @@ -139,8 +139,10 @@ hunkLoop:
FileName: file.Name,
Hunk: true,
}) {
if ignore.Hunk.Equal(hunk) {
continue hunkLoop
for _, ignoreHunk := range ignore.Hunks {
if ignoreHunk.Equal(hunk) {
continue hunkLoop
}
}
}
if !prompt {
Expand All @@ -151,6 +153,7 @@ hunkLoop:
sep := getPrintSeparator(append(hunk.Changes, strings.Split(unifiedFmt.Header, "\n")...))
fmt.Printf("%[1]s\n%[2]s\n%[3]s%[1]s\n", sep, unifiedFmt.Header, hunk.Original)
fmt.Print(promptMessage)
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
switch scanner.Text() {
case "Y":
Expand All @@ -162,11 +165,32 @@ hunkLoop:
case "i":
// Copy loop variable.
hunk := hunk
conf.Ignore = append(conf.Ignore, &config.IgnoreRule{
RepositoryName: &syncedRepo.Name,
FileName: &file.Name,
Hunk: &hunk,
})
found := false
for _, ignore := range conf.Ignore {
if ignore.RepositoryName != nil && *ignore.RepositoryName == syncedRepo.Name &&
ignore.FileName != nil && *ignore.FileName == file.Name {
ignore.Hunks = append(ignore.Hunks, hunk)
found = true
break
}
}
if !found {
conf.Ignore = append(conf.Ignore, &config.IgnoreRule{
RepositoryName: &syncedRepo.Name,
FileName: &file.Name,
Hunks: []diff.Hunk{hunk},
})
}
case "h":
fmt.Printf(`Enter one of the following characters:
- Y (accept all hunks for %s - applies only to %s repository)
- y (accept the hunk)
- n (reject the hunk)
- i (ignore the hunk permanently, an ignore rule will be added to your config file)
- h (display this help message)
`, file.Path, syncedRepo.URL)
fmt.Print(promptMessage)
continue
default:
fmt.Println("Invalid input. Please enter Y (all), y (yes), n (no), i (ignore), or h (help).")
fmt.Print(promptMessage)
Expand Down Expand Up @@ -449,7 +473,7 @@ func getIgnoreRules(conf *config.Config, query ignoreRulesQuery) []*config.Ignor
if ignore.FileName != nil && *ignore.FileName != query.FileName {
continue
}
if query.Hunk && ignore.Hunk != nil {
if query.Hunk && ignore.Hunks != nil {
rules = append(rules, ignore)
}
if query.Regex && ignore.Regex != nil {
Expand Down

0 comments on commit 65e3cc5

Please sign in to comment.