diff --git a/v3/cmd/wails3/main.go b/v3/cmd/wails3/main.go index 2ea7e92f..f99f8675 100644 --- a/v3/cmd/wails3/main.go +++ b/v3/cmd/wails3/main.go @@ -25,7 +25,7 @@ func init() { } func main() { - app := clir.NewCli("wails", "The Wails CLI", "v3") + app := clir.NewCli("wails", "The Wails3 CLI", "v3") app.NewSubCommandFunction("init", "Initialise a new project", commands.Init) app.NewSubCommandFunction("build", "Build the project", commands.Build) app.NewSubCommandFunction("dev", "Run in Dev mode", commands.Dev) @@ -37,7 +37,7 @@ func main() { task.Action(func() error { return commands.RunTask(&taskFlags, task.OtherArgs()) }) - task.LongDescription("\nUsage: wails task [taskname] [flags]\n\nTasks are defined in the `Taskfile.yaml` file. See https://taskfile.dev for more information.") + task.LongDescription("\nUsage: wails3 task [taskname] [flags]\n\nTasks are defined in the `Taskfile.yaml` file. See https://taskfile.dev for more information.") generate := app.NewSubCommand("generate", "Generation tools") generate.NewSubCommandFunction("build-assets", "Generate build assets", commands.GenerateBuildAssets) generate.NewSubCommandFunction("icons", "Generate icons", commands.GenerateIcons) diff --git a/v3/go.mod b/v3/go.mod index 365d8ccb..564b8f81 100644 --- a/v3/go.mod +++ b/v3/go.mod @@ -5,22 +5,20 @@ go 1.21.1 toolchain go1.21.4 require ( - github.com/atterpac/refresh v0.2.4 + github.com/atterpac/refresh v0.4.32 github.com/bep/debounce v1.2.1 - github.com/davecgh/go-spew v1.1.1 github.com/ebitengine/purego v0.4.0-alpha.4 - github.com/go-git/go-git/v5 v5.3.0 + github.com/go-git/go-git/v5 v5.11.0 github.com/go-ole/go-ole v1.2.6 github.com/go-task/task/v3 v3.31.0 github.com/godbus/dbus/v5 v5.1.0 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.6.0 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/google/uuid v1.3.0 github.com/gorilla/pat v1.0.1 github.com/gorilla/sessions v1.2.1 github.com/jackmordaunt/icns/v2 v2.2.1 github.com/jaypipes/ghw v0.12.0 - github.com/json-iterator/go v1.1.12 github.com/leaanthony/clir v1.6.0 github.com/leaanthony/go-ansi-parser v1.6.1 github.com/leaanthony/gosod v1.0.3 @@ -38,69 +36,70 @@ require ( github.com/tc-hib/winres v0.1.6 github.com/wailsapp/go-webview2 v1.0.9 github.com/wailsapp/mimetype v1.4.1 - golang.org/x/net v0.10.0 - golang.org/x/sys v0.14.0 + golang.org/x/sys v0.15.0 modernc.org/sqlite v1.21.0 ) require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect + dario.cat/mergo v1.0.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/Masterminds/semver/v3 v3.2.1 // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/Microsoft/go-winio v0.6.1 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/StackExchange/wmi v1.2.1 // indirect + github.com/alexbrainman/ps v0.0.0-20171229230509-b3e1b4a15894 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/containerd/console v1.0.3 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/dustin/go-humanize v1.0.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/fatih/color v1.15.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.2.0 // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.4.2 // indirect github.com/gookit/color v1.5.2 // indirect github.com/gorilla/context v1.1.1 // indirect github.com/gorilla/mux v1.6.2 // indirect github.com/gorilla/securecookie v1.1.1 // indirect - github.com/imdario/mergo v0.3.12 // indirect github.com/jaypipes/pcidb v1.0.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/cpuid/v2 v2.2.3 // indirect github.com/lithammer/fuzzysearch v1.1.5 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-zglob v0.0.4 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect - github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/radovskyb/watcher v1.0.7 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rjeczalik/notify v0.9.3 // indirect github.com/sajari/fuzzy v1.0.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect - github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect - github.com/xanzy/ssh-agent v0.3.0 // indirect + github.com/skeema/knownhosts v1.2.1 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.16.0 // indirect golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/image v0.5.0 // indirect golang.org/x/mod v0.12.0 // indirect + golang.org/x/net v0.19.0 // indirect golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect golang.org/x/sync v0.4.0 // indirect - golang.org/x/term v0.13.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/tools v0.6.0 // indirect + golang.org/x/term v0.15.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.13.0 // indirect google.golang.org/appengine v1.6.6 // indirect google.golang.org/protobuf v1.25.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/v3/go.sum b/v3/go.sum index f1235ca2..ec60164f 100644 --- a/v3/go.sum +++ b/v3/go.sum @@ -37,6 +37,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= @@ -53,33 +55,39 @@ github.com/MarvinJWendt/testza v0.5.1 h1:a9Fqx6vQrHQ4CyiaLhktfTTelwGotmFWy8MNhya github.com/MarvinJWendt/testza v0.5.1/go.mod h1:L7csM8IBqCc0HH4TRYZSPCIRg6zJeqzM1pm3FSYZBso= github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/alexbrainman/ps v0.0.0-20171229230509-b3e1b4a15894 h1:A6LgNoQeWttVPnIRYzKsbex/HePFxYT9ygCZvgVJDU0= +github.com/alexbrainman/ps v0.0.0-20171229230509-b3e1b4a15894/go.mod h1:Wgrp3f69GNEJz6CdHKtBqKAWdmYTd1K9IlOV+uuv4Uw= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/atomicgo/cursor v0.0.1/go.mod h1:cBON2QmmrysudxNBFthvMtN32r3jxVRIvzkUiF/RuIk= -github.com/atterpac/refresh v0.2.4 h1:rTD9qchbLa0qPIVr+qpyqkePe6+1Cs14ETXDguEvttI= -github.com/atterpac/refresh v0.2.4/go.mod h1:KiBQUk5h76Z3Yvw/k3Ys2JGDrKmKmflwS9XB6B5N9qY= +github.com/atterpac/refresh v0.4.32 h1:sy2T3rNtbGYffZQWGpqRafZ1QwQMGLkRafCTX52fv0w= +github.com/atterpac/refresh v0.4.32/go.mod h1:1mhPVWQ9R8Xlr/ouNrtAVEAsEVOt65J+6FFYWMMKRN0= github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY= github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw= github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -89,31 +97,30 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/ebitengine/purego v0.4.0-alpha.4 h1:Y7yIV06Yo5M2BAdD7EVPhfp6LZ0tEcQo5770OhYUVes= github.com/ebitengine/purego v0.4.0-alpha.4/go.mod h1:ah1In8AOtksoNK6yk5z1HTJeUkC1Ez4Wk2idgGslMwQ= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.2.0 h1:GcoouCP9J+5slw2uXAocL70z8ml4A8B/H8nEPt6CLPk= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= -github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= -github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= -github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= +github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= +github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= +github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -132,6 +139,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -163,9 +172,8 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -204,8 +212,6 @@ github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/z github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jackmordaunt/icns/v2 v2.2.1 h1:MGklwYP2yohKn2Bw7XxlF69LZe98S1vUfl5OvAulPwg= github.com/jackmordaunt/icns/v2 v2.2.1/go.mod h1:6aYIB9eSzyfHHMKqDf17Xrs1zetQPReAkiUSHzdw4cI= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= @@ -218,27 +224,22 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck= github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.2.3 h1:sxCkb+qR91z4vsqw4vGGZlDgPz3G7gjaLyK3V8y70BU= github.com/klauspost/cpuid/v2 v2.2.3/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -290,14 +291,13 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c/go.mod h1:skjdDftzkFALcuGzYSklqYd8gvat6F1gZJ4YPVbkZpM= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -327,27 +327,24 @@ github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/rjeczalik/notify v0.9.3 h1:6rJAzHTGKXGj76sbRgDiDcYj/HniypXmSJo1SWakZeY= github.com/rjeczalik/notify v0.9.3/go.mod h1:gF3zSOrafR9DQEWSE8TjfI9NkooDxbyT4UgRGKZA0lc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97 h1:3RPlVWzZ/PDqmVuf/FKHARG5EMid/tl7cv54Sw/QRVY= -github.com/rogpeppe/go-internal v1.10.1-0.20230524175051-ec119421bb97/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/sajari/fuzzy v1.0.0 h1:+FmwVvJErsd0d0hAPlj4CxqxUtQY/fOoY0DwX4ykpRY= github.com/sajari/fuzzy v1.0.0/go.mod h1:OjYR6KxoWOe9+dOlXeiCJd4dIbED4Oo8wpS89o0pwOo= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= -github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= +github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -358,16 +355,12 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8= github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/wailsapp/go-webview2 v1.0.9 h1:lrU+q0cf1wgLdR69rN+ZnRtMJNaJRrcQ4ELxoO7/xjs= github.com/wailsapp/go-webview2 v1.0.9/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo= github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs= github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -375,8 +368,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= @@ -386,18 +377,19 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= +golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -435,6 +427,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -465,12 +458,14 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -487,10 +482,10 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -502,6 +497,7 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -521,8 +517,6 @@ golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -531,19 +525,24 @@ golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -551,9 +550,11 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -600,8 +601,9 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -689,7 +691,6 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -698,7 +699,6 @@ gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/v3/internal/assetserver/assethandler.go b/v3/internal/assetserver/assethandler.go index 9b6d1135..253dd269 100644 --- a/v3/internal/assetserver/assethandler.go +++ b/v3/internal/assetserver/assethandler.go @@ -14,9 +14,6 @@ import ( "strings" ) -//go:embed defaultindex.html -var defaultHTML []byte - const ( indexHTML = "index.html" ) @@ -30,7 +27,7 @@ type assetHandler struct { retryMissingFiles bool } -func NewAssetHandler(options *Options, log *slog.Logger) (http.Handler, error) { +func NewDefaultAssetHandler(options *Options) (http.Handler, error) { vfs := options.Assets if vfs != nil { @@ -62,7 +59,7 @@ func NewAssetHandler(options *Options, log *slog.Logger) (http.Handler, error) { var result http.Handler = &assetHandler{ fs: vfs, handler: options.Handler, - logger: log, + logger: options.Logger, } if middleware := options.Middleware; middleware != nil { diff --git a/v3/internal/assetserver/assethandler_external.go b/v3/internal/assetserver/assethandler_external.go deleted file mode 100644 index 44bc79e5..00000000 --- a/v3/internal/assetserver/assethandler_external.go +++ /dev/null @@ -1,79 +0,0 @@ -//go:build dev -// +build dev - -package assetserver - -import ( - "errors" - "fmt" - "log/slog" - "net/http" - "net/http/httputil" - "net/url" -) - -func NewExternalAssetsHandler(logger *slog.Logger, options Options, url *url.URL) http.Handler { - baseHandler := options.Handler - - errSkipProxy := fmt.Errorf("skip proxying") - - proxy := httputil.NewSingleHostReverseProxy(url) - baseDirector := proxy.Director - proxy.Director = func(r *http.Request) { - baseDirector(r) - if logger != nil { - logger.Debug("[ExternalAssetHandler] Loading '%s'", r.URL) - } - } - - proxy.ModifyResponse = func(res *http.Response) error { - if baseHandler == nil { - return nil - } - - if res.StatusCode == http.StatusSwitchingProtocols { - return nil - } - - if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusMethodNotAllowed { - return errSkipProxy - } - - return nil - } - - proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) { - if baseHandler != nil && errors.Is(err, errSkipProxy) { - if logger != nil { - logger.Debug("[ExternalAssetHandler] Loading '%s' failed, using original AssetHandler", r.URL) - } - baseHandler.ServeHTTP(rw, r) - } else { - if logger != nil { - logger.Error("[ExternalAssetHandler] Proxy error: %v", err) - } - rw.WriteHeader(http.StatusBadGateway) - } - } - - var result http.Handler = http.HandlerFunc( - func(rw http.ResponseWriter, req *http.Request) { - if req.Method == http.MethodGet { - proxy.ServeHTTP(rw, req) - return - } - - if baseHandler != nil { - baseHandler.ServeHTTP(rw, req) - return - } - - rw.WriteHeader(http.StatusMethodNotAllowed) - }) - - if middleware := options.Middleware; middleware != nil { - result = middleware(result) - } - - return result -} diff --git a/v3/internal/assetserver/assetserver.go b/v3/internal/assetserver/assetserver.go index dc0785ca..4d5f0449 100644 --- a/v3/internal/assetserver/assetserver.go +++ b/v3/internal/assetserver/assetserver.go @@ -1,157 +1,60 @@ package assetserver import ( - "bytes" "fmt" - "log/slog" - "math/rand" - "net" + "html" "net/http" "net/http/httptest" "net/http/httputil" - "net/url" "strings" "time" - - "golang.org/x/net/html" ) const ( - runtimeJSPath = "/wails/runtime.js" runtimePath = "/wails/runtime" capabilitiesPath = "/wails/capabilities" flagsPath = "/wails/flags" + + webViewRequestHeaderWindowId = "x-wails-window-id" + webViewRequestHeaderWindowName = "x-wails-window-name" ) -const webViewRequestHeaderWindowId = "x-wails-window-id" -const webViewRequestHeaderWindowName = "x-wails-window-name" - -type RuntimeAssets interface { - DesktopIPC() []byte - WebsocketIPC() []byte - RuntimeDesktopJS() []byte -} - type RuntimeHandler interface { HandleRuntimeCall(w http.ResponseWriter, r *http.Request) } type AssetServer struct { - handler http.Handler - runtimeJS []byte - debug bool - ipcJS func(*http.Request) []byte - - logger *slog.Logger - runtime RuntimeAssets options *Options - servingFromDisk bool - - // Use http based runtime - runtimeHandler RuntimeHandler - - // plugin scripts - pluginScripts map[string]string - - // GetCapabilities returns the capabilities of the runtime - GetCapabilities func() []byte - - // GetFlags returns the application flags - GetFlags func() []byte - - // External dev server proxy + handler http.Handler wsHandler *httputil.ReverseProxy - // External dev server URL + pluginScripts map[string]string + devServerURL string assetServerWebView } -func NewAssetServer(options *Options, servingFromDisk bool, logger *slog.Logger, runtime RuntimeAssets, debug bool, runtimeHandler RuntimeHandler) (*AssetServer, error) { - handler, err := NewAssetHandler(options, logger) +func NewAssetServer(options *Options) (*AssetServer, error) { + result := &AssetServer{ + options: options, + } + + var err error + result.handler, err = result.setupHandler() if err != nil { return nil, err } - var buffer bytes.Buffer - buffer.Write(runtime.RuntimeDesktopJS()) - - result := &AssetServer{ - handler: handler, - runtimeJS: buffer.Bytes(), - runtimeHandler: runtimeHandler, - options: options, - - // Check if we have been given a directory to serve assets from. - // If so, this means we are in dev mode and are serving assets off disk. - // We indicate this through the `servingFromDisk` flag to ensure requests - // aren't cached in dev mode. - servingFromDisk: servingFromDisk, - logger: logger, - runtime: runtime, - debug: debug, - } - - // Check if proxy required - result.devServerURL = GetDevServerURL() - if result.devServerURL != "" { - logger.Info("Using External DevServer", "url", result.devServerURL) - // Parse devServerURL into url.URL - devServerURL, err := url.Parse(result.devServerURL) - if err != nil { - return nil, err - } - err = result.checkDevServerURL(devServerURL) - if err != nil { - return nil, err - } - result.wsHandler = httputil.NewSingleHostReverseProxy(devServerURL) - } return result, nil } -func (d *AssetServer) checkDevServerURL(devServerURL *url.URL) error { - // Open a connection to the devserver URL - hostPort := devServerURL.Hostname() + ":" + devServerURL.Port() - _, err := net.DialTimeout("tcp", hostPort, 1*time.Second) - if err != nil { - return fmt.Errorf("unable to connect to dev server: %s. Please check it's running", d.devServerURL) - } - return nil -} - -func (d *AssetServer) LogDetails() { - if d.debug { - var info = []any{ - "assetsFS", d.options.Assets != nil, - "middleware", d.options.Middleware != nil, - "handler", d.options.Handler != nil, - "devServerURL", d.devServerURL, - } - if d.devServerURL != "" { - info = append(info, "devServerURL", d.devServerURL) - } - d.logger.Info("AssetServer Info:", info...) - } -} - -func (d *AssetServer) AddPluginScript(pluginName string, script string) { - if d.pluginScripts == nil { - d.pluginScripts = make(map[string]string) - } - pluginName = strings.ReplaceAll(pluginName, "/", "_") - pluginName = html.EscapeString(pluginName) - pluginScriptName := fmt.Sprintf("/plugin_%s_%d.js", pluginName, rand.Intn(100000)) - d.pluginScripts[pluginScriptName] = script -} - -func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { +func (a *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { start := time.Now() wrapped := &contentTypeSniffer{rw: rw} - d.serveHTTP(wrapped, req) - d.logger.Info( + a.serveHTTP(wrapped, req) + a.options.Logger.Info( "Asset Request:", "windowName", req.Header.Get(webViewRequestHeaderWindowName), "windowID", req.Header.Get(webViewRequestHeaderWindowId), @@ -162,10 +65,10 @@ func (d *AssetServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { ) } -func (d *AssetServer) serveHTTP(rw http.ResponseWriter, req *http.Request) { +func (a *AssetServer) serveHTTP(rw http.ResponseWriter, req *http.Request) { - if d.wsHandler != nil { - d.wsHandler.ServeHTTP(rw, req) + if a.wsHandler != nil { + a.wsHandler.ServeHTTP(rw, req) return } else { if isWebSocket(req) { @@ -176,30 +79,26 @@ func (d *AssetServer) serveHTTP(rw http.ResponseWriter, req *http.Request) { } header := rw.Header() - if d.servingFromDisk { - header.Add(HeaderCacheControl, "no-cache") - } + // TODO: I don't think this is needed now? + //if a.servingFromDisk { + // header.Add(HeaderCacheControl, "no-cache") + //} path := req.URL.Path switch path { case "", "/", "/index.html": recorder := httptest.NewRecorder() - d.handler.ServeHTTP(recorder, req) + a.handler.ServeHTTP(recorder, req) for k, v := range recorder.Result().Header { header[k] = v } switch recorder.Code { case http.StatusOK: - content, err := d.processIndexHTML(recorder.Body.Bytes()) - if err != nil { - d.serveError(rw, err, "Unable to processIndexHTML") - return - } - d.writeBlob(rw, indexHTML, content) + a.writeBlob(rw, indexHTML, recorder.Body.Bytes()) case http.StatusNotFound: - d.writeBlob(rw, indexHTML, defaultHTML) + a.writeBlob(rw, indexHTML, defaultIndexHTML()) default: rw.WriteHeader(recorder.Code) @@ -207,83 +106,62 @@ func (d *AssetServer) serveHTTP(rw http.ResponseWriter, req *http.Request) { } return - case runtimeJSPath: - d.writeBlob(rw, path, d.runtimeJS) - case capabilitiesPath: - var data = []byte("{}") - if d.GetCapabilities != nil { - data = d.GetCapabilities() - } - d.writeBlob(rw, path, data) + var data = a.options.GetCapabilities() + a.writeBlob(rw, path, data) case flagsPath: - var data = []byte("{}") - if d.GetFlags != nil { - data = d.GetFlags() - } - d.writeBlob(rw, path, data) + var data = a.options.GetFlags() + a.writeBlob(rw, path, data) case runtimePath: - d.runtimeHandler.HandleRuntimeCall(rw, req) + a.options.RuntimeHandler.ServeHTTP(rw, req) return default: // Check if this is a plugin script - if script, ok := d.pluginScripts[path]; ok { - d.writeBlob(rw, path, []byte(script)) + if script, ok := a.pluginScripts[path]; ok { + a.writeBlob(rw, path, []byte(script)) } else { - d.handler.ServeHTTP(rw, req) + a.handler.ServeHTTP(rw, req) return } } } -func (d *AssetServer) processIndexHTML(indexHTML []byte) ([]byte, error) { - htmlNode, err := getHTMLNode(indexHTML) - if err != nil { - return nil, err - } - - if d.debug { - err = appendSpinnerToBody(htmlNode) - if err != nil { - return nil, err - } - } - - // Inject plugins - for scriptName := range d.pluginScripts { - if err := insertScriptInHead(htmlNode, scriptName); err != nil { - return nil, err - } - } - - var buffer bytes.Buffer - err = html.Render(&buffer, htmlNode) - if err != nil { - return nil, err - } - return buffer.Bytes(), nil -} - -func (d *AssetServer) writeBlob(rw http.ResponseWriter, filename string, blob []byte) { +func (a *AssetServer) writeBlob(rw http.ResponseWriter, filename string, blob []byte) { err := serveFile(rw, filename, blob) if err != nil { - d.serveError(rw, err, "Unable to write content %s", filename) + a.serveError(rw, err, "Unable to write content %s", filename) } } -func (d *AssetServer) serveError(rw http.ResponseWriter, err error, msg string, args ...interface{}) { +func (a *AssetServer) serveError(rw http.ResponseWriter, err error, msg string, args ...interface{}) { args = append(args, err) - d.logError(msg+": %s", args...) + a.options.Logger.Error(msg+":", args...) rw.WriteHeader(http.StatusInternalServerError) } -func (d *AssetServer) logInfo(message string, args ...interface{}) { - d.logger.Info("Asset Request: "+message, args...) +func (a *AssetServer) LogDetails() { + if a.options.IsDebug { + var info = []any{ + "assetsFS", a.options.Assets != nil, + "middleware", a.options.Middleware != nil, + "handler", a.options.Handler != nil, + } + if a.devServerURL != "" { + info = append(info, "devServerURL", a.devServerURL) + } + a.options.Logger.Info("AssetServer Info:", info...) + } } -func (d *AssetServer) logError(message string, args ...interface{}) { - d.logger.Error("Asset Request: "+message, args...) +func (a *AssetServer) AddPluginScript(pluginName string, script string) { + if a.pluginScripts == nil { + a.pluginScripts = make(map[string]string) + } + pluginName = strings.ReplaceAll(pluginName, "/", "_") + pluginName = html.EscapeString(pluginName) + pluginScriptName := fmt.Sprintf("/wails/plugin/%s.js", pluginName) + a.pluginScripts[pluginScriptName] = script } diff --git a/v3/internal/assetserver/assetserver_dev.go b/v3/internal/assetserver/assetserver_dev.go deleted file mode 100644 index c7dde514..00000000 --- a/v3/internal/assetserver/assetserver_dev.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !production - -package assetserver - -import ( - "os" -) - -func GetDevServerURL() string { - return os.Getenv("WAILS_DEVSERVER_URL") -} diff --git a/v3/internal/assetserver/assetserver_production.go b/v3/internal/assetserver/assetserver_production.go deleted file mode 100644 index f87a5a78..00000000 --- a/v3/internal/assetserver/assetserver_production.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build production - -package assetserver - -func GetDevServerURL() string { - return "" -} diff --git a/v3/internal/assetserver/assetserver_webview.go b/v3/internal/assetserver/assetserver_webview.go index 66bc9597..f0961796 100644 --- a/v3/internal/assetserver/assetserver_webview.go +++ b/v3/internal/assetserver/assetserver_webview.go @@ -23,9 +23,9 @@ type assetServerWebView struct { // ServeWebViewRequest processes the HTTP Request asynchronously by faking a golang HTTP Server. // The request will be finished with a StatusNotImplemented code if no handler has written to the response. // The AssetServer takes ownership of the request and the caller mustn't close it or access it in any other way. -func (d *AssetServer) ServeWebViewRequest(req webview.Request) { - d.dispatchInit.Do(func() { - workers := d.dispatchWorkers +func (a *AssetServer) ServeWebViewRequest(req webview.Request) { + a.dispatchInit.Do(func() { + workers := a.dispatchWorkers if workers <= 0 { return } @@ -34,7 +34,7 @@ func (d *AssetServer) ServeWebViewRequest(req webview.Request) { for i := 0; i < workers; i++ { go func() { for req := range workerC { - d.processWebViewRequest(req) + a.processWebViewRequest(req) } }() } @@ -42,34 +42,34 @@ func (d *AssetServer) ServeWebViewRequest(req webview.Request) { dispatchC := make(chan webview.Request) go queueingDispatcher(50, dispatchC, workerC) - d.dispatchReqC = dispatchC + a.dispatchReqC = dispatchC }) - if d.dispatchReqC == nil { - go d.processWebViewRequest(req) + if a.dispatchReqC == nil { + go a.processWebViewRequest(req) } else { - d.dispatchReqC <- req + a.dispatchReqC <- req } } -func (d *AssetServer) processWebViewRequest(r webview.Request) { +func (a *AssetServer) processWebViewRequest(r webview.Request) { uri, _ := r.URL() - d.processWebViewRequestInternal(r) + a.processWebViewRequestInternal(r) if err := r.Close(); err != nil { - d.logError("Unable to call close for request for uri '%s'", uri) + a.options.Logger.Error("Unable to call close for request for uri '%s'", uri) } } // processHTTPRequest processes the HTTP Request by faking a golang HTTP Server. // The request will be finished with a StatusNotImplemented code if no handler has written to the response. -func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { +func (a *AssetServer) processWebViewRequestInternal(r webview.Request) { uri := "unknown" var err error wrw := r.Response() defer func() { if err := wrw.Finish(); err != nil { - d.logError("Error finishing request '%s': %s", uri, err) + a.options.Logger.Error("Error finishing request '%s': %s", uri, err) } }() @@ -78,26 +78,26 @@ func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { uri, err = r.URL() if err != nil { - d.logError("Error processing request, unable to get URL: %s (HttpResponse=500)", err) + a.options.Logger.Error("Error processing request, unable to get URL: %s (HttpResponse=500)", err) http.Error(rw, err.Error(), http.StatusInternalServerError) return } method, err := r.Method() if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Method: %w", err)) + a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Method: %w", err)) return } header, err := r.Header() if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Header: %w", err)) + a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Header: %w", err)) return } body, err := r.Body() if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Body: %w", err)) + a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Body: %w", err)) return } @@ -108,7 +108,7 @@ func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { req, err := http.NewRequest(method, uri, body) if err != nil { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Request: %w", err)) + a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("HTTP-Request: %w", err)) return } @@ -119,8 +119,8 @@ func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { req.URL.Fragment = "" req.URL.RawFragment = "" - if url := req.URL; req.RequestURI == "" && url != nil { - req.RequestURI = url.String() + if requestURL := req.URL; req.RequestURI == "" && requestURL != nil { + req.RequestURI = requestURL.String() } req.Header = header @@ -137,28 +137,28 @@ func (d *AssetServer) processWebViewRequestInternal(r webview.Request) { if req.ContentLength == 0 { req.ContentLength, _ = strconv.ParseInt(req.Header.Get(HeaderContentLength), 10, 64) } else { - req.Header.Set(HeaderContentLength, fmt.Sprintf("%d", req.ContentLength)) + req.Header.Set(HeaderContentLength, fmt.Sprintf("%a", req.ContentLength)) } if host := req.Header.Get(HeaderHost); host != "" { req.Host = host } - if expectedHost := d.ExpectedWebViewHost; expectedHost != "" && expectedHost != req.Host { - d.webviewRequestErrorHandler(uri, rw, fmt.Errorf("expected host '%s' in request, but was '%s'", expectedHost, req.Host)) + if expectedHost := a.ExpectedWebViewHost; expectedHost != "" && expectedHost != req.Host { + a.webviewRequestErrorHandler(uri, rw, fmt.Errorf("expected host '%s' in request, but was '%s'", expectedHost, req.Host)) return } - d.ServeHTTP(rw, req) + a.ServeHTTP(rw, req) } -func (d *AssetServer) webviewRequestErrorHandler(uri string, rw http.ResponseWriter, err error) { +func (a *AssetServer) webviewRequestErrorHandler(uri string, rw http.ResponseWriter, err error) { logInfo := uri if uri, err := url.ParseRequestURI(uri); err == nil { logInfo = strings.Replace(logInfo, fmt.Sprintf("%s://%s", uri.Scheme, uri.Host), "", 1) } - d.logError("Error processing request (HttpResponse=500)", "details", logInfo, "error", err.Error()) + a.options.Logger.Error("Error processing request (HttpResponse=500)", "details", logInfo, "error", err.Error()) http.Error(rw, err.Error(), http.StatusInternalServerError) } diff --git a/v3/internal/assetserver/build_dev.go b/v3/internal/assetserver/build_dev.go new file mode 100644 index 00000000..cd84afb3 --- /dev/null +++ b/v3/internal/assetserver/build_dev.go @@ -0,0 +1,103 @@ +//go:build !production + +package assetserver + +import ( + _ "embed" + "errors" + "fmt" + "net/http" + "net/http/httputil" + "net/url" + "os" +) + +//go:embed defaultindex.html +var defaultHTML []byte + +func defaultIndexHTML() []byte { + return defaultHTML +} + +func (a *AssetServer) setupHandler() (http.Handler, error) { + + // Do we have an external dev server URL? + a.devServerURL = GetDevServerURL() + if a.devServerURL == "" { + return NewDefaultAssetHandler(a.options) + } + + // Parse the URL + parsedURL, err := url.Parse(a.devServerURL) + if err != nil { + return nil, fmt.Errorf("invalid FRONTEND_DEVSERVER_URL. Should be valid URL: %s", err.Error()) + } + + baseHandler := a.options.Handler + + errSkipProxy := fmt.Errorf("skip proxying") + + proxy := httputil.NewSingleHostReverseProxy(parsedURL) + baseDirector := proxy.Director + proxy.Director = func(r *http.Request) { + baseDirector(r) + if a.options.Logger != nil { + a.options.Logger.Debug("ExternalAssetHandler: loading", "url", r.URL) + } + } + + proxy.ModifyResponse = func(res *http.Response) error { + if baseHandler == nil { + return nil + } + + if res.StatusCode == http.StatusSwitchingProtocols { + return nil + } + + if res.StatusCode == http.StatusNotFound || res.StatusCode == http.StatusMethodNotAllowed { + return errSkipProxy + } + + return nil + } + + proxy.ErrorHandler = func(rw http.ResponseWriter, r *http.Request, err error) { + if baseHandler != nil && errors.Is(err, errSkipProxy) { + if a.options.Logger != nil { + a.options.Logger.Debug("ExternalAssetHandler: Loading file failed, using original AssetHandler", "url", r.URL) + } + baseHandler.ServeHTTP(rw, r) + } else { + if a.options.Logger != nil { + a.options.Logger.Error("ExternalAssetHandler: Proxy error", "error", err.Error()) + } + rw.WriteHeader(http.StatusBadGateway) + } + } + + var result http.Handler = http.HandlerFunc( + func(rw http.ResponseWriter, req *http.Request) { + if req.Method == http.MethodGet { + proxy.ServeHTTP(rw, req) + return + } + + if baseHandler != nil { + baseHandler.ServeHTTP(rw, req) + return + } + + rw.WriteHeader(http.StatusMethodNotAllowed) + }) + + if middleware := a.options.Middleware; middleware != nil { + result = middleware(result) + } + + return result, nil +} + +func GetDevServerURL() string { + return os.Getenv("FRONTEND_DEVSERVER_URL") +} diff --git a/v3/internal/assetserver/build_production.go b/v3/internal/assetserver/build_production.go new file mode 100644 index 00000000..0f858faf --- /dev/null +++ b/v3/internal/assetserver/build_production.go @@ -0,0 +1,17 @@ +//go:build production + +package assetserver + +import "net/http" + +func defaultIndexHTML() []byte { + return []byte{} +} + +func (a *AssetServer) setupHandler() (http.Handler, error) { + return NewDefaultAssetHandler(a.options) +} + +func GetDevServerURL() string { + return "" +} diff --git a/v3/internal/assetserver/common.go b/v3/internal/assetserver/common.go index b787cc6b..484858cf 100644 --- a/v3/internal/assetserver/common.go +++ b/v3/internal/assetserver/common.go @@ -2,13 +2,10 @@ package assetserver import ( "bytes" - "errors" "fmt" "io" "net/http" "strings" - - "golang.org/x/net/html" ) const ( @@ -16,8 +13,9 @@ const ( HeaderContentType = "Content-Type" HeaderContentLength = "Content-Length" HeaderUserAgent = "User-Agent" - HeaderCacheControl = "Cache-Control" - HeaderUpgrade = "Upgrade" + // TODO: Is this needed? + HeaderCacheControl = "Cache-Control" + HeaderUpgrade = "Upgrade" WailsUserAgentValue = "wails.io" ) @@ -35,80 +33,6 @@ func serveFile(rw http.ResponseWriter, filename string, blob []byte) error { return err } -func createScriptNode(scriptName string) *html.Node { - return &html.Node{ - Type: html.ElementNode, - Data: "script", - Attr: []html.Attribute{ - { - Key: "src", - Val: scriptName, - }, - }, - } -} - -func createDivNode(id string) *html.Node { - return &html.Node{ - Type: html.ElementNode, - Data: "div", - Attr: []html.Attribute{ - { - Namespace: "", - Key: "id", - Val: id, - }, - }, - } -} - -func insertScriptInHead(htmlNode *html.Node, scriptName string) error { - headNode := findFirstTag(htmlNode, "head") - if headNode == nil { - return errors.New("cannot find head in HTML") - } - scriptNode := createScriptNode(scriptName) - if headNode.FirstChild != nil { - headNode.InsertBefore(scriptNode, headNode.FirstChild) - } else { - headNode.AppendChild(scriptNode) - } - return nil -} - -func appendSpinnerToBody(htmlNode *html.Node) error { - bodyNode := findFirstTag(htmlNode, "body") - if bodyNode == nil { - return errors.New("cannot find body in HTML") - } - scriptNode := createDivNode("wails-spinner") - bodyNode.AppendChild(scriptNode) - return nil -} - -func getHTMLNode(htmldata []byte) (*html.Node, error) { - return html.Parse(bytes.NewReader(htmldata)) -} - -func findFirstTag(htmlnode *html.Node, tagName string) *html.Node { - var extractor func(*html.Node) *html.Node - var result *html.Node - extractor = func(node *html.Node) *html.Node { - if node.Type == html.ElementNode && node.Data == tagName { - return node - } - for child := node.FirstChild; child != nil; child = child.NextSibling { - result := extractor(child) - if result != nil { - return result - } - } - return nil - } - result = extractor(htmlnode) - return result -} - func isWebSocket(req *http.Request) bool { upgrade := req.Header.Get(HeaderUpgrade) return strings.EqualFold(upgrade, "websocket") diff --git a/v3/internal/assetserver/fs.go b/v3/internal/assetserver/fs.go index 7ecc9cec..65f24ed7 100644 --- a/v3/internal/assetserver/fs.go +++ b/v3/internal/assetserver/fs.go @@ -2,6 +2,7 @@ package assetserver import ( "embed" + "errors" "fmt" "io/fs" "os" @@ -10,18 +11,18 @@ import ( ) // FindEmbedRootPath finds the root path in the embed FS. It's the directory which contains all the files. -func FindEmbedRootPath(fsys embed.FS) (string, error) { +func FindEmbedRootPath(fileSystem embed.FS) (string, error) { stopErr := fmt.Errorf("files or multiple dirs found") fPath := "" - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() { fPath = path - if entries, dErr := fs.ReadDir(fsys, path); dErr != nil { + if entries, dErr := fs.ReadDir(fileSystem, path); dErr != nil { return dErr } else if len(entries) <= 1 { return nil @@ -31,20 +32,20 @@ func FindEmbedRootPath(fsys embed.FS) (string, error) { return stopErr }) - if err != nil && err != stopErr { + if err != nil && !errors.Is(err, stopErr) { return "", err } return fPath, nil } -func FindPathToFile(fsys fs.FS, file string) (string, error) { - stat, _ := fs.Stat(fsys, file) +func FindPathToFile(fileSystem fs.FS, file string) (string, error) { + stat, _ := fs.Stat(fileSystem, file) if stat != nil { return ".", nil } var indexFiles []string - err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } diff --git a/v3/internal/assetserver/mimecache.go b/v3/internal/assetserver/mimecache.go index 9d97e8f5..c43de519 100644 --- a/v3/internal/assetserver/mimecache.go +++ b/v3/internal/assetserver/mimecache.go @@ -15,8 +15,8 @@ var ( // The list of builtin mime-types by extension as defined by // the golang standard lib package "mime" // The standard lib also takes into account mime type definitions from - // etc files like '/etc/apache2/mime.types' but we want to have the - // same behavivour on all platforms and not depend on some external file. + // /etc files like '/etc/apache2/mime.types' but we want to have the + // same behaviour on all platforms and not depend on some external file. mimeTypesByExt = map[string]string{ ".avif": "image/avif", ".css": "text/css; charset=utf-8", diff --git a/v3/internal/assetserver/options.go b/v3/internal/assetserver/options.go index 674451a0..0a3e8530 100644 --- a/v3/internal/assetserver/options.go +++ b/v3/internal/assetserver/options.go @@ -3,6 +3,7 @@ package assetserver import ( "fmt" "io/fs" + "log/slog" "net/http" ) @@ -33,6 +34,21 @@ type Options struct { // Multiple Middlewares can be chained together with: // ChainMiddleware(middleware ...Middleware) Middleware Middleware Middleware + + // Logger is the logger used by the AssetServer. If not defined, no logging will be done. + Logger *slog.Logger + + // RuntimeHandler is the handler used for the runtime calls. + RuntimeHandler http.Handler + + // GetCapabilities returns the capabilities of the runtime + GetCapabilities func() []byte + + // GetFlags returns the application flags + GetFlags func() []byte + + // IsDebug is true if the server is running in debug mode + IsDebug bool } // Validate the options diff --git a/v3/internal/assetserver/testdata/index.html b/v3/internal/assetserver/testdata/index.html deleted file mode 100644 index 76da518f..00000000 --- a/v3/internal/assetserver/testdata/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/v3/internal/assetserver/testdata/main.css b/v3/internal/assetserver/testdata/main.css deleted file mode 100644 index 57b00e6c..00000000 --- a/v3/internal/assetserver/testdata/main.css +++ /dev/null @@ -1,39 +0,0 @@ - -html { - text-align: center; - color: white; - background-color: rgba(1, 1, 1, 0.1); -} - -body { - color: white; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - margin: 0; -} - -#result { - margin-top: 1rem; -} - -button { - -webkit-appearance: default-button; - padding: 6px; -} - -#name { - border-radius: 3px; - outline: none; - height: 20px; - -webkit-font-smoothing: antialiased; -} - -#logo { - width: 40%; - height: 40%; - padding-top: 20%; - margin: auto; - display: block; - background-position: center; - background-repeat: no-repeat; - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTUxIDQzNiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMiIgeG1sbnM6dj0iaHR0cHM6Ly92ZWN0YS5pby9uYW5vIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iPjxwYXRoIGQ9Ik0xMDQuMDEgMzQ0LjM4OGgxOC40MDFsLTEuNzY4IDM5LjE2MSAxMi4xNDctMzkuMTYxaDE0Ljg2N2wtLjE4MSAzOS4xNjEgMTAuNTYxLTM5LjE2MWgxOC40MDFsLTIzLjI5NyA2Ni4xNzVoLTE2Ljk5N2wuMTgxLTQxLjM4My0xMi45MTcgNDEuMzgzaC0xNi45NTFsLTIuNDQ3LTY2LjE3NXptMTIwLjk3NSA0My4wNTloNy4zODhsLjIyNy0yNC41MjEtNy42MTUgMjQuNTIxem0tMjUuNzQ0IDIzLjExNmwyNC44ODMtNjYuMTc1aDIxLjgwMWw0LjY2NyA2Ni4xNzVoLTE4LjY3NGwuMDkyLTkuNzQ2aC0xMC45MjRsLTIuOTAxIDkuNzQ2aC0xOC45NDR6bTg4LjE4MyAwbDEwLjQ3LTY2LjE3NmgxOC40OTNsLTEwLjUxNiA2Ni4xNzUtMTguNDQ2LjAwMXptNjUuNzkzIDBsMTAuNTE2LTY2LjE3NWgxOC41MzZsLTcuODg2IDQ5Ljc2NmgxMy41NTJsLTIuNTgyIDE2LjQwOWgtMzIuMTM2em03NC43MjItMjAuMzUyYzIuMDU0IDEuNzIzIDQuMjE1IDMuMDUzIDYuNDgyIDMuOTlzNC40NCAxLjQwNCA2LjUyNiAxLjQwNGMxLjg0MyAwIDMuMzA4LS41MDYgNC4zOTYtMS41MThzMS42MzItMi4zOTUgMS42MzItNC4xNDhjMC0xLjUwOS0uNDU0LTMuMDEzLTEuMzU5LTQuNTA5cy0yLjY2LTMuNDgxLTUuMjU4LTUuOTU5Yy0zLjE0NC0zLjA1Mi01LjMwMy01Ljc0MS02LjQ4Mi04LjA2OXMtMS43NjYtNC44OTQtMS43NjYtNy43MDRjMC02LjMxNSAyLjAwMS0xMS4zMzIgNi4wMDUtMTUuMDQ4czkuNDM0LTUuNTc1IDE2LjI5NC01LjU3NWMyLjc4IDAgNS40MjIuMzEgNy45MzEuOTNzNS4wNiAxLjU3OSA3LjY2MSAyLjg3OGwtMi42MyAxNi4xMzZjLTEuOTk1LTEuMzktMy45MzUtMi40NDctNS44MjMtMy4xNzNzLTMuNjk0LTEuMDg5LTUuNDE3LTEuMDg5Yy0xLjU0MSAwLTIuNzU4LjQtMy42NDkgMS4ycy0xLjMzOCAxLjg5OC0xLjMzOCAzLjI4OGMwIDEuODc1IDEuNzA4IDQuNTAzIDUuMTIzIDcuODg2bC45OTcuOTk2YzMuNDQ1IDMuMzg2IDUuNzExIDYuMjg2IDYuNzk4IDguNzA1czEuNjMxIDUuMjA5IDEuNjMxIDguMzg0YzAgNy4wNzEtMi4xODMgMTIuNjQ2LTYuNTUgMTYuNzI0cy0xMC4zNDEgNi4xMi0xNy45MjUgNi4xMmMtMy4yMzQgMC02LjI5Mi0uMzg1LTkuMTc4LTEuMTU1cy01LjMxLTEuODM4LTcuMjc0LTMuMTk3bDMuMTczLTE3LjQ5NXoiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNLjg4My0uMDgxTC4xMjEuMDgxLjI1Ni0uMDYzLjg4My0uMDgxeiIgZmlsbD0idXJsKCNBKSIgdHJhbnNmb3JtPSJtYXRyaXgoLTE2Ni41OTkgNC41NzEzMiA0LjU3MTMyIDE2Ni41OTkgMTQ3LjQwMyAxNjcuNjQ4KSIvPjxwYXRoIGQ9Ik0uODc4LS4yODVMLS4wNzMuNzEtMS4xODYuNTQyLjAxNS4yMDctLjg0Ni4wNzcuMzU1LS4yNThsLS44Ni0uMTNMLjY0OS0uNzFsLjIyOS40MjV6IiBmaWxsPSJ1cmwoI0IpIiB0cmFuc2Zvcm09Im1hdHJpeCgtMTA2LjQ0MyAtMTYuMDY2OSAtMTYuMDY2OSAxMDYuNDQzIDQyOC4xOSAxODguMDMzKSIvPjxwYXRoIGQ9Ik0uNDQtLjA0aDAgMEwuMjY1LS4wNTYuMTc3LjQzNy0uMzExLS4yNTUuMjYyLS40MzdoLjMwNkwuNDQtLjA0eiIgZmlsbD0idXJsKCNDKSIgdHJhbnNmb3JtPSJtYXRyaXgoLTExNC40ODQgLTE2Mi40MDggLTE2Mi40MDggMTE0LjQ4NCAzMzMuMjkxIDI4NS44MDQpIi8+PHBhdGggZD0iTS41IDBoMCAwIDB6IiBmaWxsPSJ1cmwoI0QpIiB0cmFuc2Zvcm09Im1hdHJpeCg2MS42OTE5IDU4LjgwOTEgNTguODA5MSAtNjEuNjkxOSAyNTguNjMxIDE4MC40MTMpIi8+PHBhdGggZD0iTS42MjItLjExNWguMTM5bC4wNDUuMTAyLjAyLjE5NS0uMjA0LS4yOTd6IiBmaWxsPSJ1cmwoI0UpIiB0cmFuc2Zvcm09Im1hdHJpeCgyMzguMTI2IDI5OC44OTMgMjk4Ljg5MyAtMjM4LjEyNiAxMTMuNTE2IC0xNTAuNTM2KSIvPjxwYXRoIGQ9Ik0uNDY3LjAwNUwuNDkuMDYyLjI3MS0uMDYyLjQ2Ny4wMDV6IiBmaWxsPSJ1cmwoI0YpIiB0cmFuc2Zvcm09Im1hdHJpeCgtMzY5LjUyOSAtOTcuNDExOCAtOTcuNDExOCAzNjkuNTI5IDU4Mi4zOCA5NC4wMjcpIi8+PGcgZmlsbD0idXJsKCNCKSI+PHBhdGggZD0iTS4yLjAwMWwuMDE5LS4wMTkuMzk1LjAzLS4wOTUuMDc3TC4yODIuMDY4LjIuMTM1LjQ2My4xOTQuMzc0LjI2Ni4xMzguMTg2aDAgMEwuMDQ3LjAzMy0uMTMxLS4yNjYuMi4wMDF6IiB0cmFuc2Zvcm09Im1hdHJpeCgtNDk2LjE1NiAtNTMuOTc1MSAtNTMuOTc1MSA0OTYuMTU2IDM2Ny44ODggMTI1LjA4NSkiLz48cGF0aCBkPSJNLjczNSAwaDAgMCAweiIgdHJhbnNmb3JtPSJtYXRyaXgoMTg1LjA3NiAxNzYuNDI3IDE3Ni40MjcgLTE4NS4wNzYgMTUzLjQ0NiA4MC4xNDg4KSIvPjwvZz48L2c+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJBIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLC0zLjQ2OTQ1ZS0xOCwtMy40Njk0NWUtMTgsLTEsMCwtMy4wNTc2MWUtMDYpIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkIiIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIwIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkMiIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIwIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsLTEuMTEwMjJlLTE2LC0xLjExMDIyZS0xNiwtMSwwLC0yLjYxODYxZS0wNikiIHhsaW5rOmhyZWY9IiNHIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNlMzMyMzIiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM2YjAwMGQiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iRCIgeDE9IjAiIHkxPSIwIiB4Mj0iMSIgeTI9IjAiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwtNS41NTExMmUtMTcsLTUuNTUxMTJlLTE3LC0xLDAsLTEuNTc1NjJlLTA2KSIgeGxpbms6aHJlZj0iI0ciPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2UzMzIzMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzZiMDAwZCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJFIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MDE4OTksLTAuNTk3NDYsLTAuNTk3NDYsMC44MDE4OTksMS4zNDk1LDAuNDQ3NDU3KSIgeGxpbms6aHJlZj0iI0ciPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2UzMzIzMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzZiMDAwZCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJGIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLC0yLjc3NTU2ZS0xNywtMi43NzU1NmUtMTcsLTEsMCwtMS45MjgyNmUtMDYpIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIi8+PC9kZWZzPjwvc3ZnPg=="); -} diff --git a/v3/internal/assetserver/testdata/main.js b/v3/internal/assetserver/testdata/main.js deleted file mode 100644 index 274b4667..00000000 --- a/v3/internal/assetserver/testdata/main.js +++ /dev/null @@ -1,20 +0,0 @@ -import {ready} from '@wails/runtime'; - -ready(() => { - // Get input + focus - let nameElement = document.getElementById("name"); - nameElement.focus(); - - // Setup the greet function - window.greet = function () { - - // Get name - let name = nameElement.value; - - // Call App.Greet(name) - window.backend.main.App.Greet(name).then((result) => { - // Update result with data back from App.Greet() - document.getElementById("result").innerText = result; - }); - }; -}); \ No newline at end of file diff --git a/v3/internal/assetserver/testdata/subdir/index.html b/v3/internal/assetserver/testdata/subdir/index.html deleted file mode 100644 index 76da518f..00000000 --- a/v3/internal/assetserver/testdata/subdir/index.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/v3/internal/assetserver/testdata/subdir/main.css b/v3/internal/assetserver/testdata/subdir/main.css deleted file mode 100644 index 57b00e6c..00000000 --- a/v3/internal/assetserver/testdata/subdir/main.css +++ /dev/null @@ -1,39 +0,0 @@ - -html { - text-align: center; - color: white; - background-color: rgba(1, 1, 1, 0.1); -} - -body { - color: white; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; - margin: 0; -} - -#result { - margin-top: 1rem; -} - -button { - -webkit-appearance: default-button; - padding: 6px; -} - -#name { - border-radius: 3px; - outline: none; - height: 20px; - -webkit-font-smoothing: antialiased; -} - -#logo { - width: 40%; - height: 40%; - padding-top: 20%; - margin: auto; - display: block; - background-position: center; - background-repeat: no-repeat; - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNTUxIDQzNiIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbWl0ZXJsaW1pdD0iMiIgeG1sbnM6dj0iaHR0cHM6Ly92ZWN0YS5pby9uYW5vIj48ZyBmaWxsLXJ1bGU9Im5vbnplcm8iPjxwYXRoIGQ9Ik0xMDQuMDEgMzQ0LjM4OGgxOC40MDFsLTEuNzY4IDM5LjE2MSAxMi4xNDctMzkuMTYxaDE0Ljg2N2wtLjE4MSAzOS4xNjEgMTAuNTYxLTM5LjE2MWgxOC40MDFsLTIzLjI5NyA2Ni4xNzVoLTE2Ljk5N2wuMTgxLTQxLjM4My0xMi45MTcgNDEuMzgzaC0xNi45NTFsLTIuNDQ3LTY2LjE3NXptMTIwLjk3NSA0My4wNTloNy4zODhsLjIyNy0yNC41MjEtNy42MTUgMjQuNTIxem0tMjUuNzQ0IDIzLjExNmwyNC44ODMtNjYuMTc1aDIxLjgwMWw0LjY2NyA2Ni4xNzVoLTE4LjY3NGwuMDkyLTkuNzQ2aC0xMC45MjRsLTIuOTAxIDkuNzQ2aC0xOC45NDR6bTg4LjE4MyAwbDEwLjQ3LTY2LjE3NmgxOC40OTNsLTEwLjUxNiA2Ni4xNzUtMTguNDQ2LjAwMXptNjUuNzkzIDBsMTAuNTE2LTY2LjE3NWgxOC41MzZsLTcuODg2IDQ5Ljc2NmgxMy41NTJsLTIuNTgyIDE2LjQwOWgtMzIuMTM2em03NC43MjItMjAuMzUyYzIuMDU0IDEuNzIzIDQuMjE1IDMuMDUzIDYuNDgyIDMuOTlzNC40NCAxLjQwNCA2LjUyNiAxLjQwNGMxLjg0MyAwIDMuMzA4LS41MDYgNC4zOTYtMS41MThzMS42MzItMi4zOTUgMS42MzItNC4xNDhjMC0xLjUwOS0uNDU0LTMuMDEzLTEuMzU5LTQuNTA5cy0yLjY2LTMuNDgxLTUuMjU4LTUuOTU5Yy0zLjE0NC0zLjA1Mi01LjMwMy01Ljc0MS02LjQ4Mi04LjA2OXMtMS43NjYtNC44OTQtMS43NjYtNy43MDRjMC02LjMxNSAyLjAwMS0xMS4zMzIgNi4wMDUtMTUuMDQ4czkuNDM0LTUuNTc1IDE2LjI5NC01LjU3NWMyLjc4IDAgNS40MjIuMzEgNy45MzEuOTNzNS4wNiAxLjU3OSA3LjY2MSAyLjg3OGwtMi42MyAxNi4xMzZjLTEuOTk1LTEuMzktMy45MzUtMi40NDctNS44MjMtMy4xNzNzLTMuNjk0LTEuMDg5LTUuNDE3LTEuMDg5Yy0xLjU0MSAwLTIuNzU4LjQtMy42NDkgMS4ycy0xLjMzOCAxLjg5OC0xLjMzOCAzLjI4OGMwIDEuODc1IDEuNzA4IDQuNTAzIDUuMTIzIDcuODg2bC45OTcuOTk2YzMuNDQ1IDMuMzg2IDUuNzExIDYuMjg2IDYuNzk4IDguNzA1czEuNjMxIDUuMjA5IDEuNjMxIDguMzg0YzAgNy4wNzEtMi4xODMgMTIuNjQ2LTYuNTUgMTYuNzI0cy0xMC4zNDEgNi4xMi0xNy45MjUgNi4xMmMtMy4yMzQgMC02LjI5Mi0uMzg1LTkuMTc4LTEuMTU1cy01LjMxLTEuODM4LTcuMjc0LTMuMTk3bDMuMTczLTE3LjQ5NXoiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNLjg4My0uMDgxTC4xMjEuMDgxLjI1Ni0uMDYzLjg4My0uMDgxeiIgZmlsbD0idXJsKCNBKSIgdHJhbnNmb3JtPSJtYXRyaXgoLTE2Ni41OTkgNC41NzEzMiA0LjU3MTMyIDE2Ni41OTkgMTQ3LjQwMyAxNjcuNjQ4KSIvPjxwYXRoIGQ9Ik0uODc4LS4yODVMLS4wNzMuNzEtMS4xODYuNTQyLjAxNS4yMDctLjg0Ni4wNzcuMzU1LS4yNThsLS44Ni0uMTNMLjY0OS0uNzFsLjIyOS40MjV6IiBmaWxsPSJ1cmwoI0IpIiB0cmFuc2Zvcm09Im1hdHJpeCgtMTA2LjQ0MyAtMTYuMDY2OSAtMTYuMDY2OSAxMDYuNDQzIDQyOC4xOSAxODguMDMzKSIvPjxwYXRoIGQ9Ik0uNDQtLjA0aDAgMEwuMjY1LS4wNTYuMTc3LjQzNy0uMzExLS4yNTUuMjYyLS40MzdoLjMwNkwuNDQtLjA0eiIgZmlsbD0idXJsKCNDKSIgdHJhbnNmb3JtPSJtYXRyaXgoLTExNC40ODQgLTE2Mi40MDggLTE2Mi40MDggMTE0LjQ4NCAzMzMuMjkxIDI4NS44MDQpIi8+PHBhdGggZD0iTS41IDBoMCAwIDB6IiBmaWxsPSJ1cmwoI0QpIiB0cmFuc2Zvcm09Im1hdHJpeCg2MS42OTE5IDU4LjgwOTEgNTguODA5MSAtNjEuNjkxOSAyNTguNjMxIDE4MC40MTMpIi8+PHBhdGggZD0iTS42MjItLjExNWguMTM5bC4wNDUuMTAyLjAyLjE5NS0uMjA0LS4yOTd6IiBmaWxsPSJ1cmwoI0UpIiB0cmFuc2Zvcm09Im1hdHJpeCgyMzguMTI2IDI5OC44OTMgMjk4Ljg5MyAtMjM4LjEyNiAxMTMuNTE2IC0xNTAuNTM2KSIvPjxwYXRoIGQ9Ik0uNDY3LjAwNUwuNDkuMDYyLjI3MS0uMDYyLjQ2Ny4wMDV6IiBmaWxsPSJ1cmwoI0YpIiB0cmFuc2Zvcm09Im1hdHJpeCgtMzY5LjUyOSAtOTcuNDExOCAtOTcuNDExOCAzNjkuNTI5IDU4Mi4zOCA5NC4wMjcpIi8+PGcgZmlsbD0idXJsKCNCKSI+PHBhdGggZD0iTS4yLjAwMWwuMDE5LS4wMTkuMzk1LjAzLS4wOTUuMDc3TC4yODIuMDY4LjIuMTM1LjQ2My4xOTQuMzc0LjI2Ni4xMzguMTg2aDAgMEwuMDQ3LjAzMy0uMTMxLS4yNjYuMi4wMDF6IiB0cmFuc2Zvcm09Im1hdHJpeCgtNDk2LjE1NiAtNTMuOTc1MSAtNTMuOTc1MSA0OTYuMTU2IDM2Ny44ODggMTI1LjA4NSkiLz48cGF0aCBkPSJNLjczNSAwaDAgMCAweiIgdHJhbnNmb3JtPSJtYXRyaXgoMTg1LjA3NiAxNzYuNDI3IDE3Ni40MjcgLTE4NS4wNzYgMTUzLjQ0NiA4MC4xNDg4KSIvPjwvZz48L2c+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJBIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLC0zLjQ2OTQ1ZS0xOCwtMy40Njk0NWUtMTgsLTEsMCwtMy4wNTc2MWUtMDYpIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkIiIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIwIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkMiIHgxPSIwIiB5MT0iMCIgeDI9IjEiIHkyPSIwIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsLTEuMTEwMjJlLTE2LC0xLjExMDIyZS0xNiwtMSwwLC0yLjYxODYxZS0wNikiIHhsaW5rOmhyZWY9IiNHIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNlMzMyMzIiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiM2YjAwMGQiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCBpZD0iRCIgeDE9IjAiIHkxPSIwIiB4Mj0iMSIgeTI9IjAiIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwtNS41NTExMmUtMTcsLTUuNTUxMTJlLTE3LC0xLDAsLTEuNTc1NjJlLTA2KSIgeGxpbms6aHJlZj0iI0ciPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2UzMzIzMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzZiMDAwZCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJFIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MDE4OTksLTAuNTk3NDYsLTAuNTk3NDYsMC44MDE4OTksMS4zNDk1LDAuNDQ3NDU3KSIgeGxpbms6aHJlZj0iI0ciPjxzdG9wIG9mZnNldD0iMCIgc3RvcC1jb2xvcj0iI2UzMzIzMiIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzZiMDAwZCIvPjwvbGluZWFyR3JhZGllbnQ+PGxpbmVhckdyYWRpZW50IGlkPSJGIiB4MT0iMCIgeTE9IjAiIHgyPSIxIiB5Mj0iMCIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLC0yLjc3NTU2ZS0xNywtMi43NzU1NmUtMTcsLTEsMCwtMS45MjgyNmUtMDYpIiB4bGluazpocmVmPSIjRyI+PHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjZTMzMjMyIi8+PHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjNmIwMDBkIi8+PC9saW5lYXJHcmFkaWVudD48bGluZWFyR3JhZGllbnQgaWQ9IkciIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIi8+PC9kZWZzPjwvc3ZnPg=="); -} diff --git a/v3/internal/assetserver/testdata/subdir/main.js b/v3/internal/assetserver/testdata/subdir/main.js deleted file mode 100644 index 274b4667..00000000 --- a/v3/internal/assetserver/testdata/subdir/main.js +++ /dev/null @@ -1,20 +0,0 @@ -import {ready} from '@wails/runtime'; - -ready(() => { - // Get input + focus - let nameElement = document.getElementById("name"); - nameElement.focus(); - - // Setup the greet function - window.greet = function () { - - // Get name - let name = nameElement.value; - - // Call App.Greet(name) - window.backend.main.App.Greet(name).then((result) => { - // Update result with data back from App.Greet() - document.getElementById("result").innerText = result; - }); - }; -}); \ No newline at end of file diff --git a/v3/internal/assetserver/testdata/testdata.go b/v3/internal/assetserver/testdata/testdata.go deleted file mode 100644 index 5387070e..00000000 --- a/v3/internal/assetserver/testdata/testdata.go +++ /dev/null @@ -1,6 +0,0 @@ -package testdata - -import "embed" - -//go:embed index.html main.css main.js -var TopLevelFS embed.FS diff --git a/v3/internal/commands/build-assets.go b/v3/internal/commands/build-assets.go index 484df6e5..be0e2002 100644 --- a/v3/internal/commands/build-assets.go +++ b/v3/internal/commands/build-assets.go @@ -8,6 +8,7 @@ import ( "io/fs" "os" "path/filepath" + "runtime" "strings" "time" ) @@ -18,6 +19,7 @@ var buildAssets embed.FS type BuildAssetsOptions struct { Dir string `description:"The directory to generate the files into" default:"build"` Name string `description:"The name of the project"` + Binary string `description:"The name of the binary"` ProductName string `description:"The name of the product" default:"My Product"` ProductDescription string `description:"The description of the product" default:"My Product Description"` ProductVersion string `description:"The version of the product" default:"0.1.0"` @@ -52,6 +54,13 @@ func GenerateBuildAssets(options *BuildAssetsOptions) error { options.ProductIdentifier = "com.wails." + normaliseName(options.Name) } + if options.Binary == "" { + options.Binary = normaliseName(options.Name) + if runtime.GOOS == "windows" { + options.Binary += ".exe" + } + } + tfs, err := fs.Sub(buildAssets, "build_assets") if err != nil { return err diff --git a/v3/internal/commands/build_assets/devmode.config.tmpl.toml b/v3/internal/commands/build_assets/devmode.config.tmpl.toml new file mode 100644 index 00000000..e6826c40 --- /dev/null +++ b/v3/internal/commands/build_assets/devmode.config.tmpl.toml @@ -0,0 +1,35 @@ +[config] +root_path = ".." +# debug | info | warn | error | mute +# Defaults to Info if not provided +log_level = "info" +# Debounce setting for ignoring reptitive file system notifications +debounce = 1000 # Milliseconds +# Sets what files the watcher should ignore +[config.ignore] +# Directories to ignore +dir = [".git", "node_modules", "frontend", "bin"] +# Files to ignore +file = [".DS_Store", ".gitignore", ".gitkeep"] +# File extensions to watch +watched_extension = ["*.go"] +# Add .gitignore paths to ignore +git_ignore = true + +[config.background] +cmd = "wails3 task dev:frontend" + +[[config.executes]] +cmd = "go mod tidy" +blocking = true + +[[config.executes]] +cmd = "wails3 task build" +blocking = true + +[[config.executes]] +cmd = "KILL_STALE" + +[[config.executes]] +cmd = "./bin/{{.Binary}}" +primary = true \ No newline at end of file diff --git a/v3/internal/commands/watcher.go b/v3/internal/commands/watcher.go index 362d92c4..c1e20c72 100644 --- a/v3/internal/commands/watcher.go +++ b/v3/internal/commands/watcher.go @@ -2,42 +2,29 @@ package commands import ( "github.com/atterpac/refresh/engine" - "strings" + "github.com/wailsapp/wails/v3/internal/signal" + "os" ) type WatcherOptions struct { - Path string `description:"The path to watch" default:"."` - PreExec string `description:"The command to run before the main command"` - Exec string `description:"The command to run when a change is detected"` - PostExec string `description:"The command to run after the main command"` - IgnoreFiles string `description:"The files to ignore (comma separated)"` - IgnoreDirs string `description:"The directories to ignore (comma separated)"` - IgnoreExtensions string `description:"The extensions to ignore (comma separated)"` - Debounce int `description:"The debounce time in milliseconds" default:"1000"` - PreWait bool `description:"Wait for the pre-exec command to finish before running the main command"` + Config string `description:"The config file including path" default:"."` } func Watcher(options *WatcherOptions) error { - - ignore := engine.Ignore{ - File: strings.Split(options.IgnoreFiles, ","), - Dir: strings.Split(options.IgnoreDirs, ","), - Extension: strings.Split(options.IgnoreExtensions, ","), + stopChan := make(chan struct{}) + watcherEngine := engine.NewEngineFromTOML(options.Config) + signalHandler := signal.NewSignalHandler(func() { + watcherEngine.Stop() + stopChan <- struct{}{} + }) + signalHandler.ExitMessage = func(sig os.Signal) string { + return "" } - config := engine.Config{ - RootPath: options.Path, - PreExec: options.PreExec, - ExecCommand: options.Exec, - PostExec: options.PostExec, - Ignore: ignore, - LogLevel: "info", - Debounce: options.Debounce, - PreWait: options.PreWait, + signalHandler.Start() + err := watcherEngine.Start() + if err != nil { + return err } - - watch := engine.NewEngineFromConfig(config) - - watch.Start() - <-make(chan struct{}) + <-stopChan return nil } diff --git a/v3/internal/signal/signal.go b/v3/internal/signal/signal.go new file mode 100644 index 00000000..eb0ce6b1 --- /dev/null +++ b/v3/internal/signal/signal.go @@ -0,0 +1,50 @@ +package signal + +import ( + "fmt" + "log/slog" + "os" + "os/signal" + "syscall" +) + +type SignalHandler struct { + cleanup func() + ExitMessage func(sig os.Signal) string + MaxSignal int + Logger *slog.Logger + LogLevel slog.Level +} + +func NewSignalHandler(cleanup func()) *SignalHandler { + return &SignalHandler{ + cleanup: cleanup, + ExitMessage: func(sig os.Signal) string { return fmt.Sprintf("Received signal: %v. Quitting...\n", sig) }, + MaxSignal: 3, + Logger: slog.New(slog.NewTextHandler(os.Stderr, nil)), + LogLevel: slog.LevelInfo, + } +} + +func (s *SignalHandler) Start() { + ctrlC := make(chan os.Signal, s.MaxSignal) + signal.Notify(ctrlC, os.Interrupt, syscall.SIGTERM) + + go func() { + for i := 1; i <= s.MaxSignal; i++ { + sig := <-ctrlC + + if i == 1 { + s.Logger.Info(s.ExitMessage(sig)) + s.cleanup() + break + } else if i < s.MaxSignal { + s.Logger.Info("Received signal: %v. Press CTRL+C %d more times to force quit...\n", sig, s.MaxSignal-i) + continue + } else { + s.Logger.Info("Received signal: %v. Force quitting...\n", sig) + os.Exit(1) + } + } + }() +} diff --git a/v3/internal/templates/_common/Taskfile.tmpl.yml b/v3/internal/templates/_common/Taskfile.tmpl.yml index 5d427d88..8fc2e152 100644 --- a/v3/internal/templates/_common/Taskfile.tmpl.yml +++ b/v3/internal/templates/_common/Taskfile.tmpl.yml @@ -432,8 +432,8 @@ tasks: dev: summary: Runs the application in development mode preconditions: - - sh: wails3 tool checkport -u {{ "\"$FRONTEND_DEVSERVER_URL\"" }} - msg: 'Cannot connect to frontend dev server ({{ "$FRONTEND_DEVSERVER_URL" }}). Please ensure you have run `wails3 dev:frontend` in another terminal.' + - sh: wails3 tool checkport -u {{ "{{.FRONTEND_DEVSERVER_URL}}" }} + msg: 'Cannot connect to frontend dev server ({{ "{{.FRONTEND_DEVSERVER_URL}}" }}). Please ensure you have run `wails3 dev:frontend` in another terminal.' cmds: - wails3 tool watcher -path {{ "{{.PATH}}" }} -preexec {{ "\"{{.PREEXEC}}\""}} {{ "{{.PREWAIT}}" }} -postexec {{ "\"{{.POSTEXEC}}\"" }} -ignorefiles {{ "{{.IGNOREFILES}}" }} -ignoredirs {{ "{{.IGNOREDIRS}}" }} -ignoreextensions {{ "{{.IGNOREEXTENSIONS}}" }} -exec {{ "\"{{.EXEC}}\"" }} -debounce {{ "{{.DEBOUNCE}}" }} vars: @@ -446,6 +446,7 @@ tasks: IGNOREDIRS: '.git,frontend,.idea,.vscode,bin' IGNOREEXTENSIONS: '.exe,.syso' DEBOUNCE: 1000 + FRONTEND_DEVSERVER_URL: 'http://localhost:5173' env: # This is the default vite dev server port FRONTEND_DEVSERVER_URL: 'http://localhost:5173' diff --git a/v3/pkg/application/application.go b/v3/pkg/application/application.go index ef3f8e63..2b02b6ec 100644 --- a/v3/pkg/application/application.go +++ b/v3/pkg/application/application.go @@ -3,6 +3,9 @@ package application import ( "embed" "encoding/json" + "github.com/pkg/browser" + "github.com/samber/lo" + "github.com/wailsapp/wails/v3/internal/signal" "io" "log" "log/slog" @@ -12,13 +15,9 @@ import ( "strconv" "sync" - "github.com/pkg/browser" - "github.com/samber/lo" - "github.com/wailsapp/wails/v3/internal/assetserver" "github.com/wailsapp/wails/v3/internal/assetserver/webview" "github.com/wailsapp/wails/v3/internal/capabilities" - wailsruntime "github.com/wailsapp/wails/v3/internal/runtime" "github.com/wailsapp/wails/v3/pkg/events" "github.com/wailsapp/wails/v3/pkg/icons" ) @@ -63,44 +62,50 @@ func New(appOptions Options) *App { } } + if !appOptions.DisableDefaultSignalHandler { + result.signalHandler = signal.NewSignalHandler(result.Quit) + result.signalHandler.Logger = result.Logger + result.signalHandler.ExitMessage = func(sig os.Signal) string { + return "Quitting application..." + } + } + result.logStartup() result.logPlatformInfo() result.Events = NewWailsEventProcessor(result.dispatchEventToWindows) opts := &assetserver.Options{ - Assets: appOptions.Assets.FS, - Handler: appOptions.Assets.Handler, - Middleware: assetserver.Middleware(appOptions.Assets.Middleware), + Assets: appOptions.Assets.FS, + Handler: appOptions.Assets.Handler, + Middleware: assetserver.Middleware(appOptions.Assets.Middleware), + Logger: result.Logger, + IsDebug: result.isDebugMode, + RuntimeHandler: NewMessageProcessor(result.Logger), + GetCapabilities: func() []byte { + return globalApplication.capabilities.AsBytes() + }, + GetFlags: func() []byte { + updatedOptions := result.impl.GetFlags(appOptions) + flags, err := json.Marshal(updatedOptions) + if err != nil { + log.Fatal("Invalid flags provided to application: ", err.Error()) + } + return flags + }, } - assetLogger := result.Logger if appOptions.Assets.DisableLogging { - assetLogger = slog.New(slog.NewTextHandler(io.Discard, nil)) + opts.Logger = slog.New(slog.NewTextHandler(io.Discard, nil)) } - srv, err := assetserver.NewAssetServer(opts, false, assetLogger, wailsruntime.RuntimeAssetsBundle, result.isDebugMode, NewMessageProcessor(result.Logger)) + srv, err := assetserver.NewAssetServer(opts) if err != nil { result.Logger.Error("Fatal error in application initialisation: " + err.Error()) os.Exit(1) } - // Pass through the capabilities - srv.GetCapabilities = func() []byte { - return globalApplication.capabilities.AsBytes() - } - - srv.GetFlags = func() []byte { - updatedOptions := result.impl.GetFlags(appOptions) - flags, err := json.Marshal(updatedOptions) - if err != nil { - log.Fatal("Invalid flags provided to application: ", err.Error()) - } - return flags - } - result.assets = srv - result.assets.LogDetails() result.bindings, err = NewBindings(appOptions.Bind, appOptions.BindAliases) @@ -302,6 +307,9 @@ type App struct { // They are run in the order they are added and run on the main thread. // The application option `OnShutdown` is run first. shutdownTasks []func() + + // signalHandler is used to handle signals + signalHandler *signal.SignalHandler } func (a *App) init() { @@ -448,6 +456,12 @@ func (a *App) Run() error { // Setup panic handler defer processPanicHandlerRecover() + // Call post-create hooks + err := a.preRun() + if err != nil { + return err + } + a.impl = newPlatformApp(a) go func() { for { @@ -509,7 +523,7 @@ func (a *App) Run() error { } a.impl.setIcon(a.options.Icon) - err := a.impl.run() + err = a.impl.run() if err != nil { return err } @@ -682,6 +696,8 @@ func ErrorDialog() *MessageDialog { return newMessageDialog(ErrorDialogType) } +// TODO: Why isn't this used? + func OpenDirectoryDialog() *MessageDialog { return newMessageDialog(OpenDirectoryDialogType) } diff --git a/v3/pkg/application/application_dev.go b/v3/pkg/application/application_dev.go new file mode 100644 index 00000000..50eadc97 --- /dev/null +++ b/v3/pkg/application/application_dev.go @@ -0,0 +1,38 @@ +//go:build !production + +package application + +import ( + "errors" + "github.com/wailsapp/wails/v3/internal/assetserver" + "net/http" + "time" +) + +func (a *App) preRun() error { + // Check for frontend server url + frontendURL := assetserver.GetDevServerURL() + if frontendURL != "" { + // We want to check if the frontend server is running by trying to http get the url + // and if it is not, we wait 500ms and try again for a maximum of 10 times. If it is + // still not available, we return an error. + // This is to allow the frontend server to start up before the backend server. + client := http.Client{} + a.Logger.Info("Waiting for frontend dev server to start...", "url", frontendURL) + for i := 0; i < 10; i++ { + _, err := client.Get(frontendURL) + if err == nil { + a.Logger.Info("Connected to frontend dev server!") + return nil + } + // Wait 500ms + time.Sleep(500 * time.Millisecond) + if i%2 == 0 { + a.Logger.Info("Retrying...") + } + } + a.Logger.Info("failed!") + return errors.New("unable to connect to frontend server. Please check it is running") + } + return nil +} diff --git a/v3/pkg/application/application_production.go b/v3/pkg/application/application_production.go index 7b4b2e6c..0750e527 100644 --- a/v3/pkg/application/application_production.go +++ b/v3/pkg/application/application_production.go @@ -12,3 +12,5 @@ func newApplication(options Options) *App { } func (a *App) logStartup() {} + +func (a *App) preRun() error { return nil } diff --git a/v3/pkg/application/logger_default.go b/v3/pkg/application/logger_dev.go similarity index 90% rename from v3/pkg/application/logger_default.go rename to v3/pkg/application/logger_dev.go index 53401432..4952e87b 100644 --- a/v3/pkg/application/logger_default.go +++ b/v3/pkg/application/logger_dev.go @@ -1,4 +1,4 @@ -//go:build !windows +//go:build !windows && !production package application diff --git a/v3/pkg/application/logger_windows.go b/v3/pkg/application/logger_dev_windows.go similarity index 92% rename from v3/pkg/application/logger_windows.go rename to v3/pkg/application/logger_dev_windows.go index 684c6ae0..8d7518a3 100644 --- a/v3/pkg/application/logger_windows.go +++ b/v3/pkg/application/logger_dev_windows.go @@ -1,4 +1,4 @@ -//go:build windows +//go:build windows && !production package application diff --git a/v3/pkg/application/logger_prod.go b/v3/pkg/application/logger_prod.go new file mode 100644 index 00000000..3cfbf403 --- /dev/null +++ b/v3/pkg/application/logger_prod.go @@ -0,0 +1,12 @@ +//go:build production + +package application + +import ( + "io" + "log/slog" +) + +func DefaultLogger(level slog.Level) *slog.Logger { + return slog.New(slog.NewTextHandler(io.Discard, nil)) +} diff --git a/v3/pkg/application/messageprocessor.go b/v3/pkg/application/messageprocessor.go index 1f21c3ab..d9a8e685 100644 --- a/v3/pkg/application/messageprocessor.go +++ b/v3/pkg/application/messageprocessor.go @@ -1,8 +1,8 @@ package application import ( + "encoding/json" "fmt" - jsoniter "github.com/json-iterator/go" "log/slog" "net/http" "strconv" @@ -38,7 +38,10 @@ func NewMessageProcessor(logger *slog.Logger) *MessageProcessor { func (m *MessageProcessor) httpError(rw http.ResponseWriter, message string, args ...any) { m.Error(message, args...) rw.WriteHeader(http.StatusBadRequest) - rw.Write([]byte(fmt.Sprintf(message, args...))) + _, err := rw.Write([]byte(fmt.Sprintf(message, args...))) + if err != nil { + m.Error("Unable to write error message: %s", err) + } } func (m *MessageProcessor) getTargetWindow(r *http.Request) (Window, string) { @@ -63,7 +66,7 @@ func (m *MessageProcessor) getTargetWindow(r *http.Request) (Window, string) { return targetWindow, windowID } -func (m *MessageProcessor) HandleRuntimeCall(rw http.ResponseWriter, r *http.Request) { +func (m *MessageProcessor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { object := r.URL.Query().Get("object") if object == "" { m.httpError(rw, "Invalid runtime call") @@ -132,7 +135,7 @@ func (m *MessageProcessor) json(rw http.ResponseWriter, data any) { var jsonPayload = []byte("{}") var err error if data != nil { - jsonPayload, err = jsoniter.Marshal(data) + jsonPayload, err = json.Marshal(data) if err != nil { m.Error("Unable to convert data to JSON. Please report this to the Wails team! Error: %s", err) return diff --git a/v3/pkg/application/options_application.go b/v3/pkg/application/options_application.go index ca9c4c6b..d005dfb2 100644 --- a/v3/pkg/application/options_application.go +++ b/v3/pkg/application/options_application.go @@ -46,9 +46,12 @@ type Options struct { // This is also used by Wails to provide information to the frontend. Flags map[string]any - // PanicHandler is a way to register a custom panic handler + // PanicHandler is called when a panic occurs PanicHandler func(any) + // DisableDefaultSignalHandler disables the default signal handler + DisableDefaultSignalHandler bool + // KeyBindings is a map of key bindings to functions KeyBindings map[string]func(window *WebviewWindow) diff --git a/v3/pkg/application/plugins.go b/v3/pkg/application/plugins.go index 423ce2ac..915c4ee7 100644 --- a/v3/pkg/application/plugins.go +++ b/v3/pkg/application/plugins.go @@ -1,6 +1,8 @@ package application -import "github.com/wailsapp/wails/v3/internal/assetserver" +import ( + "github.com/wailsapp/wails/v3/internal/assetserver" +) type Plugin interface { Name() string diff --git a/v3/pkg/application/webview_window_windows.go b/v3/pkg/application/webview_window_windows.go index a0bf6eaf..4db536b7 100644 --- a/v3/pkg/application/webview_window_windows.go +++ b/v3/pkg/application/webview_window_windows.go @@ -5,6 +5,7 @@ package application import ( "errors" "fmt" + "github.com/wailsapp/wails/v3/internal/assetserver" "net/url" "path" "strconv" @@ -17,7 +18,6 @@ import ( "github.com/bep/debounce" "github.com/wailsapp/go-webview2/webviewloader" - "github.com/wailsapp/wails/v3/internal/assetserver" "github.com/wailsapp/wails/v3/internal/assetserver/webview" "github.com/wailsapp/wails/v3/internal/capabilities" @@ -306,6 +306,7 @@ func (w *windowsWebviewWindow) run() { w.minimise() case WindowStateFullscreen: w.fullscreen() + case WindowStateNormal: } // Process window mask @@ -1231,9 +1232,18 @@ func (w *windowsWebviewWindow) processRequest(req *edge.ICoreWebView2WebResource if reqHeaders, err := req.GetHeaders(); err == nil { useragent, _ := reqHeaders.GetHeader(assetserver.HeaderUserAgent) useragent = strings.Join([]string{useragent, assetserver.WailsUserAgentValue}, " ") - reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent) - reqHeaders.SetHeader(webViewRequestHeaderWindowId, strconv.FormatUint(uint64(w.parent.id), 10)) - reqHeaders.Release() + err = reqHeaders.SetHeader(assetserver.HeaderUserAgent, useragent) + if err != nil { + globalApplication.fatal("Error setting UserAgent header: " + err.Error()) + } + err = reqHeaders.SetHeader(webViewRequestHeaderWindowId, strconv.FormatUint(uint64(w.parent.id), 10)) + if err != nil { + globalApplication.fatal("Error setting WindowId header: " + err.Error()) + } + err = reqHeaders.Release() + if err != nil { + globalApplication.fatal("Error releasing headers: " + err.Error()) + } } if globalApplication.assets == nil { @@ -1453,7 +1463,7 @@ func (w *windowsWebviewWindow) setupChromium() { // Parse the port parsedURL, err := url.Parse(devServerURL) if err != nil { - globalApplication.fatal("Error parsing environment variable 'WAILS_DEVSERVER_URL`: " + err.Error()) + globalApplication.fatal("Error parsing environment variable 'FRONTEND_DEVSERVER_URL`: " + err.Error() + ". Please check your `Taskfile.yml` file") } port := parsedURL.Port() if port != "" { @@ -1603,7 +1613,12 @@ func (w *windowsWebviewWindow) processMessageWithAdditionalObjects(message strin return } - defer objs.Release() + defer func() { + err = objs.Release() + if err != nil { + globalApplication.error("Error releasing objects: " + err.Error()) + } + }() count, err := objs.GetCount() if err != nil { @@ -1620,6 +1635,8 @@ func (w *windowsWebviewWindow) processMessageWithAdditionalObjects(message strin } file := (*edge.ICoreWebView2File)(unsafe.Pointer(_file)) + + // TODO: Fix this defer file.Release() filepath, err := file.GetPath()