From 35217febfc2c5d6a7e5d5d2b0b3c10a168fb2ed1 Mon Sep 17 00:00:00 2001 From: James Mills Date: Mon, 1 Aug 2022 03:22:17 +0000 Subject: [PATCH] Add support for multi-arch binary and docker image releases (#20) Reviewed-on: https://git.mills.io/prologic/tube/pulls/20 --- .chglog/CHANGELOG.tpl.md | 22 ++++++ .chglog/config.yml | 37 ++++++++++ .dockerfiles/config.json | 36 ++++++++++ .dockerfiles/entrypoint.sh | 12 ++++ .goreleaser.yml | 102 +++++++++++++--------------- Dockerfile | 70 +++++++++++++++++-- Dockerfile.goreleaser | 26 +++++++ Makefile | 93 ++++++++++++++++++------- README.md | 35 ++-------- app/app.go | 20 +++--- main.go | 8 ++- media/library.go | 2 +- preflight.sh | 135 +++++++++++++++++++++++++++++++++++++ tools/release.sh | 21 ++++-- 14 files changed, 483 insertions(+), 136 deletions(-) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .dockerfiles/config.json create mode 100755 .dockerfiles/entrypoint.sh create mode 100644 Dockerfile.goreleaser create mode 100755 preflight.sh diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000..c989a89 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,22 @@ +{{ range .Versions }} + +## {{ 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 -}} diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000..2c69658 --- /dev/null +++ b/.chglog/config.yml @@ -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 diff --git a/.dockerfiles/config.json b/.dockerfiles/config.json new file mode 100644 index 0000000..b0bc86c --- /dev/null +++ b/.dockerfiles/config.json @@ -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." + } +} diff --git a/.dockerfiles/entrypoint.sh b/.dockerfiles/entrypoint.sh new file mode 100755 index 0000000..872d4fd --- /dev/null +++ b/.dockerfiles/entrypoint.sh @@ -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 "$@" diff --git a/.goreleaser.yml b/.goreleaser.yml index 0e54a2f..03cde8c 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,8 +1,18 @@ --- builds: - - - flags: -tags "static_build" - ldflags: -w -X git.mills.io/prologic/tube/.Version={{.Version}} -X git.mills.io/prologic/tube/.Commit={{.Commit}} + - id: tube + binary: tube + 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: - CGO_ENABLED=0 goos: @@ -12,57 +22,39 @@ builds: - linux goarch: - amd64 - - arm - arm64 -brews: - - - github: - owner: prologic - name: homebrew-tube - homepage: "https://github.io/prologic/tube" - description: | - tube is a Youtube-like (without censorship and features you don't need!) - Video Sharing App written in Go which also supports automatic - transcoding to MP4 H.265 AAC, multiple collections and RSS feed. - dependencies: - - ffmpeg - plist: | - - - - - LabelTube - ProgramArguments - - /usr/local/bin/tube - /usr/local/etc/tube/config.json - - WorkingDirectory - /usr/local - StandardOutPath/usr/local/log/tube.log - RunAtLoad - KeepAlive - Disabled - - + +dockers: + - image_templates: ["prologic/tube:{{ .Version }}-amd64"] + use: buildx + dockerfile: Dockerfile.goreleaser + build_flag_templates: + - "--platform=linux/amd64" + extra_files: + - ".dockerfiles/entrypoint.sh" + - ".dockerfiles/config.json" + - image_templates: ["prologic/tube:{{ .Version }}-arm64v8"] + use: buildx + goarch: arm64 + dockerfile: Dockerfile.goreleaser + build_flag_templates: + - "--platform=linux/arm64/v8" + extra_files: + - ".dockerfiles/entrypoint.sh" + - ".dockerfiles/config.json" + +docker_manifests: + - name_template: prologic/tube:{{ .Version }} + image_templates: + - prologic/tube:{{ .Version }}-amd64 + - prologic/tube:{{ .Version }}-arm64v8 + signs: - - - artifacts: checksum -archives: - - - replacements: - darwin: Darwin - linux: Linux - windows: Windows - 386: i386 - amd64: x86_64 -checksum: - name_template: 'checksums.txt' -snapshot: - name_template: "{{ .Tag }}-next" -changelog: - sort: asc - filters: - exclude: - - '^docs:' - - '^test:' + - artifacts: checksum +release: + gitea: + owner: prologic + name: tube + draft: false +gitea_urls: + api: https://git.mills.io/api/v1/ diff --git a/Dockerfile b/Dockerfile index 1257ed1..2049e14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,70 @@ # 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 -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"] -CMD [""] +VOLUME /data + +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"] diff --git a/Dockerfile.goreleaser b/Dockerfile.goreleaser new file mode 100644 index 0000000..ec6b312 --- /dev/null +++ b/Dockerfile.goreleaser @@ -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"] diff --git a/Makefile b/Makefile index 5836337..3a501dd 100644 --- a/Makefile +++ b/Makefile @@ -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 -VERSION=$(shell git describe --abbrev=0 --tags) -COMMIT=$(shell git rev-parse --short HEAD) +export CGO_ENABLED=0 +VERSION=$(shell git describe --abbrev=0 --tags 2>/dev/null || echo "0.0.0") +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 - @./tube -v +ifeq ($(BRANCH), master) +IMAGE := prologic/tube +TAG := latest +else +IMAGE := prologic/tube +TAG := dev +endif -setup: - @go get github.com/GeertJohan/go.rice/rice +all: help -build: clean - @command -v rice > /dev/null || make setup - @go generate $(shell go list)/... - @go build \ - -tags "netgo static_build" -installsuffix netgo \ - -ldflags "-w -X main.Version=$(VERSION) -X main.Commit=$(COMMIT)" \ +.PHONY: help + +help: ## Show this help message + @echo "tube - a Youtube-like (without censorship and features you don't need!) Video Sharing App" + @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) + +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 - @go install +build: server ## Build the server -docker-image: - @docker build -t prologic/tube . -docker-run: - @docker run -p 8000:8000 -t prologic/tube . +generate: ## Genereate any code required by the build + @if [ x"$(DEBUG)" = x"1" ]; then \ + echo 'Running in debug mode...'; \ + fi -test: install - @go test +install: build ## Install tube to $DESTDIR + @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 -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 diff --git a/README.md b/README.md index 533b028..5bd8515 100644 --- a/README.md +++ b/README.md @@ -23,17 +23,7 @@ MP4 H.265 AAC, multiple collections and RSS feed. ## Getting Started -### Using Homebrew - -```#!sh -$ brew tap prologic/tube -$ brew install tube -$ tube -``` - -Open http://127.0.0.1:8000/ in your Browser! - -### Using a Binary +### Prebuilt Release Binaries 1. Go grab the latest binary from the [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! -### Using Docker +### Published Docker Images ```#!sh $ docker pull prologic/tube $ 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! Where `DOCKER_MACHINE_IP` is the IP Address of your Docker Node. -### From Source +### Building From Source ```#!sh $ git clone https://git.mills.io/prologic/tube $ cd tube -$ make +$ make build $ ./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 Thank you to all those that have contributed to this project, battle-tested it, diff --git a/app/app.go b/app/app.go index 26a6405..a431a1e 100644 --- a/app/app.go +++ b/app/app.go @@ -14,15 +14,15 @@ import ( "sort" "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" "github.com/dustin/go-humanize" "github.com/fsnotify/fsnotify" "github.com/gorilla/handlers" "github.com/gorilla/mux" 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" ) @@ -298,11 +298,15 @@ func (a *App) uploadHandler(w http.ResponseWriter, r *http.Request) { if err := utils.RunCmd( a.Config.Thumbnailer.Timeout, - "mt", - "-b", - "-s", - "-n", "1", - tf.Name(), + "ffmpeg", + "-i", uf.Name(), + "-y", + "-vf", "thumbnail", + "-t", "3", + "-vframes", "1", + "-strict", "-2", + "-loglevel", "quiet", + thumbFn1, ); err != nil { err := fmt.Errorf("error generating thumbnail: %w", err) log.Error(err) diff --git a/main.go b/main.go index ae23f86..0f9331f 100644 --- a/main.go +++ b/main.go @@ -42,8 +42,12 @@ func main() { cfg := app.DefaultConfig() err := cfg.ReadFile(config) - if err != nil && !os.IsNotExist(err) { - log.Fatal(err) + if err == nil { + log.Infof("reading configuration from %s", config) + } else { + if !os.IsNotExist(err) { + log.Fatal(err) + } } a, err := app.NewApp(cfg) if err != nil { diff --git a/media/library.go b/media/library.go index 6bfedff..7de68e0 100644 --- a/media/library.go +++ b/media/library.go @@ -41,7 +41,7 @@ func (lib *Library) AddPath(p *Path) error { 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) } lib.Paths[p.Path] = p diff --git a/preflight.sh b/preflight.sh new file mode 100755 index 0000000..f3b75f8 --- /dev/null +++ b/preflight.sh @@ -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 diff --git a/tools/release.sh b/tools/release.sh index e8ab44e..77d8612 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -1,16 +1,19 @@ -#!/bin/sh +#!/bin/bash # Get the highest tag number VERSION="$(git describe --abbrev=0 --tags)" VERSION=${VERSION:-'0.0.0'} # Get number parts -MAJOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" -MINOR="${VERSION%%.*}"; VERSION="${VERSION#*.}" -PATCH="${VERSION%%.*}"; VERSION="${VERSION#*.}" +MAJOR="${VERSION%%.*}" +VERSION="${VERSION#*.}" +MINOR="${VERSION%%.*}" +VERSION="${VERSION#*.}" +PATCH="${VERSION%%.*}" +VERSION="${VERSION#*.}" # Increase version -PATCH=$((PATCH+1)) +PATCH=$((PATCH + 1)) TAG="${1}" @@ -20,6 +23,10 @@ fi 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 push --tags -goreleaser release --rm-dist +git push && git push --tags +goreleaser release \ + --rm-dist \ + --release-notes <(git-chglog "${TAG}" | tail -n+5)