1
0
mirror of https://github.com/ericchiang/pup synced 2024-11-24 08:58:08 +00:00
pup/main.go

166 lines
3.5 KiB
Go
Raw Normal View History

2014-09-01 00:01:03 +00:00
package main
import (
"code.google.com/p/go.net/html"
2014-09-16 17:11:16 +00:00
"code.google.com/p/go.net/html/charset"
2014-09-01 00:01:03 +00:00
"fmt"
2014-09-02 03:53:12 +00:00
"github.com/ericchiang/pup/funcs"
2014-09-01 00:01:03 +00:00
"github.com/ericchiang/pup/selector"
"io"
"os"
"strconv"
"strings"
)
2014-09-19 20:37:06 +00:00
const VERSION string = "0.2.2"
2014-09-01 18:18:34 +00:00
2014-09-01 00:01:03 +00:00
var (
// Flags
2014-09-02 03:53:12 +00:00
attributes []string = []string{}
inputStream io.ReadCloser = os.Stdin
indentString string = " "
maxPrintLevel int = -1
printNumber bool = false
printColor bool = false
displayer funcs.Displayer = nil
2014-09-01 00:01:03 +00:00
)
2014-09-01 18:50:10 +00:00
// Print to stderr and exit
2014-09-01 00:01:03 +00:00
func Fatal(format string, args ...interface{}) {
fmt.Fprintf(os.Stderr, format, args...)
fmt.Fprintf(os.Stderr, "\n")
os.Exit(1)
}
2014-09-01 18:50:10 +00:00
// Print help to stderr and quit
func PrintHelp() {
2014-09-01 18:18:34 +00:00
helpString := `Usage
2014-09-01 00:01:03 +00:00
pup [list of css selectors]
2014-09-01 18:18:34 +00:00
Version
%s
Flags
2014-09-01 00:01:03 +00:00
2014-09-01 18:18:34 +00:00
-c --color print result with color
2014-09-01 00:01:03 +00:00
-f --file file to read from
-h --help display this help
-i --indent number of spaces to use for indent or character
-n --number print number of elements selected
2014-09-01 18:18:34 +00:00
-l --limit restrict number of levels printed
--version display version`
Fatal(helpString, VERSION)
2014-09-01 00:01:03 +00:00
}
2014-09-01 18:50:10 +00:00
// Process command arguments and return all non-flags.
func ProcessFlags(cmds []string) []string {
2014-09-01 00:01:03 +00:00
var i int
var err error
defer func() {
if r := recover(); r != nil {
Fatal("Option '%s' requires an argument", cmds[i])
}
}()
nonFlagCmds := make([]string, len(cmds))
n := 0
for i = 0; i < len(cmds); i++ {
cmd := cmds[i]
switch cmd {
2014-09-02 03:53:12 +00:00
case "-a", "--attr":
attributes = append(attributes, cmds[i+1])
i++
2014-09-01 18:18:34 +00:00
case "-c", "--color":
printColor = true
2014-09-01 00:01:03 +00:00
case "-f", "--file":
filename := cmds[i+1]
inputStream, err = os.Open(filename)
if err != nil {
Fatal(err.Error())
}
i++
case "-h", "--help":
2014-09-01 18:50:10 +00:00
PrintHelp()
2014-09-01 00:01:03 +00:00
os.Exit(1)
case "-i", "--indent":
indentLevel, err := strconv.Atoi(cmds[i+1])
if err == nil {
2014-09-01 18:18:34 +00:00
indentString = strings.Repeat(" ", indentLevel)
2014-09-01 00:01:03 +00:00
} else {
2014-09-01 18:18:34 +00:00
indentString = cmds[i+1]
2014-09-01 00:01:03 +00:00
}
i++
case "-n", "--number":
printNumber = true
2014-09-01 18:18:34 +00:00
case "-l", "--limit":
2014-09-01 00:01:03 +00:00
maxPrintLevel, err = strconv.Atoi(cmds[i+1])
if err != nil {
Fatal("Argument for '%s' must be numeric",
cmds)
}
i++
2014-09-01 18:18:34 +00:00
case "--version":
Fatal(VERSION)
2014-09-01 00:01:03 +00:00
default:
if cmd[0] == '-' {
Fatal("Unrecognized flag '%s'", cmd)
}
nonFlagCmds[n] = cmds[i]
n++
}
}
return nonFlagCmds[:n]
}
2014-09-01 18:50:10 +00:00
// pup
2014-09-01 00:01:03 +00:00
func main() {
2014-09-01 18:50:10 +00:00
cmds := ProcessFlags(os.Args[1:])
2014-09-16 17:11:16 +00:00
cr, err := charset.NewReader(inputStream, "")
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(2)
}
root, err := html.Parse(cr)
2014-09-01 00:01:03 +00:00
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
os.Exit(2)
}
inputStream.Close()
if len(cmds) == 0 {
PrintNode(root, 0)
os.Exit(0)
}
2014-09-15 00:34:21 +00:00
selectors := make([]selector.Selector, len(cmds))
2014-09-01 00:01:03 +00:00
for i, cmd := range cmds {
2014-09-18 00:32:49 +00:00
// if this is the last element, check for a function like
// text{} or attr{}
2014-09-02 03:53:12 +00:00
if i+1 == len(cmds) {
d, err := funcs.NewDisplayFunc(cmd)
if err == nil {
displayer = d
selectors = selectors[0 : len(cmds)-1]
break
}
}
2014-09-01 18:50:10 +00:00
selectors[i], err = selector.NewSelector(cmd)
2014-09-01 00:01:03 +00:00
if err != nil {
2014-09-01 20:39:26 +00:00
Fatal("Selector parse error: %s", err)
2014-09-01 00:01:03 +00:00
}
}
currNodes := []*html.Node{root}
for _, selector := range selectors {
2014-09-18 00:32:49 +00:00
currNodes = selector.Select(currNodes)
2014-09-01 00:01:03 +00:00
}
2014-09-02 03:53:12 +00:00
if displayer != nil {
displayer.Display(currNodes)
} else if printNumber {
2014-09-01 00:01:03 +00:00
fmt.Println(len(currNodes))
} else {
for _, s := range currNodes {
2014-09-01 18:18:34 +00:00
// defined in `printing.go`
2014-09-01 00:01:03 +00:00
PrintNode(s, 0)
}
}
}