Add support for multi-arch binary and docker image releases (#20)

Reviewed-on: https://git.mills.io/prologic/tube/pulls/20
This commit is contained in:
James Mills 2022-08-01 03:22:17 +00:00
parent 3b7c29eb8a
commit 35217febfc
14 changed files with 483 additions and 136 deletions

22
.chglog/CHANGELOG.tpl.md Executable file
View file

@ -0,0 +1,22 @@
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }})
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
* {{ .Subject }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
{{ .Body }}
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}

37
.chglog/config.yml Executable file
View file

@ -0,0 +1,37 @@
---
style: Github
template: CHANGELOG.tpl.md
info:
title: CHANGELOG
repository_url: https://git.mills.io/prologic/tube
options:
commits:
filters:
Type:
- Add
- Fix
- Update
- Document
commit_groups:
title_maps:
Add: Features
Update: Updates
Fix: Bug Fixes
Document: Documentation
header:
pattern: "^((\\w+)\\s.*)$"
pattern_maps:
- Subject
- Type
refs:
actions:
- Closes
- Fixes
reverts:
pattern: "^Revert \"([\\s\\S]*)\"$"
pattern_maps:
- Header
notes:
keywords:
- NOTE
- BREAKING CHANGE

36
.dockerfiles/config.json Normal file
View file

@ -0,0 +1,36 @@
{
"library": [
{
"path": "/data/videos",
"prefix": ""
}
],
"server": {
"host": "0.0.0.0",
"port": 8000,
"store_path": "/data/tube.db",
"upload_path": "/data/uploads",
"max_upload_size": 104857600
},
"thumbnailer": {
"timeout": 60
},
"transcoder": {
"timeout": 300,
"sizes": null
},
"feed": {
"external_url": "",
"title": "Feed Title",
"link": "http://your-url.example/about",
"description": "Feed Description",
"author": {
"name": "Author Name",
"email": "author@somewhere.example"
},
"copyright": "Copyright Text"
},
"copyright": {
"content": "All Content herein Public Domain and User Contributed."
}
}

12
.dockerfiles/entrypoint.sh Executable file
View file

@ -0,0 +1,12 @@
#!/bin/sh
[ -n "${PUID}" ] && usermod -u "${PUID}" tube
[ -n "${PGID}" ] && groupmod -g "${PGID}" tube
printf "Configuring tube ..."
[ -z "${DATA}" ] && DATA="/data"
export DATA
printf "Switching UID=%s and GID=%s\n" "${PUID}" "${PGID}"
exec su-exec tube:ytube "$@"

View file

