| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- // Copyright 2017 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package external
-
- import (
- "bytes"
- "fmt"
- "io"
- "os"
- "os/exec"
- "runtime"
- "strings"
-
- "code.gitea.io/gitea/modules/markup"
- "code.gitea.io/gitea/modules/process"
- "code.gitea.io/gitea/modules/setting"
- )
-
- // RegisterRenderers registers all supported third part renderers according settings
- func RegisterRenderers() {
- for _, renderer := range setting.ExternalMarkupRenderers {
- if renderer.Enabled && renderer.Command != "" && len(renderer.FileExtensions) > 0 {
- markup.RegisterRenderer(&Renderer{renderer})
- }
- }
- }
-
- // Renderer implements markup.Renderer for external tools
- type Renderer struct {
- *setting.MarkupRenderer
- }
-
- var (
- _ markup.PostProcessRenderer = (*Renderer)(nil)
- _ markup.ExternalRenderer = (*Renderer)(nil)
- )
-
- // Name returns the external tool name
- func (p *Renderer) Name() string {
- return p.MarkupName
- }
-
- // NeedPostProcess implements markup.Renderer
- func (p *Renderer) NeedPostProcess() bool {
- return p.MarkupRenderer.NeedPostProcess
- }
-
- // Extensions returns the supported extensions of the tool
- func (p *Renderer) Extensions() []string {
- return p.FileExtensions
- }
-
- // SanitizerRules implements markup.Renderer
- func (p *Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
- return p.MarkupSanitizerRules
- }
-
- // SanitizerDisabled disabled sanitize if return true
- func (p *Renderer) SanitizerDisabled() bool {
- return p.RenderContentMode == setting.RenderContentModeNoSanitizer || p.RenderContentMode == setting.RenderContentModeIframe
- }
-
- // DisplayInIFrame represents whether render the content with an iframe
- func (p *Renderer) DisplayInIFrame() bool {
- return p.RenderContentMode == setting.RenderContentModeIframe
- }
-
- func envMark(envName string) string {
- if runtime.GOOS == "windows" {
- return "%" + envName + "%"
- }
- return "$" + envName
- }
-
- // Render renders the data of the document to HTML via the external tool.
- func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
- baseLinkSrc := ctx.RenderHelper.ResolveLink("", markup.LinkTypeDefault)
- baseLinkRaw := ctx.RenderHelper.ResolveLink("", markup.LinkTypeRaw)
- command := strings.NewReplacer(
- envMark("GITEA_PREFIX_SRC"), baseLinkSrc,
- envMark("GITEA_PREFIX_RAW"), baseLinkRaw,
- ).Replace(p.Command)
- commands := strings.Fields(command)
- args := commands[1:]
-
- if p.IsInputFile {
- // write to temp file
- f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("gitea_input")
- if err != nil {
- return fmt.Errorf("%s create temp file when rendering %s failed: %w", p.Name(), p.Command, err)
- }
- defer cleanup()
-
- _, err = io.Copy(f, input)
- if err != nil {
- _ = f.Close()
- return fmt.Errorf("%s write data to temp file when rendering %s failed: %w", p.Name(), p.Command, err)
- }
-
- err = f.Close()
- if err != nil {
- return fmt.Errorf("%s close temp file when rendering %s failed: %w", p.Name(), p.Command, err)
- }
- args = append(args, f.Name())
- }
-
- processCtx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Render [%s] for %s", commands[0], baseLinkSrc))
- defer finished()
-
- cmd := exec.CommandContext(processCtx, commands[0], args...)
- cmd.Env = append(
- os.Environ(),
- "GITEA_PREFIX_SRC="+baseLinkSrc,
- "GITEA_PREFIX_RAW="+baseLinkRaw,
- )
- if !p.IsInputFile {
- cmd.Stdin = input
- }
- var stderr bytes.Buffer
- cmd.Stdout = output
- cmd.Stderr = &stderr
- process.SetSysProcAttribute(cmd)
-
- if err := cmd.Run(); err != nil {
- return fmt.Errorf("%s render run command %s %v failed: %w\nStderr: %s", p.Name(), commands[0], args, err, stderr.String())
- }
- return nil
- }
|