X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fxds%2Fxds-server.git;a=blobdiff_plain;f=lib%2Fxdsserver%2Fsdks.go;fp=lib%2Fxdsserver%2Fsdks.go;h=38e380d156732a7c64d6f0912d991006f49ce843;hp=35aa0ba5b17d25714add5bcc29bd07e487013d37;hb=f1c182ede3c4aed0d6196d05b0a64ff93372e755;hpb=285332c351777b74abca638b8b2a2cde3c68edc6 diff --git a/lib/xdsserver/sdks.go b/lib/xdsserver/sdks.go index 35aa0ba..38e380d 100644 --- a/lib/xdsserver/sdks.go +++ b/lib/xdsserver/sdks.go @@ -26,6 +26,7 @@ import ( common "github.com/iotbzh/xds-common/golib" "github.com/iotbzh/xds-server/lib/xsapiv1" + uuid "github.com/satori/go.uuid" ) // SDKs List of installed SDK @@ -34,6 +35,7 @@ type SDKs struct { Sdks map[string]*CrossSDK mutex sync.Mutex + stop chan struct{} // signals intentional stop } // NewSDKs creates a new instance of SDKs @@ -41,40 +43,140 @@ func NewSDKs(ctx *Context) (*SDKs, error) { s := SDKs{ Context: ctx, Sdks: make(map[string]*CrossSDK), + stop: make(chan struct{}), } - // Retrieve installed sdks - sdkRD := ctx.Config.FileConf.SdkRootDir + scriptsDir := ctx.Config.FileConf.SdkScriptsDir + if !common.Exists(scriptsDir) { + // allow to use scripts/sdk in debug mode + scriptsDir = filepath.Join(filepath.Dir(ctx.Config.FileConf.SdkScriptsDir), "scripts", "sdks") + if !common.Exists(scriptsDir) { + return &s, fmt.Errorf("scripts directory doesn't exist (%v)", scriptsDir) + } + } + s.Log.Infof("SDK scripts dir: %s", scriptsDir) + + dirs, err := filepath.Glob(path.Join(scriptsDir, "*")) + if err != nil { + s.Log.Errorf("Error while retrieving SDK scripts: dir=%s, error=%s", scriptsDir, err.Error()) + return &s, err + } - if common.Exists(sdkRD) { + s.mutex.Lock() + defer s.mutex.Unlock() - // Assume that SDK install tree is /// - dirs, err := filepath.Glob(path.Join(sdkRD, "*", "*", "*")) + // Foreach directories in scripts/sdk + nbInstalled := 0 + monSdksPath := make(map[string]*xsapiv1.SDKFamilyConfig) + for _, d := range dirs { + if !common.IsDir(d) { + continue + } + + sdksList, err := ListCrossSDK(d, s.Log) if err != nil { - ctx.Log.Debugf("Error while retrieving SDKs: dir=%s, error=%s", sdkRD, err.Error()) return &s, err } - s.mutex.Lock() - defer s.mutex.Unlock() + s.LogSillyf("'%s' SDKs list: %v", d, sdksList) - for _, d := range dirs { - if !common.IsDir(d) { - continue - } - cSdk, err := NewCrossSDK(d) + for _, sdk := range sdksList { + cSdk, err := NewCrossSDK(ctx, sdk, d) if err != nil { - ctx.Log.Debugf("Error while processing SDK dir=%s, err=%s", d, err.Error()) + s.Log.Debugf("Error while processing SDK sdk=%v\n err=%s", sdk, err.Error()) continue } + if _, exist := s.Sdks[cSdk.sdk.ID]; exist { + s.Log.Warningf("Duplicate SDK ID : %v", cSdk.sdk.ID) + cSdk.sdk.ID += "_DUPLICATE_" + uuid.NewV1().String() + } s.Sdks[cSdk.sdk.ID] = cSdk + if cSdk.sdk.Status == xsapiv1.SdkStatusInstalled { + nbInstalled++ + } + + monSdksPath[cSdk.sdk.FamilyConf.RootDir] = &cSdk.sdk.FamilyConf } } - ctx.Log.Debugf("SDKs: %d cross sdks found", len(s.Sdks)) + ctx.Log.Debugf("Cross SDKs: %d defined, %d installed", len(s.Sdks), nbInstalled) + + // Start monitor thread to detect new SDKs + if len(monSdksPath) == 0 { + s.Log.Warningf("No cross SDKs definition found") + } return &s, nil } +// Stop SDKs management +func (s *SDKs) Stop() { + close(s.stop) +} + +// monitorSDKInstallation +/* TODO: cleanup +func (s *SDKs) monitorSDKInstallation(monSDKs map[string]*xsapiv1.SDKFamilyConfig) { + + // Set up a watchpoint listening for inotify-specific events + c := make(chan notify.EventInfo, 1) + + addWatcher := func(rootDir string) error { + s.Log.Debugf("SDK Register watcher: rootDir=%s", rootDir) + + if err := notify.Watch(rootDir+"/...", c, notify.Create, notify.Remove); err != nil { + return fmt.Errorf("SDK monitor: rootDir=%v err=%v", rootDir, err) + } + return nil + } + + // Add directory watchers + for dir := range monSDKs { + if err := addWatcher(dir); err != nil { + s.Log.Errorln(err.Error()) + } + } + + // Wait inotify or stop events + for { + select { + case <-s.stop: + s.Log.Debugln("Stop monitorSDKInstallation") + notify.Stop(c) + return + case ei := <-c: + s.LogSillyf("monitorSDKInstallation SDKs event %v, path %v\n", ei.Event(), ei.Path()) + + // Filter out all event that doesn't match environment file + if !strings.Contains(ei.Path(), "environment-setup-") { + continue + } + dir := path.Dir(ei.Path()) + + sdk, err := s.GetByPath(dir) + if err != nil { + s.Log.Warningf("Cannot find SDK path to notify creation") + s.LogSillyf("event: %v", ei.Event()) + continue + } + + switch ei.Event() { + case notify.Create: + // Emit Folder state change event + if err := s.events.Emit(xsapiv1.EVTSDKInstall, sdk, ""); err != nil { + s.Log.Warningf("Cannot notify SDK install: %v", err) + } + + case notify.Remove, notify.InMovedFrom: + // Emit Folder state change event + if err := s.events.Emit(xsapiv1.EVTSDKRemove, sdk, ""); err != nil { + s.Log.Warningf("Cannot notify SDK remove: %v", err) + } + } + } + } +} +*/ + // ResolveID Complete an SDK ID (helper for user that can use partial ID value) func (s *SDKs) ResolveID(id string) (string, error) { if id == "" { @@ -108,6 +210,19 @@ func (s *SDKs) Get(id string) *xsapiv1.SDK { return (*sc).Get() } +// GetByPath Find a SDK from path +func (s *SDKs) GetByPath(path string) (*xsapiv1.SDK, error) { + if path == "" { + return nil, fmt.Errorf("can't found sdk (empty path)") + } + for _, ss := range s.Sdks { + if ss.sdk.Path == path { + return ss.Get(), nil + } + } + return nil, fmt.Errorf("not found") +} + // GetAll returns all existing SDKs func (s *SDKs) GetAll() []xsapiv1.SDK { s.mutex.Lock() @@ -142,3 +257,80 @@ func (s *SDKs) GetEnvCmd(id string, defaultID string) []string { // Return default env that may be empty return []string{} } + +// Install Used to install a new SDK +func (s *SDKs) Install(id, filepath string, force bool, timeout int, sess *ClientSession) (*xsapiv1.SDK, error) { + var cSdk *CrossSDK + if id != "" && filepath != "" { + return nil, fmt.Errorf("invalid parameter, both id and filepath are set") + } + if id != "" { + var exist bool + cSdk, exist = s.Sdks[id] + if !exist { + return nil, fmt.Errorf("unknown id") + } + } else if filepath != "" { + // TODO check that file is accessible + + } else { + return nil, fmt.Errorf("invalid parameter, id or filepath must be set") + } + + s.mutex.Lock() + defer s.mutex.Unlock() + + // Launch script to install + // (note that add event will be generated by monitoring thread) + if err := cSdk.Install(filepath, force, timeout, sess); err != nil { + return &cSdk.sdk, err + } + + return &cSdk.sdk, nil +} + +// AbortInstall Used to abort SDK installation +func (s *SDKs) AbortInstall(id string, timeout int) (*xsapiv1.SDK, error) { + + if id == "" { + return nil, fmt.Errorf("invalid parameter") + } + cSdk, exist := s.Sdks[id] + if !exist { + return nil, fmt.Errorf("unknown id") + } + + s.mutex.Lock() + defer s.mutex.Unlock() + + err := cSdk.AbortInstallRemove(timeout) + + return &cSdk.sdk, err +} + +// Remove Used to uninstall a SDK +func (s *SDKs) Remove(id string) (*xsapiv1.SDK, error) { + s.mutex.Lock() + defer s.mutex.Unlock() + + cSdk, exist := s.Sdks[id] + if !exist { + return nil, fmt.Errorf("unknown id") + } + + s.mutex.Lock() + defer s.mutex.Unlock() + + // Launch script to remove/uninstall + // (note that remove event will be generated by monitoring thread) + if err := cSdk.Remove(); err != nil { + return &cSdk.sdk, err + } + + sdk := cSdk.sdk + + // Don't delete it from s.Sdks + // (always keep sdk reference to allow for example re-install) + + return &sdk, nil +}