Documentation
¶
Overview ¶
Copyright 2025 PRAS
Copyright © 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
This command implements the Prasmoid CLI update functionality using a remote update script. Instead of embedding complex update logic directly in the Go code, which would increase the binary size by approximately 2MB, this approach leverages a lightweight shell script hosted on GitHub. This design choice ensures that Prasmoid remains lightweight while maintaining robust update capabilities.
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright © 2025 PRAS ¶
Copyright 2025 PRAS ¶
Copyright 2025 PRAS
Index ¶
- Variables
- func ApplyChanges()
- func CheckForUpdates()
- func CompileI18n(config types.Config, silent bool) error
- func CreateConfigFile(locales []string) error
- func DiscoverAndRegisterCustomCommands(rootCmd *cobra.Command)
- func Execute()
- func GetCacheFilePath() string
- func GetNextVersion(version string, bump string) (string, error)
- func InitPlasmoid() error
- func InstallPlasmoid() error
- func LinkPlasmoid(dest string) error
- func ReadUpdateCache() (map[string]interface{}, error)
- func UninstallPlasmoid() error
- func UpdateChangelog(version, date, body string) error
- type Author
- type ChangesetMeta
- type KPlugin
- type Metadata
- type ProjectConfig
Constants ¶
This section is empty.
Variables ¶
var BuildCmd = &cobra.Command{ Use: "build", Short: "Build the project", Long: "Package the project files and generate the deployable .plasmoid archive.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } color.Cyan("→ Compiling translations...") if err := CompileI18n(ConfigRC, false); err != nil { color.Red("Failed to compile translations: %v", err) color.Yellow("Continuing build without translations...") } else { color.Green("Translations compiled successfully.") } color.Cyan("→ Starting plasmoid build...") plasmoidID, ierr := utils.GetDataFromMetadata("Id") version, verr := utils.GetDataFromMetadata("Version") if ierr != nil || verr != nil { color.Red("Failed to get plasmoid version: %v", fmt.Errorf("%v or %v", ierr, verr)) return } zipFileName := plasmoidID.(string) + "-" + version.(string) + ".plasmoid" if err := os.RemoveAll(buildOutputDir); err != nil { color.Red("Failed to clean build dir: %v", err) return } if err := os.MkdirAll(buildOutputDir, 0755); err != nil { color.Red("Failed to create build dir: %v", err) return } outFile, err := os.Create(filepath.Join(buildOutputDir, zipFileName)) if err != nil { color.Red("Failed to create zip file: %v", err) return } defer outFile.Close() zipWriter := zip.NewWriter(outFile) defer zipWriter.Close() if err := addFileToZip(zipWriter, "metadata.json"); err != nil { color.Red("Error adding metadata.json: %v", err) return } if err := addDirToZip(zipWriter, "contents"); err != nil { color.Red("Error adding contents/: %v", err) return } color.Green("Build complete: %s", color.YellowString(filepath.Join(buildOutputDir, zipFileName))) }, }
buildCmd represents the build command
var ChangesFolder string = ".changes"
var ChangesetAddCmd = &cobra.Command{ Use: "add", Short: "Create a new changeset", Run: func(cmd *cobra.Command, args []string) { bump = strings.ToLower(bump) version, _ := utils.GetDataFromMetadata("Version") id, _ := utils.GetDataFromMetadata("Id") var next string bumpLabels := make(map[string]string) for _, bumpType := range []string{"patch", "minor", "major"} { if nextVer, err := GetNextVersion(version.(string), bumpType); err == nil { bumpLabels[bumpType] = fmt.Sprintf("%s (%s)", bumpType, nextVer) } else { color.Red("Failed to compute next version for %s: %v", bumpType, err) return } } options := []string{bumpLabels["patch"], bumpLabels["minor"], bumpLabels["major"]} if !validBumps[bump] { var selected string err := survey.AskOne(&survey.Select{ Message: "Select version bump:", Options: options, Default: bumpLabels["patch"], }, &selected) if err != nil { color.Red("Failed to prompt for version bump: %v", err) return } parts := strings.SplitN(selected, " ", 2) bump = parts[0] } if next == "" { var err error next, err = GetNextVersion(version.(string), bump) if err != nil { color.Red("Failed to compute next version for %s: %v", bump, err) return } } if summary == "" { var err error summary, err = openEditor() if err != nil || strings.TrimSpace(summary) == "" { prompt := &survey.Input{ Message: "Enter changelog summary:", } err = survey.AskOne(prompt, &summary) if err != nil { color.Red("Failed to prompt for changelog summary: %v", err) return } } } if strings.TrimSpace(summary) == "" { color.Red("Empty changelog. Aborting.") return } if err := os.MkdirAll(ChangesFolder, 0755); err != nil { color.Red("Failed to create changes directory: %v", err) return } now := time.Now() timestamp := now.Format("2006-01-02-15-04") dateOnly := now.Format("2006-01-02") filename := filepath.Join(ChangesFolder, fmt.Sprintf("%s-%s.mdx", timestamp, bump)) content := fmt.Sprintf(`--- id: %s bump: %s next: %s date: %s --- %s `, id, bump, next, dateOnly, summary) if err := os.WriteFile(filename, []byte(content), 0644); err != nil { color.Red("Failed to write changeset: %v", err) return } var applyChanges bool applyConfirmPrompt := &survey.Confirm{ Message: color.YellowString("Changeset created. Would you like to apply it now?"), Default: false, } if err := survey.AskOne(applyConfirmPrompt, &applyChanges); err != nil { return } if applyChanges { ApplyChanges() } }, }
var ChangesetApplyCmd = &cobra.Command{ Use: "apply", Short: "Apply all .mdx changesets from the .changes directory", Run: func(cmd *cobra.Command, args []string) { ApplyChanges() }, }
changesetApplyCmd represents the changesetApply command
var ChangesetRootCmd = &cobra.Command{
Use: "changeset",
Short: "Manage release lifecycle commands",
Long: "Handle creating, applying, and managing changesets and version bumps for the plasmoid.",
}
changeset/rootCmd represents the changeset/root command
var CliConfig struct { Version string `yaml:"version"` Name string `yaml:"name"` Author string `yaml:"author"` License string `yaml:"license"` Github string `yaml:"github"` }
var CommandsAddCmd = &cobra.Command{ Use: "add", Short: "Add a custom command", Long: "Add a custom command to the project.", Run: func(cmd *cobra.Command, args []string) { invalidChars := regexp.MustCompile(`[\\/:*?"<>|\s@]`) if strings.TrimSpace(commandName) == "" || invalidChars.MatchString(commandName) { namePrompt := &survey.Input{ Message: "Command name:", } if err := survey.AskOne(namePrompt, &commandName, survey.WithValidator(func(ans interface{}) error { name := ans.(string) if name == "" { return errors.New("command name cannot be empty") } if invalidChars.MatchString(name) { return errors.New("invalid characters in command name") } baseName := filepath.Join(ConfigRC.Commands.Dir, name) if _, err := os.Stat(baseName + ".js"); err == nil { return errors.New("command name already exists with extension .js") } return nil })); err != nil { return } } template := commandTemplates["js"] if _, err := os.Stat(ConfigRC.Commands.Dir); os.IsNotExist(err) { os.MkdirAll(ConfigRC.Commands.Dir, 0755) } commandFile := commandName + ".js" filePath := filepath.Join(ConfigRC.Commands.Dir, commandFile) file, err := os.Create(filePath) if err != nil { color.Red("Error creating file: %v", err) return } defer file.Close() absCommandFilePath, _ := filepath.Abs(filePath) cwd, _ := os.Getwd() rootDir, _ := filepath.Abs(cwd) prasmoidDef := filepath.Join(rootDir, "prasmoid.d.ts") relPath, err := filepath.Rel(filepath.Dir(absCommandFilePath), prasmoidDef) if err != nil { color.Red("Error calculating relative path: %v", err) return } templateFilled := fmt.Sprintf(template, relPath, commandName) _, err = file.WriteString(templateFilled) if err != nil { color.Red("Error writing to file: %v", err) return } color.Green("Successfully created %s command at %s", commandName, color.BlueString(filePath)) }, }
var CommandsRemoveCmd = &cobra.Command{ Use: "remove", Short: "Remove a custom command", Long: "Remove a custom command to the project.", Run: func(cmd *cobra.Command, args []string) { availableCmds := []string{} filepath.Walk(ConfigRC.Commands.Dir, func(path string, info os.FileInfo, err error) error { if info.IsDir() { return nil } availableCmds = append(availableCmds, fmt.Sprintf("%s (%s)", strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())), info.Name())) return nil }) if strings.TrimSpace(rmCommandName) == "" { runtimePrompt := &survey.Select{ Message: "Select a command to remove:", Options: availableCmds, } if err := survey.AskOne(runtimePrompt, &rmCommandName); err != nil { return } } filenameRegex := regexp.MustCompile(`\(([^)]+)\)$`) matches := filenameRegex.FindStringSubmatch(rmCommandName) if len(matches) != 2 { color.Red("Invalid command format") return } fileName := matches[1] filePath := filepath.Join(ConfigRC.Commands.Dir, fileName) var confirm bool confirmPrompt := &survey.Confirm{ Message: "Are you sure you want to remove this command?", Default: true, } if err := survey.AskOne(confirmPrompt, &confirm); err != nil { return } if !confirm { return } err := os.Remove(filePath) if err != nil { color.Red("Error removing file: %v", err) return } color.Green("Successfully removed command: %s", fileName) }, }
var CommandsRootCmd = &cobra.Command{
Use: "commands",
Short: "Manage project-specific custom commands",
}
changeset/rootCmd represents the changeset/root command
var ConfigRC types.Config
project wise prasmoid config
var FileTemplates = map[string]string{ "contents/ui/main.qml": consts.MAIN_QML, "contents/config/main.xml": consts.MAIN_XML, "contents/icons/prasmoid.svg": consts.PRASMOID_SVG, ".gitignore": consts.GITIGNORE, "prasmoid.d.ts": consts.PRASMOID_DTS, }
var FormatCmd = &cobra.Command{ Use: "format", Short: "Prettify QML files", Long: "Automatically format QML source files to ensure consistent style and readability.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } if !utils.IsPackageInstalled(consts.QmlFormatPackageName["binary"]) { pm, _ := utils.DetectPackageManager() var confirm bool confirmPrompt := &survey.Confirm{ Message: "qmlformat is not installed. Do you want to install it?", Default: true, } if err := survey.AskOne(confirmPrompt, &confirm); err != nil { return } if confirm { if err := utils.InstallQmlformat(pm); err != nil { color.Red("Failed to install qmlformat.") return } color.Green("qmlformat installed successfully.") } else { color.Yellow("Operation cancelled.") return } } crrPath, _ := os.Getwd() relPath := filepath.Join(crrPath, dir) if watch { prettifyOnWatch(relPath) } else { prettify(relPath) } }, }
FormatCmd represents the format command
var I18nCompileCmd = &cobra.Command{ Use: "compile", Short: "Compile .po files to binary .mo files", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } if !utils.IsPackageInstalled("msgfmt") { color.Red("msgfmt command not found. Please install gettext.") return } if !silent { color.Cyan("Compiling translation files...") } if err := CompileI18n(ConfigRC, silent); err != nil { color.Red("Failed to compile messages: %v", err) return } if !silent { color.Green("Successfully compiled all translation files.") } if restart, _ := cmd.Flags().GetBool("restart"); restart { color.Cyan("Restarting plasmashell...") if err := restartPlasmashell(); err != nil { color.Red("Failed to restart plasmashell: %v", err) } } }, }
var I18nExtractCmd = &cobra.Command{ Use: "extract", Short: "Extract translatable strings from source files", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } if !utils.IsPackageInstalled("xgettext") { color.Red("xgettext command not found. Please install gettext.") return } color.Cyan("Extracting translatable strings...") translationsDir := ConfigRC.I18n.Dir _ = os.MkdirAll(translationsDir, 0755) if err := runXGettext(translationsDir); err != nil { color.Red("Failed to extract strings: %v", err) return } color.Green("Successfully extracted strings to %s/template.pot", translationsDir) isPoGen, _ := cmd.Flags().GetBool("no-po") if !isPoGen { if err := generatePoFiles(translationsDir); err != nil { color.Red("Failed to generate .po files: %v", err) return } } }, }
var I18nLocalesEditCmd = &cobra.Command{ Use: "edit", Short: "Edit locales for your plasmoid.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } currentLocales := ConfigRC.I18n.Locales locales := utils.AskForLocales(currentLocales) if locales != nil { ConfigRC.I18n.Locales = locales content, _ := json.MarshalIndent(ConfigRC, "", " ") fmt.Println(string(content)) os.WriteFile("prasmoid.config.js", []byte(`/// <reference path="prasmoid.d.ts" /> /** @type {PrasmoidConfig} */ const config = `+string(content)), 0644) } }, }
var InitCmd = &cobra.Command{ Use: "init", Short: "Initialize a new plasmoid project", Run: func(cmd *cobra.Command, args []string) { clearLine() printHeader() if err := gatherProjectConfig(); err != nil { color.Red("Failed to gather project config: %v", err) return } color.Yellow("Creating project at: %s", Config.Path) fmt.Println() if err := InitPlasmoid(); err != nil { color.Red("Failed to initialize plasmoid: "+ "%v", err) return } if Config.InitGit { if err := initializeGitRepo(); err != nil { color.Yellow("Could not initialize git repository: %v", err) } else { color.Green("Initialized git repository.") } } fmt.Println() color.Green("Plasmoid initialized successfully!") fmt.Println() printNextSteps() }, }
var InstallCmd = &cobra.Command{ Use: "install", Short: "Install plasmoid system-wide", Long: "Install the plasmoid to the system directories for production use.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } if err := InstallPlasmoid(); err != nil { color.Red("Failed to install plasmoid:", err) return } dest, _ := utils.GetDevDest() color.Green("Plasmoid installed successfully in %s", color.BlueString(dest)) color.Cyan("\n- Please restart plasmashell to apply changes.") }, }
InstallCmd represents the production command
var LinkCmd = &cobra.Command{ Use: "link", Short: "Link plasmoid to local development directory", Long: "Create a symlink to local development folder for easy testing.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } dest, err := utils.GetDevDest() if err != nil { color.Red(err.Error()) return } if linkWhere { fmt.Println("Plasmoid linked to:\n", "- ", color.BlueString(dest)) return } if err := LinkPlasmoid(dest); err != nil { color.Red("Failed to link plasmoid:", err) return } color.Green("Plasmoid linked successfully.") }, }
devCmd represents the dev command
var PreviewCmd = &cobra.Command{ Use: "preview", Short: "Enter plasmoid preview mode", Long: "Launch the plasmoid in preview mode for testing and development.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } watch, _ := cmd.Flags().GetBool("watch") if !utils.IsLinked() { var confirm bool confirmPrompt := &survey.Confirm{ Message: "Plasmoid is not linked. Do you want to link it first?", Default: true, } if err := survey.AskOne(confirmPrompt, &confirm); err != nil { return } if confirm { dest, err := utils.GetDevDest() if err != nil { color.Red(err.Error()) return } if err := LinkPlasmoid(dest); err != nil { color.Red("Failed to link plasmoid:", err) return } } else { fmt.Println("Operation cancelled.") return } } if !utils.IsPackageInstalled(consts.PlasmoidPreviewPackageName["binary"]) { pm, _ := utils.DetectPackageManager() var confirm bool confirmPrompt := &survey.Confirm{ Message: "plasmoidviewer is not installed. Do you want to install it first?", Default: true, } if err := survey.AskOne(confirmPrompt, &confirm); err != nil { return } if confirm { if err := utils.InstallPackage(pm, consts.PlasmoidPreviewPackageName["binary"], consts.PlasmoidPreviewPackageName); err != nil { color.Red("Failed to install plasmoidviewer:", err) return } } else { fmt.Println("Operation cancelled.") return } } if err := previewPlasmoid(watch); err != nil { color.Red("Failed to preview plasmoid:", err) return } }, }
PreviewCmd represents the preview command
var SetupCmd = &cobra.Command{ Use: "setup", Short: "Setup development environment", Long: "Install plasmoidviewer and other development dependencies.", Run: func(cmd *cobra.Command, args []string) { pm, err := utils.DetectPackageManager() if err != nil { color.Red("Failed to detect package manager.") return } if !utils.IsPackageInstalled(consts.QmlFormatPackageName["binary"]) { color.Yellow("Installing qmlformat...") if err := utils.InstallQmlformat(pm); err != nil { color.Red("Failed to install qmlformat.") return } } if !utils.IsPackageInstalled(consts.PlasmoidPreviewPackageName["binary"]) { color.Yellow("Installing plasmoidviewer...") if err := utils.InstallPlasmoidPreview(pm); err != nil { color.Red("Failed to install plasmoidviewer.") return } } if !utils.IsPackageInstalled(consts.CurlPackageName["binary"]) { color.Yellow("Installing curl...") if err := utils.InstallPackage(pm, consts.CurlPackageName["binary"], consts.CurlPackageName); err != nil { color.Red("Failed to install curl.") return } } }, }
SetupCmd represents the setup command
var UninstallCmd = &cobra.Command{ Use: "uninstall", Short: "Uninstall plasmoid system-wide", Long: "Uninstall the plasmoid from the system directories.", Run: func(cmd *cobra.Command, args []string) { if !utils.IsValidPlasmoid() { color.Red("Current directory is not a valid plasmoid.") return } if err := UninstallPlasmoid(); err != nil { color.Red("Failed to uninstall plasmoid:", err) return } color.Green("Plasmoid uninstalled successfully") }, }
UninstallCmd represents the production command
var UnlinkCmd = &cobra.Command{ Use: "unlink", Short: "Unlink development plasmoid from the system", Long: "Remove the symlink linking the development plasmoid from the system directories.", Run: func(cmd *cobra.Command, args []string) { dest, err := utils.GetDevDest() if err != nil { color.Red(err.Error()) return } _ = os.Remove(dest) _ = os.RemoveAll(dest) color.Green("Plasmoid unlinked successfully.") }, }
UnlinkCmd represents the unlink command
Functions ¶
func ApplyChanges ¶
func ApplyChanges()
func CheckForUpdates ¶
func CheckForUpdates()
func CreateConfigFile ¶ added in v0.0.3
func DiscoverAndRegisterCustomCommands ¶
DiscoverAndRegisterCustomCommands scans for Js, Go files and registers them as cobra commands.
func Execute ¶
func Execute()
Execute adds all child commands to the root command and sets flags appropriately. This is called by main.main(). It only needs to happen once to the rootCmd.
func GetCacheFilePath ¶ added in v0.0.3
func GetCacheFilePath() string
func InitPlasmoid ¶
func InitPlasmoid() error
func InstallPlasmoid ¶
func InstallPlasmoid() error
func LinkPlasmoid ¶
func ReadUpdateCache ¶
func UninstallPlasmoid ¶
func UninstallPlasmoid() error
func UpdateChangelog ¶
Types ¶
type ChangesetMeta ¶
type ChangesetMeta struct {
ID string `yaml:"id"`
Bump string `yaml:"bump"`
Next string `yaml:"next"`
Date string `yaml:"date"`
}
ChangesetMeta represents the metadata for a changeset
type KPlugin ¶
type KPlugin struct {
Authors []Author `json:"Authors,omitempty"`
Description string `json:"Description"`
EnabledByDefault bool `json:"EnabledByDefault"`
FormFactors []string `json:"FormFactors"`
Id string `json:"Id"`
License string `json:"License"`
Name string `json:"Name"`
Version string `json:"Version"`
}
Source Files
¶
- build.go
- changeset.go
- changesetAdd.go
- changesetApply.go
- commands.go
- commandsAdd.go
- commandsRemove.go
- completion.go
- extendcli.go
- format.go
- i18n.go
- i18nCompile.go
- i18nExtract.go
- i18nLocales.go
- i18nLocalesEdit.go
- init.go
- install.go
- link.go
- me.go
- preview.go
- regen.go
- regenConfig.go
- regenTypes.go
- root.go
- setup.go
- uninstall.go
- unlink.go
- update.go
- version.go