2013-07-23 17:40:19 +00:00
/ *
Copyright 2013 The Camlistore Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
2013-10-22 15:11:36 +00:00
// This file adds the "server" subcommand to devcam, to run camlistored.
2013-07-23 17:40:19 +00:00
package main
import (
2014-07-21 20:58:06 +00:00
"bytes"
2013-07-23 17:40:19 +00:00
"errors"
"flag"
"fmt"
2014-07-21 20:58:06 +00:00
"io/ioutil"
2013-07-23 17:40:19 +00:00
"log"
2014-07-21 20:58:06 +00:00
"net/http"
2013-07-23 17:40:19 +00:00
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
2014-07-21 20:58:06 +00:00
"time"
2013-07-23 17:40:19 +00:00
2014-07-21 20:58:06 +00:00
"camlistore.org/pkg/client"
2013-07-23 17:40:19 +00:00
"camlistore.org/pkg/cmdmain"
2014-07-21 20:58:06 +00:00
"camlistore.org/pkg/importer"
_ "camlistore.org/pkg/importer/allimporters"
"camlistore.org/pkg/netutil"
2013-07-23 17:40:19 +00:00
"camlistore.org/pkg/osutil"
)
type serverCmd struct {
// start of flag vars
all bool
hostname string
port string
tls bool
wipe bool
2014-07-21 20:58:06 +00:00
things bool
2013-07-23 17:40:19 +00:00
debug bool
mongo bool
mysql bool
postgres bool
2013-09-19 23:01:22 +00:00
sqlite bool
2013-07-23 17:40:19 +00:00
slow bool
throttle int
latency int
2014-02-10 23:37:41 +00:00
fullIndexSync bool
2013-07-23 17:40:19 +00:00
fullClosure bool
2014-01-14 04:11:43 +00:00
mini bool
2014-06-14 20:14:34 +00:00
publish bool // whether to build and start the publisher app(s)
2014-06-13 21:03:49 +00:00
hello bool // whether to build and start the hello demo app
2013-08-25 16:28:54 +00:00
2014-01-15 04:45:23 +00:00
openBrowser bool
flickrAPIKey string
foursquareAPIKey string
2014-03-04 21:25:10 +00:00
picasaAPIKey string
2014-03-15 01:14:18 +00:00
twitterAPIKey string
2014-01-15 04:45:23 +00:00
extraArgs string // passed to camlistored
2013-07-23 17:40:19 +00:00
// end of flag vars
2013-12-28 10:08:26 +00:00
listen string // address + port to listen on
root string // the temp dir where blobs are stored
env * Env
2013-07-23 17:40:19 +00:00
}
func init ( ) {
cmdmain . RegisterCommand ( "server" , func ( flags * flag . FlagSet ) cmdmain . CommandRunner {
2013-09-22 19:13:28 +00:00
cmd := & serverCmd {
env : NewCopyEnv ( ) ,
}
2013-07-23 17:40:19 +00:00
flags . BoolVar ( & cmd . all , "all" , false , "Listen on all interfaces." )
flags . StringVar ( & cmd . hostname , "hostname" , "" , "Hostname to advertise, defaults to the hostname reported by the kernel." )
flags . StringVar ( & cmd . port , "port" , "3179" , "Port to listen on." )
flags . BoolVar ( & cmd . tls , "tls" , false , "Use TLS." )
flags . BoolVar ( & cmd . wipe , "wipe" , false , "Wipe the blobs on disk and the indexer." )
2014-07-21 20:58:06 +00:00
flags . BoolVar ( & cmd . things , "makethings" , false , "Create various test data on startup (twitter imports for now). Requires wipe. Conflicts with mini." )
2013-07-23 17:40:19 +00:00
flags . BoolVar ( & cmd . debug , "debug" , false , "Enable http debugging." )
2014-06-14 20:14:34 +00:00
flags . BoolVar ( & cmd . publish , "publish" , true , "Enable publisher app(s)" )
2014-06-13 21:03:49 +00:00
flags . BoolVar ( & cmd . hello , "hello" , false , "Enable hello (demo) app" )
2014-01-14 04:11:43 +00:00
flags . BoolVar ( & cmd . mini , "mini" , false , "Enable minimal mode, where all optional features are disabled. (Currently just publishing)" )
2013-07-23 17:40:19 +00:00
2013-12-11 08:20:22 +00:00
flags . BoolVar ( & cmd . mongo , "mongo" , false , "Use mongodb as the indexer. Excludes -mysql, -postgres, -sqlite." )
flags . BoolVar ( & cmd . mysql , "mysql" , false , "Use mysql as the indexer. Excludes -mongo, -postgres, -sqlite." )
flags . BoolVar ( & cmd . postgres , "postgres" , false , "Use postgres as the indexer. Excludes -mongo, -mysql, -sqlite." )
flags . BoolVar ( & cmd . sqlite , "sqlite" , false , "Use sqlite as the indexer. Excludes -mongo, -mysql, -postgres." )
2013-07-23 17:40:19 +00:00
flags . BoolVar ( & cmd . slow , "slow" , false , "Add artificial latency." )
flags . IntVar ( & cmd . throttle , "throttle" , 150 , "If -slow, this is the rate in kBps, to which we should throttle." )
flags . IntVar ( & cmd . latency , "latency" , 90 , "If -slow, this is the added latency, in ms." )
2014-02-10 23:37:41 +00:00
flags . BoolVar ( & cmd . fullIndexSync , "fullindexsync" , false , "Perform full sync to indexer on startup." )
2013-07-23 17:40:19 +00:00
flags . BoolVar ( & cmd . fullClosure , "fullclosure" , false , "Use the ondisk closure library." )
2013-08-25 16:28:54 +00:00
flags . BoolVar ( & cmd . openBrowser , "openbrowser" , false , "Open the start page on startup." )
2013-11-19 04:53:46 +00:00
flags . StringVar ( & cmd . flickrAPIKey , "flickrapikey" , "" , "The key and secret to use with the Flickr importer. Formatted as '<key>:<secret>'." )
2014-01-15 04:45:23 +00:00
flags . StringVar ( & cmd . foursquareAPIKey , "foursquareapikey" , "" , "The key and secret to use with the Foursquare importer. Formatted as '<clientID>:<clientSecret>'." )
2014-03-04 21:25:10 +00:00
flags . StringVar ( & cmd . picasaAPIKey , "picasakey" , "" , "The username and password to use with the Picasa importer. Formatted as '<username>:<password>'." )
2014-03-15 01:14:18 +00:00
flags . StringVar ( & cmd . twitterAPIKey , "twitterapikey" , "" , "The key and secret to use with the Twitter importer. Formatted as '<APIkey>:<APIsecret>'." )
2013-12-27 23:20:07 +00:00
flags . StringVar ( & cmd . root , "root" , "" , "A directory to store data in. Defaults to a location in the OS temp directory." )
2013-12-25 05:35:48 +00:00
flags . StringVar ( & cmd . extraArgs , "extraargs" , "" ,
"List of comma separated options that will be passed to camlistored" )
2013-07-23 17:40:19 +00:00
return cmd
} )
}
func ( c * serverCmd ) Usage ( ) {
fmt . Fprintf ( cmdmain . Stderr , "Usage: devcam [globalopts] server [serveropts]\n" )
}
func ( c * serverCmd ) Examples ( ) [ ] string {
return [ ] string {
"-wipe -mysql -fullclosure" ,
}
}
func ( c * serverCmd ) Describe ( ) string {
2013-08-19 17:33:53 +00:00
return "run the stand-alone camlistored in dev mode."
2013-07-23 17:40:19 +00:00
}
func ( c * serverCmd ) checkFlags ( args [ ] string ) error {
if len ( args ) != 0 {
c . Usage ( )
}
2014-07-21 20:58:06 +00:00
if c . mini {
if c . things {
return cmdmain . UsageError ( "--mini and --makethings are mutually exclusive." )
}
c . publish = false
c . hello = false
}
if c . things && ! c . wipe {
return cmdmain . UsageError ( "--makethings requires --wipe." )
}
2013-08-23 22:19:21 +00:00
nindex := 0
2013-12-11 08:20:22 +00:00
for _ , v := range [ ] bool { c . mongo , c . mysql , c . postgres , c . sqlite } {
2013-08-23 22:19:21 +00:00
if v {
nindex ++
}
}
if nindex > 1 {
return fmt . Errorf ( "Only one index option allowed" )
2013-07-23 17:40:19 +00:00
}
if _ , err := strconv . ParseInt ( c . port , 0 , 0 ) ; err != nil {
return fmt . Errorf ( "Invalid -port value: %q" , c . port )
}
return nil
}
2013-12-27 23:20:07 +00:00
func ( c * serverCmd ) setRoot ( ) error {
2013-12-28 10:08:26 +00:00
if c . root == "" {
user := osutil . Username ( )
if user == "" {
return errors . New ( "Could not get username from environment" )
}
c . root = filepath . Join ( os . TempDir ( ) , "camliroot-" + user , "port" + c . port )
2013-07-23 17:40:19 +00:00
}
2013-12-27 23:20:07 +00:00
log . Printf ( "Temp dir root is %v" , c . root )
2013-07-23 17:40:19 +00:00
if c . wipe {
2013-12-27 23:20:07 +00:00
log . Printf ( "Wiping %v" , c . root )
if err := os . RemoveAll ( c . root ) ; err != nil {
return fmt . Errorf ( "Could not wipe %v: %v" , c . root , err )
2013-07-23 17:40:19 +00:00
}
}
return nil
}
func ( c * serverCmd ) makeSuffixdir ( fullpath string ) {
if err := os . MkdirAll ( fullpath , 0755 ) ; err != nil {
log . Fatalf ( "Could not create %v: %v" , fullpath , err )
}
}
func ( c * serverCmd ) setEnvVars ( ) error {
2013-12-28 10:08:26 +00:00
c . env . SetCamdevVars ( false )
2013-09-22 19:13:28 +00:00
setenv := func ( k , v string ) {
c . env . Set ( k , v )
}
2013-07-23 17:40:19 +00:00
if c . slow {
setenv ( "DEV_THROTTLE_KBPS" , fmt . Sprintf ( "%d" , c . throttle ) )
setenv ( "DEV_THROTTLE_LATENCY_MS" , fmt . Sprintf ( "%d" , c . latency ) )
}
if c . debug {
setenv ( "CAMLI_HTTP_DEBUG" , "1" )
}
2013-08-28 19:00:17 +00:00
user := osutil . Username ( )
2013-07-23 17:40:19 +00:00
if user == "" {
2013-08-28 19:00:17 +00:00
return errors . New ( "Could not get username from environment" )
2013-07-23 17:40:19 +00:00
}
2014-02-10 23:37:41 +00:00
setenv ( "CAMLI_FULL_INDEX_SYNC_ON_START" , "false" )
if c . fullIndexSync {
setenv ( "CAMLI_FULL_INDEX_SYNC_ON_START" , "true" )
}
2013-07-23 17:40:19 +00:00
setenv ( "CAMLI_DBNAME" , "devcamli" + user )
setenv ( "CAMLI_MYSQL_ENABLED" , "false" )
setenv ( "CAMLI_MONGO_ENABLED" , "false" )
setenv ( "CAMLI_POSTGRES_ENABLED" , "false" )
2013-09-19 23:01:22 +00:00
setenv ( "CAMLI_SQLITE_ENABLED" , "false" )
2013-08-23 22:19:21 +00:00
setenv ( "CAMLI_KVINDEX_ENABLED" , "false" )
2014-01-14 04:11:43 +00:00
setenv ( "CAMLI_PUBLISH_ENABLED" , strconv . FormatBool ( c . publish ) )
2014-06-13 21:03:49 +00:00
setenv ( "CAMLI_HELLO_ENABLED" , strconv . FormatBool ( c . hello ) )
2013-07-23 17:40:19 +00:00
switch {
case c . mongo :
setenv ( "CAMLI_MONGO_ENABLED" , "true" )
setenv ( "CAMLI_INDEXER_PATH" , "/index-mongo/" )
case c . postgres :
setenv ( "CAMLI_POSTGRES_ENABLED" , "true" )
setenv ( "CAMLI_INDEXER_PATH" , "/index-postgres/" )
case c . mysql :
setenv ( "CAMLI_MYSQL_ENABLED" , "true" )
setenv ( "CAMLI_INDEXER_PATH" , "/index-mysql/" )
2013-09-19 23:01:22 +00:00
case c . sqlite :
setenv ( "CAMLI_SQLITE_ENABLED" , "true" )
setenv ( "CAMLI_INDEXER_PATH" , "/index-sqlite/" )
2013-12-27 23:20:07 +00:00
if c . root == "" {
panic ( "no root set" )
2013-09-19 23:01:22 +00:00
}
2013-12-27 23:20:07 +00:00
setenv ( "CAMLI_DBNAME" , filepath . Join ( c . root , "sqliteindex.db" ) )
2013-08-23 22:19:21 +00:00
default :
setenv ( "CAMLI_KVINDEX_ENABLED" , "true" )
setenv ( "CAMLI_INDEXER_PATH" , "/index-kv/" )
2013-12-27 23:20:07 +00:00
if c . root == "" {
panic ( "no root set" )
2013-08-23 22:19:21 +00:00
}
2013-12-27 23:20:07 +00:00
setenv ( "CAMLI_DBNAME" , filepath . Join ( c . root , "kvindex.db" ) )
2013-07-23 17:40:19 +00:00
}
base := "http://localhost:" + c . port
c . listen = "127.0.0.1:" + c . port
if c . all {
c . listen = "0.0.0.0:" + c . port
if c . hostname == "" {
hostname , err := os . Hostname ( )
if err != nil {
return fmt . Errorf ( "Could not get system hostname: %v" , err )
}
base = "http://" + hostname + ":" + c . port
} else {
base = "http://" + c . hostname + ":" + c . port
}
}
setenv ( "CAMLI_TLS" , "false" )
if c . tls {
base = strings . Replace ( base , "http://" , "https://" , 1 )
setenv ( "CAMLI_TLS" , "true" )
}
setenv ( "CAMLI_BASEURL" , base )
2013-09-09 12:43:44 +00:00
setenv ( "CAMLI_DEV_CAMLI_ROOT" , camliSrcRoot )
2013-08-28 16:40:23 +00:00
setenv ( "CAMLI_AUTH" , "devauth:pass3179" )
2013-07-23 17:40:19 +00:00
fullSuffix := func ( name string ) string {
2013-12-27 23:20:07 +00:00
return filepath . Join ( c . root , name )
2013-07-23 17:40:19 +00:00
}
suffixes := map [ string ] string {
"CAMLI_ROOT" : fullSuffix ( "bs" ) ,
"CAMLI_ROOT_SHARD1" : fullSuffix ( "s1" ) ,
"CAMLI_ROOT_SHARD2" : fullSuffix ( "s2" ) ,
"CAMLI_ROOT_REPLICA1" : fullSuffix ( "r1" ) ,
"CAMLI_ROOT_REPLICA2" : fullSuffix ( "r2" ) ,
"CAMLI_ROOT_REPLICA3" : fullSuffix ( "r3" ) ,
"CAMLI_ROOT_CACHE" : fullSuffix ( "cache" ) ,
"CAMLI_ROOT_ENCMETA" : fullSuffix ( "encmeta" ) ,
"CAMLI_ROOT_ENCBLOB" : fullSuffix ( "encblob" ) ,
}
for k , v := range suffixes {
c . makeSuffixdir ( v )
setenv ( k , v )
}
setenv ( "CAMLI_PORT" , c . port )
2013-11-19 04:53:46 +00:00
if c . flickrAPIKey != "" {
setenv ( "CAMLI_FLICKR_ENABLED" , "true" )
setenv ( "CAMLI_FLICKR_API_KEY" , c . flickrAPIKey )
}
2014-01-15 04:45:23 +00:00
if c . foursquareAPIKey != "" {
setenv ( "CAMLI_FOURSQUARE_ENABLED" , "true" )
setenv ( "CAMLI_FOURSQUARE_API_KEY" , c . foursquareAPIKey )
}
2014-03-04 21:25:10 +00:00
if c . picasaAPIKey != "" {
setenv ( "CAMLI_PICASA_ENABLED" , "true" )
setenv ( "CAMLI_PICASA_API_KEY" , c . picasaAPIKey )
}
2014-03-15 01:14:18 +00:00
if c . twitterAPIKey != "" {
setenv ( "CAMLI_TWITTER_ENABLED" , "true" )
setenv ( "CAMLI_TWITTER_API_KEY" , c . twitterAPIKey )
}
2013-11-19 04:53:46 +00:00
setenv ( "CAMLI_CONFIG_DIR" , "config" )
2014-06-15 21:14:35 +00:00
setenv ( "CAMLI_APP_BINDIR" , "bin" )
2013-07-23 17:40:19 +00:00
return nil
}
func ( c * serverCmd ) setupIndexer ( ) error {
args := [ ] string { "dbinit" }
switch {
case c . postgres :
args = append ( args ,
"-dbtype=postgres" ,
"-user=postgres" ,
"-password=postgres" ,
"-host=localhost" ,
2013-09-23 10:06:18 +00:00
"-dbname=" + c . env . m [ "CAMLI_DBNAME" ] )
2013-07-23 17:40:19 +00:00
case c . mysql :
args = append ( args ,
"-user=root" ,
"-password=root" ,
"-host=localhost" ,
2013-09-23 10:06:18 +00:00
"-dbname=" + c . env . m [ "CAMLI_DBNAME" ] )
2013-09-19 23:01:22 +00:00
case c . sqlite :
args = append ( args ,
"-dbtype=sqlite" ,
2013-09-23 10:06:18 +00:00
"-dbname=" + c . env . m [ "CAMLI_DBNAME" ] )
2013-12-12 17:08:28 +00:00
case c . mongo :
2013-12-13 16:36:34 +00:00
args = append ( args ,
"-dbtype=mongo" ,
"-host=localhost" ,
"-dbname=" + c . env . m [ "CAMLI_DBNAME" ] )
2013-07-23 17:40:19 +00:00
default :
return nil
}
if c . wipe {
args = append ( args , "-wipe" )
} else {
args = append ( args , "-ignoreexists" )
}
2013-09-09 12:43:44 +00:00
binPath := filepath . Join ( "bin" , "camtool" )
2013-07-23 17:40:19 +00:00
cmd := exec . Command ( binPath , args ... )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
if err := cmd . Run ( ) ; err != nil {
return fmt . Errorf ( "Could not run camtool dbinit: %v" , err )
}
return nil
}
func ( c * serverCmd ) syncTemplateBlobs ( ) error {
if c . wipe {
2013-09-09 12:43:44 +00:00
templateDir := "dev-server-template"
2013-07-23 17:40:19 +00:00
if _ , err := os . Stat ( templateDir ) ; err != nil {
if os . IsNotExist ( err ) {
return nil
}
return err
}
2013-12-27 23:20:07 +00:00
blobsDir := filepath . Join ( c . root , "sha1" )
2013-08-19 17:33:53 +00:00
if err := cpDir ( templateDir , blobsDir , nil ) ; err != nil {
2013-07-23 17:40:19 +00:00
return fmt . Errorf ( "Could not cp template blobs: %v" , err )
}
}
return nil
}
func ( c * serverCmd ) setFullClosure ( ) error {
if c . fullClosure {
2013-12-27 23:20:07 +00:00
oldsvn := filepath . Join ( c . root , filepath . FromSlash ( "tmp/closure-lib/.svn" ) )
2013-07-23 17:40:19 +00:00
if err := os . RemoveAll ( oldsvn ) ; err != nil {
return fmt . Errorf ( "Could not remove svn checkout of closure-lib %v: %v" ,
oldsvn , err )
}
log . Println ( "Updating closure library..." )
args := [ ] string { "run" , "third_party/closure/updatelibrary.go" , "-verbose" }
cmd := exec . Command ( "go" , args ... )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
if err := cmd . Run ( ) ; err != nil {
return fmt . Errorf ( "Could not run updatelibrary.go: %v" , err )
}
2013-09-22 19:13:28 +00:00
c . env . Set ( "CAMLI_DEV_CLOSURE_DIR" , "third_party/closure/lib/closure" )
2013-07-23 17:40:19 +00:00
}
return nil
}
2014-07-21 20:58:06 +00:00
func ( c * serverCmd ) makeThings ( ) error {
const importerPrefix = "/importer/"
// check that "/importer/" prefix is in config, just in case it ever changes.
configFile := filepath . Join ( camliSrcRoot , "config" , "dev-server-config.json" )
config , err := ioutil . ReadFile ( configFile )
if err != nil {
return fmt . Errorf ( "could not read config file %v: %v" , configFile , err )
}
if ! bytes . Contains ( config , [ ] byte ( importerPrefix ) ) {
return fmt . Errorf ( "%s prefix not found in dev config. Did it change?" , importerPrefix )
}
if err := netutil . AwaitReachable ( "localhost:" + c . port , time . Minute ) ; err != nil {
return err
}
osutil . AddSecretRingFlag ( )
setCamdevVars ( )
baseURL := c . env . m [ "CAMLI_BASEURL" ]
if baseURL == "" {
return errors . New ( "CAMLI_BASEURL is not set" )
}
cl := client . New ( baseURL )
signer , err := cl . Signer ( )
if err != nil {
return err
}
ClientId := make ( map [ string ] string )
ClientSecret := make ( map [ string ] string )
for name := range importer . All ( ) {
ClientId [ name ] = "fakeStaticClientId"
ClientSecret [ name ] = "fakeStaticClientSecret"
}
hc := importer . HostConfig {
BaseURL : baseURL ,
Prefix : importerPrefix ,
Target : cl ,
BlobSource : cl ,
Signer : signer ,
Search : cl ,
ClientId : ClientId ,
ClientSecret : ClientSecret ,
}
for name , imp := range importer . All ( ) {
mk , ok := imp . ( importer . TestDataMaker )
if ! ok {
continue
}
tr := mk . MakeTestData ( )
hc . HTTPClient = & http . Client { Transport : tr }
host , err := importer . NewHost ( hc )
if err != nil {
return fmt . Errorf ( "could not obtain Host: %v" , err )
}
rc , err := importer . CreateAccount ( host , name )
if err != nil {
return err
}
if err := mk . SetTestAccount ( rc . AccountNode ( ) ) ; err != nil {
return fmt . Errorf ( "could not set fake account node for importer %v: %v" , name , err )
}
if err := imp . Run ( rc ) ; err != nil {
return err
}
2014-01-14 04:11:43 +00:00
}
2014-07-21 20:58:06 +00:00
return nil
}
func ( c * serverCmd ) RunCommand ( args [ ] string ) error {
2013-07-23 17:40:19 +00:00
err := c . checkFlags ( args )
if err != nil {
return cmdmain . UsageError ( fmt . Sprint ( err ) )
}
2013-10-22 13:10:42 +00:00
if ! * noBuild {
2013-10-24 22:40:33 +00:00
withSqlite = c . sqlite
2014-06-13 21:03:49 +00:00
targets := [ ] string {
2013-10-22 13:10:42 +00:00
filepath . Join ( "server" , "camlistored" ) ,
filepath . Join ( "cmd" , "camtool" ) ,
2014-06-13 21:03:49 +00:00
}
if c . hello {
targets = append ( targets , filepath . Join ( "app" , "hello" ) )
}
2014-06-14 20:14:34 +00:00
if c . publish {
targets = append ( targets , filepath . Join ( "app" , "publisher" ) )
}
2014-06-13 21:03:49 +00:00
for _ , name := range targets {
2013-10-22 13:10:42 +00:00
err := build ( name )
2013-07-23 17:40:19 +00:00
if err != nil {
return fmt . Errorf ( "Could not build %v: %v" , name , err )
}
}
}
2013-12-27 23:20:07 +00:00
if err := c . setRoot ( ) ; err != nil {
2013-07-23 17:40:19 +00:00
return fmt . Errorf ( "Could not setup the camli root: %v" , err )
}
if err := c . setEnvVars ( ) ; err != nil {
return fmt . Errorf ( "Could not setup the env vars: %v" , err )
}
if err := c . setupIndexer ( ) ; err != nil {
return fmt . Errorf ( "Could not setup the indexer: %v" , err )
}
if err := c . syncTemplateBlobs ( ) ; err != nil {
return fmt . Errorf ( "Could not copy the template blobs: %v" , err )
}
if err := c . setFullClosure ( ) ; err != nil {
return fmt . Errorf ( "Could not setup the closure lib: %v" , err )
}
2013-08-28 16:40:23 +00:00
log . Printf ( "Starting dev server on %v/ui/ with password \"pass3179\"\n" ,
2013-09-23 10:06:18 +00:00
c . env . m [ "CAMLI_BASEURL" ] )
2013-07-23 17:40:19 +00:00
2013-09-09 12:43:44 +00:00
camliBin := filepath . Join ( "bin" , "camlistored" )
2013-07-23 17:40:19 +00:00
cmdArgs := [ ] string {
2013-09-09 12:43:44 +00:00
"-configfile=" + filepath . Join ( camliSrcRoot , "config" , "dev-server-config.json" ) ,
2013-08-25 16:28:54 +00:00
"-listen=" + c . listen ,
2013-09-01 18:37:09 +00:00
"-openbrowser=" + strconv . FormatBool ( c . openBrowser ) ,
2013-07-23 17:40:19 +00:00
}
2013-12-25 05:35:48 +00:00
if c . extraArgs != "" {
cmdArgs = append ( cmdArgs , strings . Split ( c . extraArgs , "," ) ... )
}
2014-07-21 20:58:06 +00:00
if c . things {
// force camlistored to be run as a child process instead of with
// syscall.Exec, so c.makeThings() is able to run.
sysExec = nil
go func ( ) {
if err := c . makeThings ( ) ; err != nil {
log . Fatalf ( "%v" , err )
}
} ( )
}
2013-09-22 19:13:28 +00:00
return runExec ( camliBin , cmdArgs , c . env )
2013-07-23 17:40:19 +00:00
}