Skip to content

Commit 9406a5a

Browse files
committed
First version
1 parent 4dccaa1 commit 9406a5a

File tree

14 files changed

+1298
-0
lines changed

14 files changed

+1298
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/bin
2+
/url-parser
3+
/url-parser.exe

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
dist: xenial
2+
language: go
3+
4+
go:
5+
- "1.13"
6+
- master
7+
8+
env: GO111MODULE=on
9+
10+
jobs:
11+
allow_failures:
12+
- go: master
13+
14+
script:
15+
- make
16+
- make check

Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM golang AS build
2+
3+
COPY . /app
4+
RUN cd /app && make
5+
6+
FROM scratch
7+
8+
COPY --from=build /app/url-parser /url-parser
9+
ENTRYPOINT ["/url-parser"]

Makefile

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
BIN = ${PWD}/bin
2+
3+
.PHONY: build
4+
build:
5+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./cmd/url-parser
6+
7+
.PHONY: check
8+
check: cs vet staticcheck test
9+
10+
.PHONY: cs
11+
cs: tools
12+
diff=$$($(BIN)/goimports -d . ); test -z "$$diff" || (echo "$$diff" && exit 1)
13+
14+
.PHONY: cs-fix
15+
cs-fix: format
16+
17+
.PHONY: format
18+
format: tools
19+
$(BIN)/goimports -w .
20+
21+
.PHONY: vet
22+
vet:
23+
go vet ./...
24+
25+
.PHONY: test
26+
test:
27+
timeout 10 go test
28+
timeout 60 go test --race
29+
timeout 120 go test --count 1000
30+
timeout 10 cmd/url-parser/main_test.sh
31+
32+
.PHONY: staticcheck
33+
staticcheck: tools
34+
$(BIN)/staticcheck ./...
35+
36+
.PHONY: tools
37+
tools: bin
38+
39+
bin: export GOBIN = $(BIN)
40+
bin:
41+
go install github.com/golang/mock/mockgen
42+
go install golang.org/x/lint/golint
43+
go install golang.org/x/tools/cmd/goimports
44+
go install honnef.co/go/tools/cmd/staticcheck

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
url-parser
2+
==========
3+
4+
```
5+
url-parser
6+
Parses given URLs and prints the desired parts of them.
7+
8+
Usage:
9+
url-parser <option> [url]...
10+
11+
Options:
12+
-c, --component=COMPONENT
13+
14+
Prints single URL component from each. URL.
15+
16+
Valid values: scheme, authority, auth, user, password,
17+
hostport, host, tld, port, path, query,
18+
fragment, basePath, file, ext, relativeUrl
19+
20+
Additionally, some components may be further formatted:
21+
host:x, host:x:y print only desired (sub)domains
22+
hostport:x, hostport:x:y same as host:*, but also includes port
23+
path:x, path:x:y print only desired parts of the path
24+
query:NAME print only query parameter named NAME
25+
fragment:NAME print only fragment part named NAME
26+
27+
x starting position; use -x to start from end
28+
y count; how many parts of the component you want to print
29+
30+
-f, --format=FORMAT
31+
32+
Prints URLs formatted according to FORMAT.
33+
34+
FORMAT is an arbitrary string containing component placeholders
35+
enclosed in curly brackets. Each {COMPONENT} will be replaced
36+
as if url-parser was called with option -c COMPONENT
37+
38+
Examples:
39+
40+
reference URL: https://www.example.com/lorem/ipsum/dolor/sit.html?metus=lectus#at=nostra&unde=omnis
41+
42+
url-parser -c host:1 <url> example.com
43+
url-parser -c path:-0:2 <url> /dolor/sit.html
44+
url-parser -c path:-1 <url> /lorem/ipsum/dolor
45+
url-parser -c path:0:2 <url> /lorem/ipsum
46+
url-parser -c fragment:unde <url> unde=omnis
47+
url-parser -c relativeUrl <url> /lorem/ipsum/dolor/sit.html?metus=lectus#at=nostra&unde=omnis
48+
url-parser -f {scheme}://{host} <url> https://www.example.com
49+
```

