package cli
import (
"fmt"
"strings"
"git.sr.ht/~hristoast/wem/cfg"
"git.sr.ht/~hristoast/wem/env"
)
type BuildCmd struct {
Fetch bool `arg:"--fetch,-f" help:"Do a git fetch"`
Force bool `arg:"--force,-F" help:"Force building even if the requested version is already installed"`
Jobs int `arg:"--jobs,-j" help:"Desired number of make jobs"`
Staging bool `arg:"--staging" help:"Apply wine staging patches before building"`
Verbose bool `arg:"--verbose" help:"Print all build output"`
Win32 bool `arg:"--win32" help:"Build a 32-bit wine instead of 64"`
WineVer string `arg:"positional,required" help:"The desired wine version to build. Should be a valid git tag string."`
}
type InitCmd struct {
EnvName string `arg:"positional,required" help:"The name of the env to init"`
}
type InstallCmd struct {
DryRun bool `arg:"--dry-run" help:"Print out a string representing what wem wants to run"`
EnvName string `arg:"positional,required" help:"The name of the env you wish to run"`
}
type HelpCmd struct{}
type CfgCmd struct {
EnvName string `arg:"positional,required" help:"Configure a wine env (no args to print the config)"`
NoRender bool `arg:"--no-render" help:"Don't render template variables in the cfg (they are always rendered at runtime)"`
NoUnchanged bool `arg:"--no-unchanged" help:"Don't display values that are unchanged by the user"`
Save bool `arg:"--save" help:"Save any changes to the configuration from CLI arguments"`
}
type CompletionCmd struct {
Bash bool `arg:"--bash" help:"Generate completions for bash"`
Fish bool `arg:"--fish" help:"Generate completions for fish"`
Stdout bool `arg:"--stdout" help:"Print to stdout instead of writing files"`
}
type ListCmd struct {
Dxvk bool `arg:"--dxvk" help:"List DXVK versions"`
Env bool `arg:"--env" help:"List available wine envs"`
Installed bool `arg:"--installed" help:"List installed versions"`
GeWine bool `arg:"--ge-wine" help:"List GE GeWine versions"`
Wine bool `arg:"--wine" help:"List wine versions"`
Vkd3d bool `arg:"--vkd3d" help:"List VKD3D-Proton versions"`
}
type ManCmd struct {
Out string `arg:"--out" help:"Optional path to write the manpage to"`
}
type GeWineCmd struct {
Version string `arg:"positional,required" help:"The desired GE Wine version to install. See 'wem list --ge-wine' for available versions."`
}
type RunCmd struct {
DryRun bool `arg:"--dry-run" help:"Print out a string representing what wem wants to run"`
EnvName string `arg:"positional,required" help:"The name of the env you wish to run"`
Exec string `arg:"--exec" help:"Run an arbitrary executable with an env's context" placeholder:"CMD"`
ExecArgs []string `arg:"--exec-args" help:"Arguments to pass to an executable with --exec" placeholder:"ARGS"`
SkipInstall bool `arg:"--skip-install" help:"Skip any configured installation"`
SkipRun bool `arg:"--skip-run" help:"Skip the configured run exe"`
Winecfg bool `arg:"--winecfg" help:"Run winecfg with an env's context"`
Winetricks bool `arg:"--winetricks" help:"Run winetricks with an env's context"`
}
type TutorialCmd struct{}
type args struct {
// Positional args
Build *BuildCmd `arg:"subcommand:build" help:"Build a wine version from source"`
Completion *CompletionCmd `arg:"subcommand:completion" help:"Generate shell completion files for WEM"`
Init *InitCmd `arg:"subcommand:init" help:"Initialize a wine env"`
Install *InstallCmd `arg:"subcommand:install" help:"Run the install exe of a wine env"`
Help *HelpCmd `arg:"subcommand:help" help:"Show detailed program usage"`
Cfg *CfgCmd `arg:"subcommand:cfg" help:"Configure a wine env"`
List *ListCmd `arg:"subcommand:list" help:"List wine envs and other things"`
Man *ManCmd `arg:"subcommand:man" help:"Display the WEM manpage"`
GeWine *GeWineCmd `arg:"subcommand:ge-wine,subcommand:proton" help:"Manage GE Wine installations"`
Run *RunCmd `arg:"subcommand:run" help:"Run a wine env"`
Tutorial *TutorialCmd `arg:"subcommand:tutorial" help:"Run the text-based, seven page WEM tutorial"`
// Info args
InfoDate string `arg:"--info-date" help:"Optional release date for this env's program"`
InfoName string `arg:"--info-name" help:"The name of this env's program"`
// InstallOpts args
GogSilentInstall bool `arg:"--gog-silent-install" help:"Pass flags to a GOG.com installer to silence as much output as possible"`
InstallArgs []string `arg:"--install-args" help:"Additional arguments to use when running this env's install program"`
InstallExe string `arg:"--install-exe" help:"The executable to run for installation"`
InstallExpected string `arg:"--install-expected" help:"A file or directory that should be expected to exist when this env is fully installed"`
InstallWorkDir string `arg:"--install-workdir" help:"The working directory to be used for installation"`
NoGogSilentInstall bool `arg:"--no-gog-silent-install" help:"Unset the GogSilentInstall value"`
NoInstallArgs bool `arg:"--no-install-args" help:"Unset the InstallArgs value"`
NoInstallExe bool `arg:"--no-install-exe" help:"Unset the InstallExe value"`
NoInstallExpected bool `arg:"--no-install-expected" help:"Unset the InstallExpected value"`
NoInstallWorkDir bool `arg:"--no-install-workdir" help:"Unset the InstallWorkDir value"`
// RunOpts args
QuietRun bool `arg:"--quiet-run" help:"Suppress output from running"`
RunArgs []string `arg:"--run-args" help:"Additional arguments to use when running this env's program"`
RunExe string `arg:"--run-exe" help:"The executable to run for this env"`
RunPrefix string `arg:"--run-prefix" help:"Optional prefix for the run exe"`
RunSuffix string `arg:"--run-suffix" help:"Optional suffix for the run exe"`
RunPre string `arg:"--run-pre" help:"Optional pre-run command to run"`
RunPost string `arg:"--run-post" help:"Optional post-run command to run"`
RunWorkDir string `arg:"--run-workdir" help:"The working directory for running this env's program"`
NoQuietRun bool `arg:"--no-quiet-run" help:"Unset the QuietRun value"`
NoRunArgs bool `arg:"--no-run-args" help:"Unset the RunArgs value"`
NoRunExe bool `arg:"--no-run-exe" help:"Unset the RunExe value"`
NoRunPrefix bool `arg:"--no-run-prefix" help:"Unset the RunPrefix value"`
NoRunSuffix bool `arg:"--no-run-suffix" help:"Unset the RunSuffix value"`
NoRunPre bool `arg:"--no-run-pre" help:"Unset the RunPre value"`
NoRunPost bool `arg:"--no-run-post" help:"Unset the RunPost value"`
NoRunWorkDir bool `arg:"--no-run-workdir" help:"Unset the RunWorkDir value"`
// Sandbox args
Sandbox bool `arg:"--sandbox" help:"Enable sandboxing with all supported features"`
SandboxBlacklist []string `arg:"--sandbox-blacklist" help:"Use the '--blacklist' firejail flag with the given paths" placeholder:"PATH1 PATH2"`
SandboxWhitelist []string `arg:"--sandbox-whitelist" help:"Use the '--whitelist' firejail flag with the given paths" placeholder:"PATH1 PATH2"`
SandboxCpu int `arg:"--sandbox-cpu" help:"Use the '--cpu=COUNT' firejail flag" placeholder:"COUNT"`
SandboxDns string `arg:"--sandbox-dns" help:"Use the '--dns=ADDRESS' firejail flag" placeholder:"ADDRESS"`
SandboxIpcNamespace bool `arg:"--sandbox-ipc-namespace" help:"Use the '--ipc-namespace' firejail flag"`
SandboxMachineId bool `arg:"--sandbox-machine-id" help:"Use the '--machine-id' firejail flag"`
SandboxNetNone bool `arg:"--sandbox-net-none" help:"Use the '--net=none' firejail flag"`
SandboxNoDbus bool `arg:"--sandbox-nodbus" help:"Use the '--nodbus' firejail flag"`
SandboxNoPrinters bool `arg:"--sandbox-noprinters" help:"Use the '--noprinters' firejail flag"`
SandboxNoU2f bool `arg:"--sandbox-nou2f" help:"Use the '--nou2f' firejail flag"`
SandboxPrivateCache bool `arg:"--sandbox-private-cache" help:"Use the '--private-cache' firejail flag"`
SandboxPrivateCwd bool `arg:"--sandbox-private-cwd" help:"Use the '--private-cwd' firejail flag"`
SandboxPrivateTmp bool `arg:"--sandbox-private-tmp" help:"Use the '--private-tmp' firejail flag"`
// SysOpts args
ReducePulseLatency bool `arg:"--reduce-pulse-latency" help:"Set the environment variable PULSE_LATENCY_MSEC=60 to improve audio quality"`
RestartPulse bool `arg:"--restart-pulse" help:"Restart Pulseaudio before running the env"`
RestoreResolution bool `arg:"--restore-resolution" help:"Attempt to restore your desktop resolution on exit"`
SingleCore bool `arg:"--single-core" help:"Force the env process to run on a single core"`
SysEnvVars []string `arg:"--sys-env-vars" help:"Environment variables to set" placeholder:"KEY=VAL KEY=VAL"`
VulkanIcdLoader string `arg:"--vulkan-icd-loader" help:"Path to a Vulkan ICD loader" placeholder:"PATH"`
NoReducePulseLatency bool `arg:"--no-reduce-pulse-latency" help:"Unset the ReducePulseLatency value"`
NoRestartPulse bool `arg:"--no-restart-pulse" help:"Unset the RestartPulse value"`
NoRestoreResolution bool `arg:"--no-restore-resolution" help:"Unset the RestoreResolution value"`
NoSingleCore bool `arg:"--no-single-core" help:"Unset the SingleCore value"`
NoSysEnvVars bool `arg:"--no-sys-env-vars" help:"Unset the SysEnvVars value"`
NoVulkanIcdLoader bool `arg:"--no-vulkan-icd-loader" help:"Unset the VulkanIcdLoader value"`
// WineOpts args
DxvkVersion string `arg:"--dxvk-version" help:"DXVK version to use, if any" placeholder:"VERSION"`
Esync bool `arg:"--esync" help:"Enable esync"`
Fsync bool `arg:"--fsync" help:"Enable fsync"`
WineArch string `arg:"--wine-arch" help:"Wine arch to use" placeholder:"win32 or win64"`
WineArgs []string `arg:"--wine-args" help:"Args to pass to wine itself" placeholder:"ARG1 ARG2"`
WineDllOverrides string `arg:"--wine-dlloverrides" help:"String to pass to WINEDLLOVERRIDES" placeholder:"dllone,dlltwo=n,b"`
WineExe string `arg:"--wine-exe" help:"Path to a wine executable" placeholder:"PATH"`
WinePrefix string `arg:"--wine-prefix" help:"Path to the wine prefix for the env" placeholder:"PATH"`
WinetricksPath string `arg:"--winetricks-path" help:"Path to a winetricks executable" placeholder:"PATH"`
VirtualDesktop string `arg:"--virtualdesktop" help:"Use a virtual desktop" placeholder:"WIDTHxHEIGHT"`
Vkd3dVersion string `arg:"--vkd3d-version" help:"The VKD3D version to use" placeholder:"VERSION"`
NoDxvkVersion bool `arg:"--no-dxvk-version,--no-dxvk" help:"Unset the DxvkVersion value"`
NoEsync bool `arg:"--no-esync" help:"Unset the Esync value"`
NoFsync bool `arg:"--no-fsync" help:"Unset the Fsync value"`
NoWineArch bool `arg:"--no-wine-arch" help:"Unset the WineArch value"`
NoWineArgs bool `arg:"--no-wine-args" help:"Unset the WineArgs value"`
NoWineDllOverrides bool `arg:"--no-wine-args" help:"Unset the WineDllOverrides value"`
NoWineExe bool `arg:"--no-wine-exe" help:"Unset the WineExe value"`
NoWinePrefix bool `arg:"--no-wine-prefix" help:"Unset the WinePrefix value"`
NoWinetricksPath bool `arg:"--no-winetricks-path" help:"Unset the WinetricksPath value"`
NoVirtualDesktop bool `arg:"--no-virtualdesktop" help:"Unset the VirtualDesktop value"`
NoVkd3dVersion bool `arg:"--no-vkd3d-version,--no-vkd3d" help:"Unset the Vkd3dVersion value"`
NoSandbox bool `arg:"--no-sandbox" help:"Disable sandboxing"`
NoSandboxBlacklist bool `arg:"--no-sandbox-blacklist" help:"Don't set firejail blacklist paths"`
NoSandboxWhitelist bool `arg:"--no-sandbox-whitelist" help:"Don't set firejail whitelist paths"`
NoSandboxCpu bool `arg:"--no-sandbox-cpu" help:"Don't use the '--cpu=COUNT' firejail flag"`
NoSandboxDns bool `arg:"--no-sandbox-dns" help:"Don't use the '--dns=ADDRESS' firejail flag"`
NoSandboxIpcNamespace bool `arg:"--no-sandbox-ipc-namespace" help:"Don't use the '--ipc-namespace' firejail flag"`
NoSandboxMachineId bool `arg:"--no-sandbox-machine-id" help:"Don't use the '--machine-id' firejail flag"`
NoSandboxNetNone bool `arg:"--no-sandbox-net-none" help:"Don't use the '--net=none' firejail flag"`
NoSandboxNoDbus bool `arg:"--no-sandbox-nodbus" help:"Don't use the '--nodbus' firejail flag"`
NoSandboxNoPrinters bool `arg:"--no-sandbox-noprinters" help:"Don't use the '--noprinters' firejail flag"`
NoSandboxNoU2f bool `arg:"--no-sandbox-nou2f" help:"Don't use the '--nou2f' firejail flag"`
NoSandboxPrivateCache bool `arg:"--no-sandbox-private-cache" help:"Don't use the '--private-cache' firejail flag"`
NoSandboxPrivateCwd bool `arg:"--no-sandbox-private-cwd" help:"Don't use the '--private-cwd' firejail flag"`
NoSandboxPrivateTmp bool `arg:"--no-sandbox-private-tmp" help:"Don't use the '--private-tmp' firejail flag"`
// The rest
CacheDir string `arg:"--cache-dir" help:"Path to the directory where archives should be cached to" placeholder:"PATH"`
GeWineDir string `arg:"--ge-wine-dir" help:"Path to the directory where GE Wine will be installed to and checked for" placeholder:"PATH"`
WineBuildDir string `arg:"--wine-build-dir" help:"Path to the directory where custom wine builds will be installed to and checked for" placeholder:"PATH"`
WineEnvDir string `arg:"--wine-env-dir" help:"Path to the directory where envs will be kept and checked for" placeholder:"PATH"`
WineSrcDir string `arg:"--wine-src-dir" help:"Path to the directory where wine source code will be kept and checked for" placeholder:"PATH"`
QuietWem bool `arg:"-q,--quiet-wem" help:"Don't print any output via WEM itself"`
}
func (args) Description() string {
return fmt.Sprintf("%s is a tool for managing wine \"envs\" or prefixes.\n", strings.ToUpper(cfg.WemName))
}
func (args) Version() string {
return fmt.Sprintf("%s %s ", cfg.WemName, cfg.WemVersion)
}
// Bind command line-supplied values onto the env.
func (a *args) applyArgs(e *env.WineEnv) {
// Info
if a.InfoDate != "" {
e.Date = a.InfoDate
}
if a.InfoName != "" {
e.Name = a.InfoName
}
// InstallOpts
if a.InstallArgs != nil {
e.InstallArgs = a.InstallArgs
}
if a.InstallExe != "" {
e.InstallExe = a.InstallExe
}
if a.InstallExpected != "" {
e.InstallExpected = a.InstallExpected
}
if a.InstallWorkDir != "" {
e.InstallWorkDir = a.InstallWorkDir
}
// RunOpts
if a.RunArgs != nil {
e.RunArgs = a.RunArgs
}
if a.RunExe != "" {
e.RunExe = a.RunExe
}
if a.RunPrefix != "" {
e.RunPrefix = a.RunPrefix
}
if a.RunSuffix != "" {
e.RunSuffix = a.RunSuffix
}
if a.RunPre != "" {
e.RunPre = a.RunPre
}
if a.RunPost != "" {
e.RunPost = a.RunPost
}
if a.RunWorkDir != "" {
e.RunWorkDir = a.RunWorkDir
}
// SysOpts
if a.ReducePulseLatency {
e.ReducePulseLatency = a.ReducePulseLatency
}
if a.RestartPulse {
e.RestartPulse = a.RestartPulse
}
if a.RestoreResolution {
e.RestoreResolution = a.RestoreResolution
}
if a.SingleCore {
e.SingleCore = a.SingleCore
}
if a.SysEnvVars != nil {
e.SysEnvVars = a.SysEnvVars
}
if a.VulkanIcdLoader != "" {
e.VulkanIcdLoader = a.VulkanIcdLoader
}
// WineOpts
if a.DxvkVersion != "" {
e.DxvkVersion = a.DxvkVersion
}
if a.Esync {
e.Esync = a.Esync
}
if a.Fsync {
e.Fsync = a.Fsync
}
if a.GogSilentInstall {
e.GogSilentInstall = a.GogSilentInstall
}
if a.QuietRun {
e.QuietRun = a.QuietRun
}
if a.WineArch != "" {
e.WineArch = a.WineArch
}
if a.WineArgs != nil {
e.WineArgs = a.WineArgs
}
if a.WineDllOverrides != "" {
e.WineDllOverrides = a.WineDllOverrides
}
if a.WineExe != "" {
e.WineExe = a.WineExe
}
if a.WinePrefix != "" {
e.WinePrefix = a.WinePrefix
}
if a.WinetricksPath != "" {
e.WinetricksPath = a.WinetricksPath
}
if a.VirtualDesktop != "" {
e.VirtualDesktop = a.VirtualDesktop
}
if a.Vkd3dVersion != "" {
e.Vkd3dVersion = a.Vkd3dVersion
}
// Apply unset args
if a.NoGogSilentInstall {
e.GogSilentInstall = false
}
if a.NoInstallArgs {
e.InstallArgs = nil
}
if a.NoInstallExe {
e.InstallExe = ""
}
if a.NoInstallExpected {
e.InstallExpected = ""
}
if a.NoInstallWorkDir {
e.InstallWorkDir = ""
}
if a.NoQuietRun {
e.QuietRun = false
}
if a.NoRunArgs {
e.RunArgs = nil
}
if a.NoRunExe {
e.RunExe = ""
}
if a.NoRunPrefix {
e.RunPrefix = ""
}
if a.NoRunSuffix {
e.RunSuffix = ""
}
if a.NoRunPre {
e.RunPre = ""
}
if a.NoRunPost {
e.RunPost = ""
}
if a.NoRunWorkDir {
e.RunWorkDir = ""
}
if a.NoReducePulseLatency {
e.ReducePulseLatency = false
}
if a.NoRestartPulse {
e.RestartPulse = false
}
if a.NoRestoreResolution {
e.RestoreResolution = false
}
if a.NoSingleCore {
e.SingleCore = false
}
if a.NoSysEnvVars {
e.SysEnvVars = nil
}
if a.NoVulkanIcdLoader {
e.VulkanIcdLoader = ""
}
if a.NoDxvkVersion {
e.DxvkVersion = ""
}
if a.NoEsync {
e.Esync = false
}
if a.NoFsync {
e.Fsync = false
}
if a.NoWineArch {
e.WineArch = ""
}
if a.NoWineArgs {
e.WineArgs = nil
}
if a.NoWineDllOverrides {
e.WineDllOverrides = ""
}
if a.NoWineExe {
e.WineExe = ""
}
if a.NoWinePrefix {
e.WinePrefix = ""
}
if a.NoWinetricksPath {
e.WinetricksPath = ""
}
if a.NoVirtualDesktop {
e.VirtualDesktop = ""
}
if a.NoVkd3dVersion {
e.Vkd3dVersion = ""
}
if a.Sandbox {
e.Sandbox = true
e.SandboxIpcNamespace = true
e.SandboxMachineId = true
e.SandboxNetNone = true
e.SandboxNoDbus = true
e.SandboxNoPrinters = true
e.SandboxNoU2f = true
e.SandboxPrivateCache = true
e.SandboxPrivateCwd = true
e.SandboxPrivateTmp = true
}
if a.SandboxBlacklist != nil {
e.SandboxBlacklist = a.SandboxBlacklist
}
if a.SandboxWhitelist != nil {
e.SandboxWhitelist = a.SandboxWhitelist
}
if a.SandboxCpu > 0 {
e.SandboxCpu = a.SandboxCpu
}
if a.SandboxDns != "" {
e.SandboxDns = a.SandboxDns
}
if a.SandboxIpcNamespace {
e.SandboxIpcNamespace = true
}
if a.SandboxMachineId {
e.SandboxMachineId = true
}
if a.SandboxNetNone {
e.SandboxNetNone = true
}
if a.SandboxNoDbus {
e.SandboxNoDbus = true
}
if a.SandboxNoPrinters {
e.SandboxNoPrinters = true
}
if a.SandboxNoU2f {
e.SandboxNoU2f = true
}
if a.SandboxPrivateCache {
e.SandboxPrivateCache = true
}
if a.SandboxPrivateCwd {
e.SandboxPrivateCwd = true
}
if a.SandboxPrivateTmp {
e.SandboxPrivateTmp = true
}
if a.NoSandbox {
e.Sandbox = false
e.SandboxBlacklist = nil
e.SandboxWhitelist = nil
e.SandboxCpu = 0
e.SandboxDns = ""
e.SandboxIpcNamespace = false
e.SandboxMachineId = false
e.SandboxNetNone = false
e.SandboxNoDbus = false
e.SandboxNoPrinters = false
e.SandboxNoU2f = false
e.SandboxPrivateCache = false
e.SandboxPrivateCwd = false
e.SandboxPrivateTmp = false
}
if a.NoSandboxCpu {
e.Sandbox = false
e.SandboxCpu = 0
}
if a.NoSandboxDns {
e.Sandbox = false
e.SandboxDns = ""
}
if a.NoSandboxIpcNamespace {
e.Sandbox = false
e.SandboxIpcNamespace = false
}
if a.NoSandboxMachineId {
e.Sandbox = false
e.SandboxMachineId = false
}
if a.NoSandboxNetNone {
e.Sandbox = false
e.SandboxNetNone = false
}
if a.NoSandboxNoDbus {
e.Sandbox = false
e.SandboxNoDbus = false
}
if a.NoSandboxNoPrinters {
e.Sandbox = false
e.SandboxNoPrinters = false
}
if a.NoSandboxNoU2f {
e.Sandbox = false
e.SandboxNoU2f = false
}
if a.NoSandboxPrivateCache {
e.Sandbox = false
e.SandboxPrivateCache = false
}
if a.NoSandboxPrivateCwd {
e.Sandbox = false
e.SandboxPrivateCwd = false
}
if a.NoSandboxPrivateTmp {
e.Sandbox = false
e.SandboxPrivateTmp = false
}
}
// NoArgs is a more clear way to indicate if there are no args.
func (a *args) NoArgs() bool {
return a.Build == nil && a.Cfg == nil && a.Completion == nil && a.GeWine == nil && a.Help == nil && a.Init == nil && a.Install == nil && a.List == nil && a.Man == nil && a.Run == nil && a.Tutorial == nil
}