woodpecker/server/main.go
Michael Steinert 441de03fb9 Serve robots.txt from /
This change allows `robots.txt` to be served from the root URL, i.e.
https://drone.io/robots.txt, which is where [web crawlers will look for
it][1]. Previously this file was only served from `/static/robots.txt`.

[1]: http://www.robotstxt.org/robotstxt.html
2014-12-24 13:03:08 -06:00

194 lines
5.3 KiB
Go

package main
import (
"database/sql"
"flag"
"fmt"
"net/http"
"os"
"strings"
"github.com/drone/config"
"github.com/drone/drone/server/middleware"
"github.com/drone/drone/server/pubsub"
"github.com/drone/drone/server/router"
"github.com/drone/drone/shared/build/log"
"github.com/GeertJohan/go.rice"
"code.google.com/p/go.net/context"
webcontext "github.com/goji/context"
"github.com/zenazn/goji/web"
_ "github.com/drone/drone/plugin/notify/email"
"github.com/drone/drone/plugin/remote/bitbucket"
"github.com/drone/drone/plugin/remote/github"
"github.com/drone/drone/plugin/remote/gitlab"
"github.com/drone/drone/plugin/remote/gogs"
"github.com/drone/drone/server/blobstore"
"github.com/drone/drone/server/capability"
"github.com/drone/drone/server/datastore"
"github.com/drone/drone/server/datastore/database"
"github.com/drone/drone/server/worker/director"
"github.com/drone/drone/server/worker/docker"
"github.com/drone/drone/server/worker/pool"
)
const (
DockerTLSWarning = `WARINING: Docker TLS cert or key not given, this may cause a build errors`
)
var (
// commit sha for the current build, set by
// the compile process.
version string = "0.3-dev"
revision string
)
var (
// Database driver configuration. Defaults to sqlite
// when no database configuration specified.
datasource = config.String("database-datasource", "drone.sqlite")
driver = config.String("database-driver", "sqlite3")
// HTTP Server settings.
port = config.String("server-port", ":8000")
sslcrt = config.String("server-ssl-cert", "")
sslkey = config.String("server-ssl-key", "")
// Enable self-registration. When false, the system admin
// must grant user access.
open = config.Bool("registration-open", false)
workers *pool.Pool
worker *director.Director
pub *pubsub.PubSub
// Docker configuration details.
dockercert = config.String("docker-cert", "")
dockerkey = config.String("docker-key", "")
nodes StringArr
db *sql.DB
caps map[string]bool
)
func main() {
log.SetPriority(log.LOG_NOTICE)
// Parses flags. The only flag that can be passed into the
// application is the location of the configuration (.toml) file.
var conf string
flag.StringVar(&conf, "config", "", "")
flag.Parse()
config.Var(&nodes, "worker-nodes")
// Parses config data. The config data can be stored in a config
// file (.toml format) or environment variables, or a combo.
config.SetPrefix("DRONE_")
err := config.Parse(conf)
if err != nil {
log.Errf("Unable to parse config: %v", err)
os.Exit(1)
}
// Setup the remote services. We need to execute these to register
// the remote plugins with the system.
//
// NOTE: this cannot be done via init() because they need to be
// executed after config.Parse
bitbucket.Register()
github.Register()
gitlab.Register()
gogs.Register()
caps = map[string]bool{}
caps[capability.Registration] = *open
// setup the database and cancel all pending
// commits in the system.
db = database.MustConnect(*driver, *datasource)
go database.NewCommitstore(db).KillCommits()
// Create the worker, director and builders
workers = pool.New()
worker = director.New()
if nodes == nil || len(nodes) == 0 {
workers.Allocate(docker.New())
workers.Allocate(docker.New())
} else {
for _, node := range nodes {
if strings.HasPrefix(node, "unix://") {
workers.Allocate(docker.NewHost(node))
} else if *dockercert != "" && *dockerkey != "" {
workers.Allocate(docker.NewHostCertFile(node, *dockercert, *dockerkey))
} else {
fmt.Println(DockerTLSWarning)
workers.Allocate(docker.NewHost(node))
}
}
}
pub = pubsub.NewPubSub()
// create handler for static resources
assets := rice.MustFindBox("app").HTTPBox()
assetserve := http.FileServer(rice.MustFindBox("app").HTTPBox())
http.Handle("/robots.txt", assetserve)
http.Handle("/static/", http.StripPrefix("/static", assetserve))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write(assets.MustBytes("index.html"))
})
// create the router and add middleware
mux := router.New()
mux.Use(middleware.Options)
mux.Use(ContextMiddleware)
mux.Use(middleware.SetHeaders)
mux.Use(middleware.SetUser)
http.Handle("/api/", mux)
// start the http server in either http or https mode,
// depending on whether a certificate was provided.
if len(*sslcrt) == 0 {
panic(http.ListenAndServe(*port, nil))
} else {
panic(http.ListenAndServeTLS(*port, *sslcrt, *sslkey, nil))
}
}
// ContextMiddleware creates a new go.net/context and
// injects into the current goji context.
func ContextMiddleware(c *web.C, h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
var ctx = context.Background()
ctx = datastore.NewContext(ctx, database.NewDatastore(db))
ctx = blobstore.NewContext(ctx, database.NewBlobstore(db))
ctx = pool.NewContext(ctx, workers)
ctx = director.NewContext(ctx, worker)
ctx = pubsub.NewContext(ctx, pub)
ctx = capability.NewContext(ctx, caps)
// add the context to the goji web context
webcontext.Set(c, ctx)
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
type StringArr []string
func (s *StringArr) String() string {
return fmt.Sprint(*s)
}
func (s *StringArr) Set(value string) error {
for _, str := range strings.Split(value, ",") {
str = strings.TrimSpace(str)
*s = append(*s, str)
}
return nil
}