From f099059707a00203cd43246d4275db24a341a49e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dennis=20Pl=C3=B6ger?= Date: Tue, 29 Oct 2024 08:11:36 +0100 Subject: [PATCH] feat: Skip rows and ignore superfluous columns Additionally, we jump to GO 1.23 --- .github/workflows/build.yml | 2 +- .github/workflows/test.yml | 2 +- .vscode/launch.json | 22 ++++++++++ go.mod | 2 +- internal/converteradapters/csv.go | 13 ++++-- .../script/converters_csv_skiprow.txtar | 12 +++++ pkg/converters/csv.go | 16 +++++-- pkg/converters/csv_test.go | 44 +++++++++++++++++-- 8 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 internal/converteradapters/testdata/script/converters_csv_skiprow.txtar diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0a3238c..c80cd1b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.21 + go-version: 1.23 - name: Build run: go build -o icarus cmd/icarus.go diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8f15024..8bbf7e9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,7 +16,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.21 + go-version: 1.23 - name: Test run: go test -v ./... diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..d60724e --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,22 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Launch file", + "type": "go", + "request": "launch", + "mode": "debug", + "program": "${file}" + }, + { + "name": "Launch Package", + "type": "go", + "request": "launch", + "mode": "auto", + "program": "${fileDirname}" + } + ] +} \ No newline at end of file diff --git a/go.mod b/go.mod index 72274ca..01d9319 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/dploeger/icarus/v2 -go 1.21 +go 1.23 require ( github.com/MakeNowJust/heredoc v1.0.0 diff --git a/internal/converteradapters/csv.go b/internal/converteradapters/csv.go index 0645b97..552b3b8 100644 --- a/internal/converteradapters/csv.go +++ b/internal/converteradapters/csv.go @@ -2,12 +2,13 @@ package converteradapters import ( "fmt" - "github.com/akamensky/argparse" - "github.com/dploeger/icarus/v2/pkg/converters" - "github.com/emersion/go-ical" "os" "strings" "time" + + "github.com/akamensky/argparse" + "github.com/dploeger/icarus/v2/pkg/converters" + "github.com/emersion/go-ical" ) type CSVConverterAdapter struct { @@ -17,6 +18,7 @@ type CSVConverterAdapter struct { hasHeaders *bool headers *[]string location *string + skipRows *int } var _ ConverterAdapter = &CSVConverterAdapter{} @@ -46,6 +48,10 @@ func (c *CSVConverterAdapter) Initialize(parser *argparse.Parser) (*argparse.Com Help: "Assume the location for all timestamps", Default: "UTC", }) + c.skipRows = command.Int("K", "skip-rows", &argparse.Options{ + Help: "Skip the number of rows before starting to parse", + Default: 0, + }) return command, nil } @@ -69,6 +75,7 @@ func (c *CSVConverterAdapter) Convert(input *os.File, output *ical.Calendar) err HasHeaders: *c.hasHeaders, Headers: *c.headers, Location: location, + SkipRows: *c.skipRows, } return converter.Convert(input, output) diff --git a/internal/converteradapters/testdata/script/converters_csv_skiprow.txtar b/internal/converteradapters/testdata/script/converters_csv_skiprow.txtar new file mode 100644 index 0000000..9ff6339 --- /dev/null +++ b/internal/converteradapters/testdata/script/converters_csv_skiprow.txtar @@ -0,0 +1,12 @@ +stdin example.csv +exec icarus convertCSV -H -K 1 +! stderr . +stdout 'SUMMARY:Test' +stdout 'DTSTART:20240826T122400Z' +stdout 'DTSTART:20240826T122400Z' +stdout 'DTEND:20240826T132400Z' + +-- example.csv -- +BOGUS +DTSTART,DTEND,SUMMARY +2024-08-26T12:24:00Z,2024-08-26T13:24:00Z,Test \ No newline at end of file diff --git a/pkg/converters/csv.go b/pkg/converters/csv.go index 64111a8..1f5f242 100644 --- a/pkg/converters/csv.go +++ b/pkg/converters/csv.go @@ -3,12 +3,13 @@ package converters import ( "encoding/csv" "fmt" - "github.com/emersion/go-ical" - "github.com/google/uuid" - "golang.org/x/exp/maps" "io" "slices" "time" + + "github.com/emersion/go-ical" + "github.com/google/uuid" + "golang.org/x/exp/maps" ) // CSVConverter converts an incoming CSV formatted file into a Calendar object @@ -19,6 +20,7 @@ type CSVConverter struct { HasHeaders bool Headers []string Location *time.Location + SkipRows int } var _ BaseConverter = &CSVConverter{} @@ -27,6 +29,11 @@ func (c *CSVConverter) Convert(input io.Reader, output *ical.Calendar) error { reader := csv.NewReader(input) reader.Comma = ([]rune(c.Separator))[0] + for range c.SkipRows { + reader.Read() + reader.FieldsPerRecord = 0 + } + var headers []string if c.HasHeaders { @@ -47,6 +54,9 @@ func (c *CSVConverter) Convert(input io.Reader, output *ical.Calendar) error { for _, row := range rows { fieldValues := make(map[string]string) for i, col := range row { + if i >= len(headers) { + continue + } var field string if slices.Contains(maps.Keys(c.FieldMap), headers[i]) { field = c.FieldMap[headers[i]] diff --git a/pkg/converters/csv_test.go b/pkg/converters/csv_test.go index 0091f3a..9bfda28 100644 --- a/pkg/converters/csv_test.go +++ b/pkg/converters/csv_test.go @@ -1,12 +1,13 @@ package converters import ( - "github.com/MakeNowJust/heredoc" - "github.com/emersion/go-ical" - "github.com/stretchr/testify/assert" "strings" "testing" "time" + + "github.com/MakeNowJust/heredoc" + "github.com/emersion/go-ical" + "github.com/stretchr/testify/assert" ) func TestConvert(t *testing.T) { @@ -218,3 +219,40 @@ func TestConvertLocation(t *testing.T) { dtEnd, _ := event.Props.Get(ical.PropDateTimeEnd).DateTime(cetLocation) assert.Equal(t, "2024-08-26 13:24", dtEnd.Format("2006-01-02 15:04"), "Wrong end time") } + +func TestConvertSkipRow(t *testing.T) { + startTime, _ := time.Parse(time.RFC3339, "2024-08-26T12:24:00Z") + endTime, _ := time.Parse(time.RFC3339, "2024-08-26T13:24:00Z") + + subject := heredoc.Docf(` + BOGUS + DTSTART,DTEND,SUMMARY + %s,%s,Test + `, + startTime.Format(time.RFC3339), + endTime.Format(time.RFC3339), + ) + + converter := CSVConverter{ + Separator: ",", + TimestampFormat: time.RFC3339, + FieldMap: nil, + HasHeaders: true, + Headers: nil, + Location: time.UTC, + SkipRows: 1, + } + + calendar := ical.NewCalendar() + + err := converter.Convert(strings.NewReader(subject), calendar) + assert.NoError(t, err, "Converter errored out") + assert.Len(t, calendar.Children, 1, "Invalid number of children in calendar") + event := calendar.Children[0] + summary, _ := event.Props.Get(ical.PropSummary).Text() + assert.Equal(t, "Test", summary) + dtStart, _ := event.Props.Get(ical.PropDateTimeStart).DateTime(startTime.Location()) + assert.Equal(t, startTime, dtStart, "Wrong start time") + dtEnd, _ := event.Props.Get(ical.PropDateTimeEnd).DateTime(endTime.Location()) + assert.Equal(t, endTime, dtEnd, "Wrong end time") +}