-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Migrating to CLI adapters to make the package
more usable
- Loading branch information
Showing
42 changed files
with
1,369 additions
and
454 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,156 +1,10 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"github.com/akamensky/argparse" | ||
"github.com/dploeger/icarus/v2/pkg/outputTypes" | ||
"github.com/dploeger/icarus/v2/pkg/processors" | ||
"github.com/emersion/go-ical" | ||
"github.com/sirupsen/logrus" | ||
"github.com/thoas/go-funk" | ||
"github.com/dploeger/icarus/v2/internal" | ||
"os" | ||
"regexp" | ||
"time" | ||
) | ||
|
||
type processorCommand struct { | ||
processor processors.BaseProcessor | ||
command *argparse.Command | ||
} | ||
|
||
func main() { | ||
availableOutputTypes := outputTypes.GetOutputTypes() | ||
parser := argparse.NewParser("icarus", "iCal file processor") | ||
inputFile := parser.File("f", "file", os.O_RDONLY, 0444, &argparse.Options{ | ||
Help: "File to read ics data from. Defaults to stdin", | ||
}) | ||
outputFile := parser.File("o", "output", os.O_RDWR, 0644, &argparse.Options{ | ||
Help: "File to write ics data to. Defaults to stdout", | ||
}) | ||
selector := parser.String("s", "selector", &argparse.Options{ | ||
Default: ".*", | ||
Help: "Regular Expression pattern to select events by their summary, description, etc.", | ||
}) | ||
selectorProps := parser.StringList("p", "selector-props", &argparse.Options{ | ||
Help: "Event properties that are searched using the text selector pattern", | ||
Default: []string{ical.PropSummary, ical.PropDescription}, | ||
}) | ||
dateSelectorStart := parser.String("b", "timestamp-start", &argparse.Options{ | ||
Help: "An RFC3339-formatted (2006-01-02T15:04:05+07:00) timestamp that selects only events starting at or after that time", | ||
Validate: func(args []string) error { | ||
_, err := time.Parse(time.RFC3339, args[0]) | ||
if err != nil { | ||
return fmt.Errorf("can not parse start timestamp: %w", err) | ||
} | ||
return nil | ||
}, | ||
}) | ||
dateSelectorEnd := parser.String("e", "timestamp-end", &argparse.Options{ | ||
Help: "An RFC3339-formatted (2006-01-02T15:04:05+07:00) timestamp that selects only events ending at or before that time", | ||
Validate: func(args []string) error { | ||
_, err := time.Parse(time.RFC3339, args[0]) | ||
if err != nil { | ||
return fmt.Errorf("can not parse end timestamp: %w", err) | ||
} | ||
return nil | ||
}, | ||
}) | ||
outputType := parser.Selector("t", "output-type", funk.Keys(availableOutputTypes).([]string), &argparse.Options{ | ||
Help: fmt.Sprintf("Type of output. Valid types:\n%s\n\t\t\t", outputTypes.GetOutputHelp()), | ||
Default: "ics", | ||
}) | ||
logLevel := parser.String("l", "loglevel", &argparse.Options{ | ||
Help: "Loglevel to use", | ||
Default: "error", | ||
}) | ||
|
||
var processorCommands []processorCommand | ||
for _, processor := range processors.GetProcessors() { | ||
if command, err := processor.Initialize(parser); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(1) | ||
} else { | ||
processorCommands = append(processorCommands, processorCommand{ | ||
processor: processor, | ||
command: command, | ||
}) | ||
} | ||
} | ||
|
||
for _, outputType := range availableOutputTypes { | ||
if err := outputType.Initialize(parser); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
if err := parser.Parse(os.Args); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(1) | ||
} | ||
|
||
if loggerLevel, err := logrus.ParseLevel(*logLevel); err != nil { | ||
logrus.Errorf("%s is not a valid log level", *logLevel) | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(1) | ||
} else { | ||
logrus.SetLevel(loggerLevel) | ||
} | ||
|
||
if (os.File{}) == *inputFile { | ||
inputFile = os.Stdin | ||
} | ||
if (os.File{}) == *outputFile { | ||
outputFile = os.Stdout | ||
} | ||
|
||
logrus.Debug("Parsing input calendar") | ||
|
||
var inputCalendar ical.Calendar | ||
dec := ical.NewDecoder(inputFile) | ||
if cal, err := dec.Decode(); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(2) | ||
} else { | ||
inputCalendar = *cal | ||
} | ||
|
||
outputCalendar := ical.NewCalendar() | ||
outputCalendar.Props = inputCalendar.Props | ||
|
||
var dStart time.Time | ||
if dateSelectorStart != nil { | ||
dStart, _ = time.Parse(time.RFC3339, *dateSelectorStart) | ||
} | ||
|
||
var dEnd time.Time | ||
if dateSelectorEnd != nil { | ||
dEnd, _ = time.Parse(time.RFC3339, *dateSelectorEnd) | ||
} | ||
|
||
toolbox := processors.Toolbox{ | ||
TextSelectorPattern: regexp.MustCompile(fmt.Sprintf("(?i)%s", *selector)), | ||
TextSelectorProps: *selectorProps, | ||
DateRangeSelectorStart: dStart, | ||
DateRangeSelectorEnd: dEnd, | ||
} | ||
|
||
for _, processorCommand := range processorCommands { | ||
if processorCommand.command.Happened() { | ||
logrus.Infof("Processor %s was selected. Starting process", processorCommand.command.GetName()) | ||
processorCommand.processor.SetToolbox(toolbox) | ||
if err := processorCommand.processor.Process(inputCalendar, outputCalendar); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(3) | ||
} | ||
} | ||
} | ||
|
||
logrus.Infof("Generating output type %s", *outputType) | ||
|
||
if err := availableOutputTypes[*outputType].Generate(outputCalendar, outputFile); err != nil { | ||
fmt.Print(parser.Usage(err)) | ||
os.Exit(4) | ||
} | ||
|
||
os.Exit(internal.Main()) | ||
} |
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Package adapters holds CLI adapters that connect the icarus CLI to the processors | ||
package adapters | ||
|
||
import ( | ||
"github.com/akamensky/argparse" | ||
"github.com/dploeger/icarus/v2/pkg/processors" | ||
"github.com/emersion/go-ical" | ||
) | ||
|
||
// The Adapter connects the Icarus CLI with a processor | ||
type Adapter interface { | ||
// Initialize creates a new subcommand for the argparse parser. | ||
Initialize(parser *argparse.Parser) (*argparse.Command, error) | ||
// SetToolbox sets the toolbox that can be used by the processor | ||
SetToolbox(toolbox processors.Toolbox) | ||
// Process processes the incoming calendar and fills the output calendar | ||
Process(input ical.Calendar, output *ical.Calendar) error | ||
} | ||
|
||
// GetAdapters returns a list of enabled processor adapters | ||
func GetAdapters() []Adapter { | ||
return []Adapter{ | ||
&FilterAdapter{}, | ||
&PrintAdapter{}, | ||
&ConvertAllDayAdapter{}, | ||
&AddDTStampAdapter{}, | ||
&AddAlarmAdapter{}, | ||
&AddPropertyAdapter{}, | ||
&DeletePropertyAdapter{}, | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package adapters_test | ||
|
||
import ( | ||
"github.com/dploeger/icarus/v2/internal" | ||
"os" | ||
"testing" | ||
) | ||
import "github.com/rogpeppe/go-internal/testscript" | ||
|
||
func TestMain(m *testing.M) { | ||
os.Exit(testscript.RunMain(m, map[string]func() int{ | ||
"icarus": internal.Main, | ||
})) | ||
} | ||
|
||
func TestAdapters(t *testing.T) { | ||
testscript.Run(t, testscript.Params{ | ||
Dir: "testdata/script", | ||
}) | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package adapters | ||
|
||
import ( | ||
"github.com/akamensky/argparse" | ||
"github.com/dploeger/icarus/v2/pkg/processors" | ||
"github.com/emersion/go-ical" | ||
) | ||
|
||
// The AddAlarmAdapter adds an alarm definition to all selected events | ||
type AddAlarmAdapter struct { | ||
alarmBefore *int | ||
toolbox processors.Toolbox | ||
} | ||
|
||
func (a *AddAlarmAdapter) Initialize(parser *argparse.Parser) (*argparse.Command, error) { | ||
command := parser.NewCommand("addAlarm", "Add an alarm to all selected events") | ||
a.alarmBefore = command.Int("A", "alarm-before", &argparse.Options{ | ||
Help: "Alarm should be set number of minutes before the event", | ||
Required: true, | ||
}) | ||
return command, nil | ||
} | ||
|
||
func (a *AddAlarmAdapter) SetToolbox(toolbox processors.Toolbox) { | ||
a.toolbox = toolbox | ||
} | ||
|
||
func (a *AddAlarmAdapter) Process(input ical.Calendar, output *ical.Calendar) error { | ||
p := processors.AddAlarmProcessor{AlarmBefore: *a.alarmBefore} | ||
p.SetToolbox(a.toolbox) | ||
return p.Process(input, output) | ||
} | ||
|
||
var _ Adapter = &AddAlarmAdapter{} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package adapters | ||
|
||
import ( | ||
"github.com/akamensky/argparse" | ||
"github.com/dploeger/icarus/v2/pkg/processors" | ||
"github.com/emersion/go-ical" | ||
"time" | ||
) | ||
|
||
// The AddDTStampAdapter adds a DTSTAMP field to all selected events | ||
type AddDTStampAdapter struct { | ||
timestamp *string | ||
overwrite *bool | ||
toolbox processors.Toolbox | ||
} | ||
|
||
func (t *AddDTStampAdapter) Initialize(parser *argparse.Parser) (*argparse.Command, error) { | ||
command := parser.NewCommand("addDTStamp", "Adds a DTStamp field to all selected events") | ||
t.timestamp = command.String("T", "timestamp", &argparse.Options{ | ||
Help: "Set DTSTAMP to this timestamp. Defaults to the current timestamp.", | ||
}) | ||
t.overwrite = command.Flag("O", "overwrite", &argparse.Options{ | ||
Help: "Overwrite DTSTAMP if event already has one", | ||
Default: true, | ||
}) | ||
return command, nil | ||
} | ||
|
||
func (t *AddDTStampAdapter) SetToolbox(toolbox processors.Toolbox) { | ||
t.toolbox = toolbox | ||
} | ||
|
||
func (t *AddDTStampAdapter) Process(input ical.Calendar, output *ical.Calendar) error { | ||
var parsedTimestamp time.Time | ||
if t.timestamp == nil || *t.timestamp == "" { | ||
parsedTimestamp = time.Now().In(time.UTC) | ||
} else { | ||
if parsed, err := time.Parse("20060102T150405Z", *t.timestamp); err != nil { | ||
return err | ||
} else { | ||
parsedTimestamp = parsed | ||
} | ||
} | ||
p := processors.AddDTStampProcessor{ | ||
Timestamp: parsedTimestamp, | ||
Overwrite: *t.overwrite, | ||
} | ||
p.SetToolbox(t.toolbox) | ||
return p.Process(input, output) | ||
} | ||
|
||
var _ Adapter = &AddDTStampAdapter{} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package adapters | ||
|
||
import ( | ||
"github.com/akamensky/argparse" | ||
"github.com/dploeger/icarus/v2/pkg/processors" | ||
"github.com/emersion/go-ical" | ||
) | ||
|
||
// The AddPropertyAdapter adds an ICS property to each selected event | ||
type AddPropertyAdapter struct { | ||
propertyName *string | ||
propertyValue *string | ||
overwrite *bool | ||
toolbox processors.Toolbox | ||
} | ||
|
||
func (a *AddPropertyAdapter) Initialize(parser *argparse.Parser) (*argparse.Command, error) { | ||
c := parser.NewCommand("addProperty", "Adds a new property to each selected event") | ||
a.propertyName = c.String("N", "name", &argparse.Options{ | ||
Help: "Name of the new property", | ||
Required: true, | ||
}) | ||
a.propertyValue = c.String("V", "value", &argparse.Options{ | ||
Help: "Value of the new property (only text values allowed)", | ||
Required: true, | ||
}) | ||
a.overwrite = c.Flag("O", "overwrite", &argparse.Options{ | ||
Help: "Overwrite property if it exists", | ||
Required: false, | ||
Default: true, | ||
}) | ||
return c, nil | ||
} | ||
|
||
func (a *AddPropertyAdapter) SetToolbox(toolbox processors.Toolbox) { | ||
a.toolbox = toolbox | ||
} | ||
|
||
func (a *AddPropertyAdapter) Process(input ical.Calendar, output *ical.Calendar) error { | ||
p := processors.AddPropertyProcessor{ | ||
PropertyName: *a.propertyName, | ||
PropertyValue: *a.propertyValue, | ||
Overwrite: *a.overwrite, | ||
} | ||
p.SetToolbox(a.toolbox) | ||
return p.Process(input, output) | ||
} | ||
|
||
var _ Adapter = &AddPropertyAdapter{} |
Oops, something went wrong.