diff --git a/.dockerignore b/.dockerignore index 96f81bc..7620946 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,4 @@ Dockerfile .git +config.ini +writefreely.db \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 2ae05a6..31285cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,35 +1,25 @@ -# Build image -FROM golang:1.12-alpine as build +FROM golang:1.12-alpine AS build -RUN apk add --update nodejs nodejs-npm make g++ git sqlite-dev -RUN npm install -g less less-plugin-clean-css -RUN go get -u github.com/jteeuwen/go-bindata/... +RUN apk add nodejs nodejs-npm make g++ ca-certificates git sqlite-dev && \ + npm install -g less less-plugin-clean-css && \ + go get -u github.com/jteeuwen/go-bindata/... -RUN mkdir -p /go/src/github.com/writeas/writefreely -WORKDIR /go/src/github.com/writeas/writefreely +WORKDIR /src +COPY ./go.mod ./go.sum ./ +RUN go mod download COPY . . +RUN make assets ui && cd cmd/writefreely && go build -v -tags='sqlite' -ENV GO111MODULE=on -RUN make build \ - && make ui -RUN mkdir /stage && \ - cp -R /go/bin \ - /go/src/github.com/writeas/writefreely/templates \ - /go/src/github.com/writeas/writefreely/static \ - /go/src/github.com/writeas/writefreely/pages \ - /go/src/github.com/writeas/writefreely/keys \ - /go/src/github.com/writeas/writefreely/cmd \ - /stage +RUN mkdir -p \ + /home/writefreely/static /home/writefreely/templates /home/writefreely/pages && \ + cp -r templates/ pages/ static/ /home/writefreely -# Final image -FROM alpine:3.8 +FROM alpine AS final -RUN apk add --no-cache openssl ca-certificates -COPY --from=build --chown=daemon:daemon /stage /go +# TODO user nobody or similar +COPY --from=build /src/cmd/writefreely/writefreely /bin +COPY --from=build /home /home -WORKDIR /go -VOLUME /go/keys EXPOSE 8080 -USER daemon - -ENTRYPOINT ["cmd/writefreely/writefreely"] +WORKDIR /home/writefreely +ENTRYPOINT [ "writefreely" ] \ No newline at end of file diff --git a/Makefile b/Makefile index c88ac79..95dd05e 100644 --- a/Makefile +++ b/Makefile @@ -1,147 +1,150 @@ GITREV=`git describe | cut -c 2-` LDFLAGS=-ldflags="-X 'github.com/writeas/writefreely.softwareVer=$(GITREV)'" GOCMD=go GOINSTALL=$(GOCMD) install $(LDFLAGS) GOBUILD=$(GOCMD) build $(LDFLAGS) GOTEST=$(GOCMD) test $(LDFLAGS) GOGET=$(GOCMD) get BINARY_NAME=writefreely DOCKERCMD=docker IMAGE_NAME=writeas/writefreely TMPBIN=./tmp all : build ci: ci-assets deps cd cmd/writefreely; $(GOBUILD) -v build: assets deps cd cmd/writefreely; $(GOBUILD) -v -tags='sqlite' +build-no-git: assets deps + cd cmd/writefreely; $(GOCMD) build -v -tags='sqlite' + build-no-sqlite: assets-no-sqlite deps-no-sqlite cd cmd/writefreely; $(GOBUILD) -v -o $(BINARY_NAME) build-linux: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi xgo --targets=linux/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely build-windows: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi xgo --targets=windows/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely build-darwin: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi xgo --targets=darwin/amd64, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely build-arm7: deps @hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/karalabe/xgo; \ fi xgo --targets=linux/arm-7, -dest build/ $(LDFLAGS) -tags='sqlite' -out writefreely ./cmd/writefreely build-docker : $(DOCKERCMD) build -t $(IMAGE_NAME):latest -t $(IMAGE_NAME):$(GITREV) . test: $(GOTEST) -v ./... run: dev-assets $(GOINSTALL) -tags='sqlite' ./... $(BINARY_NAME) --debug deps : $(GOGET) -tags='sqlite' -d -v ./... deps-no-sqlite: $(GOGET) -d -v ./... install : build cmd/writefreely/$(BINARY_NAME) --config cmd/writefreely/$(BINARY_NAME) --gen-keys cmd/writefreely/$(BINARY_NAME) --init-db cd less/; $(MAKE) install $(MFLAGS) release : clean ui assets mkdir build cp -r templates build cp -r pages build cp -r static build mkdir build/keys $(MAKE) build-linux mv build/$(BINARY_NAME)-linux-amd64 build/$(BINARY_NAME) cd build; tar -cvzf ../$(BINARY_NAME)_$(GITREV)_linux_amd64.tar.gz * rm build/$(BINARY_NAME) $(MAKE) build-arm7 mv build/$(BINARY_NAME)-linux-arm-7 build/$(BINARY_NAME) cd build; tar -cvzf ../$(BINARY_NAME)_$(GITREV)_linux_arm7.tar.gz * rm build/$(BINARY_NAME) $(MAKE) build-darwin mv build/$(BINARY_NAME)-darwin-10.6-amd64 build/$(BINARY_NAME) cd build; tar -cvzf ../$(BINARY_NAME)_$(GITREV)_macos_amd64.tar.gz * rm build/$(BINARY_NAME) $(MAKE) build-windows mv build/$(BINARY_NAME)-windows-4.0-amd64.exe build/$(BINARY_NAME).exe cd build; zip -r ../$(BINARY_NAME)_$(GITREV)_windows_amd64.zip ./* $(MAKE) build-docker $(MAKE) release-docker # This assumes you're on linux/amd64 release-linux : clean ui mkdir build cp -r templates build cp -r pages build cp -r static build mkdir build/keys $(MAKE) build-no-sqlite mv cmd/writefreely/$(BINARY_NAME) build/$(BINARY_NAME) cd build; tar -cvzf ../$(BINARY_NAME)_$(GITREV)_linux_amd64.tar.gz * release-docker : $(DOCKERCMD) push $(IMAGE_NAME) ui : force_look cd less/; $(MAKE) $(MFLAGS) assets : generate go-bindata -pkg writefreely -ignore=\\.gitignore -tags="!wflib" schema.sql sqlite.sql assets-no-sqlite: generate go-bindata -pkg writefreely -ignore=\\.gitignore -tags="!wflib" schema.sql dev-assets : generate go-bindata -pkg writefreely -ignore=\\.gitignore -debug -tags="!wflib" schema.sql sqlite.sql lib-assets : generate go-bindata -pkg writefreely -ignore=\\.gitignore -o bindata-lib.go -tags="wflib" schema.sql generate : @hash go-bindata > /dev/null 2>&1; if [ $$? -ne 0 ]; then \ $(GOGET) -u github.com/jteeuwen/go-bindata/go-bindata; \ fi $(TMPBIN): mkdir -p $(TMPBIN) $(TMPBIN)/go-bindata: deps $(TMPBIN) $(GOBUILD) -o $(TMPBIN)/go-bindata github.com/jteeuwen/go-bindata/go-bindata $(TMPBIN)/xgo: deps $(TMPBIN) $(GOBUILD) -o $(TMPBIN)/xgo github.com/karalabe/xgo ci-assets : $(TMPBIN)/go-bindata $(TMPBIN)/go-bindata -pkg writefreely -ignore=\\.gitignore -tags="!wflib" schema.sql sqlite.sql clean : -rm -rf build -rm -rf tmp cd less/; $(MAKE) clean $(MFLAGS) force_look : true diff --git a/config/config.go b/config/config.go index e27ffb9..71c60e6 100644 --- a/config/config.go +++ b/config/config.go @@ -1,185 +1,186 @@ /* * Copyright © 2018-2019 A Bunch Tell LLC. * * This file is part of WriteFreely. * * WriteFreely is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, included * in the LICENSE file in this source code package. */ // Package config holds and assists in the configuration of a writefreely instance. package config import ( - "gopkg.in/ini.v1" "strings" + + "gopkg.in/ini.v1" ) const ( // FileName is the default configuration file name FileName = "config.ini" UserNormal UserType = "user" UserAdmin = "admin" ) type ( UserType string // ServerCfg holds values that affect how the HTTP server runs ServerCfg struct { HiddenHost string `ini:"hidden_host"` Port int `ini:"port"` Bind string `ini:"bind"` TLSCertPath string `ini:"tls_cert_path"` TLSKeyPath string `ini:"tls_key_path"` Autocert bool `ini:"autocert"` TemplatesParentDir string `ini:"templates_parent_dir"` StaticParentDir string `ini:"static_parent_dir"` PagesParentDir string `ini:"pages_parent_dir"` KeysParentDir string `ini:"keys_parent_dir"` Dev bool `ini:"-"` } // DatabaseCfg holds values that determine how the application connects to a datastore DatabaseCfg struct { Type string `ini:"type"` FileName string `ini:"filename"` User string `ini:"username"` Password string `ini:"password"` Database string `ini:"database"` Host string `ini:"host"` Port int `ini:"port"` } // AppCfg holds values that affect how the application functions AppCfg struct { SiteName string `ini:"site_name"` SiteDesc string `ini:"site_description"` Host string `ini:"host"` // Site appearance Theme string `ini:"theme"` Editor string `ini:"editor"` JSDisabled bool `ini:"disable_js"` WebFonts bool `ini:"webfonts"` Landing string `ini:"landing"` WFModesty bool `ini:"wf_modesty"` // Users SingleUser bool `ini:"single_user"` OpenRegistration bool `ini:"open_registration"` MinUsernameLen int `ini:"min_username_len"` MaxBlogs int `ini:"max_blogs"` // Federation Federation bool `ini:"federation"` PublicStats bool `ini:"public_stats"` // Access Private bool `ini:"private"` // Additional functions LocalTimeline bool `ini:"local_timeline"` UserInvites string `ini:"user_invites"` // Defaults DefaultVisibility string `ini:"default_visibility"` } // Config holds the complete configuration for running a writefreely instance Config struct { Server ServerCfg `ini:"server"` Database DatabaseCfg `ini:"database"` App AppCfg `ini:"app"` } ) // New creates a new Config with sane defaults func New() *Config { c := &Config{ Server: ServerCfg{ Port: 8080, Bind: "localhost", /* IPV6 support when not using localhost? */ }, App: AppCfg{ Host: "http://localhost:8080", Theme: "write", WebFonts: true, SingleUser: true, MinUsernameLen: 3, MaxBlogs: 1, Federation: true, PublicStats: true, }, } c.UseMySQL(true) return c } // UseMySQL resets the Config's Database to use default values for a MySQL setup. func (cfg *Config) UseMySQL(fresh bool) { cfg.Database.Type = "mysql" if fresh { cfg.Database.Host = "localhost" cfg.Database.Port = 3306 } } // UseSQLite resets the Config's Database to use default values for a SQLite setup. func (cfg *Config) UseSQLite(fresh bool) { cfg.Database.Type = "sqlite3" if fresh { cfg.Database.FileName = "writefreely.db" } } // IsSecureStandalone returns whether or not the application is running as a // standalone server with TLS enabled. func (cfg *Config) IsSecureStandalone() bool { return cfg.Server.Port == 443 && cfg.Server.TLSCertPath != "" && cfg.Server.TLSKeyPath != "" } func (ac *AppCfg) LandingPath() string { if !strings.HasPrefix(ac.Landing, "/") { return "/" + ac.Landing } return ac.Landing } // Load reads the given configuration file, then parses and returns it as a Config. func Load(fname string) (*Config, error) { if fname == "" { fname = FileName } cfg, err := ini.Load(fname) if err != nil { return nil, err } // Parse INI file uc := &Config{} err = cfg.MapTo(uc) if err != nil { return nil, err } return uc, nil } // Save writes the given Config to the given file. func Save(uc *Config, fname string) error { cfg := ini.Empty() err := ini.ReflectFrom(cfg, uc) if err != nil { return err } if fname == "" { fname = FileName } return cfg.SaveTo(fname) } diff --git a/docker-compose.sqlite.yml b/docker-compose.sqlite.yml new file mode 100644 index 0000000..31594fb --- /dev/null +++ b/docker-compose.sqlite.yml @@ -0,0 +1,16 @@ +version: "3" +services: + web: + image: robjloranger/writefreely:v0.10.0 + volumes: + - ./keys:/home/writefreely/keys + - ./config.ini:/home/writefreely/config.ini + - ./writefreely.db:/home/writefreely/writefreely.db + ports: + - "8080:8080" + networks: + - writefreely + restart: unless-stopped + +networks: + writefreely: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 29a841e..65dbf0d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,32 +1,30 @@ version: "3" services: web: - build: . + image: robjloranger/writefreely:v0.10.0 volumes: - - "web-data:/go/src/app" - - "./config.ini.example:/go/src/app/config.ini" + - ./keys:/home/writefreely/keys + - ./config.ini:/home/writefreely/config.ini ports: - "8080:8080" networks: - writefreely depends_on: - db restart: unless-stopped db: image: "mariadb:latest" volumes: - - "./schema.sql:/tmp/schema.sql" - db-data:/var/lib/mysql/data networks: - writefreely environment: - MYSQL_DATABASE=writefreely - MYSQL_ROOT_PASSWORD=changeme restart: unless-stopped volumes: - web-data: db-data: networks: - writefreely: + writefreely: \ No newline at end of file diff --git a/docker-setup.sh b/docker-setup.sh deleted file mode 100755 index 46f41f3..0000000 --- a/docker-setup.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -docker-compose exec db sh -c 'exec mysql -u root -pchangeme writefreely < /tmp/schema.sql' -docker exec writefreely_web_1 writefreely --gen-keys -docker exec -it writefreely_web_1 writefreely --config \ No newline at end of file diff --git a/go.mod b/go.mod index cc5fc57..5e040ba 100644 --- a/go.mod +++ b/go.mod @@ -1,80 +1,80 @@ module github.com/writeas/writefreely require ( github.com/BurntSushi/toml v0.3.1 // indirect github.com/Unknwon/com v0.0.0-20181010210213-41959bdd855f // indirect github.com/Unknwon/i18n v0.0.0-20171114194641-b64d33658966 // indirect github.com/alecthomas/gometalinter v3.0.0+incompatible // indirect github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 // indirect github.com/captncraig/cors v0.0.0-20180620154129-376d45073b49 // indirect github.com/clbanning/mxj v1.8.4 // indirect github.com/dustin/go-humanize v1.0.0 github.com/fatih/color v1.7.0 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 // indirect github.com/go-macaron/inject v0.0.0-20160627170012-d8a0b8677191 // indirect github.com/go-macaron/session v0.0.0-20190131233854-0a0a789bf193 // indirect github.com/go-sql-driver/mysql v1.4.1 github.com/go-test/deep v1.0.1 // indirect github.com/gogits/gogs v0.11.86 github.com/gogs/chardet v0.0.0-20150115103509-2404f7772561 // indirect github.com/gogs/go-libravatar v0.0.0-20161120025154-cd1abbd55d09 // indirect github.com/gogs/gogs v0.11.86 // indirect github.com/gogs/minwinsvc v0.0.0-20170301035411-95be6356811a // indirect github.com/golang/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect github.com/gorilla/feeds v1.1.0 github.com/gorilla/mux v1.7.0 github.com/gorilla/schema v1.0.2 github.com/gorilla/sessions v1.1.3 github.com/guregu/null v3.4.0+incompatible github.com/ikeikeikeike/go-sitemap-generator v1.0.1 github.com/ikeikeikeike/go-sitemap-generator/v2 v2.0.2 github.com/imdario/mergo v0.3.7 // indirect github.com/jteeuwen/go-bindata v3.0.7+incompatible // indirect github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/kylemcc/twitter-text-go v0.0.0-20180726194232-7f582f6736ec github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/manifoldco/promptui v0.3.2 github.com/mattn/go-colorable v0.1.0 // indirect github.com/mattn/go-sqlite3 v1.10.0 github.com/mcuadros/go-version v0.0.0-20180611085657-6d5863ca60fa // indirect github.com/microcosm-cc/bluemonday v1.0.2 github.com/mitchellh/go-wordwrap v1.0.0 github.com/nicksnyder/go-i18n v1.10.0 // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d github.com/pelletier/go-toml v1.2.0 // indirect github.com/pkg/errors v0.8.1 // indirect github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304 // indirect github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c // indirect github.com/stretchr/testify v1.3.0 // indirect github.com/writeas/activity v0.1.2 github.com/writeas/go-strip-markdown v2.0.1+incompatible github.com/writeas/go-webfinger v0.0.0-20190106002315-85cf805c86d2 github.com/writeas/httpsig v1.0.0 github.com/writeas/impart v1.1.0 github.com/writeas/monday v0.0.0-20181024183321-54a7dd579219 github.com/writeas/nerds v1.0.0 github.com/writeas/openssl-go v1.0.0 // indirect github.com/writeas/saturday v1.7.1 github.com/writeas/slug v1.2.0 github.com/writeas/web-core v1.0.0 github.com/writefreely/go-nodeinfo v1.2.0 - golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f // indirect + golang.org/x/crypto v0.0.0-20190208162236-193df9c0f06f golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1 // indirect golang.org/x/net v0.0.0-20190206173232-65e2d4e15006 // indirect golang.org/x/sys v0.0.0-20190209173611-3b5209105503 // indirect golang.org/x/tools v0.0.0-20190208222737-3744606dbb67 // indirect google.golang.org/appengine v1.4.0 // indirect gopkg.in/alecthomas/kingpin.v3-unstable v3.0.0-20180810215634-df19058c872c // indirect gopkg.in/bufio.v1 v1.0.0-20140618132640-567b2bfa514e // indirect gopkg.in/clog.v1 v1.2.0 // indirect gopkg.in/ini.v1 v1.41.0 gopkg.in/macaron.v1 v1.3.2 // indirect gopkg.in/redis.v2 v2.3.2 // indirect gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 // indirect gopkg.in/yaml.v2 v2.2.2 // indirect )