Skip to content

Commit 0b03f7e

Browse files
authored
fix: cannot download store extesnion on windows (#800)
Co-authored-by: rick <[email protected]>
1 parent 51cc1ca commit 0b03f7e

File tree

1 file changed

+155
-152
lines changed

1 file changed

+155
-152
lines changed

pkg/server/store_ext_manager.go

Lines changed: 155 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -16,188 +16,191 @@ limitations under the License.
1616
package server
1717

1818
import (
19-
"context"
20-
"errors"
21-
"fmt"
22-
"io"
23-
"net/http"
24-
"os"
25-
"path/filepath"
26-
"strings"
27-
sync "sync"
28-
"syscall"
29-
"time"
30-
31-
"github.com/linuxsuren/api-testing/pkg/util/home"
32-
33-
"github.com/linuxsuren/api-testing/pkg/downloader"
34-
"github.com/linuxsuren/api-testing/pkg/logging"
35-
36-
fakeruntime "github.com/linuxsuren/go-fake-runtime"
19+
"context"
20+
"errors"
21+
"fmt"
22+
"io"
23+
"net/http"
24+
"os"
25+
"path/filepath"
26+
"strings"
27+
sync "sync"
28+
"syscall"
29+
"time"
30+
31+
"github.com/linuxsuren/api-testing/pkg/util/home"
32+
33+
"github.com/linuxsuren/api-testing/pkg/downloader"
34+
"github.com/linuxsuren/api-testing/pkg/logging"
35+
36+
fakeruntime "github.com/linuxsuren/go-fake-runtime"
3737
)
3838

3939
var (
40-
serverLogger = logging.DefaultLogger(logging.LogLevelInfo).WithName("server")
40+
serverLogger = logging.DefaultLogger(logging.LogLevelInfo).WithName("server")
4141
)
4242

4343
type ExtManager interface {
44-
Start(name, socket string) (err error)
45-
StopAll() (err error)
46-
WithDownloader(downloader.PlatformAwareOCIDownloader)
44+
Start(name, socket string) (err error)
45+
StopAll() (err error)
46+
WithDownloader(downloader.PlatformAwareOCIDownloader)
4747
}
4848

4949
type storeExtManager struct {
50-
execer fakeruntime.Execer
51-
ociDownloader downloader.PlatformAwareOCIDownloader
52-
socketPrefix string
53-
filesNeedToBeRemoved []string
54-
extStatusMap map[string]bool
55-
processs []fakeruntime.Process
56-
processChan chan fakeruntime.Process
57-
stopSingal chan struct{}
58-
lock *sync.RWMutex
50+
execer fakeruntime.Execer
51+
ociDownloader downloader.PlatformAwareOCIDownloader
52+
socketPrefix string
53+
filesNeedToBeRemoved []string
54+
extStatusMap map[string]bool
55+
processs []fakeruntime.Process
56+
processChan chan fakeruntime.Process
57+
stopSingal chan struct{}
58+
lock *sync.RWMutex
5959
}
6060

6161
var ss *storeExtManager
6262

6363
func NewStoreExtManager(execer fakeruntime.Execer) ExtManager {
64-
if ss == nil {
65-
ss = &storeExtManager{
66-
processChan: make(chan fakeruntime.Process),
67-
stopSingal: make(chan struct{}, 1),
68-
lock: &sync.RWMutex{},
69-
}
70-
ss.execer = execer
71-
ss.socketPrefix = "unix://"
72-
ss.extStatusMap = map[string]bool{}
73-
ss.processCollect()
74-
ss.WithDownloader(&nonDownloader{})
75-
}
76-
return ss
64+
if ss == nil {
65+
ss = &storeExtManager{
66+
processChan: make(chan fakeruntime.Process),
67+
stopSingal: make(chan struct{}, 1),
68+
lock: &sync.RWMutex{},
69+
}
70+
ss.execer = execer
71+
ss.socketPrefix = "unix://"
72+
ss.extStatusMap = map[string]bool{}
73+
ss.processCollect()
74+
ss.WithDownloader(&nonDownloader{})
75+
}
76+
return ss
7777
}
7878

7979
func NewStoreExtManagerInstance(execer fakeruntime.Execer) ExtManager {
80-
ss = &storeExtManager{
81-
processChan: make(chan fakeruntime.Process),
82-
stopSingal: make(chan struct{}, 1),
83-
lock: &sync.RWMutex{},
84-
}
85-
ss.execer = execer
86-
ss.socketPrefix = "unix://"
87-
ss.extStatusMap = map[string]bool{}
88-
ss.processCollect()
89-
ss.WithDownloader(&nonDownloader{})
90-
return ss
80+
ss = &storeExtManager{
81+
processChan: make(chan fakeruntime.Process),
82+
stopSingal: make(chan struct{}, 1),
83+
lock: &sync.RWMutex{},
84+
}
85+
ss.execer = execer
86+
ss.socketPrefix = "unix://"
87+
ss.extStatusMap = map[string]bool{}
88+
ss.processCollect()
89+
ss.WithDownloader(&nonDownloader{})
90+
return ss
9191
}
9292

9393
func (s *storeExtManager) Start(name, socket string) (err error) {
94-
if v, ok := s.extStatusMap[name]; ok && v {
95-
return
96-
}
97-
if s.execer.OS() == "windows" {
98-
name = name + ".exe"
99-
}
100-
targetDir := home.GetUserBinDir()
101-
targetBinaryFile := filepath.Join(targetDir, name)
102-
103-
var binaryPath string
104-
if _, err = os.Stat(targetBinaryFile); err == nil {
105-
binaryPath = targetBinaryFile
106-
} else {
107-
serverLogger.Info("failed to find extension", "error", err.Error())
108-
109-
binaryPath, err = s.execer.LookPath(name)
110-
if err != nil {
111-
err = fmt.Errorf("not found extension, try to download it, error: %v", err)
112-
go func() {
113-
reader, dErr := s.ociDownloader.Download(name, "", "")
114-
if dErr != nil {
115-
serverLogger.Error(dErr, "failed to download extension", "name", name)
116-
} else {
117-
extFile := s.ociDownloader.GetTargetFile()
118-
119-
targetFile := filepath.Base(extFile)
120-
if dErr = downloader.WriteTo(reader, targetDir, targetFile); dErr == nil {
121-
binaryPath = filepath.Join(targetDir, targetFile)
122-
s.startPlugin(socket, binaryPath, name)
123-
} else {
124-
serverLogger.Error(dErr, "failed to save extension", "targetFile", targetFile)
125-
}
126-
}
127-
}()
128-
}
129-
}
130-
131-
if err == nil {
132-
go s.startPlugin(socket, binaryPath, name)
133-
}
134-
return
94+
if v, ok := s.extStatusMap[name]; ok && v {
95+
return
96+
}
97+
platformBasedName := name
98+
if s.execer.OS() == "windows" {
99+
platformBasedName += ".exe"
100+
}
101+
targetDir := home.GetUserBinDir()
102+
targetBinaryFile := filepath.Join(targetDir, platformBasedName)
103+
104+
var binaryPath string
105+
if _, err = os.Stat(targetBinaryFile); err == nil {
106+
binaryPath = targetBinaryFile
107+
} else {
108+
serverLogger.Info("failed to find extension", "error", err.Error())
109+
110+
binaryPath, err = s.execer.LookPath(platformBasedName)
111+
if err != nil {
112+
err = fmt.Errorf("not found extension, try to download it, error: %v", err)
113+
go func() {
114+
s.ociDownloader.WithKind("store")
115+
s.ociDownloader.WithOS(s.execer.OS())
116+
reader, dErr := s.ociDownloader.Download(name, "", "")
117+
if dErr != nil {
118+
serverLogger.Error(dErr, "failed to download extension", "name", name)
119+
} else {
120+
extFile := s.ociDownloader.GetTargetFile()
121+
122+
targetFile := filepath.Base(extFile)
123+
if dErr = downloader.WriteTo(reader, targetDir, targetFile); dErr == nil {
124+
binaryPath = filepath.Join(targetDir, targetFile)
125+
s.startPlugin(socket, binaryPath, name)
126+
} else {
127+
serverLogger.Error(dErr, "failed to save extension", "targetFile", targetFile)
128+
}
129+
}
130+
}()
131+
}
132+
}
133+
134+
if err == nil {
135+
go s.startPlugin(socket, binaryPath, name)
136+
}
137+
return
135138
}
136139

137140
func (s *storeExtManager) startPlugin(socketURL, plugin, pluginName string) (err error) {
138-
if strings.Contains(socketURL, ":") && !strings.HasPrefix(socketURL, s.socketPrefix) {
139-
err = s.startPluginViaHTTP(socketURL, plugin, pluginName)
140-
return
141-
}
142-
socketFile := strings.TrimPrefix(socketURL, s.socketPrefix)
143-
_ = os.RemoveAll(socketFile) // always deleting the socket file to avoid start failing
141+
if strings.Contains(socketURL, ":") && !strings.HasPrefix(socketURL, s.socketPrefix) {
142+
err = s.startPluginViaHTTP(socketURL, plugin, pluginName)
143+
return
144+
}
145+
socketFile := strings.TrimPrefix(socketURL, s.socketPrefix)
146+
_ = os.RemoveAll(socketFile) // always deleting the socket file to avoid start failing
144147

145-
s.lock.Lock()
146-
s.filesNeedToBeRemoved = append(s.filesNeedToBeRemoved, socketFile)
147-
s.extStatusMap[pluginName] = true
148-
s.lock.Unlock()
148+
s.lock.Lock()
149+
s.filesNeedToBeRemoved = append(s.filesNeedToBeRemoved, socketFile)
150+
s.extStatusMap[pluginName] = true
151+
s.lock.Unlock()
149152

150-
if err = s.execer.RunCommandWithIO(plugin, "", os.Stdout, os.Stderr, s.processChan, "--socket", socketFile); err != nil {
151-
serverLogger.Info("failed to start ext manager", "socket", socketURL, "error: ", err.Error())
152-
}
153-
return
153+
if err = s.execer.RunCommandWithIO(plugin, "", os.Stdout, os.Stderr, s.processChan, "--socket", socketFile); err != nil {
154+
serverLogger.Info("failed to start ext manager", "socket", socketURL, "error: ", err.Error())
155+
}
156+
return
154157
}
155158

156159
func (s *storeExtManager) startPluginViaHTTP(httpURL, plugin, pluginName string) (err error) {
157-
port := strings.Split(httpURL, ":")[1]
158-
if err = s.execer.RunCommandWithIO(plugin, "", os.Stdout, os.Stderr, s.processChan, "--port", port); err != nil {
159-
serverLogger.Info("failed to start ext manager", "port", port, "error: ", err.Error())
160-
}
161-
return
160+
port := strings.Split(httpURL, ":")[1]
161+
if err = s.execer.RunCommandWithIO(plugin, "", os.Stdout, os.Stderr, s.processChan, "--port", port); err != nil {
162+
serverLogger.Info("failed to start ext manager", "port", port, "error: ", err.Error())
163+
}
164+
return
162165
}
163166

164167
func (s *storeExtManager) StopAll() error {
165-
serverLogger.Info("stop", "extensions", len(s.processs))
166-
for _, p := range s.processs {
167-
if p != nil {
168-
// Use Kill on Windows, Signal on other platforms
169-
if isWindows() {
170-
p.Kill()
171-
} else {
172-
p.Signal(syscall.SIGTERM)
173-
}
174-
}
175-
}
176-
s.stopSingal <- struct{}{}
177-
return nil
168+
serverLogger.Info("stop", "extensions", len(s.processs))
169+
for _, p := range s.processs {
170+
if p != nil {
171+
// Use Kill on Windows, Signal on other platforms
172+
if isWindows() {
173+
p.Kill()
174+
} else {
175+
p.Signal(syscall.SIGTERM)
176+
}
177+
}
178+
}
179+
s.stopSingal <- struct{}{}
180+
return nil
178181
}
179182

180183
// isWindows returns true if the program is running on Windows OS.
181184
func isWindows() bool {
182-
return strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") ||
183-
(strings.Contains(strings.ToLower(os.Getenv("GOOS")), "windows"))
185+
return strings.Contains(strings.ToLower(os.Getenv("OS")), "windows") ||
186+
(strings.Contains(strings.ToLower(os.Getenv("GOOS")), "windows"))
184187
}
185188

186189
func (s *storeExtManager) WithDownloader(ociDownloader downloader.PlatformAwareOCIDownloader) {
187-
s.ociDownloader = ociDownloader
190+
s.ociDownloader = ociDownloader
188191
}
189192

190193
func (s *storeExtManager) processCollect() {
191-
go func() {
192-
for {
193-
select {
194-
case p := <-s.processChan:
195-
s.processs = append(s.processs, p)
196-
case <-s.stopSingal:
197-
return
198-
}
199-
}
200-
}()
194+
go func() {
195+
for {
196+
select {
197+
case p := <-s.processChan:
198+
s.processs = append(s.processs, p)
199+
case <-s.stopSingal:
200+
return
201+
}
202+
}
203+
}()
201204
}
202205

203206
var ErrDownloadNotSupport = errors.New("no support")
@@ -207,44 +210,44 @@ type nonDownloader struct{}
207210
var _ downloader.PlatformAwareOCIDownloader = &nonDownloader{}
208211

209212
func (n *nonDownloader) WithBasicAuth(username string, password string) {
210-
// Do nothing because this is an empty implementation
213+
// Do nothing because this is an empty implementation
211214
}
212215

213216
func (n *nonDownloader) Download(image, tag, file string) (reader io.Reader, err error) {
214-
err = ErrDownloadNotSupport
215-
return
217+
err = ErrDownloadNotSupport
218+
return
216219
}
217220

218221
func (n *nonDownloader) WithOS(string) {
219-
// Do nothing because this is an empty implementation
222+
// Do nothing because this is an empty implementation
220223
}
221224

222225
func (n *nonDownloader) WithArch(string) {
223-
// Do nothing because this is an empty implementation
226+
// Do nothing because this is an empty implementation
224227
}
225228

226229
func (n *nonDownloader) WithRegistry(string) {
227-
// Do nothing because this is an empty implementation
230+
// Do nothing because this is an empty implementation
228231
}
229232

230233
func (n *nonDownloader) WithKind(string) {
231-
// Do nothing because this is an empty implementation
234+
// Do nothing because this is an empty implementation
232235
}
233236

234237
func (n *nonDownloader) WithImagePrefix(imagePrefix string) {
235-
// Do nothing because this is an empty implementation
238+
// Do nothing because this is an empty implementation
236239
}
237240
func (d *nonDownloader) WithRoundTripper(rt http.RoundTripper) {
238-
// Do nothing because this is an empty implementation
241+
// Do nothing because this is an empty implementation
239242
}
240243

241244
func (d *nonDownloader) WithInsecure(bool) {
242-
// Do nothing because this is an empty implementation
245+
// Do nothing because this is an empty implementation
243246
}
244247

245248
func (d *nonDownloader) WithTimeout(time.Duration) {}
246249
func (d *nonDownloader) WithContext(context.Context) {}
247250

248251
func (n *nonDownloader) GetTargetFile() string {
249-
return ""
252+
return ""
250253
}

0 commit comments

Comments
 (0)