From 917245a9a026ffac77e7c33c6ecfb474737922fe Mon Sep 17 00:00:00 2001 From: tls Date: Thu, 17 Apr 2025 18:34:43 +0800 Subject: [PATCH] feat: add windows compatibility (#133) --- .../local_runtime/environment_python.go | 13 ++++++++-- .../core/plugin_manager/local_runtime/run.go | 1 + .../media_transport/installed_bucket.go | 25 ++++++++++++++++--- .../media_transport/package_bucket.go | 17 +++++++++++-- internal/oss/local/local_storage.go | 5 ++-- pkg/entities/plugin_entities/identity.go | 2 ++ pkg/plugin_packager/decoder/zip.go | 6 ++--- 7 files changed, 56 insertions(+), 13 deletions(-) diff --git a/internal/core/plugin_manager/local_runtime/environment_python.go b/internal/core/plugin_manager/local_runtime/environment_python.go index 8287f5da..750e8b65 100644 --- a/internal/core/plugin_manager/local_runtime/environment_python.go +++ b/internal/core/plugin_manager/local_runtime/environment_python.go @@ -10,6 +10,7 @@ import ( "path" "path/filepath" "regexp" + "runtime" "strconv" "strings" "sync" @@ -32,7 +33,11 @@ func (p *LocalPluginRuntime) InitPythonEnvironment() error { os.RemoveAll(path.Join(p.State.WorkingPath, ".venv")) } else { // setup python interpreter path - pythonPath, err := filepath.Abs(path.Join(p.State.WorkingPath, ".venv/bin/python")) + pythonExec := ".venv/bin/python" + if runtime.GOOS == "windows" { + pythonExec = ".venv/Scripts/python.exe" + } + pythonPath, err := filepath.Abs(path.Join(p.State.WorkingPath, pythonExec)) if err != nil { return fmt.Errorf("failed to find python: %s", err) } @@ -85,7 +90,11 @@ func (p *LocalPluginRuntime) InitPythonEnvironment() error { } }() - pythonPath, err := filepath.Abs(path.Join(p.State.WorkingPath, ".venv/bin/python")) + pythonExec := ".venv/bin/python" + if runtime.GOOS == "windows" { + pythonExec = ".venv/Scripts/python.exe" + } + pythonPath, err := filepath.Abs(path.Join(p.State.WorkingPath, pythonExec)) if err != nil { return fmt.Errorf("failed to find python: %s", err) } diff --git a/internal/core/plugin_manager/local_runtime/run.go b/internal/core/plugin_manager/local_runtime/run.go index 50e0942f..857ad0bd 100644 --- a/internal/core/plugin_manager/local_runtime/run.go +++ b/internal/core/plugin_manager/local_runtime/run.go @@ -33,6 +33,7 @@ func (r *LocalPluginRuntime) getCmd() (*exec.Cmd, error) { cmd := exec.Command(r.pythonInterpreterPath, "-m", r.Config.Meta.Runner.Entrypoint) cmd.Dir = r.State.WorkingPath cmd.Env = cmd.Environ() + cmd.Env = append(cmd.Env, "PYTHONIOENCODING=utf-8") // for windows if r.HttpsProxy != "" { cmd.Env = append(cmd.Env, fmt.Sprintf("HTTPS_PROXY=%s", r.HttpsProxy)) } diff --git a/internal/core/plugin_manager/media_transport/installed_bucket.go b/internal/core/plugin_manager/media_transport/installed_bucket.go index 89bf578e..881fc62b 100644 --- a/internal/core/plugin_manager/media_transport/installed_bucket.go +++ b/internal/core/plugin_manager/media_transport/installed_bucket.go @@ -2,6 +2,7 @@ package media_transport import ( "path/filepath" + "runtime" "strings" "github.com/langgenius/dify-plugin-daemon/internal/oss" @@ -22,28 +23,44 @@ func (b *InstalledBucket) Save( plugin_unique_identifier plugin_entities.PluginUniqueIdentifier, file []byte, ) error { - return b.oss.Save(filepath.Join(b.installedPath, plugin_unique_identifier.String()), file) + compat_plugin_unique_identifier := plugin_unique_identifier.String() + if runtime.GOOS == "windows" { + compat_plugin_unique_identifier = strings.ReplaceAll(plugin_unique_identifier.String(), ":", "$") + } + return b.oss.Save(filepath.Join(b.installedPath, compat_plugin_unique_identifier), file) } // Exists checks if the plugin exists in the installed bucket func (b *InstalledBucket) Exists( plugin_unique_identifier plugin_entities.PluginUniqueIdentifier, ) (bool, error) { - return b.oss.Exists(filepath.Join(b.installedPath, plugin_unique_identifier.String())) + compat_plugin_unique_identifier := plugin_unique_identifier.String() + if runtime.GOOS == "windows" { + compat_plugin_unique_identifier = strings.ReplaceAll(plugin_unique_identifier.String(), ":", "$") + } + return b.oss.Exists(filepath.Join(b.installedPath, compat_plugin_unique_identifier)) } // Delete deletes the plugin from the installed bucket func (b *InstalledBucket) Delete( plugin_unique_identifier plugin_entities.PluginUniqueIdentifier, ) error { - return b.oss.Delete(filepath.Join(b.installedPath, plugin_unique_identifier.String())) + compat_plugin_unique_identifier := plugin_unique_identifier.String() + if runtime.GOOS == "windows" { + compat_plugin_unique_identifier = strings.ReplaceAll(plugin_unique_identifier.String(), ":", "$") + } + return b.oss.Delete(filepath.Join(b.installedPath, compat_plugin_unique_identifier)) } // Get gets the plugin from the installed bucket func (b *InstalledBucket) Get( plugin_unique_identifier plugin_entities.PluginUniqueIdentifier, ) ([]byte, error) { - return b.oss.Load(filepath.Join(b.installedPath, plugin_unique_identifier.String())) + compat_plugin_unique_identifier := plugin_unique_identifier.String() + if runtime.GOOS == "windows" { + compat_plugin_unique_identifier = strings.ReplaceAll(plugin_unique_identifier.String(), ":", "$") + } + return b.oss.Load(filepath.Join(b.installedPath, compat_plugin_unique_identifier)) } // List lists all the plugins in the installed bucket diff --git a/internal/core/plugin_manager/media_transport/package_bucket.go b/internal/core/plugin_manager/media_transport/package_bucket.go index b5960910..0f3c11c6 100644 --- a/internal/core/plugin_manager/media_transport/package_bucket.go +++ b/internal/core/plugin_manager/media_transport/package_bucket.go @@ -2,6 +2,8 @@ package media_transport import ( "path" + "runtime" + "strings" "github.com/langgenius/dify-plugin-daemon/internal/oss" ) @@ -17,16 +19,27 @@ func NewPackageBucket(oss oss.OSS, package_path string) *PackageBucket { // Save saves a file to the package bucket func (m *PackageBucket) Save(name string, file []byte) error { + if runtime.GOOS == "windows" { + name = strings.ReplaceAll(name, ":", "$") + } filePath := path.Join(m.packagePath, name) return m.oss.Save(filePath, file) } func (m *PackageBucket) Get(name string) ([]byte, error) { - return m.oss.Load(path.Join(m.packagePath, name)) + if runtime.GOOS == "windows" { + name = strings.ReplaceAll(name, ":", "$") + } + filePath := path.Join(m.packagePath, name) + return m.oss.Load(filePath) } func (m *PackageBucket) Delete(name string) error { // delete from storage - return m.oss.Delete(path.Join(m.packagePath, name)) + if runtime.GOOS == "windows" { + name = strings.ReplaceAll(name, ":", "$") + } + filePath := path.Join(m.packagePath, name) + return m.oss.Delete(filePath) } diff --git a/internal/oss/local/local_storage.go b/internal/oss/local/local_storage.go index 958ad90e..7cdbc078 100644 --- a/internal/oss/local/local_storage.go +++ b/internal/oss/local/local_storage.go @@ -66,13 +66,14 @@ func (l *LocalStorage) List(prefix string) ([]oss.OSSPath, error) { if !exists { return paths, nil } - prefix = filepath.Join(l.root, prefix) + prefix = filepath.ToSlash(filepath.Join(l.root, prefix)) err = filepath.WalkDir(prefix, func(path string, d fs.DirEntry, err error) error { if err != nil { return err } // remove prefix + path = filepath.ToSlash(path) path = strings.TrimPrefix(path, prefix) if path == "" { return nil @@ -101,4 +102,4 @@ func (l *LocalStorage) Delete(key string) error { func (l *LocalStorage) Type() string { return oss.OSS_TYPE_LOCAL -} \ No newline at end of file +} diff --git a/pkg/entities/plugin_entities/identity.go b/pkg/entities/plugin_entities/identity.go index 7934d86f..7f14a0ab 100644 --- a/pkg/entities/plugin_entities/identity.go +++ b/pkg/entities/plugin_entities/identity.go @@ -25,6 +25,8 @@ var ( ) func NewPluginUniqueIdentifier(identifier string) (PluginUniqueIdentifier, error) { + identifier = strings.ReplaceAll(identifier, "$", ":") // for windows + if !pluginUniqueIdentifierRegexp.MatchString(identifier) { return "", errors.New("plugin_unique_identifier is not valid: " + identifier) } diff --git a/pkg/plugin_packager/decoder/zip.go b/pkg/plugin_packager/decoder/zip.go index f2774af5..1b7aa950 100644 --- a/pkg/plugin_packager/decoder/zip.go +++ b/pkg/plugin_packager/decoder/zip.go @@ -248,18 +248,18 @@ func (z *ZipPluginDecoder) UniqueIdentity() (plugin_entities.PluginUniqueIdentif func (z *ZipPluginDecoder) ExtractTo(dst string) error { // copy to working directory if err := z.Walk(func(filename, dir string) error { - workingPath := path.Join(dst, dir) + workingPath := filepath.ToSlash(path.Join(dst, dir)) // check if directory exists if err := os.MkdirAll(workingPath, 0755); err != nil { return err } - bytes, err := z.ReadFile(filepath.Join(dir, filename)) + bytes, err := z.ReadFile(filepath.ToSlash(filepath.Join(dir, filename))) if err != nil { return err } - filename = filepath.Join(workingPath, filename) + filename = filepath.ToSlash(filepath.Join(workingPath, filename)) // copy file if err := os.WriteFile(filename, bytes, 0644); err != nil {