cmd/url-parser/main.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package main
2+
3+
import (
4+
"bufio"
5+
"flag"
6+
"fmt"
7+
"os"
8+
9+
urlparser "github.com/grongor/go-url-parser/url-parser"
10+
)
11+
12+
func usage() {
13+
app := "url-parser"
14+
fmt.Printf("%s\n Parses given URLs and prints the desired parts of them.\n\n", app)
15+
fmt.Println("Usage:")
16+
fmt.Printf(" %s <option> [url]...\n\n", app)
17+
fmt.Println("Options:")
18+
fmt.Printf(" -c, --component=COMPONENT\n\n")
19+
fmt.Printf(" Prints single URL component from each. URL.\n\n")
20+
fmt.Println(" Valid values: scheme, authority, auth, user, password,")
21+
fmt.Println(" hostport, host, tld, port, path, query,")
22+
fmt.Printf(" fragment, basePath, file, ext, relativeUrl\n\n")
23+
fmt.Printf(" Additionally, some components may be further formatted:\n")
24+
fmt.Println(" host:x, host:x:y print only desired (sub)domains")
25+
fmt.Println(" hostport:x, hostport:x:y same as host:*, but also includes port")
26+
fmt.Println(" path:x, path:x:y print only desired parts of the path")
27+
fmt.Println(" query:NAME print only query parameter named NAME")
28+
fmt.Println(" fragment:NAME print only fragment part named NAME")
29+
fmt.Println("")
30+
fmt.Println(" x starting position; use -x to start from end")
31+
fmt.Println(" y count; how many parts of the component you want to print")
32+
fmt.Println("")
33+
fmt.Printf(" -f, --format=FORMAT\n\n")
34+
fmt.Printf(" Prints URLs formatted according to FORMAT.\n\n")
35+
fmt.Println(" FORMAT is an arbitrary string containing component placeholders")
36+
fmt.Println(" enclosed in curly brackets. Each {COMPONENT} will be replaced")
37+
fmt.Println(" as if url-parser was called with option -c COMPONENT")
38+
fmt.Println("")
39+
fmt.Printf("Examples:\n\n")
40+
fmt.Printf("reference URL: https://www.example.com/lorem/ipsum/dolor/sit.html?metus=lectus#at=nostra&unde=omnis\n\n")
41+
fmt.Println("url-parser -c host:1 <url> example.com")
42+
fmt.Println("url-parser -c path:-0:2 <url> /dolor/sit.html")
43+
fmt.Println("url-parser -c path:-1 <url> /lorem/ipsum/dolor")
44+
fmt.Println("url-parser -c path:0:2 <url> /lorem/ipsum")
45+
fmt.Println("url-parser -c fragment:unde <url> unde=omnis")
46+
fmt.Println("url-parser -c relativeUrl <url> /lorem/ipsum/dolor/sit.html?metus=lectus#at=nostra&unde=omnis")
47+
fmt.Println("url-parser -f {scheme}://{host} <url> https://www.example.com")
48+
}
49+
50+
var (
51+
component string
52+
format string
53+
)
54+
55+
func main() {
56+
flag.StringVar(&component, "component", "", "")
57+
flag.StringVar(&component, "c", "", "")
58+
59+
flag.StringVar(&format, "format", "", "")
60+
flag.StringVar(&format, "f", "", "")
61+
62+
flag.Usage = usage
63+
flag.Parse()
64+
65+
if component == "" && format == "" || component != "" && format != "" {
66+
fmt.Fprintln(os.Stderr, "You must specify either --component or --format option.")
67+
os.Exit(1)
68+
}
69+
70+
if len(flag.Args()) == 0 {
71+
scanner := bufio.NewScanner(os.Stdin)
72+
for scanner.Scan() {
73+
process(scanner.Text())
74+
}
75+
} else {
76+
for _, rawUrl := range flag.Args() {
77+
process(rawUrl)
78+
}
79+
}
80+
}
81+
82+
func process(rawUrl string) {
83+
var result string
84+
var err error
85+
if component == "" {
86+
result, err = urlparser.Format(rawUrl, format)
87+
} else {
88+
result, err = urlparser.Component(rawUrl, component)
89+
}
90+
91+
if err != nil {
92+
fmt.Fprintln(os.Stderr, err.Error())
93+
}
94+
95+
fmt.Println(result)
96+
}

cmd/url-parser/main_test.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/usr/bin/env bash
2+
3+
set -o errexit
4+
set -o nounset
5+
6+
cd "$(dirname "$(realpath "$0")")"/../..
7+
go build ./cmd/url-parser
8+
9+
function clean() {
10+
rm -rf ".test-out"
11+
rm -rf ".test-err"
12+
}
13+
14+
trap "clean" EXIT
15+
16+
urls=(
17+
"http://www.example.com"
18+
"postgres://user:abc{[email protected]"
19+
"https://sub.domain.co.uk/path/file.html"
20+
"https://"
21+
)
22+
23+
# component
24+
25+
./url-parser -c "host" > .test-out 2> .test-err <<< IFS="\n" "${urls[@]}"
26+
27+
expected=$'www.example.com\n\nsub.domain.co.uk'
28+
result="$(cat .test-out)"
29+
test "$expected" = "$result" || {
30+
printf >&2 $"Unexpected parser output:\n\nExpected:\n%s\n\nResult:\n%s\n" "$expected" "$result"
31+
}
32+
33+
expectedErr=$'parse postgres://user:abc{[email protected]: net/url: invalid userinfo'
34+
resultErr="$(cat .test-err)"
35+
test "$expectedErr" = "$resultErr" || {
36+
printf >&2 $"Unexpected parser output:\n\nExpected:\n%s\n\nResult:\n%s\n" "$expectedErr" "$resultErr"
37+
}
38+
39+
# format
40+
41+
./url-parser -f "{scheme} - {tld} - {file}" > .test-out 2> .test-err <<< IFS="\n" "${urls[@]}"
42+
43+
expected=$'http - com - \n\nhttps - co.uk - file.html\nhttps - - '
44+
result="$(cat .test-out)"
45+
test "$expected" = "$result" || {
46+
printf >&2 $"Unexpected parser output:\n\nExpected:\n%s\n\nResult:\n%s\n" "$expected" "$result"
47+
}
48+
49+
expectedErr=$'parse postgres://user:abc{[email protected]: net/url: invalid userinfo'
50+
resultErr="$(cat .test-err)"
51+
test "$expectedErr" = "$resultErr" || {
52+
printf >&2 $"Unexpected parser output:\n\nExpected:\n%s\n\nResult:\n%s\n" "$expectedErr" "$resultErr"
53+
}

0 commit comments

Comments
 (0)