diff --git a/README.md b/README.md index 786c768..46c7afc 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ of this functionality. Codetainer is written in Go. +For more information, see [the slides from a talk introduction](https://www.slideshare.net/JenAndre/codetainer-a-browser-code-sandbox). + # Build & Installation ## Requirements @@ -20,6 +22,9 @@ Codetainer is written in Go. * Go >=1.4 * [godep](https://github.com/tools/godep) +## Installing from `go get` + + ## Building & Installing From Source ```bash @@ -42,22 +47,24 @@ DOCKER_OPTS="-H tcp://127.0.0.1:4500 -H unix:///var/run/docker.sock" ## Configuring codetainer -See config.toml. +See ~/.codetainer/config.toml. This file will get auto-generated the first +time you run codetainer. ```toml # Docker API server and port DockerServer = "localhost" DockerPort = 4500 -# Database path -DatabasePath = "/home/vagrant/codetainer.db" +# Database path (optional, default is ~/codetainer/codetainer.db) +# DatabasePath = "/path/to/codetainer.db" ``` ## Running an example codetainer -``` -./bin/codetainer image register ubuntu:14.04 -./bin/codetainer create ubuntu:14.04 my-codetainer-name -./bin/codetainer server # to start the API server +```bash +$ sudo docker pull ubuntu:14.04 +$ codetainer image register ubuntu:14.04 +$ codetainer create ubuntu:14.04 my-codetainer-name +$ codetainer server # to start the API server ``` diff --git a/codetainer.go b/codetainer.go index 354cc00..f062ffc 100644 --- a/codetainer.go +++ b/codetainer.go @@ -26,12 +26,12 @@ var ( // TimeFormat global time format string TimeFormat = "15:04:05" - app = kingpin.New(Name, Description) - debug = app.Flag("debug", "Enable debug logging.").Short('v').Bool() - dev = app.Flag("dev", "Enable dev mode.").Bool() - quiet = app.Flag("quiet", "Remove all output logging.").Short('q').Bool() - appSSL = app.Flag("ssl", "Enable SSL (useful outside nginx/apache).").Short('s').Bool() - configPath = app.Flag("config", "Config path (default is config.toml)").Short('c').String() + app = kingpin.New(Name, Description) + debug = app.Flag("debug", "Enable debug logging.").Short('v').Bool() + dev = app.Flag("dev", "Enable dev mode.").Bool() + quiet = app.Flag("quiet", "Remove all output logging.").Short('q').Bool() + appSSL = app.Flag("ssl", "Enable SSL (useful outside nginx/apache).").Short('s').Bool() + appConfigPath = app.Flag("config", "Config path (default is ~/.codetainer/config.toml or /etc/codetainer/config.toml)").Short('c').String() server = app.Command("server", "Start the Codetainer API server.") @@ -98,7 +98,7 @@ func Start() { initLogger() - config, err := NewConfig(*configPath) + config, err := NewConfig(*appConfigPath) if err != nil { Log.Fatal(err) diff --git a/config.go b/config.go index 9b0e7f1..62f3791 100644 --- a/config.go +++ b/config.go @@ -4,6 +4,8 @@ import ( "errors" "fmt" "os" + "os/user" + "path" "path/filepath" version "github.com/hashicorp/go-version" @@ -12,6 +14,69 @@ import ( docker "github.com/fsouza/go-dockerclient" ) +var globalConfigPath string = "/etc/codetainer/config.toml" +var globalDbPath string = "/var/codetainer/codetainer.db" + +var ( + DefaultConfigFileSettings = `# Docker API server and port +DockerServer = "localhost" +DockerPort = 4500` + GlobalConfig Config +) + +// +// detectConfigPath will return the path to the configuration file. +// Use either a global path: /etc/codetainer/config.toml +// Or a local path ~/.codetainer/config.toml +// +func detectConfigPath() (string, error) { + + if fileExists(globalConfigPath) { + return globalConfigPath, nil + } + usr, err := user.Current() + if err != nil { + return "", err + } + basePath := path.Join(usr.HomeDir, ".codetainer") + if _, err := os.Stat(basePath); err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(basePath, 0700) + if err != nil { + return "", err + } + } + } + return path.Join(basePath, "config.toml"), nil +} + +// detectDataabsePath will return the path to the database file. +// Use either a global path: /etc/codetainer/codetainer.db +// Or a local path ~/.codetainer/codetainer.db + +func detectDatabasePath() (string, error) { + + if fileExists(globalDbPath) { + return globalDbPath, nil + } + usr, err := user.Current() + if err != nil { + return "", err + } + basePath := path.Join(usr.HomeDir, ".codetainer") + if _, err := os.Stat(basePath); err != nil { + if os.IsNotExist(err) { + err := os.MkdirAll(basePath, 0700) + if err != nil { + return "", err + } + } else { + return "", err + } + } + return path.Join(basePath, "codetainer.db"), nil +} + type Config struct { DockerServerUseHttps bool DockerServer string @@ -44,21 +109,13 @@ func (c *Config) GetDatabase() (*Database, error) { func (c *Config) GetDatabasePath() string { if c.DatabasePath == "" { - // basePath := "/var/lib/codetainer/" - // basePath := "./" - c.DatabasePath = "codetainer.db" - - // if _, err := os.Stat(c.DatabasePath); err != nil { - // if os.IsNotExist(err) { - // err := os.MkdirAll("/var/lib/codetainer", 0700) - // if err != nil { - // Log.Fatal("Unable to create path for database: " + basePath) - // } - // } else { - // Log.Fatal(err) - // } - // } + p, err := detectDatabasePath() + c.DatabasePath = p + if err != nil { + Log.Fatal("Unable to create database at ~/.codetainer/codetainer.db or "+globalDbPath, err) + } } + Log.Debugf("Using database path: %s", c.DatabasePath) return c.DatabasePath } @@ -120,7 +177,7 @@ func (c *Config) TestConfig() bool { configured the Docker API to accept remote HTTP connections? E.g., your docker service needs to have the following parameters in the -command line: +command line in order to use web sockets: /usr/bin/docker -d -H tcp://127.0.0.1:4500 @@ -141,40 +198,34 @@ and DockerPort: return true } -var ( - ConfigPath = "config.toml" - - DefaultConfigFileSettings = `# Docker API server and port -DockerServer = "localhost" -DockerPort = 4500` - GlobalConfig Config -) - func NewConfig(configPath string) (*Config, error) { - Log.Debugf("Loading %s configurations", Name) - + var err error if configPath == "" { - configPath = ConfigPath + configPath, err = detectConfigPath() + if err != nil { + Log.Fatal("Unable to load config from ~/.codetainer/config.toml or /etc/codetainer/config.toml", err) + } } + Log.Debugf("Loading %s configurations from %s", Name, configPath) config := &Config{} if !IsExist(configPath) { configData := []byte(DefaultConfigFileSettings) - f, err := os.Create(ConfigPath) + f, err := os.Create(configPath) if err != nil { Log.Error(err) - Log.Fatalf("Unable to create configuration file: %s.", ConfigPath) + Log.Fatalf("Unable to create configuration file: %s.", configPath) } _, err = f.Write(configData) if err != nil { Log.Error(err) - Log.Fatalf("Unable to create configuration file: %s.", ConfigPath) + Log.Fatalf("Unable to create configuration file: %s.", configPath) } f.Sync()