166 lines
4.0 KiB
Go
166 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/spf13/cobra"
|
|
yaml "gopkg.in/yaml.v2"
|
|
"src.lwithers.me.uk/go/htpack/cmd/htpacker/packer"
|
|
"src.lwithers.me.uk/go/htpack/packed"
|
|
)
|
|
|
|
var packCmd = &cobra.Command{
|
|
Use: "pack",
|
|
Short: "creates a packfile from a YAML spec or set of files/dirs",
|
|
Long: `When given a YAML spec file (a template for which can be generated
|
|
with the "yaml" command), files will be packed exactly as per the spec. The
|
|
--content-type flag cannot be used and no extra files can be specified.
|
|
|
|
When given a list of files and directories to pack, the content type for each
|
|
file will be automatically detected. It is possible to override the content
|
|
type by specifying one or more --content-type flags. These take an argument in
|
|
the form "pattern:content/type". The pattern is matched using common glob
|
|
(* = wildcard), very similar to .gitignore. If the pattern contains any
|
|
directory names, these must match the final components of the file to pack's
|
|
path. If the pattern starts with a "/", then the full path must be matched
|
|
exactly.
|
|
`,
|
|
|
|
RunE: func(c *cobra.Command, args []string) error {
|
|
// convert "out" to an absolute path, so that it will still
|
|
// work after chdir
|
|
out, err := c.Flags().GetString("out")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
out, err = filepath.Abs(out)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// if "spec" is present, convert to an absolute path
|
|
spec, err := c.Flags().GetString("spec")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if spec != "" {
|
|
spec, err = filepath.Abs(spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// chdir if required
|
|
chdir, err := c.Flags().GetString("chdir")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if chdir != "" {
|
|
if err = os.Chdir(chdir); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// parse content-type globs
|
|
ctGlobList, err := c.Flags().GetStringArray("content-type")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ctGlobs, err := parseGlobs(ctGlobList)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// if "spec" is not present, then we expect a list of input
|
|
// files, and we'll build a spec from them
|
|
if spec == "" {
|
|
if len(args) == 0 {
|
|
return errors.New("need --yaml, " +
|
|
"or one or more filenames")
|
|
}
|
|
err = PackFiles2(c, args, ctGlobs, out)
|
|
} else {
|
|
if len(args) != 0 {
|
|
return errors.New("cannot specify files " +
|
|
"when using --yaml")
|
|
}
|
|
if ctGlobs != nil {
|
|
return errors.New("cannot specify --content-type " +
|
|
"when using --yaml")
|
|
}
|
|
err = PackSpec(c, spec, out)
|
|
}
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func init() {
|
|
packCmd.Flags().StringP("out", "O", "",
|
|
"Output filename")
|
|
packCmd.MarkFlagRequired("out")
|
|
packCmd.Flags().StringP("spec", "y", "",
|
|
"YAML specification file (if not present, just pack files)")
|
|
packCmd.Flags().StringP("chdir", "C", "",
|
|
"Change to directory before searching for input files")
|
|
packCmd.Flags().StringArrayP("content-type", "", nil,
|
|
"Override content type for pattern, e.g. \"*.foo=bar/baz\" (like .gitignore)")
|
|
}
|
|
|
|
func PackFiles(c *cobra.Command, args []string, out string) error {
|
|
return PackFiles2(c, args, nil, out)
|
|
}
|
|
|
|
func PackFiles2(c *cobra.Command, args []string, ctGlobs ctGlobList, out string) error {
|
|
ftp, err := filesFromList(args)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ctGlobs.ApplyContentTypes(ftp)
|
|
|
|
return doPack(ftp, out)
|
|
}
|
|
|
|
func PackSpec(c *cobra.Command, spec, out string) error {
|
|
raw, err := ioutil.ReadFile(spec)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var ftp packer.FilesToPack
|
|
if err := yaml.UnmarshalStrict(raw, &ftp); err != nil {
|
|
return fmt.Errorf("parsing YAML spec %s: %v", spec, err)
|
|
}
|
|
|
|
return doPack(ftp, out)
|
|
}
|
|
|
|
func doPack(ftp packer.FilesToPack, out string) error {
|
|
prog := newUiProgress(ftp)
|
|
err := packer.Pack2(ftp, out, prog)
|
|
prog.Complete()
|
|
|
|
if err == nil {
|
|
fin, err := os.Open(out)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer fin.Close()
|
|
|
|
_, dir, err := packed.Load(fin)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
inspectSummary(dir)
|
|
}
|
|
return err
|
|
}
|