From a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 Mon Sep 17 00:00:00 2001 From: Nippy Date: Sat, 9 May 2026 13:33:09 +0200 Subject: raveos update --- .../core/internal/plugins/manager.go | 588 --------------------- 1 file changed, 588 deletions(-) delete mode 100644 raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/plugins/manager.go (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/plugins/manager.go') diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/plugins/manager.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/plugins/manager.go deleted file mode 100644 index 1c0ddf5..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/plugins/manager.go +++ /dev/null @@ -1,588 +0,0 @@ -package plugins - -import ( - "crypto/sha256" - "encoding/hex" - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - "github.com/spf13/afero" -) - -type Manager struct { - fs afero.Fs - pluginsDir string - gitClient GitClient -} - -func NewManager() (*Manager, error) { - return NewManagerWithFs(afero.NewOsFs()) -} - -func NewManagerWithFs(fs afero.Fs) (*Manager, error) { - pluginsDir := getPluginsDir() - return &Manager{ - fs: fs, - pluginsDir: pluginsDir, - gitClient: &realGitClient{}, - }, nil -} - -func getPluginsDir() string { - configDir, err := os.UserConfigDir() - if err != nil { - log.Error("failed to get user config dir", "err", err) - return "" - } - return filepath.Join(configDir, "DankMaterialShell", "plugins") -} - -func (m *Manager) IsInstalled(plugin Plugin) (bool, error) { - path, err := m.findInstalledPath(plugin.ID) - if err != nil { - return false, err - } - return path != "", nil -} - -func (m *Manager) findInstalledPath(pluginID string) (string, error) { - // Check user plugins directory - path, err := m.findInDir(m.pluginsDir, pluginID) - if err != nil { - return "", err - } - if path != "" { - return path, nil - } - - // Check system plugins directory - systemDir := "/etc/xdg/quickshell/dms-plugins" - return m.findInDir(systemDir, pluginID) -} - -func (m *Manager) findInDir(dir, pluginID string) (string, error) { - // First, check if folder with exact ID name exists - exactPath := filepath.Join(dir, pluginID) - if exists, _ := afero.DirExists(m.fs, exactPath); exists { - return exactPath, nil - } - - // Scan all folders and check plugin.json for matching ID - exists, err := afero.DirExists(m.fs, dir) - if err != nil || !exists { - return "", nil - } - - entries, err := afero.ReadDir(m.fs, dir) - if err != nil { - return "", nil - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(dir, name) - isPlugin := entry.IsDir() || entry.Mode()&os.ModeSymlink != 0 - if !isPlugin { - if info, err := m.fs.Stat(fullPath); err == nil && info.IsDir() { - isPlugin = true - } - } - - if isPlugin && m.getPluginID(fullPath) == pluginID { - return fullPath, nil - } - } - - return "", nil -} - -func (m *Manager) Install(plugin Plugin) error { - pluginPath := filepath.Join(m.pluginsDir, plugin.ID) - - exists, err := afero.DirExists(m.fs, pluginPath) - if err != nil { - return fmt.Errorf("failed to check if plugin exists: %w", err) - } - - if exists { - return fmt.Errorf("plugin already installed: %s", plugin.Name) - } - - if err := m.fs.MkdirAll(m.pluginsDir, 0o755); err != nil { - return fmt.Errorf("failed to create plugins directory: %w", err) - } - - reposDir := filepath.Join(m.pluginsDir, ".repos") - if err := m.fs.MkdirAll(reposDir, 0o755); err != nil { - return fmt.Errorf("failed to create repos directory: %w", err) - } - - if plugin.Path != "" { - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - repoExists, err := afero.DirExists(m.fs, repoPath) - if err != nil { - return fmt.Errorf("failed to check if repo exists: %w", err) - } - - if !repoExists { - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - m.fs.RemoveAll(repoPath) //nolint:errcheck - return fmt.Errorf("failed to clone repository: %w", err) - } - } else { - // Pull latest changes if repo already exists - if err := m.gitClient.Pull(repoPath); err != nil { - // If pull fails (e.g., corrupted shallow clone), delete and re-clone - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to remove corrupted repository: %w", err) - } - - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone repository: %w", err) - } - } - } - - sourcePath := filepath.Join(repoPath, plugin.Path) - sourceExists, err := afero.DirExists(m.fs, sourcePath) - if err != nil { - return fmt.Errorf("failed to check plugin path: %w", err) - } - if !sourceExists { - return fmt.Errorf("plugin path does not exist in repository: %s", plugin.Path) - } - - if err := m.createSymlink(sourcePath, pluginPath); err != nil { - return fmt.Errorf("failed to create symlink: %w", err) - } - - metaPath := pluginPath + ".meta" - metaContent := fmt.Sprintf("repo=%s\npath=%s\nrepodir=%s", plugin.Repo, plugin.Path, repoName) - if err := afero.WriteFile(m.fs, metaPath, []byte(metaContent), 0o644); err != nil { - return fmt.Errorf("failed to write metadata: %w", err) - } - } else { - if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil { - m.fs.RemoveAll(pluginPath) //nolint:errcheck - return fmt.Errorf("failed to clone plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) getRepoName(repoURL string) string { - hash := sha256.Sum256([]byte(repoURL)) - return hex.EncodeToString(hash[:])[:16] -} - -func (m *Manager) createSymlink(source, dest string) error { - if symlinkFs, ok := m.fs.(afero.Symlinker); ok { - return symlinkFs.SymlinkIfPossible(source, dest) - } - return os.Symlink(source, dest) -} - -func (m *Manager) Update(plugin Plugin) error { - pluginPath, err := m.findInstalledPath(plugin.ID) - if err != nil { - return fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot update system plugin: %s", plugin.Name) - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - // Try to pull, if it fails (e.g., shallow clone corruption), delete and re-clone - if err := m.gitClient.Pull(repoPath); err != nil { - // Repository is likely corrupted or has issues, delete and re-clone - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to remove corrupted repository: %w", err) - } - - if err := m.gitClient.PlainClone(repoPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone repository: %w", err) - } - } - } else { - // Try to pull, if it fails, delete and re-clone - if err := m.gitClient.Pull(pluginPath); err != nil { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove corrupted plugin: %w", err) - } - - if err := m.gitClient.PlainClone(pluginPath, plugin.Repo); err != nil { - return fmt.Errorf("failed to re-clone plugin: %w", err) - } - } - } - - return nil -} - -func (m *Manager) Uninstall(plugin Plugin) error { - pluginPath, err := m.findInstalledPath(plugin.ID) - if err != nil { - return fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return fmt.Errorf("plugin not installed: %s", plugin.Name) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot uninstall system plugin: %s", plugin.Name) - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - shouldCleanup, err := m.shouldCleanupRepo(repoPath, plugin.Repo, plugin.ID) - if err != nil { - return fmt.Errorf("failed to check repo cleanup: %w", err) - } - - if err := m.fs.Remove(pluginPath); err != nil { - return fmt.Errorf("failed to remove symlink: %w", err) - } - - if err := m.fs.Remove(metaPath); err != nil { - return fmt.Errorf("failed to remove metadata: %w", err) - } - - if shouldCleanup { - if err := m.fs.RemoveAll(repoPath); err != nil { - return fmt.Errorf("failed to cleanup repository: %w", err) - } - } - } else { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) shouldCleanupRepo(repoPath, repoURL, excludePlugin string) (bool, error) { - installed, err := m.ListInstalled() - if err != nil { - return false, err - } - - registry, err := NewRegistry() - if err != nil { - return false, err - } - - allPlugins, err := registry.List() - if err != nil { - return false, err - } - - for _, id := range installed { - if id == excludePlugin { - continue - } - - for _, p := range allPlugins { - if p.ID == id && p.Repo == repoURL && p.Path != "" { - return false, nil - } - } - } - - return true, nil -} - -func (m *Manager) ListInstalled() ([]string, error) { - installedMap := make(map[string]bool) - - exists, err := afero.DirExists(m.fs, m.pluginsDir) - if err != nil { - return nil, err - } - - if exists { - entries, err := afero.ReadDir(m.fs, m.pluginsDir) - if err != nil { - return nil, fmt.Errorf("failed to read plugins directory: %w", err) - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(m.pluginsDir, name) - isPlugin := false - - if entry.IsDir() { - isPlugin = true - } else if entry.Mode()&os.ModeSymlink != 0 { - isPlugin = true - } else { - info, err := m.fs.Stat(fullPath) - if err == nil && info.IsDir() { - isPlugin = true - } - } - - if isPlugin { - // Read plugin.json to get the actual plugin ID - pluginID := m.getPluginID(fullPath) - if pluginID != "" { - installedMap[pluginID] = true - } - } - } - } - - systemPluginsDir := "/etc/xdg/quickshell/dms-plugins" - systemExists, err := afero.DirExists(m.fs, systemPluginsDir) - if err == nil && systemExists { - entries, err := afero.ReadDir(m.fs, systemPluginsDir) - if err == nil { - for _, entry := range entries { - if entry.IsDir() { - fullPath := filepath.Join(systemPluginsDir, entry.Name()) - // Read plugin.json to get the actual plugin ID - pluginID := m.getPluginID(fullPath) - if pluginID != "" { - installedMap[pluginID] = true - } - } - } - } - } - - var installed []string - for name := range installedMap { - installed = append(installed, name) - } - - return installed, nil -} - -// getPluginID reads the plugin.json file and returns the plugin ID -func (m *Manager) getPluginID(pluginPath string) string { - manifest := m.getPluginManifest(pluginPath) - if manifest == nil { - return "" - } - return manifest.ID -} - -func (m *Manager) getPluginManifest(pluginPath string) *pluginManifest { - manifestPath := filepath.Join(pluginPath, "plugin.json") - data, err := afero.ReadFile(m.fs, manifestPath) - if err != nil { - return nil - } - - var manifest pluginManifest - if err := json.Unmarshal(data, &manifest); err != nil { - return nil - } - - return &manifest -} - -type pluginManifest struct { - ID string `json:"id"` - Name string `json:"name"` -} - -func (m *Manager) GetPluginsDir() string { - return m.pluginsDir -} - -func (m *Manager) UninstallByIDOrName(idOrName string) error { - pluginPath, err := m.findInstalledPathByIDOrName(idOrName) - if err != nil { - return err - } - if pluginPath == "" { - return fmt.Errorf("plugin not found: %s", idOrName) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot uninstall system plugin: %s", idOrName) - } - - metaPath := pluginPath + ".meta" - metaExists, _ := afero.Exists(m.fs, metaPath) - - if metaExists { - if err := m.fs.Remove(pluginPath); err != nil { - return fmt.Errorf("failed to remove symlink: %w", err) - } - if err := m.fs.Remove(metaPath); err != nil { - return fmt.Errorf("failed to remove metadata: %w", err) - } - } else { - if err := m.fs.RemoveAll(pluginPath); err != nil { - return fmt.Errorf("failed to remove plugin: %w", err) - } - } - - return nil -} - -func (m *Manager) UpdateByIDOrName(idOrName string) error { - pluginPath, err := m.findInstalledPathByIDOrName(idOrName) - if err != nil { - return err - } - if pluginPath == "" { - return fmt.Errorf("plugin not found: %s", idOrName) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return fmt.Errorf("cannot update system plugin: %s", idOrName) - } - - metaPath := pluginPath + ".meta" - metaExists, _ := afero.Exists(m.fs, metaPath) - - if metaExists { - // Plugin is from monorepo, but we don't know the repo URL without registry - // Just try to pull from existing .git in the symlink target - return fmt.Errorf("cannot update monorepo plugin without registry info: %s", idOrName) - } - - // Standalone plugin - just pull - if err := m.gitClient.Pull(pluginPath); err != nil { - return fmt.Errorf("failed to update plugin: %w", err) - } - - return nil -} - -func (m *Manager) findInstalledPathByIDOrName(idOrName string) (string, error) { - path, err := m.findInDirByIDOrName(m.pluginsDir, idOrName) - if err != nil { - return "", err - } - if path != "" { - return path, nil - } - - systemDir := "/etc/xdg/quickshell/dms-plugins" - return m.findInDirByIDOrName(systemDir, idOrName) -} - -func (m *Manager) findInDirByIDOrName(dir, idOrName string) (string, error) { - // Check exact folder name match first - exactPath := filepath.Join(dir, idOrName) - if exists, _ := afero.DirExists(m.fs, exactPath); exists { - return exactPath, nil - } - - exists, err := afero.DirExists(m.fs, dir) - if err != nil || !exists { - return "", nil - } - - entries, err := afero.ReadDir(m.fs, dir) - if err != nil { - return "", nil - } - - for _, entry := range entries { - name := entry.Name() - if name == ".repos" || strings.HasSuffix(name, ".meta") { - continue - } - - fullPath := filepath.Join(dir, name) - isPlugin := entry.IsDir() || entry.Mode()&os.ModeSymlink != 0 - if !isPlugin { - if info, err := m.fs.Stat(fullPath); err == nil && info.IsDir() { - isPlugin = true - } - } - - if !isPlugin { - continue - } - - manifest := m.getPluginManifest(fullPath) - if manifest == nil { - continue - } - - if manifest.ID == idOrName || manifest.Name == idOrName { - return fullPath, nil - } - } - - return "", nil -} - -func (m *Manager) HasUpdates(pluginID string, plugin Plugin) (bool, error) { - pluginPath, err := m.findInstalledPath(pluginID) - if err != nil { - return false, fmt.Errorf("failed to find plugin: %w", err) - } - - if pluginPath == "" { - return false, fmt.Errorf("plugin not installed: %s", pluginID) - } - - if strings.HasPrefix(pluginPath, "/etc/xdg/quickshell/dms-plugins") { - return false, nil - } - - metaPath := pluginPath + ".meta" - metaExists, err := afero.Exists(m.fs, metaPath) - if err != nil { - return false, fmt.Errorf("failed to check metadata: %w", err) - } - - if metaExists { - // Plugin is from a monorepo, check the repo directory - reposDir := filepath.Join(m.pluginsDir, ".repos") - repoName := m.getRepoName(plugin.Repo) - repoPath := filepath.Join(reposDir, repoName) - - return m.gitClient.HasUpdates(repoPath) - } - - // Plugin is a standalone repo - return m.gitClient.HasUpdates(pluginPath) -} -- cgit v1.3