1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-17 10:56:24 -07:00

Add *NIX installation compatibility

This commit is contained in:
Eggbertx 2019-08-01 21:05:06 -07:00
parent 51881dba85
commit cfed861f1c
15 changed files with 336 additions and 172 deletions

View file

@ -1,4 +1,4 @@
Copyright (c) 2013-2018, Eggbertx
Copyright (c) 2013-2019, Eggbertx
All rights reserved.
Redistribution and use in source and binary forms, with or without

278
build.sh
View file

@ -1,7 +1,9 @@
#!/bin/bash
set -eo pipefail
if [ -e "version" ]; then version="v`cat version` "; fi
echo "Gochan ${version}build script"
echo ""
BIN=gochan
VERSION=`cat version`
BUILDTIME=`date +%y%m%d.%H%M`
@ -17,18 +19,89 @@ if [ -z "$GOPATH" ]; then
fi
function usage {
echo "usage: $0 [command or valid \$GOOS]"
echo "commands:"
echo " clean"
echo " dependencies install necessary dependencies"
echo " docker-image create Docker image (not yet implemented)"
echo " help show this message and exit"
echo " release [GOOS] create release archives for Linux, macOS, and Windows"
echo " or a specific platform, if specified"
echo ""
echo "Any other \"command\" will be treated as a GOOS to build gochan"
echo "If no arguments are given, gochan will be built for the current OS"
exit 0
if [ -z "$2" ]; then
cat - << EOF
Usage:
$0 [command or valid GOOS] [command arguments]
Commands:
clean remove any built binaries and releases
dependencies install necessary gochan dependencies
docker-image create Docker image (not yet implemented)
help show this help message
install install gochan to the system or specified location
release create release archives for deployment
sass use Sass to transpile the sass source files
Any other "command" will be treated as a GOOS to build gochan. If no commands
are given, gochan will be built for the current OS
EOF
exit
fi
case "$2" in
clean)
cat - <<- EOF
Usage: $0 clean
remove any built binaries and releases
EOF
;;
dependencies)
cat - <<- EOF
Usage: $0 dependencies
install necessary gochan dependencies
EOF
;;
docker-image)
cat - <<- EOF
Usage: $0 docker-image
create a Docker image (not yet implemented)
EOF
;;
help)
cat - <<- EOF
Usage: $0 help
show the help message and quits
EOF
;;
install)
cat - << EOF
Usage:
$0 install [--document-root /path/to/html] [--symlinks] [destination]
Installs gochan on the current system
Arguments:
--document-root|--html /path/to/html
install document root resources to specified path, otherwise
they are installed to ./html/
--symlinks|-s
create symbolic links instead of copying, useful for testing
Install locations if no destination is provided:
./gochan => /usr/local/bin/gochan
./gochan[.example].json => /etc/gochan/gochan.json
./templates/ => /usr/share/gochan/templates/
./log => => /var/log/gochan/
/etc/gochan/gochan.json will only be created if it doesn't already exist
EOF
;;
release)
cat - <<- EOF
Usage: $0 release [GOOS]
create release archives for Linux, macOS, and Windows or the specified platform
for deployment
EOF
;;
sass)
cat - <<- EOF
Usage: $0 sass [/path/to/html]
use sass to transpile the sass source files to ./html/css or the specified
document root
EOF
;;
*)
echo "Invalid command"
;;
esac
exit
}
function build {
@ -66,6 +139,7 @@ function release {
cp $BIN $DIRNAME
if [ "$GCOS" = "linux" ]; then
strip $DIRNAME/$BIN
cp gochan.service $DIRNAME
fi
mkdir -p $DIRNAME/html
@ -98,43 +172,143 @@ if [ $# = 0 ]; then
exit 0
fi
case "$1" in
clean)
rm -f $BIN
rm -f $BIN.exe
rm -rf releases
;;
dependencies)
go get -v \
github.com/disintegration/imaging \
github.com/nranchev/go-libGeoIP \
github.com/go-sql-driver/mysql \
github.com/lib/pq \
golang.org/x/net/html \
github.com/aquilax/tripcode \
golang.org/x/crypto/bcrypt \
github.com/frustra/bbcode \
github.com/mattn/go-sqlite3
;;
docker-image)
echo "Docker image creation not yet implemented"
exit 1
# docker build . -t="eggbertx/gochan"
;;
help)
usage
;;
release)
if [ -n "$2" ]; then
release $2
while [ -n "$1" ]; do
case "$1" in
clean)
rm -f $BIN
rm -f $BIN.exe
rm -rf releases
;;
dependencies)
go get -v \
github.com/disintegration/imaging \
github.com/nranchev/go-libGeoIP \
github.com/go-sql-driver/mysql \
github.com/lib/pq \
golang.org/x/net/html \
github.com/aquilax/tripcode \
golang.org/x/crypto/bcrypt \
github.com/frustra/bbcode \
github.com/mattn/go-sqlite3
;;
docker-image)
echo "Docker image creation not yet implemented"
exit 1
else
release linux
release macos
release windows
fi
;;
*)
build $1
;;
esac
# docker build . -t="eggbertx/gochan"
;;
help|-h|--help)
usage $@
;;
install)
shift
symarg=""
documentroot=""
installdir=""
configpath=""
while [ -n "$1" ]; do
case "$1" in
--symlinks|-s)
symarg="-s"
;;
--document-root|--html)
if [ -n "$2" ] && [ "$2" != "--symlinks" ] && [ "$2" != "-s" ]; then
shift
documentroot="$1"
fi
;;
*)
installdir="$1"
;;
esac
shift
done
if [ "$symarg" = "-s" ]; then
echo "Creating symlinks"
fi
if [ -n "$installdir" ]; then
echo "Install location: '$installdir'"
if [ -z "$documentroot" ]; then
documentroot=$installdir/html
fi
cp $symarg $PWD/gochan $installdir/gochan
cp $symarg $PWD/*.sql $installdir/
cp $symarg -r $PWD/templates $installdir/templates/
cp gochan.example.json $installdir/
if [ -f gochan.json ]; then
echo "Copying config file to $installdir/gochan.json"
cp $symarg $PWD/gochan.json $installdir/gochan.json
fi
mkdir -p $installdir/log
else
echo "Installing gochan globally"
if [ -z "$documentroot" ]; then
documentroot=/srv/gochan
fi
cp $symarg $PWD/gochan /usr/local/bin/gochan
mkdir -p /usr/local/share/gochan
cp $symarg $PWD/*.sql /usr/local/share/gochan/
cp $symarg -r $PWD/templates /usr/local/share/gochan/templates/
echo "Creating /etc/gochan/ (if it doesn't already exist)"
mkdir -p /etc/gochan
cp gochan.example.json /etc/gochan/
if [ ! -f /etc/gochan/gochan.json ] && [ -f gochan.json ]; then
echo "Copying gochan.json to /etc/gochan/gochan.json"
cp $symarg $PWD/gochan.json /etc/gochan/gochan.json
fi
echo "Creating /var/log/gochan (if it doesn't already exist)"
mkdir -p /var/log/gochan
fi
echo "Installing document root files and directories"
mkdir -p $documentroot
cp -r $symarg -f $PWD/html/css/ $documentroot/css/
cp -r $symarg -f $PWD/html/javascript/ $documentroot/javascript/
files=$PWD/html/*
for f in $files; do
if [ -f $f ]; then
destfile=$documentroot/$(basename $f)
echo "Installing $f to $destfile"
# rm -f $destfile
cp $symarg -f $f $destfile
fi
done
echo "Installation complete. Make sure to set the following values in gochan.json:"
echo "DocumentRoot => $documentroot"
echo "TemplateDir => /usr/local/share/gochan/templates"
echo "LogDir => /var/log/gochan"
exit 0
;;
release)
if [ -n "$2" ]; then
release $2
else
release linux
release macos
release windows
fi
;;
sass)
if [ -z `which sass` ]; then
echo "Sass is not installed, exiting."
exit 1
fi
shift
sassdir="html"
if [ -n "$1" ]; then sassdir=$1; fi
mkdir -p $sassdir
sass --style expanded --no-source-map sass:$sassdir/css
;;
*)
build $1
shift
;;
esac
shift
done

View file

@ -6,7 +6,7 @@ server {
listen 80;
listen [::]:80;
server_name localhost;
client_max_body_size 5M;
client_max_body_size 12M;
location / {
fastcgi_pass 127.0.0.1:9000;

View file

@ -5,7 +5,7 @@ server {
listen 80;
listen[::]:80;
server_name localhost;
client_max_body_size 5M;
client_max_body_size 12M;
location / {
proxy_pass http://127.0.0.1:8080;

View file

@ -2,8 +2,6 @@
"ListenIP": "127.0.0.1",
"Port": 8080,
"FirstPage": ["index.html","board.html","firstrun.html"],
"Error404Path": "/error/404.html",
"Error500Path": "/error/500.html",
"Username": "gochan",
"UseFastCGI": false,

View file

@ -4,7 +4,6 @@ After=network.target
[Service]
ExecStart=/home/vagrant/gochan/gochan
WorkingDirectory=/home/vagrant/gochan
[Install]
WantedBy=default.target
WantedBy=multi-user.target

View file

@ -7,6 +7,6 @@
<h1>404: File not found</h1>
<img src="/error/lol 404.gif" border="0" alt="">
<p>The requested file could not be found on this server. Are you just typing random stuff in the address bar? If you followed a link from this site here, then post <a href="/site">here</a></p>
<hr><address>http://gochan.org powered by Gochan v2.8.0</address>
<hr><address>http://gochan.org powered by Gochan v2.9.0</address>
</body>
</html>

View file

@ -7,6 +7,6 @@
<h1>500: Internal Server error</h1>
<img src="/error/derpy server.gif" border="0" alt="">
<p>The server encountered an error while trying to serve the page, and we apologize for the inconvenience. The <a href="https://en.wikipedia.org/wiki/Idiot">system administrator</a> will try to fix things as soon has he/she/it can.</p>
<hr><address>http://gochan.org powered by Gochan v2.8.0</address>
<hr><address>http://gochan.org powered by Gochan v2.9.0</address>
</body>
</html>

View file

@ -119,11 +119,12 @@ func connectToSQLServer() {
func initDB(initFile string) error {
var err error
if _, err = os.Stat(initFile); err != nil {
filePath := findResource(initFile, "/usr/local/share/gochan/"+initFile, "/usr/share/gochan/"+initFile)
if filePath == "" {
return fmt.Errorf("SQL database initialization file (%s) missing. Please reinstall gochan", initFile)
}
sqlBytes, err := ioutil.ReadFile(initFile)
sqlBytes, err := ioutil.ReadFile(filePath)
if err != nil {
return err
}

View file

@ -305,9 +305,6 @@ var (
)
func loadTemplate(files ...string) (*template.Template, error) {
if len(files) == 0 {
return nil, fmt.Errorf("No files named in call to loadTemplate")
}
var templates []string
for i, file := range files {
templates = append(templates, file)

View file

@ -280,13 +280,11 @@ type Style struct {
// GochanConfig stores crucial info and is read from/written to gochan.json
type GochanConfig struct {
ListenIP string
Port int
FirstPage []string
Error404Path string
Error500Path string
Username string
UseFastCGI bool
ListenIP string
Port int
FirstPage []string
Username string
UseFastCGI bool
DocumentRoot string
TemplateDir string
@ -359,10 +357,16 @@ type GochanConfig struct {
}
func initConfig() {
jfile, err := ioutil.ReadFile("gochan.json")
cfgPath := findResource("gochan.json", "/etc/gochan/gochan.json")
if cfgPath == "" {
println(0, "gochan.json not found")
os.Exit(1)
}
jfile, err := ioutil.ReadFile(cfgPath)
if err != nil {
printf(0, "Error reading \"gochan.json\": %s\n", err.Error())
os.Exit(2)
printf(0, "Error reading 'gochan.json': %s\n", err.Error())
os.Exit(1)
}
if err = json.Unmarshal(jfile, &config); err != nil {
@ -382,12 +386,12 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
printf(0, "Error parsing \"gochan.json\": %s\n", err.Error())
}
os.Exit(2)
os.Exit(1)
}
if config.ListenIP == "" {
println(0, "ListenIP not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
if config.Port == 0 {
@ -398,23 +402,13 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
config.FirstPage = []string{"index.html", "board.html"}
}
if config.Error404Path == "" {
println(0, "Error404Path not set in gochan.json, halting.")
os.Exit(2)
}
if config.Error500Path == "" {
println(0, "Error500Path not set in gochan.json, halting.")
os.Exit(2)
}
if config.Username == "" {
config.Username = "gochan"
}
if config.DocumentRoot == "" {
println(0, "DocumentRoot not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
wd, wderr := os.Getwd()
@ -425,14 +419,16 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
}
}
config.TemplateDir = findResource(config.TemplateDir, "templates", "/usr/local/share/gochan/templates/", "/usr/share/gochan/templates/")
if config.TemplateDir == "" {
println(0, "TemplateDir not set in gochan.json, halting.")
os.Exit(2)
println(0, "Unable to locate template directory, halting.")
os.Exit(1)
}
config.LogDir = findResource(config.LogDir, "log", "/var/log/gochan/")
if config.LogDir == "" {
println(0, "LogDir not set in gochan.json, halting.")
os.Exit(2)
println(0, "Unable to locate log dirLogDir not set in gochan.json, halting.")
os.Exit(1)
}
accessLogFile, err := os.OpenFile(path.Join(config.LogDir, "access.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0777)
@ -461,12 +457,12 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
if config.DBtype == "" {
println(0, "DBtype not set in gochan.json, halting (currently supported values: mysql).")
os.Exit(2)
os.Exit(1)
}
if config.DBhost == "" {
println(0, "DBhost not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
if config.DBname == "" {
@ -479,7 +475,7 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
if config.DBpassword == "" {
println(0, "DBpassword not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
if config.LockdownMessage == "" {
@ -496,7 +492,7 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
if config.SiteDomain == "" {
println(0, "SiteDomain not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
if config.SiteWebfolder == "" {
@ -511,13 +507,13 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
if config.DomainRegex == "" {
println(0, "DomainRegex not set in gochan.json, consider using (https|http):\\/\\/("+config.SiteDomain+")\\/(.*)")
println(0, "This should work in most cases. Halting")
os.Exit(2)
os.Exit(1)
//config.DomainRegex = "(https|http):\\/\\/(" + config.SiteDomain + ")\\/(.*)"
}
if config.Styles == nil {
println(0, "Styles not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
if config.DefaultStyle == "" {
@ -604,7 +600,7 @@ DefaultStyle must refer to a given Style's Filename field. If DefaultStyle does
if config.RandomSeed == "" {
println(0, "RandomSeed not set in gochan.json, halting.")
os.Exit(2)
os.Exit(1)
}
bbcompiler = bbcode.NewCompiler(true, true)
bbcompiler.SetTag("center", nil)

View file

@ -354,6 +354,18 @@ func getThumbnailPath(thumbType string, img string) string {
return img[0:index] + thumbSuffix
}
// findResource searches for a file in the given paths and returns the first one it finds
// or a blank string if none of the paths exist
func findResource(paths ...string) string {
var err error
for _, filepath := range paths {
if _, err = os.Stat(filepath); err == nil {
return filepath
}
}
return ""
}
// paginate returns a 2d array of a specified interface from a 1d array passed in,
// with a specified number of values per array in the 2d array.
// interfaceLength is the number of interfaces per array in the 2d array (e.g, threads per page)

6
vagrant/Vagrantfile vendored
View file

@ -1,6 +1,7 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
DBTYPE = "mysql" # must be "mysql", "postgresql", or "sqlite3"
Vagrant.configure("2") do |config|
config.ssh.username = "vagrant"
@ -13,5 +14,8 @@ Vagrant.configure("2") do |config|
provider.cpus = "4"
provider.memory = "4096"
end
config.vm.provision :shell, path: "bootstrap.sh"
config.vm.provision :shell, path: "bootstrap.sh", env: {
:DBTYPE => DBTYPE
}, args: "install"
end

View file

@ -4,31 +4,35 @@
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
export DBTYPE=mysql
if [ -z "$DBTYPE" ]; then
echo "DBTYPE environment variable not set, must be 'mysql', 'postgresql', or 'sqlite3'"
exit 1
fi
apt-get -y update && apt-get -y upgrade
if [ "$DBTYPE" == "mysql" ]; then
# Using MySQL (stable)
apt-get -y install mariadb-server mariadb-client
mysql -uroot -e "CREATE DATABASE IF NOT EXISTS gochan; \
GRANT USAGE ON *.* TO gochan IDENTIFIED BY ''; \
GRANT ALL PRIVILEGES ON gochan.* TO gochan; \
SET PASSWORD FOR 'gochan'@'%' = PASSWORD('gochan');
FLUSH PRIVILEGES;"
systemctl enable mysql
systemctl start mysql &
wait
# Using MySQL (stable)
apt-get -y install mariadb-server mariadb-client
mysql -uroot <<- EOF
CREATE DATABASE IF NOT EXISTS gochan;
GRANT USAGE ON *.* TO gochan IDENTIFIED BY 'gochan'; \
GRANT ALL PRIVILEGES ON gochan.* TO gochan; \
SET PASSWORD FOR 'gochan'@'%' = PASSWORD('gochan');
FLUSH PRIVILEGES;
EOF
systemctl enable mysql
systemctl start mysql &
wait
elif [ "$DBTYPE" == "postgresql" ]; then
# using PostgreSQL (mostly stable)
apt-get -y install postgresql postgresql-contrib
# using PostgreSQL (mostly stable)
apt-get -y install postgresql postgresql-contrib
sudo -u postgres psql -f - << EOF
CREATE USER gochan PASSWORD 'gochan';
CREATE DATABASE gochan;
GRANT ALL PRIVILEGES ON DATABASE gochan TO gochan;
EOF
sudo -u postgres psql -f - <<- EOF
CREATE USER gochan PASSWORD 'gochan';
CREATE DATABASE gochan;
GRANT ALL PRIVILEGES ON DATABASE gochan TO gochan;
EOF
echo "127.0.0.1:5432:gochan:gochan:gochan" > /home/vagrant/.pgpass
chown vagrant:vagrant /home/vagrant/.pgpass
chmod 0600 /home/vagrant/.pgpass
@ -36,15 +40,15 @@ EOF
systemctl start postgresql &
wait
elif [ "$DBTYPE" == "sqlite3" ]; then
# using SQLite (mostly stable)
apt-get -y install sqlite3
# using SQLite (mostly stable)
apt-get -y install sqlite3
elif [ "$DBTYPE" == "mssql" ]; then
# using Microsoft SQL Server (currently unsupported)
echo "Microsoft SQL Server not supported yet";
exit 1
# using Microsoft SQL Server (currently unsupported)
echo "Microsoft SQL Server not supported yet";
exit 1
else
echo "Invalid DB type: $DBTYPE"
exit 1
echo "Unsupported DB type: $DBTYPE"
exit 1
fi
apt-get -y install git subversion mercurial golang-1.10 nginx ffmpeg
@ -66,9 +70,6 @@ wait
mkdir -p /vagrant/lib
cd /vagrant
su - vagrant
export GOCHAN_PATH=/home/vagrant/gochan
export GOPATH=/vagrant/lib
mkdir /home/vagrant/bin
ln -s /usr/lib/go-1.10/bin/* /home/vagrant/bin/
@ -79,13 +80,8 @@ function changePerms {
chown -R vagrant:vagrant $1
}
function makeLink {
ln -sf /vagrant/$1 $GOCHAN_PATH/
}
cat << EOF >>/home/vagrant/.bashrc
export GOPATH=$GOPATH
export GOCHAN_PATH=$GOCHAN_PATH
export DBTYPE=$DBTYPE
EOF
@ -104,55 +100,42 @@ else
fi
EOF
cat << EOF >/home/vagrant/buildgochan.sh
#!/usr/bin/env bash
cd /vagrant && ./build.sh && cd ~/gochan && ./gochan
EOF
chmod +x /home/vagrant/dbconnect.sh
chmod +x /home/vagrant/buildgochan.sh
./build.sh dependencies
./build.sh
./build.sh install -s
echo "Done installing"
rm -f $GOCHAN_PATH/gochan
rm -f $GOCHAN_PATH/initdb*.sql
if [ -d /lib/systemd ]; then
ln -s /vagrant/gochan.service /lib/systemd/system/gochan.service
systemctl enable gochan.service
fi
install -m 775 -o vagrant -g vagrant -d $GOCHAN_PATH
makeLink html
makeLink log
makeLink gochan
makeLink templates
ln -sf /vagrant/initdb*.sql $GOCHAN_PATH/
changePerms $GOCHAN_PATH
cp gochan.example.json /etc/gochan/gochan.json
mkdir -p /home/vagrant/.config/systemd/user/
ln -s /vagrant/gochan.service /home/vagrant/.config/systemd/user/gochan.service
sed /vagrant/gochan.example.json \
-e 's/"Port": 8080,/"Port": 9000,/' \
-e 's/"UseFastCGI": false,/"UseFastCGI": true,/' \
-e 's/"DomainRegex": ".*",/"DomainRegex": "(https|http):\\\/\\\/(.*)\\\/(.*)",/' \
sed -i /etc/gochan/gochan.json \
-e 's/"Port": 8080/"Port": 9000/' \
-e 's/"UseFastCGI": false/"UseFastCGI": true/' \
-e 's/"DomainRegex": ".*"/"DomainRegex": "(https|http):\\\/\\\/(.*)\\\/(.*)"/' \
-e 's#"DocumentRoot": "html"#"DocumentRoot": "/srv/gochan"#' \
-e 's#"TemplateDir": "templates"#"TemplateDir": "/usr/local/share/gochan/templates"#' \
-e 's#"LogDir": "log"#"LogDir": "/var/log/gochan"#' \
-e 's/"DBpassword": ""/"DBpassword": "gochan"/' \
-e 's/"RandomSeed": ""/"RandomSeed": "abc123"/' \
-e 's/"Verbosity": 0/"Verbosity": 1/' \
-e "w $GOCHAN_PATH/gochan.json"
-e 's/"Verbosity": 0/"Verbosity": 1/'
if [ "$DBTYPE" = "postgresql" ]; then
sed \
-e 's/"DBtype": ".*",/"DBtype": "postgres",/' \
-e 's/"DBhost": ".*",/"DBhost": "127.0.0.1",/' \
-i $GOCHAN_PATH/gochan.json
sed -i /etc/gochan/gochan.json \
-e 's/"DBtype": ".*"/"DBtype": "postgres"/' \
-e 's/"DBhost": ".*"/"DBhost": "127.0.0.1"/'
elif [ "$DBTYPE" = "sqlite3" ]; then
sed \
-e 's/"DBtype": ".*",/"DBtype": "sqlite3",/' \
-e 's/"DBhost": ".*",/"DBhost": "gochan.db",/' \
-i $GOCHAN_PATH/gochan.json
sed -i /etc/gochan/gochan.json \
-e 's/"DBtype": ".*"/"DBtype": "sqlite3"/' \
-e 's/"DBhost": ".*"/"DBhost": "gochan.db"/'
fi
echo
echo "Server set up, please run \"vagrant ssh\" on your host machine and"
echo "(optionally) \"systemctl --user start gochan\" in the guest."
echo "Server set up, please run \"vagrant ssh\" on your host machine."
echo "Then browse to http://172.27.0.3/manage to complete installation."
# echo "If you want gochan to run on system startup run \"systemctl --user enable gochan\""
# TODO: add further instructions as default initial announcement or /manage?action=firstrun

View file

@ -1 +1 @@
2.8.0
2.9.0