Skip to content

Commit

Permalink
vpkutil, cmd/*: Refactor common CLI argument parsing and setup
Browse files Browse the repository at this point in the history
  • Loading branch information
pg9182 committed Apr 13, 2024
1 parent e5c84ed commit 1597920
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 163 deletions.
62 changes: 16 additions & 46 deletions cmd/tf2-vpk2tar/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,28 @@ import (
"runtime"
"time"

"github.com/pg9182/tf2vpk"
"github.com/pg9182/tf2vpk/internal"
"github.com/pg9182/tf2vpk/vpkutil"
"github.com/spf13/pflag"
)

var (
Output = pflag.StringP("output", "o", "-", "The file to write the tar archive to")
VPKPrefix = pflag.StringP("vpk-prefix", "p", "english", "VPK prefix")
Verbose = pflag.BoolP("verbose", "v", false, "Write information about processed files to stderr")
Test = pflag.BoolP("test", "t", false, "Don't create a tar archive; only attempt to read the entire VPK and verify checksums")
Threads = pflag.IntP("threads", "j", runtime.NumCPU(), "The number of decompression threads to use (0 to only decompress chunks as they are read) (defaults to the number of cores)")
ResolveOpen = vpkutil.NewCLIResolveOpen(pflag.CommandLine, 0, false)

Exclude = pflag.StringSlice("exclude", nil, "Excludes files or directories matching the provided glob (anchor to the start with /)")
Include = pflag.StringSlice("include", nil, "Negates --exclude for files or directories matching the provided glob")
Output = pflag.StringP("output", "o", "-", "The file to write the tar archive to")
Verbose = pflag.BoolP("verbose", "v", false, "Write information about processed files to stderr")
Test = pflag.BoolP("test", "t", false, "Don't create a tar archive; only attempt to read the entire VPK and verify checksums")
Threads = pflag.IntP("threads", "j", runtime.NumCPU(), "The number of decompression threads to use (0 to only decompress chunks as they are read) (defaults to the number of cores)")

IncludeExclude = vpkutil.NewCLIIncludeExclude(pflag.CommandLine)

Help = pflag.BoolP("help", "h", false, "Show this help message")
)

func main() {
pflag.Parse()

argv := pflag.Args()
if len(argv) == 0 || len(argv) > 2 || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] (vpk_dir vpk_name)|vpk_path\n\noptions:\n%s", os.Args[0], pflag.CommandLine.FlagUsages())
if !ResolveOpen.ArgCheck() || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] %s\n\noptions:\n%s", os.Args[0], ResolveOpen.ArgHelp(), pflag.CommandLine.FlagUsages())
if !*Help {
os.Exit(2)
}
Expand All @@ -46,23 +44,9 @@ func main() {
runtime.GOMAXPROCS(*Threads)
}

var (
err error
vpk tf2vpk.ValvePak
)
if len(argv) == 2 {
vpk, err = tf2vpk.VPK(argv[0], *VPKPrefix, argv[1]), nil
} else {
vpk, err = tf2vpk.VPKFromPath(argv[0], *VPKPrefix)
}
_, r, err := ResolveOpen.ResolveOpen()
if err != nil {
fmt.Fprintf(os.Stderr, "error: resolve vpk: %v\n", err)
os.Exit(1)
}

r, err := tf2vpk.NewReader(vpk)
if err != nil {
fmt.Fprintf(os.Stderr, "error: open vpk: %v\n", err)
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
defer r.Close()
Expand Down Expand Up @@ -92,24 +76,10 @@ func main() {
}

for _, f := range r.Root.File {
var excluded bool
for _, x := range *Exclude {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process excludes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = true
}
}
for _, x := range *Include {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process includes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = false
}
}
if excluded {
if skip, err := IncludeExclude.Skip(f); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
} else if skip {
continue
}
var sz uint64
Expand Down
51 changes: 11 additions & 40 deletions cmd/tf2-vpklist/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import (

"github.com/pg9182/tf2vpk"
"github.com/pg9182/tf2vpk/internal"
"github.com/pg9182/tf2vpk/vpkutil"
"github.com/spf13/pflag"
)

var (
VPKPrefix = pflag.StringP("vpk-prefix", "p", "english", "VPK prefix")
ResolveOpen = vpkutil.NewCLIResolveOpen(pflag.CommandLine, 0, false)

HumanReadable = pflag.BoolP("human-readable", "h", false, "Show values in human-readable form")
HumanReadableFlags = pflag.BoolP("human-readable-flags", "f", false, "If displaying flags, also show them in human-readable form at the very end of the line (delimited by a #)")
Expand All @@ -24,18 +25,16 @@ var (

Threads = pflag.IntP("threads", "j", runtime.NumCPU(), "The number of decompression threads to use while verifying checksums (0 to only decompress chunks as they are read) (defaults to the number of cores)")

Exclude = pflag.StringSlice("exclude", nil, "Excludes files or directories matching the provided glob (anchor to the start with /)")
Include = pflag.StringSlice("include", nil, "Negates --exclude for files or directories matching the provided glob")
IncludeExclude = vpkutil.NewCLIIncludeExclude(pflag.CommandLine)

Help = pflag.Bool("help", false, "Show this help message")
)

func main() {
pflag.Parse()

argv := pflag.Args()
if len(argv) == 0 || len(argv) > 2 || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] (vpk_dir vpk_name)|vpk_path\n\noptions:\n%s", os.Args[0], pflag.CommandLine.FlagUsages())
if !ResolveOpen.ArgCheck() || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] %s\n\noptions:\n%s", os.Args[0], ResolveOpen.ArgHelp(), pflag.CommandLine.FlagUsages())
if !*Help {
os.Exit(2)
}
Expand All @@ -49,23 +48,9 @@ func main() {
runtime.GOMAXPROCS(*Threads)
}

var (
err error
vpk tf2vpk.ValvePak
)
if len(argv) == 2 {
vpk, err = tf2vpk.VPK(argv[0], *VPKPrefix, argv[1]), nil
} else {
vpk, err = tf2vpk.VPKFromPath(argv[0], *VPKPrefix)
}
if err != nil {
fmt.Fprintf(os.Stderr, "error: resolve vpk: %v\n", err)
os.Exit(1)
}

r, err := tf2vpk.NewReader(vpk)
_, r, err := ResolveOpen.ResolveOpen()
if err != nil {
fmt.Fprintf(os.Stderr, "error: open vpk: %v\n", err)
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}
defer r.Close()
Expand All @@ -77,24 +62,10 @@ func main() {

var testErrCount int
for _, f := range r.Root.File {
var excluded bool
for _, x := range *Exclude {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process excludes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = true
}
}
for _, x := range *Include {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process includes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = false
}
}
if excluded {
if skip, err := IncludeExclude.Skip(f); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
} else if skip {
continue
}

Expand Down
34 changes: 5 additions & 29 deletions cmd/tf2-vpkoptim/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/pg9182/tf2vpk"
"github.com/pg9182/tf2vpk/internal"
"github.com/pg9182/tf2vpk/vpkutil"
"github.com/spf13/pflag"
)

Expand All @@ -24,9 +25,7 @@ var (
DryRun = pflag.BoolP("dry-run", "n", false, "Don't write output files")

Merge = pflag.Bool("merge", false, "Merges all blocks (i.e., _XXX.vpk)")
Exclude = pflag.StringSlice("exclude", nil, "Excludes files or directories matching the provided glob (anchor to the start with /)")
ExcludeBSPLump = pflag.IntSlice("exclude-bsp-lump", nil, "Shortcut for --exclude to remove %04x.bsp_lump")
Include = pflag.StringSlice("include", nil, "Negates --exclude for files or directories matching the provided glob")
IncludeExclude = vpkutil.NewCLIIncludeExclude(pflag.CommandLine)

Help = pflag.BoolP("help", "h", false, "Show this help message")
)
Expand Down Expand Up @@ -177,32 +176,9 @@ func optimize(ctx context.Context, inputDir, outputDir, vpkName string) error {
var nf []tf2vpk.ValvePakFile
var nfd int
for _, f := range r.Root.File {
var excluded bool
for _, x := range *Exclude {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
return fmt.Errorf("process excludes: match %q against glob %q: %w", f.Path, x, err)
} else if m {
vlog(VDebug, "--- exclude %q: matched %q", x, f.Path)
excluded = true
}
}
for _, x := range *ExcludeBSPLump {
if m, err := internal.MatchGlobParents(fmt.Sprintf("%04x.bsp_lump", x), f.Path); err != nil {
return fmt.Errorf("process bsp lump excludes: match %q against glob %q: %w", f.Path, x, err)
} else if m {
vlog(VDebug, "--- exclude lump %d: matched %q", x, f.Path)
excluded = true
}
}
for _, x := range *Include {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
return fmt.Errorf("process includes: match %q against glob %q: %w", f.Path, x, err)
} else if m {
excluded = false
vlog(VDebug, "--- include %q: matched %q", x, f.Path)
}
}
if excluded {
if skip, err := IncludeExclude.Skip(f); err != nil {
return err
} else if skip {
vlog(VVerbose, "--- excluding %s", f.Path)
nfd++
continue
Expand Down
64 changes: 16 additions & 48 deletions cmd/tf2-vpkunpack/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,29 @@ import (
"path/filepath"
"runtime"

"github.com/pg9182/tf2vpk"
"github.com/pg9182/tf2vpk/internal"
"github.com/pg9182/tf2vpk/vpkutil"
"github.com/spf13/pflag"
)

var (
VPKPrefix = pflag.StringP("vpk-prefix", "p", "english", "VPK prefix")
ResolveOpen = vpkutil.NewCLIResolveOpen(pflag.CommandLine, 1, true)

VPKFlagsExplicit = pflag.Bool("vpkflags-explicit", false, "Do not optimize vpkflags for inheritance; generate one line for each file")
VPKIgnoreEmpty = pflag.Bool("vpkignore-no-default", false, "Do not add default vpkignore entries")
Threads = pflag.IntP("threads", "j", runtime.NumCPU(), "The number of decompression threads to use while verifying checksums (0 to only decompress chunks as they are read) (defaults to the number of cores)")

Exclude = pflag.StringSlice("exclude", nil, "Excludes files or directories matching the provided glob (anchor to the start with /)")
Include = pflag.StringSlice("include", nil, "Negates --exclude for files or directories matching the provided glob")
IncludeExclude = vpkutil.NewCLIIncludeExclude(pflag.CommandLine)

Help = pflag.Bool("help", false, "Show this help message")
)

func main() {
pflag.Parse()

argv := pflag.Args()
if len(argv) == 0 || len(argv) > 3 || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] empty_output_path [(vpk_dir vpk_name)|vpk_path]\n\noptions:\n%s", os.Args[0], pflag.CommandLine.FlagUsages())
args := pflag.Args()
if len(args) == 0 || !ResolveOpen.ArgCheck() || *Help {
fmt.Fprintf(os.Stderr, "usage: %s [options] empty_output_path %s\n\noptions:\n%s", os.Args[0], ResolveOpen.ArgHelp(), pflag.CommandLine.FlagUsages())
if !*Help {
os.Exit(2)
}
Expand All @@ -49,36 +47,20 @@ func main() {
runtime.GOMAXPROCS(*Threads)
}

vpkOut := argv[0]
vpkOut := args[0]

var (
err error
vpk tf2vpk.ValvePak
)
if len(argv) == 3 {
fmt.Printf("unpacking vpk %q (in %q) to %q\n", argv[1], argv[2], vpkOut)
vpk, err = tf2vpk.VPK(argv[1], *VPKPrefix, argv[2]), nil
} else if len(argv) == 2 {
fmt.Printf("unpacking vpk %q to %q\n", argv[1], vpkOut)
vpk, err = tf2vpk.VPKFromPath(argv[1], *VPKPrefix)
} else {
if len(args) == 1 {
fmt.Printf("initializing new vpk in %q\n", vpkOut)
vpk, err = nil, nil
} else {
fmt.Printf("unpacking vpk to %q\n", vpkOut)
}

_, r, err := ResolveOpen.ResolveOpen()
if err != nil {
fmt.Fprintf(os.Stderr, "error: resolve vpk: %v\n", err)
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
}

var r *tf2vpk.Reader
if vpk != nil {
if r, err = tf2vpk.NewReader(vpk); err != nil {
fmt.Fprintf(os.Stderr, "error: open vpk: %v\n", err)
os.Exit(1)
}
defer r.Close()
}

if *VPKFlagsExplicit && r != nil {
fmt.Printf("... generating .vpkflags (without inheritance)\n")
} else {
Expand Down Expand Up @@ -153,24 +135,10 @@ func main() {
var excludedCount int
if r != nil {
for i, f := range r.Root.File {
var excluded bool
for _, x := range *Exclude {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process excludes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = true
}
}
for _, x := range *Include {
if m, err := internal.MatchGlobParents(x, f.Path); err != nil {
fmt.Fprintf(os.Stderr, "error: process includes: match %q against glob %q: %v\n", f.Path, x, err)
os.Exit(1)
} else if m {
excluded = false
}
}
if excluded {
if skip, err := IncludeExclude.Skip(f); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err)
os.Exit(1)
} else if skip {
excludedCount++
fmt.Printf("[%4d/%4d] %s (excluded)\n", i+1, len(r.Root.File), f.Path)
continue
Expand Down
Loading

0 comments on commit 1597920

Please sign in to comment.