123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- // SiYuan - Refactor your thinking
- // Copyright (c) 2020-present, b3log.org
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU Affero General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU Affero General Public License for more details.
- //
- // You should have received a copy of the GNU Affero General Public License
- // along with this program. If not, see <https://www.gnu.org/licenses/>.
- package model
- import (
- "errors"
- "fmt"
- "path"
- "path/filepath"
- "strings"
- "sync"
- "time"
- "github.com/88250/gulu"
- "github.com/siyuan-note/logging"
- "github.com/siyuan-note/siyuan/kernel/bazaar"
- "github.com/siyuan-note/siyuan/kernel/util"
- "golang.org/x/mod/semver"
- )
- func BatchUpdateBazaarPackages(frontend string) {
- plugins, widgets, icons, themes, templates := UpdatedPackages(frontend)
- total := len(plugins) + len(widgets) + len(icons) + len(themes) + len(templates)
- if 1 > total {
- return
- }
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(235), 1, total))
- defer util.PushClearProgress()
- count := 1
- for _, plugin := range plugins {
- err := bazaar.InstallPlugin(plugin.RepoURL, plugin.RepoHash, filepath.Join(util.DataDir, "plugins", plugin.Name), Conf.System.ID)
- if nil != err {
- logging.LogErrorf("update plugin [%s] failed: %s", plugin.Name, err)
- util.PushErrMsg(fmt.Sprintf(Conf.language(238)), 5000)
- return
- }
- count++
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, plugin.Name))
- }
- for _, widget := range widgets {
- err := bazaar.InstallWidget(widget.RepoURL, widget.RepoHash, filepath.Join(util.DataDir, "widgets", widget.Name), Conf.System.ID)
- if nil != err {
- logging.LogErrorf("update widget [%s] failed: %s", widget.Name, err)
- util.PushErrMsg(fmt.Sprintf(Conf.language(238)), 5000)
- return
- }
- count++
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, widget.Name))
- }
- for _, icon := range icons {
- err := bazaar.InstallIcon(icon.RepoURL, icon.RepoHash, filepath.Join(util.IconsPath, icon.Name), Conf.System.ID)
- if nil != err {
- logging.LogErrorf("update icon [%s] failed: %s", icon.Name, err)
- util.PushErrMsg(fmt.Sprintf(Conf.language(238)), 5000)
- return
- }
- count++
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, icon.Name))
- }
- for _, template := range templates {
- err := bazaar.InstallTemplate(template.RepoURL, template.RepoHash, filepath.Join(util.DataDir, "templates", template.Name), Conf.System.ID)
- if nil != err {
- logging.LogErrorf("update template [%s] failed: %s", template.Name, err)
- util.PushErrMsg(fmt.Sprintf(Conf.language(238)), 5000)
- return
- }
- count++
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, template.Name))
- }
- for _, theme := range themes {
- err := bazaar.InstallTheme(theme.RepoURL, theme.RepoHash, filepath.Join(util.ThemesPath, theme.Name), Conf.System.ID)
- if nil != err {
- logging.LogErrorf("update theme [%s] failed: %s", theme.Name, err)
- util.PushErrMsg(fmt.Sprintf(Conf.language(238)), 5000)
- return
- }
- count++
- util.PushEndlessProgress(fmt.Sprintf(Conf.language(236), count, total, theme.Name))
- }
- util.ReloadUI()
- go func() {
- util.WaitForUILoaded()
- time.Sleep(500)
- util.PushMsg(fmt.Sprintf(Conf.language(237), total), 5000)
- }()
- return
- }
- func UpdatedPackages(frontend string) (plugins []*bazaar.Plugin, widgets []*bazaar.Widget, icons []*bazaar.Icon, themes []*bazaar.Theme, templates []*bazaar.Template) {
- wg := &sync.WaitGroup{}
- wg.Add(5)
- go func() {
- defer wg.Done()
- tmp := InstalledPlugins(frontend, "")
- for _, plugin := range tmp {
- if plugin.Outdated {
- plugins = append(plugins, plugin)
- }
- }
- }()
- go func() {
- defer wg.Done()
- tmp := InstalledWidgets("")
- for _, widget := range tmp {
- if widget.Outdated {
- widgets = append(widgets, widget)
- }
- }
- }()
- go func() {
- defer wg.Done()
- tmp := InstalledIcons("")
- for _, icon := range tmp {
- if icon.Outdated {
- icons = append(icons, icon)
- }
- }
- }()
- go func() {
- defer wg.Done()
- tmp := InstalledThemes("")
- for _, theme := range tmp {
- if theme.Outdated {
- themes = append(themes, theme)
- }
- }
- }()
- go func() {
- defer wg.Done()
- tmp := InstalledTemplates("")
- for _, template := range tmp {
- if template.Outdated {
- templates = append(templates, template)
- }
- }
- }()
- wg.Wait()
- if 1 > len(plugins) {
- plugins = []*bazaar.Plugin{}
- }
- if 1 > len(widgets) {
- widgets = []*bazaar.Widget{}
- }
- if 1 > len(icons) {
- icons = []*bazaar.Icon{}
- }
- if 1 > len(themes) {
- themes = []*bazaar.Theme{}
- }
- if 1 > len(templates) {
- templates = []*bazaar.Template{}
- }
- return
- }
- func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
- ret = bazaar.GetPackageREADME(repoURL, repoHash, packageType)
- return
- }
- func BazaarPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) {
- plugins = bazaar.Plugins(frontend)
- plugins = filterPlugins(plugins, keyword)
- for _, plugin := range plugins {
- plugin.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "plugins", plugin.Name))
- if plugin.Installed {
- if pluginConf, err := bazaar.PluginJSON(plugin.Name); nil == err && nil != plugin {
- plugin.Outdated = 0 > semver.Compare("v"+pluginConf.Version, "v"+plugin.Version)
- }
- }
- }
- return
- }
- func filterPlugins(plugins []*bazaar.Plugin, keyword string) (ret []*bazaar.Plugin) {
- ret = []*bazaar.Plugin{}
- keywords := getSearchKeywords(keyword)
- for _, plugin := range plugins {
- if matchPackage(keywords, plugin.Package) {
- ret = append(ret, plugin)
- }
- }
- return
- }
- func InstalledPlugins(frontend, keyword string) (plugins []*bazaar.Plugin) {
- plugins = bazaar.InstalledPlugins(frontend, true)
- plugins = filterPlugins(plugins, keyword)
- petals := getPetals()
- for _, plugin := range plugins {
- petal := getPetalByName(plugin.Name, petals)
- if nil != petal {
- plugin.Enabled = petal.Enabled
- }
- }
- return
- }
- func InstallBazaarPlugin(repoURL, repoHash, pluginName string) error {
- installPath := filepath.Join(util.DataDir, "plugins", pluginName)
- err := bazaar.InstallPlugin(repoURL, repoHash, installPath, Conf.System.ID)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(46), pluginName, err))
- }
- return nil
- }
- func UninstallBazaarPlugin(pluginName, frontend string) error {
- installPath := filepath.Join(util.DataDir, "plugins", pluginName)
- err := bazaar.UninstallPlugin(installPath)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(47), err.Error()))
- }
- petals := getPetals()
- var tmp []*Petal
- for i, petal := range petals {
- if petal.Name != pluginName {
- tmp = append(tmp, petals[i])
- }
- }
- petals = tmp
- if 1 > len(petals) {
- petals = []*Petal{}
- }
- savePetals(petals)
- return nil
- }
- func BazaarWidgets(keyword string) (widgets []*bazaar.Widget) {
- widgets = bazaar.Widgets()
- widgets = filterWidgets(widgets, keyword)
- for _, widget := range widgets {
- widget.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "widgets", widget.Name))
- if widget.Installed {
- if widgetConf, err := bazaar.WidgetJSON(widget.Name); nil == err && nil != widget {
- widget.Outdated = 0 > semver.Compare("v"+widgetConf.Version, "v"+widget.Version)
- }
- }
- }
- return
- }
- func filterWidgets(widgets []*bazaar.Widget, keyword string) (ret []*bazaar.Widget) {
- ret = []*bazaar.Widget{}
- keywords := getSearchKeywords(keyword)
- for _, w := range widgets {
- if matchPackage(keywords, w.Package) {
- ret = append(ret, w)
- }
- }
- return
- }
- func InstalledWidgets(keyword string) (widgets []*bazaar.Widget) {
- widgets = bazaar.InstalledWidgets()
- widgets = filterWidgets(widgets, keyword)
- return
- }
- func InstallBazaarWidget(repoURL, repoHash, widgetName string) error {
- installPath := filepath.Join(util.DataDir, "widgets", widgetName)
- err := bazaar.InstallWidget(repoURL, repoHash, installPath, Conf.System.ID)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(46), widgetName, err))
- }
- return nil
- }
- func UninstallBazaarWidget(widgetName string) error {
- installPath := filepath.Join(util.DataDir, "widgets", widgetName)
- err := bazaar.UninstallWidget(installPath)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(47), err.Error()))
- }
- return nil
- }
- func BazaarIcons(keyword string) (icons []*bazaar.Icon) {
- icons = bazaar.Icons()
- icons = filterIcons(icons, keyword)
- for _, installed := range Conf.Appearance.Icons {
- for _, icon := range icons {
- if installed == icon.Name {
- icon.Installed = true
- if iconConf, err := bazaar.IconJSON(icon.Name); nil == err {
- icon.Outdated = 0 > semver.Compare("v"+iconConf.Version, "v"+icon.Version)
- }
- }
- icon.Current = icon.Name == Conf.Appearance.Icon
- }
- }
- return
- }
- func filterIcons(icons []*bazaar.Icon, keyword string) (ret []*bazaar.Icon) {
- ret = []*bazaar.Icon{}
- keywords := getSearchKeywords(keyword)
- for _, i := range icons {
- if matchPackage(keywords, i.Package) {
- ret = append(ret, i)
- }
- }
- return
- }
- func InstalledIcons(keyword string) (icons []*bazaar.Icon) {
- icons = bazaar.InstalledIcons()
- icons = filterIcons(icons, keyword)
- for _, icon := range icons {
- icon.Current = icon.Name == Conf.Appearance.Icon
- }
- return
- }
- func InstallBazaarIcon(repoURL, repoHash, iconName string) error {
- installPath := filepath.Join(util.IconsPath, iconName)
- err := bazaar.InstallIcon(repoURL, repoHash, installPath, Conf.System.ID)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(46), iconName, err))
- }
- Conf.Appearance.Icon = iconName
- Conf.Save()
- InitAppearance()
- return nil
- }
- func UninstallBazaarIcon(iconName string) error {
- installPath := filepath.Join(util.IconsPath, iconName)
- err := bazaar.UninstallIcon(installPath)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(47), err.Error()))
- }
- InitAppearance()
- return nil
- }
- func BazaarThemes(keyword string) (ret []*bazaar.Theme) {
- ret = bazaar.Themes()
- ret = filterThemes(ret, keyword)
- installs := Conf.Appearance.DarkThemes
- installs = append(installs, Conf.Appearance.LightThemes...)
- for _, installed := range installs {
- for _, theme := range ret {
- if installed == theme.Name {
- theme.Installed = true
- if themeConf, err := bazaar.ThemeJSON(theme.Name); nil == err {
- theme.Outdated = 0 > semver.Compare("v"+themeConf.Version, "v"+theme.Version)
- }
- theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight
- }
- }
- }
- return
- }
- func filterThemes(themes []*bazaar.Theme, keyword string) (ret []*bazaar.Theme) {
- ret = []*bazaar.Theme{}
- keywords := getSearchKeywords(keyword)
- for _, t := range themes {
- if matchPackage(keywords, t.Package) {
- ret = append(ret, t)
- }
- }
- return
- }
- func InstalledThemes(keyword string) (ret []*bazaar.Theme) {
- ret = bazaar.InstalledThemes()
- ret = filterThemes(ret, keyword)
- for _, theme := range ret {
- theme.Current = theme.Name == Conf.Appearance.ThemeDark || theme.Name == Conf.Appearance.ThemeLight
- }
- return
- }
- func InstallBazaarTheme(repoURL, repoHash, themeName string, mode int, update bool) error {
- closeThemeWatchers()
- installPath := filepath.Join(util.ThemesPath, themeName)
- err := bazaar.InstallTheme(repoURL, repoHash, installPath, Conf.System.ID)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(46), themeName, err))
- }
- if !update {
- // 更新主题后不需要对该主题进行切换 https://github.com/siyuan-note/siyuan/issues/4966
- if 0 == mode {
- Conf.Appearance.ThemeLight = themeName
- } else {
- Conf.Appearance.ThemeDark = themeName
- }
- Conf.Appearance.Mode = mode
- Conf.Appearance.ThemeJS = gulu.File.IsExist(filepath.Join(installPath, "theme.js"))
- Conf.Save()
- }
- InitAppearance()
- return nil
- }
- func UninstallBazaarTheme(themeName string) error {
- closeThemeWatchers()
- installPath := filepath.Join(util.ThemesPath, themeName)
- err := bazaar.UninstallTheme(installPath)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(47), err.Error()))
- }
- InitAppearance()
- return nil
- }
- func BazaarTemplates(keyword string) (templates []*bazaar.Template) {
- templates = bazaar.Templates()
- templates = filterTemplates(templates, keyword)
- for _, template := range templates {
- template.Installed = util.IsPathRegularDirOrSymlinkDir(filepath.Join(util.DataDir, "templates", template.Name))
- if template.Installed {
- if templateConf, err := bazaar.TemplateJSON(template.Name); nil == err && nil != templateConf {
- template.Outdated = 0 > semver.Compare("v"+templateConf.Version, "v"+template.Version)
- }
- }
- }
- return
- }
- func filterTemplates(templates []*bazaar.Template, keyword string) (ret []*bazaar.Template) {
- ret = []*bazaar.Template{}
- keywords := getSearchKeywords(keyword)
- for _, t := range templates {
- if matchPackage(keywords, t.Package) {
- ret = append(ret, t)
- }
- }
- return
- }
- func InstalledTemplates(keyword string) (templates []*bazaar.Template) {
- templates = bazaar.InstalledTemplates()
- templates = filterTemplates(templates, keyword)
- return
- }
- func InstallBazaarTemplate(repoURL, repoHash, templateName string) error {
- installPath := filepath.Join(util.DataDir, "templates", templateName)
- err := bazaar.InstallTemplate(repoURL, repoHash, installPath, Conf.System.ID)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(46), templateName, err))
- }
- return nil
- }
- func UninstallBazaarTemplate(templateName string) error {
- installPath := filepath.Join(util.DataDir, "templates", templateName)
- err := bazaar.UninstallTemplate(installPath)
- if nil != err {
- return errors.New(fmt.Sprintf(Conf.Language(47), err.Error()))
- }
- return nil
- }
- func matchPackage(keywords []string, pkg *bazaar.Package) bool {
- if 1 > len(keywords) {
- return true
- }
- if nil == pkg || nil == pkg.DisplayName || nil == pkg.Description {
- return false
- }
- for _, keyword := range keywords {
- if strings.Contains(strings.ToLower(pkg.DisplayName.Default), keyword) ||
- strings.Contains(strings.ToLower(pkg.DisplayName.ZhCN), keyword) ||
- strings.Contains(strings.ToLower(pkg.DisplayName.ZhCHT), keyword) ||
- strings.Contains(strings.ToLower(pkg.DisplayName.EnUS), keyword) ||
- strings.Contains(strings.ToLower(pkg.Description.Default), keyword) ||
- strings.Contains(strings.ToLower(pkg.Description.ZhCN), keyword) ||
- strings.Contains(strings.ToLower(pkg.Description.ZhCHT), keyword) ||
- strings.Contains(strings.ToLower(pkg.Description.EnUS), keyword) ||
- strings.Contains(strings.ToLower(path.Base(pkg.RepoURL)), keyword) {
- return true
- }
- for _, pkgKeyword := range pkg.Keywords {
- if strings.Contains(strings.ToLower(pkgKeyword), keyword) {
- return true
- }
- }
- }
- return false
- }
- func getSearchKeywords(query string) (ret []string) {
- query = strings.TrimSpace(query)
- if "" == query {
- return
- }
- keywords := strings.Split(query, " ")
- for _, k := range keywords {
- if "" != k {
- ret = append(ret, strings.ToLower(k))
- }
- }
- return
- }
|