Last active
February 1, 2022 18:00
-
-
Save amitkbiswas01/1972181a2b14d19be15681fafe2f46fa to your computer and use it in GitHub Desktop.
Program to convert output from `git diff` for a folder to a JSON file based on the line change.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright 2022 Amit Biswas. All rights reserved. | |
// Use of this source code is governed by the | |
// GNU GENERAL PUBLIC LICENSE v3.0 | |
// Program to convert output from `git diff` for a folder to a | |
// JSON file based on the line change. If the diff for a file is | |
// nothing other than line number changes, it excludes the file | |
// from JSON listing. | |
// For example, if the diff for file A is like below, where the | |
// content is same but line number is changed, this file won't be | |
// listed in the JSON. | |
// diff --git a/A.txt b/A.txt | |
// index 5e486ea..916d710 100644 | |
// --- a/A.txt | |
// +++ b/A.txt | |
// @@ -1,5 +1,5 @@ | |
// Hello World! | |
// -I am excited about programming. | |
// - | |
// Thanks! | |
// + | |
// +I am excited about programming. | |
package main | |
import ( | |
"encoding/json" | |
"os" | |
"os/exec" | |
"regexp" | |
"strings" | |
) | |
// generate git diff for loc folder | |
func generateDiff(loc string) ([]byte, error) { | |
args := []string{"cd", loc, "&&", "git", "diff"} | |
cmd := exec.Command("/bin/bash", "-c", strings.Join(args, " ")) | |
return cmd.CombinedOutput() | |
} | |
// writes selected diffs to a json file in loc folder | |
func writeToJSON(loc string, selectedDiffs map[string]map[string][]string) { | |
// create or overwrite previous file | |
file, err := os.OpenFile(loc+"/result.json", os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0755) | |
if err != nil { | |
panic(err) | |
} | |
// close file when writeToJSON ends | |
defer file.Close() | |
// convert map to JSON | |
jsonDiff, err := json.Marshal(selectedDiffs) | |
if err != nil { | |
panic(err) | |
} | |
// write to file | |
if _, err := file.WriteString(string(jsonDiff)); err != nil { | |
panic(err) | |
} | |
} | |
func main() { | |
// determine folder location from cmd arguments | |
loc := "." | |
if len(os.Args) > 1 && os.Args[1] != "" { | |
loc = os.Args[1] | |
} | |
// generate diff as []byte | |
diff, err := generateDiff(loc) | |
if err != nil { | |
panic("Couldn't generate diff. Check the folder path.") | |
} | |
// create slice of lines from diff string | |
lines := strings.Split(string(diff), "\n") | |
if len(lines) == 0 { | |
panic("No diff found!") | |
} | |
allDiffs := make(map[string]map[string][]string) | |
selectedDiffs := make(map[string]map[string][]string) | |
currentfilepath := "" | |
for _, line := range lines { | |
// select only if changed line or filepath line | |
// - negate: true | |
// + negate: false | |
// --- a/config/drupal/default/addtoany.settings.yml | |
// +++ a/config/drupal/default/addtoany.settings.yml | |
matched, err := regexp.MatchString("^[+-]([+-][+-])?[a-zA-Z _].*", line) | |
if err != nil { | |
panic(err) | |
} | |
if matched { | |
// select only filepath line | |
// --- a/config/drupal/default/addtoany.settings.yml | |
// +++ a/config/drupal/default/addtoany.settings.yml | |
if strings.HasPrefix(line, "+++") || strings.HasPrefix(line, "---") { | |
// extract filepath from full path | |
// config/drupal/default/addtoany.settings.yml | |
fullpath := regexp.MustCompile(` [ab]/`).Split(line, -1) | |
filepath := fullpath[len(fullpath)-1] | |
// init entry against the filepath | |
if _, ok := allDiffs[filepath]; !ok { | |
allDiffs[filepath] = make(map[string][]string) | |
currentfilepath = filepath | |
} | |
} else { | |
// if changed line, add according to add/delete | |
if string(line[0]) == "+" { | |
allDiffs[currentfilepath]["+"] = append(allDiffs[currentfilepath]["+"], line[1:]) | |
} | |
if string(line[0]) == "-" { | |
allDiffs[currentfilepath]["-"] = append(allDiffs[currentfilepath]["-"], line[1:]) | |
} | |
} | |
} | |
} | |
// after building map from diff, filter the map to get | |
// diff which are not positional changes. Meaning, if a | |
// statement was on line 10, and now on line 15, the diff | |
// for the file will be excluded. | |
for key, val := range allDiffs { | |
added := val["+"] | |
deleted := val["-"] | |
for _, va := range added { | |
found := false | |
for _, vd := range deleted { | |
if va == vd { | |
found = true | |
break | |
} | |
} | |
if found == false { | |
if _, ok := selectedDiffs[key]; !ok { | |
selectedDiffs[key] = map[string][]string{ | |
"+": val["+"], | |
"-": val["-"], | |
} | |
} | |
} | |
} | |
} | |
// write to JSON | |
writeToJSON(loc, selectedDiffs) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment