mirror of
https://github.com/siyuan-note/siyuan.git
synced 2026-03-13 07:56:14 +01:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
commit
7831dccd7e
15 changed files with 202 additions and 158 deletions
|
|
@ -67,6 +67,36 @@ if (process.platform === "linux") {
|
|||
app.commandLine.appendSwitch("wayland-text-input-version", "3");
|
||||
}
|
||||
|
||||
app.setAsDefaultProtocolClient("siyuan");
|
||||
|
||||
app.commandLine.appendSwitch("disable-web-security");
|
||||
app.commandLine.appendSwitch("auto-detect", "false");
|
||||
app.commandLine.appendSwitch("no-proxy-server");
|
||||
app.commandLine.appendSwitch("enable-features", "PlatformHEVCDecoderSupport");
|
||||
app.commandLine.appendSwitch("xdg-portal-required-version", "4");
|
||||
|
||||
// Support set Chromium command line arguments on the desktop https://github.com/siyuan-note/siyuan/issues/9696
|
||||
writeLog("app is packaged [" + app.isPackaged + "], command line args [" + process.argv.join(", ") + "]");
|
||||
let argStart = 1;
|
||||
if (!app.isPackaged) {
|
||||
argStart = 2;
|
||||
}
|
||||
|
||||
for (let i = argStart; i < process.argv.length; i++) {
|
||||
let arg = process.argv[i];
|
||||
if (arg.startsWith("--workspace=") || arg.startsWith("--openAsHidden") || arg.startsWith("--port=") || arg.startsWith("siyuan://")) {
|
||||
// 跳过内置参数
|
||||
if (arg.startsWith("--openAsHidden")) {
|
||||
openAsHidden = true;
|
||||
writeLog("open as hidden");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch(arg);
|
||||
writeLog("command line switch [" + arg + "]");
|
||||
}
|
||||
|
||||
try {
|
||||
firstOpen = !fs.existsSync(path.join(confDir, "workspace.json"));
|
||||
if (!fs.existsSync(confDir)) {
|
||||
|
|
@ -297,28 +327,6 @@ const showErrorWindow = (titleZh, titleEn, content, emoji = "⚠️") => {
|
|||
return errWindow.id;
|
||||
};
|
||||
|
||||
const writeLog = (out) => {
|
||||
console.log(out);
|
||||
const logFile = path.join(confDir, "app.log");
|
||||
let log = "";
|
||||
const maxLogLines = 1024;
|
||||
try {
|
||||
if (fs.existsSync(logFile)) {
|
||||
log = fs.readFileSync(logFile).toString();
|
||||
let lines = log.split("\n");
|
||||
if (maxLogLines < lines.length) {
|
||||
log = lines.slice(maxLogLines / 2, maxLogLines).join("\n") + "\n";
|
||||
}
|
||||
}
|
||||
out = out.toString();
|
||||
out = new Date().toISOString().replace(/T/, " ").replace(/\..+/, "") + " " + out;
|
||||
log += out + "\n";
|
||||
fs.writeFileSync(logFile, log);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
};
|
||||
|
||||
let openAsHidden = false;
|
||||
const isOpenAsHidden = function () {
|
||||
return 1 === workspaces.length && openAsHidden;
|
||||
|
|
@ -730,36 +738,6 @@ const initKernel = (workspace, port, lang) => {
|
|||
});
|
||||
};
|
||||
|
||||
app.setAsDefaultProtocolClient("siyuan");
|
||||
|
||||
app.commandLine.appendSwitch("disable-web-security");
|
||||
app.commandLine.appendSwitch("auto-detect", "false");
|
||||
app.commandLine.appendSwitch("no-proxy-server");
|
||||
app.commandLine.appendSwitch("enable-features", "PlatformHEVCDecoderSupport");
|
||||
app.commandLine.appendSwitch("xdg-portal-required-version", "4");
|
||||
|
||||
// Support set Chromium command line arguments on the desktop https://github.com/siyuan-note/siyuan/issues/9696
|
||||
writeLog("app is packaged [" + app.isPackaged + "], command line args [" + process.argv.join(", ") + "]");
|
||||
let argStart = 1;
|
||||
if (!app.isPackaged) {
|
||||
argStart = 2;
|
||||
}
|
||||
|
||||
for (let i = argStart; i < process.argv.length; i++) {
|
||||
let arg = process.argv[i];
|
||||
if (arg.startsWith("--workspace=") || arg.startsWith("--openAsHidden") || arg.startsWith("--port=") || arg.startsWith("siyuan://")) {
|
||||
// 跳过内置参数
|
||||
if (arg.startsWith("--openAsHidden")) {
|
||||
openAsHidden = true;
|
||||
writeLog("open as hidden");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
app.commandLine.appendSwitch(arg);
|
||||
writeLog("command line switch [" + arg + "]");
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
const resetTrayMenu = (tray, lang, mainWindow) => {
|
||||
if (!mainWindow || mainWindow.isDestroyed()) {
|
||||
|
|
@ -1542,3 +1520,26 @@ app.on("before-quit", (event) => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function writeLog(out) {
|
||||
console.log(out);
|
||||
const logFile = path.join(confDir, "app.log");
|
||||
let log = "";
|
||||
const maxLogLines = 1024;
|
||||
try {
|
||||
if (fs.existsSync(logFile)) {
|
||||
log = fs.readFileSync(logFile).toString();
|
||||
let lines = log.split("\n");
|
||||
if (maxLogLines < lines.length) {
|
||||
log = lines.slice(maxLogLines / 2, maxLogLines).join("\n") + "\n";
|
||||
}
|
||||
}
|
||||
out = out.toString();
|
||||
out = new Date().toISOString().replace(/T/, " ").replace(/\..+/, "") + " " + out;
|
||||
log += out + "\n";
|
||||
fs.writeFileSync(logFile, log);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
19
app/pnpm-lock.yaml
generated
19
app/pnpm-lock.yaml
generated
|
|
@ -1415,6 +1415,10 @@ packages:
|
|||
resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==}
|
||||
engines: {node: '>=14.14'}
|
||||
|
||||
fs-extra@11.3.4:
|
||||
resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==}
|
||||
engines: {node: '>=14.14'}
|
||||
|
||||
fs-extra@7.0.1:
|
||||
resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==}
|
||||
engines: {node: '>=6 <7 || >=8'}
|
||||
|
|
@ -1465,16 +1469,17 @@ packages:
|
|||
|
||||
glob@10.4.5:
|
||||
resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==}
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
hasBin: true
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
glob@8.1.0:
|
||||
resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==}
|
||||
engines: {node: '>=12'}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
global-agent@3.0.0:
|
||||
resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
|
||||
|
|
@ -2491,6 +2496,7 @@ packages:
|
|||
tar@6.2.1:
|
||||
resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==}
|
||||
engines: {node: '>=10'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
temp-file@3.4.0:
|
||||
resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==}
|
||||
|
|
@ -2849,7 +2855,7 @@ snapshots:
|
|||
dependencies:
|
||||
cross-dirname: 0.1.0
|
||||
debug: 4.4.3
|
||||
fs-extra: 11.3.3
|
||||
fs-extra: 11.3.4
|
||||
minimist: 1.2.8
|
||||
postject: 1.0.0-alpha.6
|
||||
transitivePeerDependencies:
|
||||
|
|
@ -4221,6 +4227,13 @@ snapshots:
|
|||
jsonfile: 6.2.0
|
||||
universalify: 2.0.1
|
||||
|
||||
fs-extra@11.3.4:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
jsonfile: 6.2.0
|
||||
universalify: 2.0.1
|
||||
optional: true
|
||||
|
||||
fs-extra@7.0.1:
|
||||
dependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
|
|
|||
|
|
@ -192,7 +192,7 @@ export class App {
|
|||
openFileById({app: this, id: data.data.id, action: [Constants.CB_GET_FOCUS]});
|
||||
break;
|
||||
case "exit":
|
||||
if (isBrowser()) {
|
||||
if (isBrowser() && !isInMobileApp()) {
|
||||
window.location.href = "about:blank";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ func getBazaarPackageREADME(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
ret.Data = map[string]interface{}{
|
||||
"html": model.GetPackageREADME(repoURL, repoHash, pkgType),
|
||||
"html": model.GetBazaarPackageREADME(c.Request.Context(), repoURL, repoHash, pkgType),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ func InstalledIcons() (ret []*Icon) {
|
|||
packageInstallSizeCache.SetDefault(icon.RepoURL, is)
|
||||
}
|
||||
icon.HInstallSize = humanize.BytesCustomCeil(uint64(icon.InstallSize), 2)
|
||||
icon.PreferredReadme = loadInstalledReadme(installPath, "/appearance/icons/"+dirName+"/", icon.Readme)
|
||||
icon.PreferredReadme = getInstalledPackageREADME(installPath, "/appearance/icons/"+dirName+"/", icon.Readme)
|
||||
icon.Outdated = isOutdatedIcon(icon, bazaarIcons)
|
||||
ret = append(ret, icon)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ func InstalledPlugins(frontend string) (ret []*Plugin) {
|
|||
packageInstallSizeCache.SetDefault(plugin.RepoURL, is)
|
||||
}
|
||||
plugin.HInstallSize = humanize.BytesCustomCeil(uint64(plugin.InstallSize), 2)
|
||||
plugin.PreferredReadme = loadInstalledReadme(installPath, "/plugins/"+dirName+"/", plugin.Readme)
|
||||
plugin.PreferredReadme = getInstalledPackageREADME(installPath, "/plugins/"+dirName+"/", plugin.Readme)
|
||||
plugin.Outdated = isOutdatedPlugin(plugin, bazaarPlugins)
|
||||
plugin.Incompatible = isIncompatiblePlugin(plugin, frontend)
|
||||
ret = append(ret, plugin)
|
||||
|
|
|
|||
|
|
@ -18,26 +18,45 @@ package bazaar
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/88250/gulu"
|
||||
"github.com/88250/lute"
|
||||
"github.com/88250/lute/ast"
|
||||
"github.com/88250/lute/parse"
|
||||
"github.com/siyuan-note/logging"
|
||||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
textUnicode "golang.org/x/text/encoding/unicode"
|
||||
"golang.org/x/text/transform"
|
||||
)
|
||||
|
||||
func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
||||
// getReadmeFileCandidates 根据包的 README 配置返回去重的按优先级排序的 README 候选文件名列表:当前语言首选、default、README.md。
|
||||
func getReadmeFileCandidates(readme LocaleStrings) []string {
|
||||
preferred := getPreferredReadme(readme)
|
||||
defaultName := "README.md"
|
||||
if v := strings.TrimSpace(readme["default"]); v != "" {
|
||||
defaultName = v
|
||||
}
|
||||
return gulu.Str.RemoveDuplicatedElem([]string{preferred, defaultName, "README.md"})
|
||||
}
|
||||
|
||||
// GetBazaarPackageREADME 获取集市包的在线 README。
|
||||
func GetBazaarPackageREADME(ctx context.Context, repoURL, repoHash, packageType string) (ret string) {
|
||||
repoURLHash := repoURL + "@" + repoHash
|
||||
|
||||
stageIndexLock.RLock()
|
||||
stageIndex := cachedStageIndex[packageType]
|
||||
stageIndexLock.RUnlock()
|
||||
if nil == stageIndex {
|
||||
return
|
||||
if stageIndex == nil {
|
||||
var err error
|
||||
stageIndex, err = getStageIndex(ctx, packageType)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
url := strings.TrimPrefix(repoURLHash, "https://github.com/")
|
||||
|
|
@ -48,113 +67,106 @@ func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
|||
break
|
||||
}
|
||||
}
|
||||
if nil == repo || nil == repo.Package {
|
||||
if repo == nil || repo.Package == nil {
|
||||
return
|
||||
}
|
||||
|
||||
readme := getPreferredReadme(repo.Package.Readme)
|
||||
|
||||
data, err := downloadPackage(repoURLHash+"/"+readme, false, "")
|
||||
if err != nil {
|
||||
ret = fmt.Sprintf("Load bazaar package's preferred README(%s) failed: %s", readme, err.Error())
|
||||
// 回退到 Default README
|
||||
var defaultReadme string
|
||||
if len(repo.Package.Readme) > 0 {
|
||||
defaultReadme = repo.Package.Readme["default"]
|
||||
}
|
||||
if "" == strings.TrimSpace(defaultReadme) {
|
||||
defaultReadme = "README.md"
|
||||
}
|
||||
if readme != defaultReadme {
|
||||
data, err = downloadPackage(repoURLHash+"/"+defaultReadme, false, "")
|
||||
if err != nil {
|
||||
ret += fmt.Sprintf("<br>Load bazaar package's default README(%s) failed: %s", defaultReadme, err.Error())
|
||||
}
|
||||
}
|
||||
// 回退到 README.md
|
||||
if err != nil && readme != "README.md" && defaultReadme != "README.md" {
|
||||
data, err = downloadPackage(repoURLHash+"/README.md", false, "")
|
||||
if err != nil {
|
||||
ret += fmt.Sprintf("<br>Load bazaar package's README.md failed: %s", err.Error())
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
return
|
||||
candidates := getReadmeFileCandidates(repo.Package.Readme)
|
||||
var data []byte
|
||||
var loadErr error
|
||||
var errMsgs []string
|
||||
for _, name := range candidates {
|
||||
data, loadErr = downloadPackage(repoURLHash+"/"+name, false, "")
|
||||
if loadErr == nil {
|
||||
break
|
||||
}
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("Load bazaar package's README(%s) failed: %s", name, loadErr.Error()))
|
||||
}
|
||||
|
||||
if 2 < len(data) {
|
||||
if 255 == data[0] && 254 == data[1] {
|
||||
data, _, err = transform.Bytes(textUnicode.UTF16(textUnicode.LittleEndian, textUnicode.ExpectBOM).NewDecoder(), data)
|
||||
} else if 254 == data[0] && 255 == data[1] {
|
||||
data, _, err = transform.Bytes(textUnicode.UTF16(textUnicode.BigEndian, textUnicode.ExpectBOM).NewDecoder(), data)
|
||||
}
|
||||
}
|
||||
|
||||
ret, err = renderREADME(repoURL, data)
|
||||
return
|
||||
}
|
||||
|
||||
func loadInstalledReadme(installPath, basePath string, readme LocaleStrings) (ret string) {
|
||||
readmeFilename := getPreferredReadme(readme)
|
||||
readmeData, readErr := os.ReadFile(filepath.Join(installPath, readmeFilename))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
if loadErr != nil {
|
||||
ret = strings.Join(errMsgs, "<br>")
|
||||
return
|
||||
}
|
||||
|
||||
logging.LogWarnf("read installed %s failed: %s", readmeFilename, readErr)
|
||||
ret = fmt.Sprintf("File %s not found", readmeFilename)
|
||||
// 回退到 Default README
|
||||
var defaultReadme string
|
||||
if len(readme) > 0 {
|
||||
defaultReadme = strings.TrimSpace(readme["default"])
|
||||
}
|
||||
if "" == defaultReadme {
|
||||
defaultReadme = "README.md"
|
||||
}
|
||||
if readmeFilename != defaultReadme {
|
||||
readmeData, readErr = os.ReadFile(filepath.Join(installPath, defaultReadme))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
return
|
||||
if len(data) > 2 {
|
||||
var decoded []byte
|
||||
var err error
|
||||
if data[0] == 0xFF && data[1] == 0xFE {
|
||||
decoded, _, err = transform.Bytes(textUnicode.UTF16(textUnicode.LittleEndian, textUnicode.ExpectBOM).NewDecoder(), data)
|
||||
} else if data[0] == 0xFE && data[1] == 0xFF {
|
||||
decoded, _, err = transform.Bytes(textUnicode.UTF16(textUnicode.BigEndian, textUnicode.ExpectBOM).NewDecoder(), data)
|
||||
}
|
||||
logging.LogWarnf("read installed %s failed: %s", defaultReadme, readErr)
|
||||
ret += fmt.Sprintf("<br>File %s not found", defaultReadme)
|
||||
}
|
||||
// 回退到 README.md
|
||||
if nil != readErr && readmeFilename != "README.md" && defaultReadme != "README.md" {
|
||||
readmeData, readErr = os.ReadFile(filepath.Join(installPath, "README.md"))
|
||||
if nil == readErr {
|
||||
ret, _ = renderLocalREADME(basePath, readmeData)
|
||||
return
|
||||
if decoded != nil && err == nil {
|
||||
data = decoded
|
||||
}
|
||||
logging.LogWarnf("read installed README.md failed: %s", readErr)
|
||||
ret += "<br>File README.md not found"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func renderREADME(repoURL string, mdData []byte) (ret string, err error) {
|
||||
mdData = bytes.TrimPrefix(mdData, []byte("\xef\xbb\xbf"))
|
||||
luteEngine := lute.New()
|
||||
luteEngine.SetSoftBreak2HardBreak(false)
|
||||
luteEngine.SetCodeSyntaxHighlight(false)
|
||||
linkBase := "https://cdn.jsdelivr.net/gh/" + strings.TrimPrefix(repoURL, "https://github.com/")
|
||||
ret = renderPackageREADME(linkBase, data)
|
||||
return
|
||||
}
|
||||
|
||||
// getInstalledPackageREADME 获取集市包的本地 README。
|
||||
func getInstalledPackageREADME(installPath, linkBase string, readme LocaleStrings) (ret string) {
|
||||
candidates := getReadmeFileCandidates(readme)
|
||||
var errMsgs []string
|
||||
for _, name := range candidates {
|
||||
readmeData, readErr := os.ReadFile(filepath.Join(installPath, name))
|
||||
if readErr == nil {
|
||||
ret = renderPackageREADME(linkBase, readmeData)
|
||||
return
|
||||
}
|
||||
logging.LogWarnf("read installed %s failed: %s", name, readErr)
|
||||
errMsgs = append(errMsgs, fmt.Sprintf("File [%s] not found", name))
|
||||
}
|
||||
ret = strings.Join(errMsgs, "<br>")
|
||||
return
|
||||
}
|
||||
|
||||
// renderPackageREADME 渲染 README Markdown 为 HTML。
|
||||
func renderPackageREADME(linkBase string, mdData []byte) (ret string) {
|
||||
mdData = bytes.TrimPrefix(mdData, []byte("\xef\xbb\xbf")) // 移除文件开头的 BOM
|
||||
luteEngine := lute.New()
|
||||
luteEngine.SetSoftBreak2HardBreak(false)
|
||||
luteEngine.SetCodeSyntaxHighlight(false)
|
||||
luteEngine.SetLinkBase(linkBase)
|
||||
ret = luteEngine.Md2HTML(string(mdData))
|
||||
|
||||
tree := parse.Parse("", mdData, luteEngine.ParseOptions)
|
||||
normalizeNodesIAL(tree)
|
||||
ret = luteEngine.Tree2HTML(tree, luteEngine.RenderOptions, luteEngine.ParseOptions)
|
||||
ret = util.LinkTarget(ret, linkBase)
|
||||
return
|
||||
}
|
||||
|
||||
func renderLocalREADME(basePath string, mdData []byte) (ret string, err error) {
|
||||
mdData = bytes.TrimPrefix(mdData, []byte("\xef\xbb\xbf"))
|
||||
luteEngine := lute.New()
|
||||
luteEngine.SetSoftBreak2HardBreak(false)
|
||||
luteEngine.SetCodeSyntaxHighlight(false)
|
||||
linkBase := basePath
|
||||
luteEngine.SetLinkBase(linkBase)
|
||||
ret = luteEngine.Md2HTML(string(mdData))
|
||||
ret = util.LinkTarget(ret, linkBase)
|
||||
return
|
||||
func normalizeNodesIAL(tree *parse.Tree) {
|
||||
if tree == nil || tree.Root == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ast.Walk(tree.Root, func(n *ast.Node, entering bool) ast.WalkStatus {
|
||||
if !entering {
|
||||
return ast.WalkContinue
|
||||
}
|
||||
if n.Type == ast.NodeCodeBlock {
|
||||
// 代码块添加 code-block 类名以修正样式。
|
||||
n.KramdownIAL = addClassToKramdownIAL(n.KramdownIAL, "code-block")
|
||||
}
|
||||
return ast.WalkContinue
|
||||
})
|
||||
}
|
||||
|
||||
func addClassToKramdownIAL(ial [][]string, class string) [][]string {
|
||||
for i, attr := range ial {
|
||||
if len(attr) < 2 || attr[0] != "class" {
|
||||
continue
|
||||
}
|
||||
for _, item := range strings.Fields(attr[1]) {
|
||||
if item == class {
|
||||
return ial
|
||||
}
|
||||
}
|
||||
attr[1] = strings.TrimSpace(attr[1] + " " + class)
|
||||
ial[i] = attr
|
||||
return ial
|
||||
}
|
||||
return append(ial, []string{"class", class})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ func InstalledTemplates() (ret []*Template) {
|
|||
packageInstallSizeCache.SetDefault(template.RepoURL, is)
|
||||
}
|
||||
template.HInstallSize = humanize.BytesCustomCeil(uint64(template.InstallSize), 2)
|
||||
template.PreferredReadme = loadInstalledReadme(installPath, "/templates/"+dirName+"/", template.Readme)
|
||||
template.PreferredReadme = getInstalledPackageREADME(installPath, "/templates/"+dirName+"/", template.Readme)
|
||||
template.Outdated = isOutdatedTemplate(template, bazaarTemplates)
|
||||
ret = append(ret, template)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ func InstalledThemes() (ret []*Theme) {
|
|||
packageInstallSizeCache.SetDefault(theme.RepoURL, is)
|
||||
}
|
||||
theme.HInstallSize = humanize.BytesCustomCeil(uint64(theme.InstallSize), 2)
|
||||
theme.PreferredReadme = loadInstalledReadme(installPath, "/appearance/themes/"+dirName+"/", theme.Readme)
|
||||
theme.PreferredReadme = getInstalledPackageREADME(installPath, "/appearance/themes/"+dirName+"/", theme.Readme)
|
||||
theme.Outdated = isOutdatedTheme(theme, bazaarThemes)
|
||||
ret = append(ret, theme)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ func InstalledWidgets() (ret []*Widget) {
|
|||
packageInstallSizeCache.SetDefault(widget.RepoURL, is)
|
||||
}
|
||||
widget.HInstallSize = humanize.BytesCustomCeil(uint64(widget.InstallSize), 2)
|
||||
widget.PreferredReadme = loadInstalledReadme(installPath, "/widgets/"+dirName+"/", widget.Readme)
|
||||
widget.PreferredReadme = getInstalledPackageREADME(installPath, "/widgets/"+dirName+"/", widget.Readme)
|
||||
widget.Outdated = isOutdatedWidget(widget, bazaarWidgets)
|
||||
ret = append(ret, widget)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
|
|
@ -192,8 +193,9 @@ func UpdatedPackages(frontend string) (plugins []*bazaar.Plugin, widgets []*baza
|
|||
return
|
||||
}
|
||||
|
||||
func GetPackageREADME(repoURL, repoHash, packageType string) (ret string) {
|
||||
ret = bazaar.GetPackageREADME(repoURL, repoHash, packageType)
|
||||
// GetBazaarPackageREADME 获取集市包的在线 README。
|
||||
func GetBazaarPackageREADME(ctx context.Context, repoURL, repoHash, packageType string) (ret string) {
|
||||
ret = bazaar.GetBazaarPackageREADME(ctx, repoURL, repoHash, packageType)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -807,7 +807,9 @@ func Close(force, setCurrentWorkspace bool, execInstallPkg int) (exitCode int) {
|
|||
time.Sleep(30 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
closeSyncWebSocket()
|
||||
|
||||
go func() {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
logging.LogInfof("exited kernel")
|
||||
|
|
|
|||
|
|
@ -1237,6 +1237,9 @@ func (tx *Transaction) doInsert0(operation *Operation, tree *parse.Tree) (ret *T
|
|||
insertedNode = insertedNode.FirstChild
|
||||
}
|
||||
node.InsertBefore(insertedNode)
|
||||
for _, remain := range remains {
|
||||
node.InsertBefore(remain)
|
||||
}
|
||||
} else if "" != previousID {
|
||||
node = treenode.GetNodeInTree(tree, previousID)
|
||||
if nil == node {
|
||||
|
|
|
|||
|
|
@ -318,6 +318,11 @@ func serveExport(ginServer *gin.Engine) {
|
|||
}
|
||||
|
||||
fullPath := filepath.Join(exportBaseDir, decodedPath)
|
||||
if util.IsSensitivePath(fullPath) {
|
||||
logging.LogErrorf("refuse to export sensitive file [%s]", c.Request.URL.Path)
|
||||
c.Status(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(fullPath)
|
||||
if os.IsNotExist(err) {
|
||||
|
|
|
|||
|
|
@ -391,6 +391,12 @@ func IsSensitivePath(p string) bool {
|
|||
}
|
||||
}
|
||||
|
||||
// 工作空间/conf 目录(小写比较)
|
||||
workspaceConfPrefix := strings.ToLower(filepath.Join(WorkspaceDir, "conf"))
|
||||
if strings.HasPrefix(pp, workspaceConfPrefix) {
|
||||
return true
|
||||
}
|
||||
|
||||
homePrefixes := []string{
|
||||
strings.ToLower(filepath.Join(HomeDir, ".ssh")),
|
||||
strings.ToLower(filepath.Join(HomeDir, ".config")),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue