gitea源码

external.go 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // Copyright 2017 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package external
  4. import (
  5. "bytes"
  6. "fmt"
  7. "io"
  8. "os"
  9. "os/exec"
  10. "runtime"
  11. "strings"
  12. "code.gitea.io/gitea/modules/markup"
  13. "code.gitea.io/gitea/modules/process"
  14. "code.gitea.io/gitea/modules/setting"
  15. )
  16. // RegisterRenderers registers all supported third part renderers according settings
  17. func RegisterRenderers() {
  18. for _, renderer := range setting.ExternalMarkupRenderers {
  19. if renderer.Enabled && renderer.Command != "" && len(renderer.FileExtensions) > 0 {
  20. markup.RegisterRenderer(&Renderer{renderer})
  21. }
  22. }
  23. }
  24. // Renderer implements markup.Renderer for external tools
  25. type Renderer struct {
  26. *setting.MarkupRenderer
  27. }
  28. var (
  29. _ markup.PostProcessRenderer = (*Renderer)(nil)
  30. _ markup.ExternalRenderer = (*Renderer)(nil)
  31. )
  32. // Name returns the external tool name
  33. func (p *Renderer) Name() string {
  34. return p.MarkupName
  35. }
  36. // NeedPostProcess implements markup.Renderer
  37. func (p *Renderer) NeedPostProcess() bool {
  38. return p.MarkupRenderer.NeedPostProcess
  39. }
  40. // Extensions returns the supported extensions of the tool
  41. func (p *Renderer) Extensions() []string {
  42. return p.FileExtensions
  43. }
  44. // SanitizerRules implements markup.Renderer
  45. func (p *Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
  46. return p.MarkupSanitizerRules
  47. }
  48. // SanitizerDisabled disabled sanitize if return true
  49. func (p *Renderer) SanitizerDisabled() bool {
  50. return p.RenderContentMode == setting.RenderContentModeNoSanitizer || p.RenderContentMode == setting.RenderContentModeIframe
  51. }
  52. // DisplayInIFrame represents whether render the content with an iframe
  53. func (p *Renderer) DisplayInIFrame() bool {
  54. return p.RenderContentMode == setting.RenderContentModeIframe
  55. }
  56. func envMark(envName string) string {
  57. if runtime.GOOS == "windows" {
  58. return "%" + envName + "%"
  59. }
  60. return "$" + envName
  61. }
  62. // Render renders the data of the document to HTML via the external tool.
  63. func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
  64. baseLinkSrc := ctx.RenderHelper.ResolveLink("", markup.LinkTypeDefault)
  65. baseLinkRaw := ctx.RenderHelper.ResolveLink("", markup.LinkTypeRaw)
  66. command := strings.NewReplacer(
  67. envMark("GITEA_PREFIX_SRC"), baseLinkSrc,
  68. envMark("GITEA_PREFIX_RAW"), baseLinkRaw,
  69. ).Replace(p.Command)
  70. commands := strings.Fields(command)
  71. args := commands[1:]
  72. if p.IsInputFile {
  73. // write to temp file
  74. f, cleanup, err := setting.AppDataTempDir("git-repo-content").CreateTempFileRandom("gitea_input")
  75. if err != nil {
  76. return fmt.Errorf("%s create temp file when rendering %s failed: %w", p.Name(), p.Command, err)
  77. }
  78. defer cleanup()
  79. _, err = io.Copy(f, input)
  80. if err != nil {
  81. _ = f.Close()
  82. return fmt.Errorf("%s write data to temp file when rendering %s failed: %w", p.Name(), p.Command, err)
  83. }
  84. err = f.Close()
  85. if err != nil {
  86. return fmt.Errorf("%s close temp file when rendering %s failed: %w", p.Name(), p.Command, err)
  87. }
  88. args = append(args, f.Name())
  89. }
  90. processCtx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Render [%s] for %s", commands[0], baseLinkSrc))
  91. defer finished()
  92. cmd := exec.CommandContext(processCtx, commands[0], args...)
  93. cmd.Env = append(
  94. os.Environ(),
  95. "GITEA_PREFIX_SRC="+baseLinkSrc,
  96. "GITEA_PREFIX_RAW="+baseLinkRaw,
  97. )
  98. if !p.IsInputFile {
  99. cmd.Stdin = input
  100. }
  101. var stderr bytes.Buffer
  102. cmd.Stdout = output
  103. cmd.Stderr = &stderr
  104. process.SetSysProcAttribute(cmd)
  105. if err := cmd.Run(); err != nil {
  106. return fmt.Errorf("%s render run command %s %v failed: %w\nStderr: %s", p.Name(), commands[0], args, err, stderr.String())
  107. }
  108. return nil
  109. }