|
|
@ -1,9 +1,7 @@ |
|
|
package main |
|
|
package main |
|
|
|
|
|
|
|
|
import ( |
|
|
import ( |
|
|
"fmt" |
|
|
|
|
|
"io/ioutil" |
|
|
"io/ioutil" |
|
|
"net/http" |
|
|
|
|
|
"net/url" |
|
|
"net/url" |
|
|
"os" |
|
|
"os" |
|
|
"strings" |
|
|
"strings" |
|
|
@ -11,7 +9,6 @@ import ( |
|
|
|
|
|
|
|
|
"github.com/a8m/mark" |
|
|
"github.com/a8m/mark" |
|
|
"github.com/docopt/docopt-go" |
|
|
"github.com/docopt/docopt-go" |
|
|
"github.com/fatih/color" |
|
|
|
|
|
"golang.org/x/net/html" |
|
|
"golang.org/x/net/html" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
@ -37,41 +34,11 @@ func main() { |
|
|
panic(err) |
|
|
panic(err) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
checkURLs(extractURLs(n), args["--verbose"].(bool)) |
|
|
if !newURLChecker(5*time.Second, args["--verbose"].(bool)).CheckMany(extractURLs(n)) { |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func checkURLs(ss []string, verbose bool) { |
|
|
|
|
|
client := &http.Client{Timeout: 5 * time.Second} |
|
|
|
|
|
bs := make(chan bool, len(ss)) |
|
|
|
|
|
|
|
|
|
|
|
for _, s := range ss { |
|
|
|
|
|
go checkURL(client, s, bs, verbose) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
ok := true |
|
|
|
|
|
|
|
|
|
|
|
for i := 0; i < len(ss); i++ { |
|
|
|
|
|
ok = ok && <-bs |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if !ok { |
|
|
|
|
|
os.Exit(1) |
|
|
os.Exit(1) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func checkURL(client *http.Client, s string, bs chan bool, verbose bool) { |
|
|
|
|
|
_, err := client.Get(s) |
|
|
|
|
|
|
|
|
|
|
|
if s := color.New(color.FgCyan).SprintFunc()(s); err != nil { |
|
|
|
|
|
printToStderr( |
|
|
|
|
|
color.New(color.FgRed).SprintFunc()("ERROR") + "\t" + s + "\t" + err.Error()) |
|
|
|
|
|
} else if err == nil && verbose { |
|
|
|
|
|
printToStderr(color.New(color.FgGreen).SprintFunc()("OK") + "\t" + s) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bs <- err == nil |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func extractURLs(n *html.Node) []string { |
|
|
func extractURLs(n *html.Node) []string { |
|
|
ss := make(map[string]bool) |
|
|
ss := make(map[string]bool) |
|
|
ns := make([]*html.Node, 0, 1024) |
|
|
ns := make([]*html.Node, 0, 1024) |
|
|
@ -99,16 +66,6 @@ func extractURLs(n *html.Node) []string { |
|
|
return stringSetToSlice(ss) |
|
|
return stringSetToSlice(ss) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func stringSetToSlice(s2b map[string]bool) []string { |
|
|
|
|
|
ss := make([]string, 0, len(s2b)) |
|
|
|
|
|
|
|
|
|
|
|
for s := range s2b { |
|
|
|
|
|
ss = append(ss, s) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ss |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func isURL(s string) bool { |
|
|
func isURL(s string) bool { |
|
|
u, err := url.Parse(s) |
|
|
u, err := url.Parse(s) |
|
|
return err == nil && (u.Scheme == "http" || u.Scheme == "https") |
|
|
return err == nil && (u.Scheme == "http" || u.Scheme == "https") |
|
|
@ -117,10 +74,10 @@ func isURL(s string) bool { |
|
|
func getArgs() map[string]interface{} { |
|
|
func getArgs() map[string]interface{} { |
|
|
usage := `Link checker for Markdown and HTML |
|
|
usage := `Link checker for Markdown and HTML |
|
|
|
|
|
|
|
|
Usage: |
|
|
Usage: |
|
|
linkcheck [-v] <filename> |
|
|
linkcheck [-v] <filename> |
|
|
|
|
|
|
|
|
Options: |
|
|
Options: |
|
|
-v, --verbose Be verbose` |
|
|
-v, --verbose Be verbose` |
|
|
|
|
|
|
|
|
args, err := docopt.Parse(usage, nil, true, "linkcheck", true) |
|
|
args, err := docopt.Parse(usage, nil, true, "linkcheck", true) |
|
|
@ -131,7 +88,3 @@ Options: |
|
|
|
|
|
|
|
|
return args |
|
|
return args |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func printToStderr(xs ...interface{}) { |
|
|
|
|
|
fmt.Fprintln(os.Stderr, xs...) |
|
|
|
|
|
} |
|
|
|
|
|
|