You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

186 lines
4.2 KiB
Go

package main
import (
"fmt"
"log"
"os"
"strings"
"github.com/alecthomas/repr"
"github.com/aziis98/cabret/config"
"github.com/aziis98/cabret/runner"
"github.com/spf13/pflag"
)
const HelpMessage = `usage: cabret <SUBCOMMAND> [OPTIONS...]
subcommands:
build [OPTIONS...] Builds the current project
serve [OPTIONS...] Starts an http server and watches files for changes
`
func main() {
flagSet := pflag.FlagSet{
Usage: func() {
fmt.Print(HelpMessage)
},
}
if err := flagSet.Parse(os.Args[1:]); err != nil {
if err != pflag.ErrHelp {
log.Fatal(err)
}
return
}
switch flagSet.Arg(0) {
case "serve":
if err := serveSubcommand(os.Args[2:]); err != nil {
if err != pflag.ErrHelp {
log.Fatal(err)
}
return
}
case "build":
if err := buildSubcommand(os.Args[2:]); err != nil {
if err != pflag.ErrHelp {
log.Fatal(err)
}
return
}
default:
fmt.Print(HelpMessage)
}
}
const BuildHelpMessage = `usage: cabret build [OPTIONS...]
options:
-c, --config <path> Path to configuration file (default is "Cabretfile.yaml")
-v, --verbose Be more verbose
`
func buildSubcommand(args []string) error {
flagSet := pflag.FlagSet{
Usage: func() { fmt.Print(BuildHelpMessage) },
}
var configFile string
flagSet.StringVarP(&configFile, "config", "c",
"Cabretfile.yaml",
`path to configuration file`,
)
var verbose bool
flagSet.BoolVarP(&verbose, "verbose", "v",
false,
`verbose output`,
)
if err := flagSet.Parse(args); err != nil {
return err
}
cabretfile, err := config.ReadCabretfile(configFile)
if err != nil {
return err
}
if err := runner.RunConfig(cabretfile); err != nil {
return err
}
return nil
}
const ServeHelpMessage = `usage: cabret serve [OPTIONS...]
options:
-c, --config <path> Path to configuration file (default is "Cabretfile.yaml")
-v, --verbose Be more verbose
-w, --watch <pattern> List of paths to watch for rebuild
-m, --mount <path> Mount a file or folder on the default static file
server, this will mount file or folder at "<path>"
on route "<path>".
-m, --mount <from>:<to> Mount a file or folder on the default static file
server, this will mount file or folder at "<from>"
on route "<to>".
By default the mount list is "public/:/", "dist/:/", "out/:/".
The server will also serve a special js script on "/cabret/live-reload.js" that
will add live reload on file change for development, this can be included with
the following tag
<script type="module" src="/__cabret__/live-reload.js" async></script>
`
func serveSubcommand(args []string) error {
flagSet := pflag.FlagSet{
Usage: func() { fmt.Print(ServeHelpMessage) },
}
var configFile string
flagSet.StringVarP(&configFile, "config", "c",
"Cabretfile.yaml",
`path to configuration file`,
)
var verbose bool
flagSet.BoolVarP(&verbose, "verbose", "v",
false,
`verbose output`,
)
var watchedPatterns []string
flagSet.StringArrayVarP(&watchedPatterns, "watch", "w",
[]string{"src/**/"},
`list of paths to watch for rebuild`,
)
var mounts []string
flagSet.StringArrayVarP(&mounts, "mount", "m",
[]string{"public/:/", "out/:/", "dist/:/"},
`list of paths to mount for the static file server`,
)
err := flagSet.Parse(args)
if err != nil {
return err
}
serveMounts := make([]serveMount, len(mounts))
for i, m := range mounts {
path, route, found := strings.Cut(m, ":")
if !found {
if strings.HasPrefix(path, "/") {
return fmt.Errorf(`cannot mount an absolute path without a route: "%s"`, path)
}
route = "/" + path
}
if !strings.HasPrefix(route, "/") {
return fmt.Errorf(`route must start with a slash: "%s"`, route)
}
serveMounts[i] = serveMount{path, route}
}
log.Printf(`configFile = %v`, repr.String(configFile))
log.Printf(`verbose = %v`, repr.String(verbose))
log.Printf(`watchedPatterns = %v`, repr.String(watchedPatterns))
log.Printf(`serveMounts = %v`, repr.String(serveMounts))
return serve(serveConfig{
configFile,
verbose,
watchedPatterns,
serveMounts,
})
}