mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-08 08:32:16 +01:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5828fa01a | ||
|
|
662d3ff795 | ||
|
|
a97f05db3b | ||
|
|
5a439ca70c | ||
|
|
551faca3a3 | ||
|
|
c25ffe9639 |
18
.github/stale.yml
vendored
Normal file
18
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
# Number of days of inactivity before an issue becomes stale
|
||||
daysUntilStale: 60
|
||||
# Number of days of inactivity before a stale issue is closed
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- bug
|
||||
- documentation
|
||||
- enhancement
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: wontfix
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
||||
closeComment: false
|
||||
2
.github/workflows/continuous_integration.yml
vendored
2
.github/workflows/continuous_integration.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Run linters
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
version: v1.39
|
||||
version: v1.42
|
||||
|
||||
tests:
|
||||
needs:
|
||||
|
||||
2
Makefile
2
Makefile
@@ -11,7 +11,7 @@ GOTENBERG_VERSION=snapshot
|
||||
GOTENBERG_USER_GID=1001
|
||||
GOTENBERG_USER_UID=1001
|
||||
PDFTK_VERSION=1353200058 # See https://gitlab.com/pdftk-java/pdftk/-/releases - Binary package.
|
||||
GOLANGCI_LINT_VERSION=v1.39.0 # See https://github.com/golangci/golangci-lint/releases.
|
||||
GOLANGCI_LINT_VERSION=v1.42.0 # See https://github.com/golangci/golangci-lint/releases.
|
||||
|
||||
.PHONY: build
|
||||
build: ## Build the Gotenberg's Docker image
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# Note: ARG instructions do not create additional layers.
|
||||
# Instead, next layers will concatenate them.
|
||||
ARG GOLANG_VERSION
|
||||
# Note: we have to repeat ARG instructions in each build stage that uses them.
|
||||
ARG GOTENBERG_VERSION
|
||||
|
||||
FROM golang:$GOLANG_VERSION AS builder
|
||||
@@ -18,18 +19,21 @@ RUN go mod download &&\
|
||||
|
||||
# Copy the source code.
|
||||
COPY cmd ./cmd
|
||||
COPY internal ./internal
|
||||
COPY pkg ./pkg
|
||||
|
||||
# Build the binary.
|
||||
RUN go build -o gotenberg -ldflags "-X gotenberg.version=$GOTENBERG_VERSION" cmd/gotenberg/main.go
|
||||
ARG GOTENBERG_VERSION
|
||||
|
||||
FROM debian:buster-slim
|
||||
RUN go build -o gotenberg -ldflags "-X 'github.com/gotenberg/gotenberg/v7/cmd.Version=$GOTENBERG_VERSION'" cmd/gotenberg/main.go
|
||||
|
||||
FROM debian:bullseye-slim
|
||||
|
||||
ARG GOTENBERG_VERSION
|
||||
|
||||
LABEL author="Julien Neuhart" \
|
||||
description="A Docker-powered stateless API for PDF files." \
|
||||
github="https://github.com/gotenberg/gotenberg" \
|
||||
version="$GOTENBER_VERSION" \
|
||||
version="$GOTENBERG_VERSION" \
|
||||
website="https://gotenberg.dev"
|
||||
|
||||
# Improve fonts subpixel hinting and smoothing.
|
||||
@@ -80,6 +84,7 @@ RUN \
|
||||
fonts-telu \
|
||||
fonts-thai-tlwg \
|
||||
ttf-wqy-zenhei \
|
||||
fonts-arphic-ukai \
|
||||
fonts-arphic-uming \
|
||||
fonts-ipafont-mincho \
|
||||
fonts-ipafont-gothic \
|
||||
@@ -98,11 +103,8 @@ RUN \
|
||||
fonts-sil-gentium \
|
||||
fonts-sil-gentium-basic &&\
|
||||
rm -f ./ttf-mscorefonts-installer_3.8_all.deb &&\
|
||||
echo "deb https://httpredir.debian.org/debian/ buster-backports main contrib non-free" >> /etc/apt/sources.list &&\
|
||||
apt-get update -qq &&\
|
||||
# Install Chromium and LibreOffice.
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium &&\
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends -t buster-backports libreoffice &&\
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends chromium libreoffice &&\
|
||||
# Download unoconv (Python script).
|
||||
curl -Ls https://raw.githubusercontent.com/dagwieers/unoconv/master/unoconv -o /usr/bin/unoconv &&\
|
||||
chmod +x /usr/bin/unoconv &&\
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package gotenberg
|
||||
package gotenbergcmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -25,10 +25,13 @@ Version: %s
|
||||
-------------------------------------------------------
|
||||
`
|
||||
|
||||
var version = "snapshot"
|
||||
// Version is the... version of the Gotenberg application. We set it at the
|
||||
// build stage of the Docker image.
|
||||
var Version = "snapshot"
|
||||
|
||||
// Run starts the Gotenberg application. Call this in the main of your program.
|
||||
func Run() {
|
||||
fmt.Printf(banner, version)
|
||||
fmt.Printf(banner, Version)
|
||||
|
||||
// Creates the roo` FlagSet and adds the modules flags to it.
|
||||
fs := flag.NewFlagSet("gotenberg", flag.ExitOnError)
|
||||
@@ -1,16 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
gotenbergapp "github.com/gotenberg/gotenberg/v7/internal/app/gotenberg"
|
||||
gotenbergcmd "github.com/gotenberg/gotenberg/v7/cmd"
|
||||
|
||||
// Gotenberg modules.
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/standard"
|
||||
// PDF engines.
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/libreoffice/pdfengine"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/pdfcpu"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/pdftk"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gotenbergapp.Run()
|
||||
gotenbergcmd.Run()
|
||||
}
|
||||
|
||||
@@ -382,11 +382,7 @@ func (a *API) Start() error {
|
||||
checks := append(a.healthChecks, health.WithTimeout(a.processTimeout))
|
||||
checker := health.NewChecker(checks...)
|
||||
|
||||
return func(echoCtx echo.Context) error {
|
||||
health.NewHandler(checker).ServeHTTP(echoCtx.Response().Writer, echoCtx.Request())
|
||||
|
||||
return nil
|
||||
}
|
||||
return echo.WrapHandler(health.NewHandler(checker))
|
||||
}(),
|
||||
timeoutMiddleware(hardTimeout),
|
||||
)
|
||||
|
||||
@@ -257,12 +257,18 @@ func (mod Chromium) Routes() ([]api.MultipartFormDataRoute, error) {
|
||||
// drastically. In such a scenario, the given context may also be done before
|
||||
// the end of the conversion.
|
||||
func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath string, options Options) error {
|
||||
debug := debugLogger{logger: logger.Named("chromium.debug")}
|
||||
userProfileDirPath := gotenberg.NewDirPath()
|
||||
|
||||
args := append(chromedp.DefaultExecAllocatorOptions[:],
|
||||
chromedp.CombinedOutput(debug),
|
||||
chromedp.ExecPath(mod.binPath),
|
||||
chromedp.NoSandbox,
|
||||
// See:
|
||||
// https://github.com/gotenberg/gotenberg/issues/327
|
||||
// https://github.com/chromedp/chromedp/issues/904
|
||||
chromedp.DisableGPU,
|
||||
// See:
|
||||
// https://github.com/puppeteer/puppeteer/issues/661
|
||||
// https://github.com/puppeteer/puppeteer/issues/2410
|
||||
chromedp.Flag("font-render-hinting", "none"),
|
||||
@@ -284,7 +290,9 @@ func (mod Chromium) PDF(ctx context.Context, logger *zap.Logger, URL, outputPath
|
||||
allocatorCtx, cancel := chromedp.NewExecAllocator(ctx, args...)
|
||||
defer cancel()
|
||||
|
||||
taskCtx, cancel := chromedp.NewContext(allocatorCtx)
|
||||
taskCtx, cancel := chromedp.NewContext(allocatorCtx,
|
||||
chromedp.WithDebugf(debug.Printf),
|
||||
)
|
||||
defer cancel()
|
||||
|
||||
// We validate the "main" URL against our allow / deny lists.
|
||||
|
||||
31
pkg/modules/chromium/debug.go
Normal file
31
pkg/modules/chromium/debug.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package chromium
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// debugLogger is wrapper around a zap.Logger which is used for debugging
|
||||
// Chromium.
|
||||
type debugLogger struct {
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// Write logs the bytes in a debug message.
|
||||
func (debug debugLogger) Write(p []byte) (n int, err error) {
|
||||
debug.logger.Debug(string(p))
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Printf logs a debug message.
|
||||
func (debug debugLogger) Printf(format string, v ...interface{}) {
|
||||
debug.logger.Debug(fmt.Sprintf(format, v...))
|
||||
}
|
||||
|
||||
// Interface guards.
|
||||
var (
|
||||
_ io.Writer = (*debugLogger)(nil)
|
||||
)
|
||||
24
pkg/modules/chromium/debug_test.go
Normal file
24
pkg/modules/chromium/debug_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package chromium
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestDebugLogger_Write(t *testing.T) {
|
||||
actual, err := debugLogger{logger: zap.NewNop()}.Write([]byte("foo"))
|
||||
expected := len([]byte("foo"))
|
||||
|
||||
if actual != expected {
|
||||
t.Errorf("expected %d but got %d", expected, actual)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("expected not error but got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDebugLogger_Printf(t *testing.T) {
|
||||
debugLogger{logger: zap.NewNop()}.Printf("%s", "foo")
|
||||
}
|
||||
@@ -432,6 +432,29 @@ func TestConvertMarkdownHandler(t *testing.T) {
|
||||
outputDir: "/tmp/foo",
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
{
|
||||
ctx: func() *api.MockContext {
|
||||
ctx := &api.MockContext{Context: &api.Context{}}
|
||||
|
||||
ctx.SetDirPath("/tmp/foo")
|
||||
ctx.SetFiles(map[string]string{
|
||||
"index.html": "/tests/test/testdata/chromium/markdown/sample3/index.html",
|
||||
"markdown1.md": "/tests/test/testdata/chromium/markdown/sample3/markdown.md",
|
||||
})
|
||||
|
||||
return ctx
|
||||
}(),
|
||||
api: func() API {
|
||||
chromiumAPI := struct{ ProtoAPI }{}
|
||||
chromiumAPI.pdf = func(_ context.Context, _ *zap.Logger, _, _ string, _ Options) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
return chromiumAPI
|
||||
}(),
|
||||
outputDir: "/tmp/foo",
|
||||
expectOutputPathsCount: 1,
|
||||
},
|
||||
} {
|
||||
func() {
|
||||
if tc.outputDir != "" {
|
||||
|
||||
@@ -5,7 +5,10 @@ import (
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/chromium"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/gc"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/libreoffice"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/libreoffice/pdfengine"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/libreoffice/unoconv"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/logging"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/pdfcpu"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/pdfengines"
|
||||
_ "github.com/gotenberg/gotenberg/v7/pkg/modules/pdftk"
|
||||
)
|
||||
|
||||
18
test/testdata/chromium/markdown/sample3/index.html
vendored
Normal file
18
test/testdata/chromium/markdown/sample3/index.html
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Gutenberg</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Table in markdown</h1>
|
||||
|
||||
<h2>toHTML</h2>
|
||||
{{ toHTML "markdown.md" }}
|
||||
|
||||
<h2>Actual HTML</h2>
|
||||
<textarea readonly="readonly" cols="100" rows="50">
|
||||
{{ toHTML "markdown.md" }}
|
||||
</textarea>
|
||||
</body>
|
||||
</html>
|
||||
5
test/testdata/chromium/markdown/sample3/markdown.md
vendored
Normal file
5
test/testdata/chromium/markdown/sample3/markdown.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
| Tables | Are | Cool |
|
||||
|----------|:-------------:|------:|
|
||||
| col 1 is | left-aligned | $1600 |
|
||||
| col 2 is | centered | $12 |
|
||||
| col 3 is | right-aligned | $1 |
|
||||
Reference in New Issue
Block a user