yamldiff re-implementation in go
This commit is contained in:
		
							parent
							
								
									03a1a4e132
								
							
						
					
					
						commit
						3a6a913ef2
					
				
							
								
								
									
										99
									
								
								cmd/yamldiff/yamldiff.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								cmd/yamldiff/yamldiff.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	yaml "github.com/goccy/go-yaml" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| ) | ||||
| 
 | ||||
| func read(file string) []byte { | ||||
| 	data, err := os.ReadFile(file) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return data | ||||
| } | ||||
| 
 | ||||
| func parse(data []byte) yaml.MapSlice { | ||||
| 	var result yaml.MapSlice | ||||
| 	decoder := yaml.NewDecoder(bytes.NewReader(data), | ||||
| 		yaml.UseOrderedMap()) | ||||
| 	err := decoder.Decode(&result) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
| 
 | ||||
| type TypeId int | ||||
| 
 | ||||
| const ( | ||||
| 	Map TypeId = iota | ||||
| 	Slice | ||||
| 	Scalar | ||||
| ) | ||||
| 
 | ||||
| func Type(elem any) TypeId { | ||||
| 	switch elem.(type) { | ||||
| 	case yaml.MapSlice: | ||||
| 		return Map | ||||
| 	case []any: | ||||
| 		return Slice | ||||
| 	default: | ||||
| 		return Scalar | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func subtract(yaml1 yaml.MapSlice, yaml2 yaml.MapSlice) yaml.MapSlice { | ||||
| 	res := make(yaml.MapSlice, 0) | ||||
| 	for _, item := range yaml2 { | ||||
| 		k := item.Key | ||||
| 		v1 := item.Value | ||||
| 		v2 := yaml1.ToMap()[k] | ||||
| 		switch { | ||||
| 		case reflect.DeepEqual(v1, v2): | ||||
| 			// delete is implicit by not copying to the output
 | ||||
| 		case Type(v1) == Map && Type(v2) == Map: | ||||
| 			diff := subtract(v2.(yaml.MapSlice), v1.(yaml.MapSlice)) | ||||
| 			if len(diff) > 0 { | ||||
| 				res = append(res, item) | ||||
| 			} | ||||
| 		case Type(v1) == Slice && Type(v2) == Slice: | ||||
| 			if !reflect.DeepEqual(v1, v2) { | ||||
| 				res = append(res, item) | ||||
| 			} | ||||
| 		default: | ||||
| 			res = append(res, item) | ||||
| 		} | ||||
| 	} | ||||
| 	return res | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	if len(os.Args) != 3 { | ||||
| 		fmt.Fprintf(os.Stderr, ` | ||||
| Usage: yamldiff <file1> <file2>") | ||||
|   Shows changes and additions made in <file2> w.r.t. <file1>  | ||||
| `) | ||||
| 	} | ||||
| 	file1 := os.Args[1] | ||||
| 	file2 := os.Args[2] | ||||
| 
 | ||||
| 	yaml1 := parse(read(file1)) | ||||
| 	yaml2 := parse(read(file2)) | ||||
| 
 | ||||
| 	subtract(yaml2, yaml1) | ||||
| 
 | ||||
| 	enc := yaml.NewEncoder(os.Stdout, | ||||
| 		yaml.UseLiteralStyleIfMultiline(true), | ||||
| 		yaml.Indent(2), // Set indentation
 | ||||
| 		//yaml.UseOrderedMap(), // Preserve map order
 | ||||
| 	) | ||||
| 	err := enc.Encode(yaml2) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user