Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: readium/go-toolkit
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: develop
Choose a base ref
...
head repository: readium/go-toolkit
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 1 commit
  • 15 files changed
  • 2 contributors

Commits on Jun 17, 2024

  1. Upgrades to rwp utility and repo CI/CD (#91)

    Co-authored-by: Mickaël Menu <[email protected]>
    chocolatkey and mickael-menu authored Jun 17, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    c0251c5 View commit details
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -2,21 +2,21 @@ name: Build and Test

on:
push:
branches: [ main ]
branches: [ main, develop ]
pull_request:
branches: [ '**' ]

jobs:

build:
runs-on: ubuntu-latest
runs-on: [self-hosted, arm64]
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: 1.21
go-version: '>=1.22.0'

- name: Build
run: go build -v ./...
51 changes: 43 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -7,24 +7,59 @@ on:

permissions:
contents: write
packages: write

env:
IMAGE_NAME: rwp

jobs:
release:
runs-on: ubuntu-latest
runs-on: [self-hosted, arm64]
steps:
- uses: actions/checkout@v3
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v3
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '>=1.21.0'
cache: true
- uses: goreleaser/goreleaser-action@v4
go-version: '>=1.22.0'
- name: Build release
uses: goreleaser/goreleaser-action@v5
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
container:
runs-on: [self-hosted, arm64]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- run: git fetch --force --tags
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push Docker image
run: docker buildx build --platform=linux/amd64,linux/arm64,linux/arm/v7 . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
# This changes all uppercase characters to lowercase.
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
# This strips the git ref prefix from the version.
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# This strips the "v" prefix from the tag name.
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# This uses the Docker `latest` tag convention.
[ "$VERSION" == "main" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker buildx build --push \
--tag $IMAGE_ID:$VERSION \
--platform linux/amd64,linux/arm64,linux/arm/v7 .
26 changes: 17 additions & 9 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -2,29 +2,37 @@
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- main: ./cmd/rwp/
env:
- CGO_ENABLED=0
id: rwp
binary: rwp
goos:
- linux
- windows
- darwin
goamd64:
- v3

- main: ./cmd/server/
id: rwp-server
binary: rwp-server
goos:
- linux
- windows
- darwin
# - main: ./cmd/server/
# env:
# - CGO_ENABLED=0
# id: rwp-server
# binary: rwp-server
# goos:
# - linux
# - windows
# - darwin

archives:
- format: tar.gz
# this name template makes the OS and Arch compatible with the results of uname.
# Used to start with {{ .ProjectName }}
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
rwp_
{{- tolower .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
11 changes: 1 addition & 10 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -6,13 +6,4 @@ All notable changes to this project will be documented in this file.

## [Unreleased]

### Added

* Add the [Media Type API](https://readium.org/architecture/proposals/001-media-type.html).
* Add the file and archive fetchers of the [Fetcher API](https://readium.org/architecture/proposals/002-composite-fetcher-api.html).

### Changed

* Restructuring of the repo's folders
* Removal of legacy models (LCP etc.)
* Updated shared models to latest specs
TODO
56 changes: 56 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
FROM --platform=$BUILDPLATFORM golang:1-bookworm as builder
ARG BUILDARCH TARGETOS TARGETARCH

# Install GoReleaser
RUN wget --no-verbose "https://github.com/goreleaser/goreleaser/releases/download/v1.26.2/goreleaser_1.26.2_$BUILDARCH.deb"
RUN dpkg -i "goreleaser_1.26.2_$BUILDARCH.deb"

# Create and change to the app directory.
WORKDIR /app

# Retrieve application dependencies.
# This allows the container build to reuse cached dependencies.
# Expecting to copy go.mod and if present go.sum.
COPY go.* ./
RUN go mod download

# Copy local code to the container image.
COPY . ./

# RUN git lfs pull && ls -alh publications

# Run goreleaser
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg \
GOOS=$TARGETOS GOARCH=$TARGETARCH goreleaser build --single-target --id rwp --skip=validate --snapshot --output ./rwp

# Run tests
# FROM builder AS tester
# RUN go test ./...

# Produces very small images
FROM gcr.io/distroless/static-debian12 AS packager

# Extra metadata
LABEL org.opencontainers.image.source="https://github.com/readium/go-toolkit"

# Add Fedora's mimetypes (pretty up-to-date and expansive)
# since the distroless container doesn't have any. Go uses
# this file as part of its mime package, and readium/go-toolkit
# has a mediatype package that falls back to Go's mime
# package to discover a file's mimetype when all else fails.
ADD https://pagure.io/mailcap/raw/master/f/mime.types /etc/

# Add two demo EPUBs to the container by default
ADD --chown=nonroot:nonroot https://readium-playground-files.storage.googleapis.com/demo/moby-dick.epub /srv/publications/
ADD --chown=nonroot:nonroot https://readium-playground-files.storage.googleapis.com/demo/BellaOriginal3.epub /srv/publications/

# Copy built Go binary
COPY --from=builder "/app/rwp" /opt/

EXPOSE 15080

USER nonroot:nonroot

ENTRYPOINT ["/opt/rwp"]
CMD ["serve", "/srv/publications", "--address", "0.0.0.0"]
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -56,3 +56,8 @@ rwp manifest --infer-a11y=merged publication.epub | jq .metadata
| `feature` | `tableOfContents` | If the publications contains a table of contents (check for the presence of a `toc` collection in RWPM) |
| `feature` | `MathML` | If the publication contains any resource with MathML (check for the presence of the `contains` property where the value is `mathml` in `readingOrder` or `resources` in RWPM) |
| `feature` | `synchronizedAudioText` | If the publication contains any reference to Media Overlays (TBD in RWPM) |
### HTTP streaming of local publications
`rwp serve` starts an HTTP server that serves EPUB, CBZ and other compatible formats from a given directory.
A log is printed to stdout.
112 changes: 112 additions & 0 deletions cmd/rwp/cmd/serve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package cmd

import (
"errors"
"fmt"
"net/http"
"os"
"path/filepath"
"time"

"log/slog"

"github.com/readium/go-toolkit/cmd/rwp/cmd/serve"
"github.com/readium/go-toolkit/pkg/streamer"
"github.com/spf13/cobra"
)

var debugFlag bool

var bindAddressFlag string

var bindPortFlag uint16

var serveCmd = &cobra.Command{
Use: "serve <directory>",
Short: "Start a local HTTP server, serving a specified directory of publications",
Long: `Start a local HTTP server, serving a specified directory of publications.
This command will start an HTTP serve listening by default on 'localhost:15080',
serving all compatible files (EPUB, PDF, CBZ, etc.) found in the directory
as Readium Web Publications. To get started, the manifest can be accessed from
'http://localhost:15080/<filename in base64url encoding without padding>/manifest.json'.
This file serves as the entry point and contains metadata and links to the rest
of the files that can be accessed for the publication.
For debugging purposes, the server also exposes a '/list.json' endpoint that
returns a list of all the publications found in the directory along with their
encoded paths. This will be replaced by an OPDS 2 feed in a future release.
Note: This server is not meant for production usage, and should not be exposed
to the internet except for testing/debugging purposes.`,
Args: func(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return errors.New("expects a directory path to serve publications from")
} else if len(args) > 1 {
return errors.New("accepts a directory path")
}
return nil
},

SuggestFor: []string{"server"},
RunE: func(cmd *cobra.Command, args []string) error {
// By the time we reach this point, we know that the arguments were
// properly parsed, and we don't want to show the usage if an API error
// occurs.
cmd.SilenceUsage = true

path := filepath.Clean(args[0])
fi, err := os.Stat(path)
if err != nil {
if os.IsNotExist(err) {
return fmt.Errorf("given directory %s does not exist", path)
}
return fmt.Errorf("failed to stat %s: %w", path, err)
}
if !fi.IsDir() {
return fmt.Errorf("given path %s is not a directory", path)
}

// Log level
if debugFlag {
slog.SetLogLoggerLevel(slog.LevelDebug)
} else {
slog.SetLogLoggerLevel(slog.LevelInfo)
}

pubServer := serve.NewServer(serve.ServerConfig{
Debug: debugFlag,
BaseDirectory: path,
JSONIndent: indentFlag,
InferA11yMetadata: streamer.InferA11yMetadata(inferA11yFlag),
})

bind := fmt.Sprintf("%s:%d", bindAddressFlag, bindPortFlag)
httpServer := &http.Server{
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
Addr: bind,
Handler: pubServer.Routes(),
}
slog.Info("Starting HTTP server", "address", "http://"+httpServer.Addr)
if err := httpServer.ListenAndServe(); err != http.ErrServerClosed {
slog.Error("Server stopped", "error", err)
} else {
slog.Info("Goodbye!")
}

return nil
},
}

func init() {
rootCmd.AddCommand(serveCmd)

serveCmd.Flags().StringVarP(&bindAddressFlag, "address", "a", "localhost", "Address to bind the HTTP server to")
serveCmd.Flags().Uint16VarP(&bindPortFlag, "port", "p", 15080, "Port to bind the HTTP server to")
serveCmd.Flags().StringVarP(&indentFlag, "indent", "i", "", "Indentation used to pretty-print JSON files")
serveCmd.Flags().Var(&inferA11yFlag, "infer-a11y", "Infer accessibility metadata: no, merged, split")
serveCmd.Flags().BoolVarP(&debugFlag, "debug", "d", false, "Enable debug mode")

}
Loading