@ -1,8 +1,18 @@
--- ---
builds: builds:
- - id: tube
flags: -tags "static_build" binary: tube
ldflags: -w -X git.mills.io/prologic/tube/.Version={{.Version}} -X git.mills.io/prologic/tube/.Commit={{.Commit}} main: .
flags:
- -installsuffix=netgo
tags:
- embed
- netcgo
- static_build
ldflags: >-
-w
-X git.mills.io/prologic/tube.Version={{.Version}}
-X git.mills.io/prologic/tube.Commit={{.Commit}}
env: env:
- CGO_ENABLED=0 - CGO_ENABLED=0
goos: goos:
@ -12,57 +22,39 @@ builds:
- linux - linux
goarch: goarch:
- amd64 - amd64
- arm
- arm64 - arm64
brews:
- dockers:
github: - image_templates: ["prologic/tube:{{ .Version }}-amd64"]
owner: prologic use: buildx
name: homebrew-tube dockerfile: Dockerfile.goreleaser
homepage: "https://github.io/prologic/tube" build_flag_templates:
description: | - "--platform=linux/amd64"
tube is a Youtube-like (without censorship and features you don't need!) extra_files:
Video Sharing App written in Go which also supports automatic - ".dockerfiles/entrypoint.sh"
transcoding to MP4 H.265 AAC, multiple collections and RSS feed. - ".dockerfiles/config.json"
dependencies: - image_templates: ["prologic/tube:{{ .Version }}-arm64v8"]
- ffmpeg use: buildx
plist: | goarch: arm64
<?xml version=1.0 encoding=UTF-8?> dockerfile: Dockerfile.goreleaser
<!DOCTYPE plist PUBLIC \“-//Apple Computer//DTD PLIST 1.0//EN\” \”http://www.apple.com/DTDs/PropertyList-1.0.dtd\” > build_flag_templates:
<plist version=1.0> - "--platform=linux/arm64/v8"
<dict> extra_files:
<key>Label</key><string>Tube</string> - ".dockerfiles/entrypoint.sh"
<key>ProgramArguments</key> - ".dockerfiles/config.json"
<array>
<string>/usr/local/bin/tube</string> docker_manifests:
<string>/usr/local/etc/tube/config.json - name_template: prologic/tube:{{ .Version }}
</array> image_templates:
<key>WorkingDirectory</key> - prologic/tube:{{ .Version }}-amd64
<string>/usr/local</string> - prologic/tube:{{ .Version }}-arm64v8
<key>StandardOutPath</key><string>/usr/local/log/tube.log</string>
<key>RunAtLoad</key></true/>
<key>KeepAlive</key><true/>
<key>Disabled</key><false/>
</dict>
</plist>
signs: signs:
- - artifacts: checksum
artifacts: checksum release:
archives: gitea:
- owner: prologic
replacements: name: tube
darwin: Darwin draft: false
linux: Linux gitea_urls:
windows: Windows api: https://git.mills.io/api/v1/
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'

View file

@ -1,14 +1,70 @@
# Build # Build
FROM prologic/go-builder:latest AS build FROM golang:alpine AS build
RUN apk add --no-cache -U build-base git make ffmpeg-dev
RUN mkdir -p /src
WORKDIR /src
# Copy Makefile
COPY Makefile ./
# Install deps
RUN make deps
# Copy go.mod and go.sum and install and cache dependencies
COPY go.mod .
COPY go.sum .
# Copy static assets
COPY ./static/* ./static/
# Copy templates
COPY ./templates/* ./templates/
# Copy sources
COPY *.go ./
COPY ./app/*.go ./app/
COPY ./importers/*.go ./importers/
COPY ./media/*.go ./media/
COPY ./utils/*.go ./utils/
# Version/Commit (there there is no .git in Docker build context)
# NOTE: This is fairly low down in the Dockerfile instructions so
# we don't break the Docker build cache just be changing
# unrelated files that actually haven't changed but caused the
# COMMIT value to change.
ARG VERSION="0.0.0"
ARG COMMIT="HEAD"
# Build server binary
RUN make server VERSION=$VERSION COMMIT=$COMMIT
# Runtime # Runtime
FROM golang:alpine FROM alpine:latest
RUN apk --no-cache -U add git build-base ffmpeg ffmpeg-dev RUN apk --no-cache -U add su-exec shadow ca-certificates tzdata ffmpeg
RUN go install github.com/mutschler/mt@latest ENV PUID=1000
ENV PGID=1000
COPY --from=build /src/tube /tube RUN addgroup -g "${PGID}" tube && \
adduser -D -H -G tube -h /var/empty -u "${PUID}" tube && \
mkdir -p /data && chown -R tube:tube /data
ENTRYPOINT ["/tube"] VOLUME /data
CMD [""]
WORKDIR /
# force cgo resolver
ENV GODEBUG=netdns=cgo
COPY --from=build /src/tube /usr/local/bin/tube
COPY .dockerfiles/entrypoint.sh /init
COPY .dockerfiles/config.json /
ENTRYPOINT ["/init"]
CMD ["tube"]

26
Dockerfile.goreleaser Normal file
View file

@ -0,0 +1,26 @@
# Runtime
FROM alpine:latest
RUN apk --no-cache -U add su-exec shadow ca-certificates tzdata ffmpeg
ENV PUID=1000
ENV PGID=1000
RUN addgroup -g "${PGID}" tube && \
adduser -D -H -G tube -h /var/empty -u "${PUID}" tube && \
mkdir -p /data && chown -R tube:tube /data
VOLUME /data
WORKDIR /
# force cgo resolver
ENV GODEBUG=netdns=cgo
COPY tube /usr/local/bin
COPY .dockerfiles/entrypoint.sh /init
COPY .dockerfiles/config.json /
ENTRYPOINT ["/init"]
CMD ["tube"]

View file

@ -1,38 +1,81 @@
.PHONY: dev setup build install image test release clean -include environ.inc
.PHONY: help deps dev build install image release test clean clean-all
CGO_ENABLED=0 export CGO_ENABLED=0
VERSION=$(shell git describe --abbrev=0 --tags) VERSION=$(shell git describe --abbrev=0 --tags 2>/dev/null || echo "0.0.0")
COMMIT=$(shell git rev-parse --short HEAD) COMMIT=$(shell git rev-parse --short HEAD || echo "HEAD")
BRANCH=$(shell git rev-parse --abbrev-ref HEAD)
GOCMD=go
GOVER=$(shell go version | grep -o -E 'go1\.17\.[0-9]+')
all: dev DESTDIR=/usr/local/bin
dev: build ifeq ($(BRANCH), master)
@./tube -v IMAGE := prologic/tube
TAG := latest
else
IMAGE := prologic/tube
TAG := dev
endif
setup: all: help
@go get github.com/GeertJohan/go.rice/rice
build: clean .PHONY: help
@command -v rice > /dev/null || make setup
@go generate $(shell go list)/... help: ## Show this help message
@go build \ @echo "tube - a Youtube-like (without censorship and features you don't need!) Video Sharing App"
-tags "netgo static_build" -installsuffix netgo \ @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[$$()% a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
-ldflags "-w -X main.Version=$(VERSION) -X main.Commit=$(COMMIT)" \
preflight: ## Run preflight checks to ensure you have the right build tools
@./preflight.sh
deps: ## Install any dependencies required
dev : DEBUG=1
dev : server ## Build debug version of tube
@./tube
server: generate ## Build the tube server
@$(GOCMD) build -tags "embed netgo static_build" -installsuffix netgo \
-ldflags "-w \
-X $(shell go list).Version=$(VERSION) \
-X $(shell go list).Commit=$(COMMIT)" \
. .
install: build build: server ## Build the server
@go install
docker-image: generate: ## Genereate any code required by the build
@docker build -t prologic/tube . @if [ x"$(DEBUG)" = x"1" ]; then \
docker-run: echo 'Running in debug mode...'; \
@docker run -p 8000:8000 -t prologic/tube . fi
test: install install: build ## Install tube to $DESTDIR
@go test @install -D -m 755 tube $(DESTDIR)/tube
release: ifeq ($(PUBLISH), 1)
image: generate ## Build the Docker image
@docker build --build-arg VERSION="$(VERSION)" --build-arg COMMIT="$(COMMIT)" -t $(IMAGE):$(TAG) .
@docker push $(IMAGE):$(TAG)
else
image: generate
@docker build --build-arg VERSION="$(VERSION)" --build-arg COMMIT="$(COMMIT)" -t $(IMAGE):$(TAG) .
endif
release: generate ## Release a new version to Gitea
@./tools/release.sh @./tools/release.sh
clean: fmt: ## Format sources fiels
@$(GOCMD) fmt ./...
test: ## Run test suite
@CGO_ENABLED=1 $(GOCMD) test -v -cover -race ./...
coverage: ## Get test coverage report
@CGO_ENABLED=1 $(GOCMD) test -v -cover -race -cover -coverprofile=coverage.out ./...
@$(GOCMD) tool cover -html=coverage.out
clean: ## Remove untracked files
@git clean -f -d -x
clean-all: ## Remove untracked and Git ignores files
@git clean -f -d -X @git clean -f -d -X

View file

@ -23,17 +23,7 @@ MP4 H.265 AAC, multiple collections and RSS feed.
## Getting Started ## Getting Started
### Using Homebrew ### Prebuilt Release Binaries
```#!sh
$ brew tap prologic/tube
$ brew install tube
$ tube
```
Open http://127.0.0.1:8000/ in your Browser!
### Using a Binary
1. Go grab the latest binary from the 1. Go grab the latest binary from the
[Releases](https://git.mills.io/prologic/tube/releases) page for your [Releases](https://git.mills.io/prologic/tube/releases) page for your
@ -43,28 +33,23 @@ Open http://127.0.0.1:8000/ in your Browser!
Open http://127.0.0.1:8000/ in your Browser! Open http://127.0.0.1:8000/ in your Browser!
### Using Docker ### Published Docker Images
```#!sh ```#!sh
$ docker pull prologic/tube $ docker pull prologic/tube
$ docker run -p 8000:8000 -v /path/to/data:/data $ docker run -p 8000:8000 -v /path/to/data:/data
``` ```
or using makefile:
``` make docker-run ```
Open http://DOCKER_MACHINE_IP:8000/ in your Browser! Open http://DOCKER_MACHINE_IP:8000/ in your Browser!
Where `DOCKER_MACHINE_IP` is the IP Address of your Docker Node. Where `DOCKER_MACHINE_IP` is the IP Address of your Docker Node.
### From Source ### Building From Source
```#!sh ```#!sh
$ git clone https://git.mills.io/prologic/tube $ git clone https://git.mills.io/prologic/tube
$ cd tube $ cd tube
$ make $ make build
$ ./tube $ ./tube
``` ```
@ -217,18 +202,6 @@ Set `path` to the value of the path where you want to store videos and where
} }
} }
## Stargazers over time
[![Stargazers over time](https://starcharts.herokuapp.com/prologic/tube.svg)](https://starcharts.herokuapp.com/prologic/tube)
## Support
Support the ongoing development of Tube!
**Sponser**
- Become a [Sponsor](https://www.patreon.com/prologic)
## Contributors ## Contributors
Thank you to all those that have contributed to this project, battle-tested it, Thank you to all those that have contributed to this project, battle-tested it,

View file

@ -14,15 +14,15 @@ import (
"sort" "sort"
"strings" "strings"
"git.mills.io/prologic/tube/importers"
"git.mills.io/prologic/tube/media"
"git.mills.io/prologic/tube/utils"
rice "github.com/GeertJohan/go.rice" rice "github.com/GeertJohan/go.rice"
"github.com/dustin/go-humanize" "github.com/dustin/go-humanize"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/gorilla/handlers" "github.com/gorilla/handlers"
"github.com/gorilla/mux" "github.com/gorilla/mux"
shortuuid "github.com/lithammer/shortuuid/v3" shortuuid "github.com/lithammer/shortuuid/v3"
"git.mills.io/prologic/tube/importers"
"git.mills.io/prologic/tube/media"
"git.mills.io/prologic/tube/utils"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -298,11 +298,15 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) {
if err := utils.RunCmd( if err := utils.RunCmd(
a.Config.Thumbnailer.Timeout, a.Config.Thumbnailer.Timeout,
"mt", "ffmpeg",
"-b", "-i", uf.Name(),
"-s", "-y",
"-n", "1", "-vf", "thumbnail",
tf.Name(), "-t", "3",
"-vframes", "1",
"-strict", "-2",
"-loglevel", "quiet",
thumbFn1,
); err != nil { ); err != nil {
err := fmt.Errorf("error generating thumbnail: %w", err) err := fmt.Errorf("error generating thumbnail: %w", err)
log.Error(err) log.Error(err)

View file

@ -42,9 +42,13 @@ func main() {
cfg := app.DefaultConfig() cfg := app.DefaultConfig()
err := cfg.ReadFile(config) err := cfg.ReadFile(config)
if err != nil && !os.IsNotExist(err) { if err == nil {
log.Infof("reading configuration from %s", config)
} else {
if !os.IsNotExist(err) {
log.Fatal(err) log.Fatal(err)
} }
}
a, err := app.NewApp(cfg) a, err := app.NewApp(cfg)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

View file

@ -41,7 +41,7 @@ func (lib *Library) AddPath(p *Path) error {
return errors.New("media: duplicate library prefix") return errors.New("media: duplicate library prefix")
} }
} }
if err := os.MkdirAll(p.Path, 07550); err != nil { if err := os.MkdirAll(p.Path, 0755); err != nil {
return fmt.Errorf("error creating library path %s: %w", p.Path, err) return fmt.Errorf("error creating library path %s: %w", p.Path, err)
} }
lib.Paths[p.Path] = p lib.Paths[p.Path] = p

135
preflight.sh Executable file
View file

@ -0,0 +1,135 @@
#!/bin/sh
set -e
color() {
fg="$1"
bg="${2}"
ft="${3:-0}"
printf "\33[%s;%s;%s" "$ft" "$fg" "$bg"
}
color_reset() {
printf "\033[0m"
}
ok() {
if [ -t 1 ]; then
printf "%s[ OK ]%s\n" "$(color 37 42m 1)" "$(color_reset)"
else
printf "%s\n" "[ OK ]"
fi
}
err() {
if [ -t 1 ]; then
printf "%s[ ERR ]%s\n" "$(color 37 41m 1)" "$(color_reset)"
else
printf "%s\n" "[ ERR ]"
fi
}
run() {
retval=0
logfile="$(mktemp -t "run-XXXXXX")"
if "$@" 2> "$logfile"; then
ok
else
retval=$?
err
cat "$logfile" || true
fi
rm -rf "$logfile"
return $retval
}
progress() {
printf "%-40s" "$(printf "%s ... " "$1")"
}
log() {
printf "%s\n" "$1"
}
log2() {
printf "%s\n" "$1" 1>&2
}
error() {
log "ERROR: ${1}"
}
fail() {
log "FATAL: ${1}"
exit 1
}
check_goversion() {
progress "Checking Go version"
if ! command -v go > /dev/null 2>&1; then
log2 "Cannot find the Go compiler"
return 1
fi
gover="$(go version | grep -o -E 'go[0-9]+\.[0-9]+(\.[0-9]+)?')"
if ! go version | grep -E 'go1\.1[78](\.[0-9]+)?' > /dev/null; then
log2 "Go 1.17+ is required, found ${gover}"
return 1
fi
return 0
}
check_path() {
progress "Checking \$PATH"
gobin="$(eval "$(go env | grep GOBIN)")"
gopath="$(eval "$(go env | grep GOPATH)")"
if [ -n "$gobin" ] && ! echo "$PATH" | grep "$gobin" > /dev/null; then
log2 "\$GOBIN '$gobin' is not in your \$PATH"
return 1
fi
if [ -n "$gopath" ] && ! echo "$PATH" | grep "$gopath/bin" > /dev/null; then
log2 "\$GOPATH/bin '$gopath/bin' is not in your \$PATH"
return 1
fi
if ! echo "$PATH" | grep "$HOME/go/bin" > /dev/null; then
log2 "\$HOME/go/bin is not in your \$PATH"
return 1
fi
return 0
}
check_deps() {
progress "Checking deps"
if ! command -v ffmpeg > /dev/null 2>&1; then
log2 "ffmpeg not found, Please install it using your OS package manager"
return 1
fi
return 0
}
steps="check_goversion check_path check_deps"
_main() {
for step in $steps; do
if ! run "$step"; then
fail "🙁 preflight failed"
fi
done
log "🥳 All Done! Ready to build, run: make build"
}
if [ -n "$0" ] && [ x"$0" != x"-bash" ]; then
_main "$@"
fi

View file

@ -1,16 +1,19 @@
#!/bin/sh #!/bin/bash
# Get the highest tag number # Get the highest tag number
VERSION="$(git describe --abbrev=0 --tags)" VERSION="$(git describe --abbrev=0 --tags)"
VERSION=${VERSION:-'0.0.0'} VERSION=${VERSION:-'0.0.0'}
# Get number parts # Get number parts
MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" MAJOR="${VERSION%%.*}"
MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" VERSION="${VERSION#*.}"
PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}" MINOR="${VERSION%%.*}"
VERSION="${VERSION#*.}"
PATCH="${VERSION%%.*}"
VERSION="${VERSION#*.}"
# Increase version # Increase version
PATCH=$((PATCH+1)) PATCH=$((PATCH + 1))
TAG="${1}" TAG="${1}"
@ -20,6 +23,10 @@ fi
echo "Releasing ${TAG} ..." echo "Releasing ${TAG} ..."
git-chglog --next-tag="${TAG}" --output CHANGELOG.md
git commit -a -m "Update CHANGELOG for ${TAG}"
git tag -a -s -m "Release ${TAG}" "${TAG}" git tag -a -s -m "Release ${TAG}" "${TAG}"
git push --tags git push && git push --tags
goreleaser release --rm-dist goreleaser release \
--rm-dist \
--release-notes <(git-chglog "${TAG}" | tail -n+5)