mirror of
https://github.com/thegeeklab/url-parser.git
synced 2024-11-18 03:00:43 +00:00
feat: add option to read url from stdin (#66)
This commit is contained in:
parent
db299322bc
commit
0af993f5b1
@ -53,6 +53,7 @@ COMMANDS:
|
|||||||
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
--url value source url to parse [$URL_PARSER_URL]
|
--url value source url to parse [$URL_PARSER_URL]
|
||||||
|
--stdin read url to parse from stdin (default: false) [$URL_PARSER_STDIN]
|
||||||
--help, -h show help
|
--help, -h show help
|
||||||
--version, -v print the version
|
--version, -v print the version
|
||||||
```
|
```
|
||||||
|
@ -2,7 +2,9 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/thegeeklab/url-parser/command"
|
"github.com/thegeeklab/url-parser/command"
|
||||||
@ -21,19 +23,25 @@ func main() {
|
|||||||
fmt.Printf("%s version=%s date=%s\n", c.App.Name, c.App.Version, BuildDate)
|
fmt.Printf("%s version=%s date=%s\n", c.App.Name, c.App.Version, BuildDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &config.Config{}
|
cfg := &config.Config{}
|
||||||
|
|
||||||
app := &cli.App{
|
app := &cli.App{
|
||||||
Name: "url-parser",
|
Name: "url-parser",
|
||||||
Usage: "Parse URL and shows the part of it.",
|
Usage: "Parse URL and shows the part of it.",
|
||||||
Version: BuildVersion,
|
Version: BuildVersion,
|
||||||
Action: command.Run(config),
|
Action: command.Run(cfg),
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "url",
|
Name: "url",
|
||||||
Usage: "source url to parse",
|
Usage: "source url to parse",
|
||||||
EnvVars: []string{"URL_PARSER_URL"},
|
EnvVars: []string{"URL_PARSER_URL"},
|
||||||
Destination: &config.URL,
|
Destination: &cfg.URL,
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "stdin",
|
||||||
|
Usage: "read url to parse from stdin",
|
||||||
|
EnvVars: []string{"URL_PARSER_STDIN"},
|
||||||
|
Destination: &cfg.Stdin,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Commands: []*cli.Command{
|
Commands: []*cli.Command{
|
||||||
@ -41,59 +49,89 @@ func main() {
|
|||||||
Name: "all",
|
Name: "all",
|
||||||
Aliases: []string{"a"},
|
Aliases: []string{"a"},
|
||||||
Usage: "Get all parts from url",
|
Usage: "Get all parts from url",
|
||||||
Action: command.Run(config),
|
Action: command.Run(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "scheme",
|
Name: "scheme",
|
||||||
Aliases: []string{"s"},
|
Aliases: []string{"s"},
|
||||||
Usage: "Get scheme from url",
|
Usage: "Get scheme from url",
|
||||||
Action: command.Scheme(config),
|
Action: command.Scheme(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "user",
|
Name: "user",
|
||||||
Aliases: []string{"u"},
|
Aliases: []string{"u"},
|
||||||
Usage: "Get username from url",
|
Usage: "Get username from url",
|
||||||
Action: command.User(config),
|
Action: command.User(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "password",
|
Name: "password",
|
||||||
Aliases: []string{"pw"},
|
Aliases: []string{"pw"},
|
||||||
Usage: "Get password from url",
|
Usage: "Get password from url",
|
||||||
Action: command.Password(config),
|
Action: command.Password(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "path",
|
Name: "path",
|
||||||
Aliases: []string{"pt"},
|
Aliases: []string{"pt"},
|
||||||
Usage: "Get path from url",
|
Usage: "Get path from url",
|
||||||
Action: command.Path(config),
|
Action: command.Path(cfg),
|
||||||
Flags: command.PathFlags(config),
|
Flags: command.PathFlags(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "host",
|
Name: "host",
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Get hostname from url",
|
Usage: "Get hostname from url",
|
||||||
Action: command.Host(config),
|
Action: command.Host(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "port",
|
Name: "port",
|
||||||
Aliases: []string{"p"},
|
Aliases: []string{"p"},
|
||||||
Usage: "Get port from url",
|
Usage: "Get port from url",
|
||||||
Action: command.Port(config),
|
Action: command.Port(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "query",
|
Name: "query",
|
||||||
Aliases: []string{"q"},
|
Aliases: []string{"q"},
|
||||||
Usage: "Get query from url",
|
Usage: "Get query from url",
|
||||||
Action: command.Query(config),
|
Action: command.Query(cfg),
|
||||||
Flags: command.QueryFlags(config),
|
Flags: command.QueryFlags(cfg),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "fragment",
|
Name: "fragment",
|
||||||
Aliases: []string{"f"},
|
Aliases: []string{"f"},
|
||||||
Usage: "Get fragment from url",
|
Usage: "Get fragment from url",
|
||||||
Action: command.Fragment(config),
|
Action: command.Fragment(cfg),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Before: func(ctx *cli.Context) error {
|
||||||
|
if cfg.URL == "" && !cfg.Stdin {
|
||||||
|
_ = cli.ShowAppHelp(ctx)
|
||||||
|
|
||||||
|
return fmt.Errorf("error: %w", config.ErrRequiredFlagsNotSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.URL != "" && cfg.Stdin {
|
||||||
|
_ = cli.ShowAppHelp(ctx)
|
||||||
|
|
||||||
|
return fmt.Errorf("error: %w", config.ErrExclusiveFlags)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Stdin {
|
||||||
|
stat, _ := os.Stdin.Stat()
|
||||||
|
if (stat.Mode() & os.ModeCharDevice) == 0 {
|
||||||
|
stdin, err := io.ReadAll(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error: %w: %w", config.ErrEmptyStdin, err)
|
||||||
|
}
|
||||||
|
cfg.URL = strings.TrimSuffix(string(stdin), "\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.URL == "" {
|
||||||
|
return fmt.Errorf("error: %w", config.ErrEmptyStdin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/thegeeklab/url-parser/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseURL(raw string) *url.URL {
|
func parseURL(raw string) *url.URL {
|
||||||
@ -12,7 +14,7 @@ func parseURL(raw string) *url.URL {
|
|||||||
|
|
||||||
url, err := url.Parse(urlString)
|
url, err := url.Parse(urlString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(fmt.Errorf("%w: %w", config.ErrParseURL, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return url
|
return url
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Fragment prints out the fragment part from the url.
|
// Fragment prints out the fragment part from the url.
|
||||||
func Fragment(config *config.Config) cli.ActionFunc {
|
func Fragment(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if len(parts.Scheme) > 0 {
|
if len(parts.Scheme) > 0 {
|
||||||
fmt.Println(parts.Fragment)
|
fmt.Println(parts.Fragment)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Host prints out the host part from the url.
|
// Host prints out the host part from the url.
|
||||||
func Host(config *config.Config) cli.ActionFunc {
|
func Host(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if len(parts.Scheme) > 0 {
|
if len(parts.Scheme) > 0 {
|
||||||
fmt.Println(parts.Hostname())
|
fmt.Println(parts.Hostname())
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Password prints out the password part from url.
|
// Password prints out the password part from url.
|
||||||
func Password(config *config.Config) cli.ActionFunc {
|
func Password(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if parts.User != nil {
|
if parts.User != nil {
|
||||||
pw, _ := parts.User.Password()
|
pw, _ := parts.User.Password()
|
||||||
|
@ -9,23 +9,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// PathFlags defines flags for path subcommand.
|
// PathFlags defines flags for path subcommand.
|
||||||
func PathFlags(config *config.Config) []cli.Flag {
|
func PathFlags(cfg *config.Config) []cli.Flag {
|
||||||
return []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.IntFlag{
|
&cli.IntFlag{
|
||||||
Name: "path-index",
|
Name: "path-index",
|
||||||
Usage: "filter parsed path by index",
|
Usage: "filter parsed path by index",
|
||||||
EnvVars: []string{"URL_PARSER_PATH_INDEX"},
|
EnvVars: []string{"URL_PARSER_PATH_INDEX"},
|
||||||
Value: -1,
|
Value: -1,
|
||||||
Destination: &config.PathIndex,
|
Destination: &cfg.PathIndex,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path prints out the path part from url.
|
// Path prints out the path part from url.
|
||||||
func Path(config *config.Config) cli.ActionFunc {
|
func Path(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
i := config.PathIndex
|
i := cfg.PathIndex
|
||||||
|
|
||||||
if len(parts.Path) > 0 {
|
if len(parts.Path) > 0 {
|
||||||
if i > -1 {
|
if i > -1 {
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Port prints out the port from the url.
|
// Port prints out the port from the url.
|
||||||
func Port(config *config.Config) cli.ActionFunc {
|
func Port(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if len(parts.Scheme) > 0 {
|
if len(parts.Scheme) > 0 {
|
||||||
fmt.Println(parts.Port())
|
fmt.Println(parts.Port())
|
||||||
|
@ -8,22 +8,22 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// QueryFlags defines flags for query subcommand.
|
// QueryFlags defines flags for query subcommand.
|
||||||
func QueryFlags(config *config.Config) []cli.Flag {
|
func QueryFlags(cfg *config.Config) []cli.Flag {
|
||||||
return []cli.Flag{
|
return []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "query-field",
|
Name: "query-field",
|
||||||
Usage: "filter parsed query string by field name",
|
Usage: "filter parsed query string by field name",
|
||||||
EnvVars: []string{"URL_PARSER_QUERY_FIELD"},
|
EnvVars: []string{"URL_PARSER_QUERY_FIELD"},
|
||||||
Destination: &config.QueryField,
|
Destination: &cfg.QueryField,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query prints out the query part from url.
|
// Query prints out the query part from url.
|
||||||
func Query(config *config.Config) cli.ActionFunc {
|
func Query(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
f := config.QueryField
|
f := cfg.QueryField
|
||||||
|
|
||||||
if len(parts.RawQuery) > 0 {
|
if len(parts.RawQuery) > 0 {
|
||||||
if f != "" {
|
if f != "" {
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Run default command and print out full url.
|
// Run default command and print out full url.
|
||||||
func Run(config *config.Config) cli.ActionFunc {
|
func Run(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if len(parts.String()) > 0 {
|
if len(parts.String()) > 0 {
|
||||||
fmt.Println(parts)
|
fmt.Println(parts)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Scheme prints out the scheme part from the url.
|
// Scheme prints out the scheme part from the url.
|
||||||
func Scheme(config *config.Config) cli.ActionFunc {
|
func Scheme(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if len(parts.Scheme) > 0 {
|
if len(parts.Scheme) > 0 {
|
||||||
fmt.Println(parts.Scheme)
|
fmt.Println(parts.Scheme)
|
||||||
|
@ -8,9 +8,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// User prints out the user part from url.
|
// User prints out the user part from url.
|
||||||
func User(config *config.Config) cli.ActionFunc {
|
func User(cfg *config.Config) cli.ActionFunc {
|
||||||
return func(ctx *cli.Context) error {
|
return func(ctx *cli.Context) error {
|
||||||
parts := parseURL(config.URL)
|
parts := parseURL(cfg.URL)
|
||||||
|
|
||||||
if parts.User != nil {
|
if parts.User != nil {
|
||||||
if len(parts.User.Username()) > 0 {
|
if len(parts.User.Username()) > 0 {
|
||||||
|
@ -1,7 +1,18 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrRequiredFlagsNotSet = errors.New("either \"url\" or \"stdin\" must be set")
|
||||||
|
ErrExclusiveFlags = errors.New("\"url\" and \"stdin\" are mutually exclusive")
|
||||||
|
ErrEmptyStdin = errors.New("\"stdin\" must not be empty")
|
||||||
|
ErrReadStdin = errors.New("failed to read \"stdin\"")
|
||||||
|
ErrParseURL = errors.New("failed to parse url")
|
||||||
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
URL string
|
URL string
|
||||||
|
Stdin bool
|
||||||
QueryField string
|
QueryField string
|
||||||
PathIndex int
|
PathIndex int
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user