diff --git a/cmd/root.go b/cmd/root.go index d854c9a..bf310c0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -21,26 +21,62 @@ package cmd import ( + "errors" "fmt" + "io" "os" + "time" + "github.com/aswinkarthik93/csvdiff/pkg/digest" homedir "github.com/mitchellh/go-homedir" "github.com/spf13/cobra" "github.com/spf13/viper" ) var cfgFile string +var timed bool // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "csvdiff", + Use: "csvdiff ", Short: "A diff tool for database tables dumped as csv files", Long: `Differentiates two csv files and finds out the additions and modifications. Most suitable for csv files created from database tables`, + PreRunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 2 { + return errors.New("Pass 2 files. Usage: csvdiff ") + } + return nil + }, // Uncomment the following line if your bare application // has an action associated with it: - // Run: func(cmd *cobra.Command, args []string) { - // }, + Run: func(cmd *cobra.Command, args []string) { + if !timed { + defer timeTrack(time.Now(), "csvdiff") + } + + baseFile := newReadCloser(args[0]) + defer baseFile.Close() + deltaFile := newReadCloser(args[1]) + defer deltaFile.Close() + + baseConfig := digest.NewConfig(baseFile, config.GetPrimaryKeys(), config.GetValueColumns()) + deltaConfig := digest.NewConfig(deltaFile, config.GetPrimaryKeys(), config.GetValueColumns()) + + diff := digest.Diff(baseConfig, deltaConfig) + + fmt.Printf("Additions %d\n", len(diff.Additions)) + fmt.Printf("Modifications %d\n", len(diff.Modifications)) + fmt.Println("Rows:") + + for _, added := range diff.Additions { + fmt.Printf("%s,%s\n", added, "ADDED") + } + + for _, modified := range diff.Modifications { + fmt.Printf("%s,%s\n", modified, "MODIFIED") + } + }, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -63,6 +99,12 @@ func init() { // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + + rootCmd.Flags().IntSliceVarP(&config.PrimaryKeyPositions, "primary-key", "p", []int{0}, "Primary key positions of the Input CSV as comma separated values Eg: 1,2") + rootCmd.Flags().IntSliceVarP(&config.ValueColumnPositions, "columns", "", []int{}, "Selectively compare positions in CSV Eg: 1,2. Default is entire row") + + rootCmd.Flags().BoolVarP(&debug, "debug", "", false, "Debug mode") + rootCmd.Flags().BoolVarP(&timed, "time", "", false, "Measure time") } // initConfig reads in config file and ENV variables if set. @@ -90,3 +132,12 @@ func initConfig() { fmt.Println("Using config file:", viper.ConfigFileUsed()) } } + +func newReadCloser(filename string) io.ReadCloser { + file, err := os.Open(filename) + if err != nil { + panic(err) + } + + return file +} diff --git a/cmd/run.go b/cmd/run.go index cf3c9da..2efc197 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -49,7 +49,7 @@ var ( var newLine []byte func init() { - rootCmd.AddCommand(digestCmd) + // rootCmd.AddCommand(digestCmd) newLine = []byte{'\n'} digestCmd.Flags().StringVarP(&config.Base, "base", "b", "", "The base csv file") @@ -77,9 +77,9 @@ func run() { log.Fatal(err) } - baseConfig := digest.NewConfig(config.GetBaseReader(), false, config.GetPrimaryKeys(), config.GetValueColumns()) + baseConfig := digest.NewConfig(config.GetBaseReader(), config.GetPrimaryKeys(), config.GetValueColumns()) - deltaConfig := digest.NewConfig(config.GetDeltaReader(), true, config.GetPrimaryKeys(), config.GetValueColumns()) + deltaConfig := digest.NewConfig(config.GetDeltaReader(), config.GetPrimaryKeys(), config.GetValueColumns()) var wg sync.WaitGroup baseChannel := make(chan message) diff --git a/pkg/digest/digest.go b/pkg/digest/digest.go index 8075a7a..7adab19 100644 --- a/pkg/digest/digest.go +++ b/pkg/digest/digest.go @@ -38,7 +38,7 @@ type Config struct { } // NewConfig creates an instance of Config struct. -func NewConfig(r io.Reader, createSourceMap bool, primaryKey Positions, valueColumns Positions) *Config { +func NewConfig(r io.Reader, primaryKey Positions, valueColumns Positions) *Config { return &Config{ Reader: r, Key: primaryKey,