chore: remove dependency on caddy server
							parent
							
								
									0523b31b96
								
							
						
					
					
						commit
						7177184678
					
				
							
								
								
									
										10
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										10
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -4,9 +4,9 @@ go 1.18
 | 
			
		|||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/asdine/storm/v3 v3.2.1
 | 
			
		||||
	github.com/caddyserver/caddy v1.0.3
 | 
			
		||||
	github.com/disintegration/imaging v1.6.2
 | 
			
		||||
	github.com/dsoprea/go-exif/v3 v3.0.0-20201216222538-db167117f483
 | 
			
		||||
	github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568
 | 
			
		||||
	github.com/golang-jwt/jwt/v4 v4.4.1
 | 
			
		||||
	github.com/gorilla/mux v1.8.0
 | 
			
		||||
	github.com/gorilla/websocket v1.5.0
 | 
			
		||||
| 
						 | 
				
			
			@ -32,27 +32,20 @@ require (
 | 
			
		|||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/andybalholm/brotli v1.0.1 // indirect
 | 
			
		||||
	github.com/cenkalti/backoff v2.1.1+incompatible // indirect
 | 
			
		||||
	github.com/davecgh/go-spew v1.1.1 // indirect
 | 
			
		||||
	github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
 | 
			
		||||
	github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d // indirect
 | 
			
		||||
	github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e // indirect
 | 
			
		||||
	github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
 | 
			
		||||
	github.com/fsnotify/fsnotify v1.5.1 // indirect
 | 
			
		||||
	github.com/go-acme/lego v2.5.0+incompatible // indirect
 | 
			
		||||
	github.com/go-errors/errors v1.1.1 // indirect
 | 
			
		||||
	github.com/go-ole/go-ole v1.2.6 // indirect
 | 
			
		||||
	github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect
 | 
			
		||||
	github.com/golang/snappy v0.0.2 // indirect
 | 
			
		||||
	github.com/google/uuid v1.1.2 // indirect
 | 
			
		||||
	github.com/hashicorp/hcl v1.0.0 // indirect
 | 
			
		||||
	github.com/inconshreveable/mousetrap v1.0.0 // indirect
 | 
			
		||||
	github.com/klauspost/compress v1.11.4 // indirect
 | 
			
		||||
	github.com/klauspost/cpuid v1.2.0 // indirect
 | 
			
		||||
	github.com/klauspost/pgzip v1.2.5 // indirect
 | 
			
		||||
	github.com/magiconair/properties v1.8.6 // indirect
 | 
			
		||||
	github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2 // indirect
 | 
			
		||||
	github.com/miekg/dns v1.1.25 // indirect
 | 
			
		||||
	github.com/mitchellh/mapstructure v1.4.3 // indirect
 | 
			
		||||
	github.com/nwaples/rardecode v1.1.0 // indirect
 | 
			
		||||
	github.com/pelletier/go-toml v1.9.4 // indirect
 | 
			
		||||
| 
						 | 
				
			
			@ -68,6 +61,5 @@ require (
 | 
			
		|||
	golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
 | 
			
		||||
	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
 | 
			
		||||
	gopkg.in/ini.v1 v1.66.4 // indirect
 | 
			
		||||
	gopkg.in/square/go-jose.v2 v2.2.2 // indirect
 | 
			
		||||
	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										56
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										56
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -47,13 +47,7 @@ github.com/andybalholm/brotli v1.0.1 h1:KqhlKozYbRtJvsPrrEeXcO+N2l6NYT5A2QAFmSUL
 | 
			
		|||
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
 | 
			
		||||
github.com/asdine/storm/v3 v3.2.1 h1:I5AqhkPK6nBZ/qJXySdI7ot5BlXSZ7qvDY1zAn5ZJac=
 | 
			
		||||
github.com/asdine/storm/v3 v3.2.1/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
 | 
			
		||||
github.com/bifurcation/mint v0.0.0-20180715133206-93c51c6ce115/go.mod h1:zVt7zX3K/aDCk9Tj+VM7YymsX66ERvzCJzw8rFCX2JU=
 | 
			
		||||
github.com/caddyserver/caddy v1.0.3 h1:i9gRhBgvc5ifchwWtSe7pDpsdS9+Q0Rw9oYQmYUTw1w=
 | 
			
		||||
github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
 | 
			
		||||
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
 | 
			
		||||
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
 | 
			
		||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 | 
			
		||||
github.com/cheekybits/genny v0.0.0-20170328200008-9127e812e1e9/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ=
 | 
			
		||||
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=
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +74,6 @@ github.com/dsoprea/go-logging v0.0.0-20200517223158-a10564966e9d/go.mod h1:7I+3P
 | 
			
		|||
github.com/dsoprea/go-utility v0.0.0-20200711062821-fab8125e9bdf/go.mod h1:95+K3z2L0mqsVYd6yveIv1lmtT3tcQQ3dVakPySffW8=
 | 
			
		||||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e h1:IxIbA7VbCNrwumIYjDoMOdf4KOSkMC6NJE4s8oRbE7E=
 | 
			
		||||
github.com/dsoprea/go-utility/v2 v2.0.0-20200717064901-2fccff4aa15e/go.mod h1:uAzdkPTub5Y9yQwXe8W4m2XuP0tK4a9Q/dantD0+uaU=
 | 
			
		||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 | 
			
		||||
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=
 | 
			
		||||
| 
						 | 
				
			
			@ -89,11 +82,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
 | 
			
		|||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 | 
			
		||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
 | 
			
		||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
 | 
			
		||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 | 
			
		||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
 | 
			
		||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
 | 
			
		||||
github.com/go-acme/lego v2.5.0+incompatible h1:5fNN9yRQfv8ymH3DSsxla+4aYeQt2IgfZqHKVnK8f0s=
 | 
			
		||||
github.com/go-acme/lego v2.5.0+incompatible/go.mod h1:yzMNe9CasVUhkquNvti5nAtPmG94USbYxYrZfTkIn0M=
 | 
			
		||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
 | 
			
		||||
github.com/go-errors/errors v1.0.2/go.mod h1:psDX2osz5VnTOnFWbDeWwS7yejl+uV3FEWEp4lssFEs=
 | 
			
		||||
github.com/go-errors/errors v1.1.1 h1:ljK/pL5ltg3qoN+OtN6yCv9HWSfMwxSx90GJCZQxYNg=
 | 
			
		||||
| 
						 | 
				
			
			@ -165,37 +155,29 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
 | 
			
		|||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
			
		||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 | 
			
		||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 | 
			
		||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
 | 
			
		||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 | 
			
		||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 | 
			
		||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 | 
			
		||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 | 
			
		||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
 | 
			
		||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 | 
			
		||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 | 
			
		||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
 | 
			
		||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 | 
			
		||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
 | 
			
		||||
github.com/hashicorp/golang-lru v0.0.0-20180201235237-0fb14efe8c47/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 | 
			
		||||
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/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 | 
			
		||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 | 
			
		||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
 | 
			
		||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
			
		||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
 | 
			
		||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 | 
			
		||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 | 
			
		||||
github.com/jimstudt/http-authentication v0.0.0-20140401203705-3eca13d6893a/go.mod h1:wK6yTYYcgjHE1Z1QtXACPDjcFJyBskHEdagmnq3vsP8=
 | 
			
		||||
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/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 | 
			
		||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 | 
			
		||||
github.com/klauspost/compress v1.11.4 h1:kz40R/YWls3iqT9zX9AHN3WoVsrAWVyui5sxuLqiXqU=
 | 
			
		||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
 | 
			
		||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
 | 
			
		||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 | 
			
		||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
 | 
			
		||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
 | 
			
		||||
| 
						 | 
				
			
			@ -205,37 +187,21 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
 | 
			
		|||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 | 
			
		||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 | 
			
		||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 | 
			
		||||
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
 | 
			
		||||
github.com/lucas-clemente/aes12 v0.0.0-20171027163421-cd47fb39b79f/go.mod h1:JpH9J1c9oX6otFSgdUHwUBUizmKlrMjxWnIAjff4m04=
 | 
			
		||||
github.com/lucas-clemente/quic-clients v0.1.0/go.mod h1:y5xVIEoObKqULIKivu+gD/LU90pL73bTdtQjPBvtCBk=
 | 
			
		||||
github.com/lucas-clemente/quic-go v0.10.2/go.mod h1:hvaRS9IHjFLMq76puFJeWNfmn+H70QZ/CXoxqw9bzao=
 | 
			
		||||
github.com/lucas-clemente/quic-go-certificates v0.0.0-20160823095156-d2f86524cced/go.mod h1:NCcRLrOTZbzhZvixZLlERbJtDtYsmMw8Jc4vS8Z0g58=
 | 
			
		||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
 | 
			
		||||
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
 | 
			
		||||
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
 | 
			
		||||
github.com/marten-seemann/qtls v0.2.3/go.mod h1:xzjG7avBwGGbdZ8dTGxlBnLArsVKLvwmjgmPuiQEcYk=
 | 
			
		||||
github.com/maruel/natural v1.0.0 h1:C1GqgYygkdnwD1H1psoEVsPazXyUqRooEvX/XyWFFDg=
 | 
			
		||||
github.com/maruel/natural v1.0.0/go.mod h1:eFVhYCcUOfZFxXoDZam8Ktya72wa79fNC3lc/leA0DQ=
 | 
			
		||||
github.com/marusama/semaphore/v2 v2.5.0 h1:o/1QJD9DBYOWRnDhPwDVAXQn6mQYD0gZaS1Tpx6DJGM=
 | 
			
		||||
github.com/marusama/semaphore/v2 v2.5.0/go.mod h1:z9nMiNUekt/LTpTUQdpp+4sJeYqUGpwMHfW0Z8V8fnQ=
 | 
			
		||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
 | 
			
		||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
 | 
			
		||||
github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2 h1:xKE9kZ5C8gelJC3+BNM6LJs1x21rivK7yxfTZMAuY2s=
 | 
			
		||||
github.com/mholt/certmagic v0.6.2-0.20190624175158-6a42ef9fe8c2/go.mod h1:g4cOPxcjV0oFq3qwpjSA30LReKD8AoIfwAY9VvG35NY=
 | 
			
		||||
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 | 
			
		||||
github.com/miekg/dns v1.1.25 h1:dFwPR6SfLtrSwgDcIq2bcU/gVutB4sNApq2HBdqcakg=
 | 
			
		||||
github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
 | 
			
		||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 | 
			
		||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 | 
			
		||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
 | 
			
		||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 | 
			
		||||
github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0=
 | 
			
		||||
github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
 | 
			
		||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
 | 
			
		||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
 | 
			
		||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 | 
			
		||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
 | 
			
		||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
 | 
			
		||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 | 
			
		||||
github.com/pelletier/go-toml/v2 v2.0.0 h1:P7Bq0SaI8nsexyay5UAyDo+ICWy5MQPgEZ5+l8JQTKo=
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +216,6 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF
 | 
			
		|||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
 | 
			
		||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 | 
			
		||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 | 
			
		||||
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
 | 
			
		||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 | 
			
		||||
github.com/shirou/gopsutil/v3 v3.22.5 h1:atX36I/IXgFiB81687vSiBI5zrMsxcIBkP9cQMJQoJA=
 | 
			
		||||
github.com/shirou/gopsutil/v3 v3.22.5/go.mod h1:so9G9VzeHt/hsd0YwqprnjHnfARAUktauykSbr+y2gA=
 | 
			
		||||
| 
						 | 
				
			
			@ -268,7 +233,6 @@ github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44=
 | 
			
		|||
github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk=
 | 
			
		||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 | 
			
		||||
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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 | 
			
		||||
| 
						 | 
				
			
			@ -302,12 +266,9 @@ 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=
 | 
			
		||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 | 
			
		||||
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 | 
			
		||||
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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
 | 
			
		||||
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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 | 
			
		||||
| 
						 | 
				
			
			@ -352,12 +313,9 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
			
		|||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 | 
			
		||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 | 
			
		||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
golang.org/x/net v0.0.0-20190328230028-74de082e2cca/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 | 
			
		||||
| 
						 | 
				
			
			@ -365,7 +323,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
 | 
			
		|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 | 
			
		||||
| 
						 | 
				
			
			@ -407,13 +364,9 @@ 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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a h1:DcqTD9SDLc+1P/r1EmRBwnVsrOwW+kk2vWf9n+1sGhs=
 | 
			
		||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/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-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
| 
						 | 
				
			
			@ -422,8 +375,6 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
 | 
			
		|||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
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-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 | 
			
		||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/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=
 | 
			
		||||
| 
						 | 
				
			
			@ -481,7 +432,6 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw
 | 
			
		|||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
			
		||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
 | 
			
		||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 | 
			
		||||
| 
						 | 
				
			
			@ -615,16 +565,10 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
 | 
			
		|||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
 | 
			
		||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 | 
			
		||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
 | 
			
		||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 | 
			
		||||
gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4=
 | 
			
		||||
gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 | 
			
		||||
gopkg.in/mcuadros/go-syslog.v2 v2.2.1/go.mod h1:l5LPIyOOyIdQquNg+oU6Z3524YwrcqEm0aKH+5zpt2U=
 | 
			
		||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
 | 
			
		||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
 | 
			
		||||
gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
 | 
			
		||||
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
 | 
			
		||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,136 @@
 | 
			
		|||
// Copyright 2015 Light Code Labs, LLC
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package runner
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"unicode"
 | 
			
		||||
 | 
			
		||||
	"github.com/flynn/go-shlex"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	osWindows = "windows"
 | 
			
		||||
	osLinux   = "linux"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var runtimeGoos = runtime.GOOS
 | 
			
		||||
 | 
			
		||||
// SplitCommandAndArgs takes a command string and parses it shell-style into the
 | 
			
		||||
// command and its separate arguments.
 | 
			
		||||
func SplitCommandAndArgs(command string) (cmd string, args []string, err error) {
 | 
			
		||||
	var parts []string
 | 
			
		||||
 | 
			
		||||
	if runtimeGoos == osWindows {
 | 
			
		||||
		parts = parseWindowsCommand(command) // parse it Windows-style
 | 
			
		||||
	} else {
 | 
			
		||||
		parts, err = parseUnixCommand(command) // parse it Unix-style
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			err = errors.New("error parsing command: " + err.Error())
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(parts) == 0 {
 | 
			
		||||
		err = errors.New("no command contained in '" + command + "'")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cmd = parts[0]
 | 
			
		||||
	if len(parts) > 1 {
 | 
			
		||||
		args = parts[1:]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseUnixCommand parses a unix style command line and returns the
 | 
			
		||||
// command and its arguments or an error
 | 
			
		||||
func parseUnixCommand(cmd string) ([]string, error) {
 | 
			
		||||
	return shlex.Split(cmd)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseWindowsCommand parses windows command lines and
 | 
			
		||||
// returns the command and the arguments as an array. It
 | 
			
		||||
// should be able to parse commonly used command lines.
 | 
			
		||||
// Only basic syntax is supported:
 | 
			
		||||
//  - spaces in double quotes are not token delimiters
 | 
			
		||||
//  - double quotes are escaped by either backspace or another double quote
 | 
			
		||||
//  - except for the above case backspaces are path separators (not special)
 | 
			
		||||
//
 | 
			
		||||
// Many sources point out that escaping quotes using backslash can be unsafe.
 | 
			
		||||
// Use two double quotes when possible. (Source: http://stackoverflow.com/a/31413730/2616179 )
 | 
			
		||||
//
 | 
			
		||||
// This function has to be used on Windows instead
 | 
			
		||||
// of the shlex package because this function treats backslash
 | 
			
		||||
// characters properly.
 | 
			
		||||
func parseWindowsCommand(cmd string) []string {
 | 
			
		||||
	const backslash = '\\'
 | 
			
		||||
	const quote = '"'
 | 
			
		||||
 | 
			
		||||
	var parts []string
 | 
			
		||||
	var part string
 | 
			
		||||
	var inQuotes bool
 | 
			
		||||
	var lastRune rune
 | 
			
		||||
 | 
			
		||||
	for i, ch := range cmd {
 | 
			
		||||
		if i != 0 {
 | 
			
		||||
			lastRune = rune(cmd[i-1])
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ch == backslash {
 | 
			
		||||
			// put it in the part - for now we don't know if it's an
 | 
			
		||||
			// escaping char or path separator
 | 
			
		||||
			part += string(ch)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ch == quote {
 | 
			
		||||
			if lastRune == backslash {
 | 
			
		||||
				// remove the backslash from the part and add the escaped quote instead
 | 
			
		||||
				part = part[:len(part)-1]
 | 
			
		||||
				part += string(ch)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if lastRune == quote {
 | 
			
		||||
				// revert the last change of the inQuotes state
 | 
			
		||||
				// it was an escaping quote
 | 
			
		||||
				inQuotes = !inQuotes
 | 
			
		||||
				part += string(ch)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// normal escaping quotes
 | 
			
		||||
			inQuotes = !inQuotes
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if unicode.IsSpace(ch) && !inQuotes && len(part) > 0 {
 | 
			
		||||
			parts = append(parts, part)
 | 
			
		||||
			part = ""
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		part += string(ch)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(part) > 0 {
 | 
			
		||||
		parts = append(parts, part)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return parts
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,304 @@
 | 
			
		|||
// Copyright 2015 Light Code Labs, LLC
 | 
			
		||||
//
 | 
			
		||||
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
// you may not use this file except in compliance with the License.
 | 
			
		||||
// You may obtain a copy of the License at
 | 
			
		||||
//
 | 
			
		||||
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
//
 | 
			
		||||
// Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
// See the License for the specific language governing permissions and
 | 
			
		||||
// limitations under the License.
 | 
			
		||||
 | 
			
		||||
package runner
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"testing"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestParseUnixCommand(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		input    string
 | 
			
		||||
		expected []string
 | 
			
		||||
	}{
 | 
			
		||||
		// 0 - empty command
 | 
			
		||||
		{
 | 
			
		||||
			input:    ``,
 | 
			
		||||
			expected: []string{},
 | 
			
		||||
		},
 | 
			
		||||
		// 1 - command without arguments
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command`,
 | 
			
		||||
			expected: []string{`command`},
 | 
			
		||||
		},
 | 
			
		||||
		// 2 - command with single argument
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command arg1`,
 | 
			
		||||
			expected: []string{`command`, `arg1`},
 | 
			
		||||
		},
 | 
			
		||||
		// 3 - command with multiple arguments
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command arg1 arg2`,
 | 
			
		||||
			expected: []string{`command`, `arg1`, `arg2`},
 | 
			
		||||
		},
 | 
			
		||||
		// 4 - command with single argument with space character - in quotes
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command "arg1 arg1"`,
 | 
			
		||||
			expected: []string{`command`, `arg1 arg1`},
 | 
			
		||||
		},
 | 
			
		||||
		// 5 - command with multiple spaces and tab character
 | 
			
		||||
		{
 | 
			
		||||
			input:    "command arg1    arg2\targ3",
 | 
			
		||||
			expected: []string{`command`, `arg1`, `arg2`, `arg3`},
 | 
			
		||||
		},
 | 
			
		||||
		// 6 - command with single argument with space character - escaped with backspace
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command arg1\ arg2`,
 | 
			
		||||
			expected: []string{`command`, `arg1 arg2`},
 | 
			
		||||
		},
 | 
			
		||||
		// 7 - single quotes should escape special chars
 | 
			
		||||
		{
 | 
			
		||||
			input:    `command 'arg1\ arg2'`,
 | 
			
		||||
			expected: []string{`command`, `arg1\ arg2`},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, test := range tests {
 | 
			
		||||
		errorPrefix := fmt.Sprintf("Test [%d]: ", i)
 | 
			
		||||
		errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
 | 
			
		||||
		actual, _ := parseUnixCommand(test.input)
 | 
			
		||||
		if len(actual) != len(test.expected) {
 | 
			
		||||
			t.Errorf(errorPrefix+"Expected %d parts, got %d: %#v."+errorSuffix, len(test.expected), len(actual), actual)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for j := 0; j < len(actual); j++ {
 | 
			
		||||
			if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart {
 | 
			
		||||
				t.Errorf(errorPrefix+"Expected: %v Actual: %v (index %d)."+errorSuffix, expectedPart, actualPart, j)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestParseWindowsCommand(t *testing.T) {
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		input    string
 | 
			
		||||
		expected []string
 | 
			
		||||
	}{
 | 
			
		||||
		{ // 0 - empty command - do not fail
 | 
			
		||||
			input:    ``,
 | 
			
		||||
			expected: []string{},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 1 - cmd without args
 | 
			
		||||
			input:    `cmd`,
 | 
			
		||||
			expected: []string{`cmd`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 2 - multiple args
 | 
			
		||||
			input:    `cmd arg1 arg2`,
 | 
			
		||||
			expected: []string{`cmd`, `arg1`, `arg2`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 3 - multiple args with space
 | 
			
		||||
			input:    `cmd "combined arg" arg2`,
 | 
			
		||||
			expected: []string{`cmd`, `combined arg`, `arg2`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 4 - path without spaces
 | 
			
		||||
			input:    `mkdir C:\Windows\foo\bar`,
 | 
			
		||||
			expected: []string{`mkdir`, `C:\Windows\foo\bar`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 5 - command with space in quotes
 | 
			
		||||
			input:    `"command here"`,
 | 
			
		||||
			expected: []string{`command here`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 6 - argument with escaped quotes (two quotes)
 | 
			
		||||
			input:    `cmd ""arg""`,
 | 
			
		||||
			expected: []string{`cmd`, `"arg"`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 7 - argument with escaped quotes (backslash)
 | 
			
		||||
			input:    `cmd \"arg\"`,
 | 
			
		||||
			expected: []string{`cmd`, `"arg"`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 8 - two quotes (escaped) inside an inQuote element
 | 
			
		||||
			input:    `cmd "a ""quoted value"`,
 | 
			
		||||
			expected: []string{`cmd`, `a "quoted value`},
 | 
			
		||||
		},
 | 
			
		||||
		// TODO - see how many quotes are displayed if we use "", """, """""""
 | 
			
		||||
		{ // 9 - two quotes outside an inQuote element
 | 
			
		||||
			input:    `cmd a ""quoted value`,
 | 
			
		||||
			expected: []string{`cmd`, `a`, `"quoted`, `value`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 10 - path with space in quotes
 | 
			
		||||
			input:    `mkdir "C:\directory name\foobar"`,
 | 
			
		||||
			expected: []string{`mkdir`, `C:\directory name\foobar`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 11 - space without quotes
 | 
			
		||||
			input:    `mkdir C:\ space`,
 | 
			
		||||
			expected: []string{`mkdir`, `C:\`, `space`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 12 - space in quotes
 | 
			
		||||
			input:    `mkdir "C:\ space"`,
 | 
			
		||||
			expected: []string{`mkdir`, `C:\ space`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 13 - UNC
 | 
			
		||||
			input:    `mkdir \\?\C:\Users`,
 | 
			
		||||
			expected: []string{`mkdir`, `\\?\C:\Users`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 14 - UNC with space
 | 
			
		||||
			input:    `mkdir "\\?\C:\Program Files"`,
 | 
			
		||||
			expected: []string{`mkdir`, `\\?\C:\Program Files`},
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		{ // 15 - unclosed quotes - treat as if the path ends with quote
 | 
			
		||||
			input:    `mkdir "c:\Program files`,
 | 
			
		||||
			expected: []string{`mkdir`, `c:\Program files`},
 | 
			
		||||
		},
 | 
			
		||||
		{ // 16 - quotes used inside the argument
 | 
			
		||||
			input:    `mkdir "c:\P"rogra"m f"iles`,
 | 
			
		||||
			expected: []string{`mkdir`, `c:\Program files`},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, test := range tests {
 | 
			
		||||
		errorPrefix := fmt.Sprintf("Test [%d]: ", i)
 | 
			
		||||
		errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
 | 
			
		||||
 | 
			
		||||
		actual := parseWindowsCommand(test.input)
 | 
			
		||||
		if len(actual) != len(test.expected) {
 | 
			
		||||
			t.Errorf(errorPrefix+"Expected %d parts, got %d: %#v."+errorSuffix, len(test.expected), len(actual), actual)
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		for j := 0; j < len(actual); j++ {
 | 
			
		||||
			if expectedPart, actualPart := test.expected[j], actual[j]; expectedPart != actualPart {
 | 
			
		||||
				t.Errorf(errorPrefix+"Expected: %v Actual: %v (index %d)."+errorSuffix, expectedPart, actualPart, j)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSplitCommandAndArgs(t *testing.T) {
 | 
			
		||||
	// force linux parsing. It's more robust and covers error cases
 | 
			
		||||
	runtimeGoos = osLinux
 | 
			
		||||
	defer func() {
 | 
			
		||||
		runtimeGoos = runtime.GOOS
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	var parseErrorContent = "error parsing command:"
 | 
			
		||||
	var noCommandErrContent = "no command contained in"
 | 
			
		||||
 | 
			
		||||
	tests := []struct {
 | 
			
		||||
		input              string
 | 
			
		||||
		expectedCommand    string
 | 
			
		||||
		expectedArgs       []string
 | 
			
		||||
		expectedErrContent string
 | 
			
		||||
	}{
 | 
			
		||||
		// 0 - empty command
 | 
			
		||||
		{
 | 
			
		||||
			input:              ``,
 | 
			
		||||
			expectedCommand:    ``,
 | 
			
		||||
			expectedArgs:       nil,
 | 
			
		||||
			expectedErrContent: noCommandErrContent,
 | 
			
		||||
		},
 | 
			
		||||
		// 1 - command without arguments
 | 
			
		||||
		{
 | 
			
		||||
			input:              `command`,
 | 
			
		||||
			expectedCommand:    `command`,
 | 
			
		||||
			expectedArgs:       nil,
 | 
			
		||||
			expectedErrContent: ``,
 | 
			
		||||
		},
 | 
			
		||||
		// 2 - command with single argument
 | 
			
		||||
		{
 | 
			
		||||
			input:              `command arg1`,
 | 
			
		||||
			expectedCommand:    `command`,
 | 
			
		||||
			expectedArgs:       []string{`arg1`},
 | 
			
		||||
			expectedErrContent: ``,
 | 
			
		||||
		},
 | 
			
		||||
		// 3 - command with multiple arguments
 | 
			
		||||
		{
 | 
			
		||||
			input:              `command arg1 arg2`,
 | 
			
		||||
			expectedCommand:    `command`,
 | 
			
		||||
			expectedArgs:       []string{`arg1`, `arg2`},
 | 
			
		||||
			expectedErrContent: ``,
 | 
			
		||||
		},
 | 
			
		||||
		// 4 - command with unclosed quotes
 | 
			
		||||
		{
 | 
			
		||||
			input:              `command "arg1 arg2`,
 | 
			
		||||
			expectedCommand:    "",
 | 
			
		||||
			expectedArgs:       nil,
 | 
			
		||||
			expectedErrContent: parseErrorContent,
 | 
			
		||||
		},
 | 
			
		||||
		// 5 - command with unclosed quotes
 | 
			
		||||
		{
 | 
			
		||||
			input:              `command 'arg1 arg2"`,
 | 
			
		||||
			expectedCommand:    "",
 | 
			
		||||
			expectedArgs:       nil,
 | 
			
		||||
			expectedErrContent: parseErrorContent,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, test := range tests {
 | 
			
		||||
		errorPrefix := fmt.Sprintf("Test [%d]: ", i)
 | 
			
		||||
		errorSuffix := fmt.Sprintf(" Command to parse: [%s]", test.input)
 | 
			
		||||
		actualCommand, actualArgs, actualErr := SplitCommandAndArgs(test.input)
 | 
			
		||||
 | 
			
		||||
		// test if error matches expectation
 | 
			
		||||
		if test.expectedErrContent != "" {
 | 
			
		||||
			if actualErr == nil {
 | 
			
		||||
				t.Errorf(errorPrefix+"Expected error with content [%s], found no error."+errorSuffix, test.expectedErrContent)
 | 
			
		||||
			} else if !strings.Contains(actualErr.Error(), test.expectedErrContent) {
 | 
			
		||||
				t.Errorf(errorPrefix+"Expected error with content [%s], found [%v]."+errorSuffix, test.expectedErrContent, actualErr)
 | 
			
		||||
			}
 | 
			
		||||
		} else if actualErr != nil {
 | 
			
		||||
			t.Errorf(errorPrefix+"Expected no error, found [%v]."+errorSuffix, actualErr)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// test if command matches
 | 
			
		||||
		if test.expectedCommand != actualCommand {
 | 
			
		||||
			t.Errorf(errorPrefix+"Expected command: [%s], actual: [%s]."+errorSuffix, test.expectedCommand, actualCommand)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// test if arguments match
 | 
			
		||||
		if len(test.expectedArgs) != len(actualArgs) {
 | 
			
		||||
			t.Errorf(errorPrefix+"Wrong number of arguments! Expected [%v], actual [%v]."+errorSuffix, test.expectedArgs, actualArgs)
 | 
			
		||||
		} else {
 | 
			
		||||
			// test args only if the count matches.
 | 
			
		||||
			for j, actualArg := range actualArgs {
 | 
			
		||||
				expectedArg := test.expectedArgs[j]
 | 
			
		||||
				if actualArg != expectedArg {
 | 
			
		||||
					t.Errorf(errorPrefix+"Argument at position [%d] differ! Expected [%s], actual [%s]"+errorSuffix, j, expectedArg, actualArg)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func ExampleSplitCommandAndArgs() {
 | 
			
		||||
	var commandLine string
 | 
			
		||||
	var command string
 | 
			
		||||
	var args []string
 | 
			
		||||
 | 
			
		||||
	// just for the test - change GOOS and reset it at the end of the test
 | 
			
		||||
	runtimeGoos = osWindows
 | 
			
		||||
	defer func() {
 | 
			
		||||
		runtimeGoos = runtime.GOOS
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	commandLine = `mkdir /P "C:\Program Files"`
 | 
			
		||||
	command, args, _ = SplitCommandAndArgs(commandLine)
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("Windows: %s: %s [%s]\n", commandLine, command, strings.Join(args, ","))
 | 
			
		||||
 | 
			
		||||
	// set GOOS to linux
 | 
			
		||||
	runtimeGoos = osLinux
 | 
			
		||||
 | 
			
		||||
	commandLine = `mkdir -p /path/with\ space`
 | 
			
		||||
	command, args, _ = SplitCommandAndArgs(commandLine)
 | 
			
		||||
 | 
			
		||||
	fmt.Printf("Linux: %s: %s [%s]\n", commandLine, command, strings.Join(args, ","))
 | 
			
		||||
 | 
			
		||||
	// Output:
 | 
			
		||||
	// Windows: mkdir /P "C:\Program Files": mkdir [/P,C:\Program Files]
 | 
			
		||||
	// Linux: mkdir -p /path/with\ space: mkdir [-p,/path/with space]
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -3,8 +3,6 @@ package runner
 | 
			
		|||
import (
 | 
			
		||||
	"os/exec"
 | 
			
		||||
 | 
			
		||||
	"github.com/caddyserver/caddy"
 | 
			
		||||
 | 
			
		||||
	"github.com/filebrowser/filebrowser/v2/settings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +13,7 @@ func ParseCommand(s *settings.Settings, raw string) ([]string, error) {
 | 
			
		|||
	var command []string
 | 
			
		||||
 | 
			
		||||
	if len(s.Shell) == 0 {
 | 
			
		||||
		cmd, args, err := caddy.SplitCommandAndArgs(raw)
 | 
			
		||||
		cmd, args, err := SplitCommandAndArgs(raw)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue