in v2/aetest/instance.go [203:325]
func (i *instance) startChild() (err error) {
if PrepareDevAppserver != nil {
if err := PrepareDevAppserver(); err != nil {
return err
}
}
executable := os.Getenv("APPENGINE_DEV_APPSERVER_BINARY")
var appserverArgs []string
if len(executable) == 0 {
executable, err = findPython()
if err != nil {
return fmt.Errorf("Could not find python interpreter: %v", err)
}
devAppserver, err := findDevAppserver()
if err != nil {
return fmt.Errorf("Could not find dev_appserver.py: %v", err)
}
appserverArgs = append(appserverArgs, devAppserver)
}
i.appDir, err = ioutil.TempDir("", "appengine-aetest")
if err != nil {
return err
}
defer func() {
if err != nil {
os.RemoveAll(i.appDir)
}
}()
err = os.Mkdir(filepath.Join(i.appDir, "app"), 0755)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(i.appDir, "app", "app.yaml"), []byte(i.appYAML()), 0644)
if err != nil {
return err
}
err = ioutil.WriteFile(filepath.Join(i.appDir, "app", "stubapp.go"), []byte(appSource), 0644)
if err != nil {
return err
}
appserverArgs = append(appserverArgs,
"--port=0",
"--api_port=0",
"--admin_port=0",
"--automatic_restart=false",
"--skip_sdk_update_check=true",
"--clear_datastore=true",
"--clear_search_indexes=true",
"--datastore_path", filepath.Join(i.appDir, "datastore"),
)
if i.opts != nil && i.opts.StronglyConsistentDatastore {
appserverArgs = append(appserverArgs, "--datastore_consistency_policy=consistent")
}
if i.opts != nil && i.opts.SupportDatastoreEmulator != nil {
appserverArgs = append(appserverArgs, fmt.Sprintf("--support_datastore_emulator=%t", *i.opts.SupportDatastoreEmulator))
}
appserverArgs = append(appserverArgs, filepath.Join(i.appDir, "app"))
i.child = exec.Command(executable, appserverArgs...)
i.child.Stdout = os.Stdout
var stderr io.Reader
stderr, err = i.child.StderrPipe()
if err != nil {
return err
}
if err = i.child.Start(); err != nil {
return err
}
// Read stderr until we have read the URLs of the API server and admin interface.
errc := make(chan error, 1)
go func() {
s := bufio.NewScanner(stderr)
for s.Scan() {
// Pass stderr along as we go so the user can see it.
if !(i.opts != nil && i.opts.SuppressDevAppServerLog) {
fmt.Fprintln(os.Stderr, s.Text())
}
if match := apiServerAddrRE.FindStringSubmatch(s.Text()); match != nil {
u, err := url.Parse(match[1])
if err != nil {
errc <- fmt.Errorf("failed to parse API URL %q: %v", match[1], err)
return
}
i.apiURL = u
}
if match := adminServerAddrRE.FindStringSubmatch(s.Text()); match != nil {
i.adminURL = match[1]
}
if i.adminURL != "" && i.apiURL != nil {
// Pass along stderr to the user after we're done with it.
if !(i.opts != nil && i.opts.SuppressDevAppServerLog) {
go io.Copy(os.Stderr, stderr)
}
break
}
}
errc <- s.Err()
}()
select {
case <-time.After(i.startupTimeout):
if p := i.child.Process; p != nil {
p.Kill()
}
return errors.New("timeout starting child process")
case err := <-errc:
if err != nil {
return fmt.Errorf("error reading child process stderr: %v", err)
}
}
if i.adminURL == "" {
return errors.New("unable to find admin server URL")
}
if i.apiURL == nil {
return errors.New("unable to find API server URL")
}
return nil
}