Skip to content

Instantly share code, notes, and snippets.

@amitkbiswas01
Last active February 1, 2022 18:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amitkbiswas01/1972181a2b14d19be15681fafe2f46fa to your computer and use it in GitHub Desktop.
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.
// 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