in sweet/generators/tile38.go [47:219]
func (_ Tile38) Generate(cfg *common.GenConfig) error {
if cfg.AssetsDir != cfg.OutputDir {
// Copy over the datasets which are used to generate
// the server's persistent data.
if err := os.MkdirAll(filepath.Join(cfg.OutputDir, "gen-data", "geonames"), 0755); err != nil {
return err
}
if err := os.MkdirAll(filepath.Join(cfg.OutputDir, "gen-data", "datahub"), 0755); err != nil {
return err
}
err := copyFiles(cfg.OutputDir, cfg.AssetsDir, []string{
"gen-data/geonames/allCountries.txt",
"gen-data/geonames/LICENSE",
"gen-data/datahub/countries.geojson",
"gen-data/datahub/LICENSE",
"gen-data/README.md",
})
if err != nil {
return err
}
}
// Create a temporary directory where we can put the Tile38
// source and build it.
tmpDir, err := ioutil.TempDir("", "tile38-gen")
if err != nil {
return err
}
// In order to generate the assets, we need a working Tile38
// server. Use the harness code to get the source.
srcDir := filepath.Join(tmpDir, "src")
if err := os.MkdirAll(srcDir, os.ModePerm); err != nil {
return err
}
if err := (harnesses.Tile38{}).Get(srcDir); err != nil {
return err
}
// Add the Go tool to PATH, since tile38's Makefile doesn't provide enough
// visibility into how tile38 is built to allow us to pass this information
// directly.
env := cfg.GoTool.Env.Prefix("PATH", filepath.Join(filepath.Dir(cfg.GoTool.Tool))+":")
// Build Tile38.
cmd := exec.Command("make", "-C", srcDir)
cmd.Env = env.Collapse()
if err := cmd.Run(); err != nil {
return err
}
// Launch the server.
//
// Generate the datastore in the tmp directory and copy it
// over later, otherwise if cfg.OutputDir == cfg.AssetsDir, then
// we might launch the server with an old database.
serverPath := filepath.Join(srcDir, "tile38-server")
tmpDataPath := filepath.Join(srcDir, "tile38-data")
var buf bytes.Buffer
srvCmd, err := launchServer(serverPath, tmpDataPath, &buf)
if err != nil {
log.Printf("=== Server stdout+stderr ===")
for _, line := range strings.Split(buf.String(), "\n") {
log.Printf(line)
}
return fmt.Errorf("error: starting server: %v", err)
}
// Clean up the server process after we're done.
defer func() {
if r := srvCmd.Process.Signal(os.Interrupt); r != nil {
if err == nil {
err = r
} else {
fmt.Fprintf(os.Stderr, "failed to shut down server: %v\n", r)
}
return
}
if _, r := srvCmd.Process.Wait(); r != nil {
if err == nil {
err = r
} else if r != nil {
fmt.Fprintf(os.Stderr, "failed to wait for server to exit: %v\n", r)
}
return
}
if err != nil && buf.Len() != 0 {
log.Printf("=== Server stdout+stderr ===")
for _, line := range strings.Split(buf.String(), "\n") {
log.Printf(line)
}
}
if err == nil {
// Copy database to the output directory.
// We cannot do this until we've stopped the
// server because the data might not have been
// written back yet. An interrupt should have
// the server shut down gracefully.
err = fileutil.CopyDir(
filepath.Join(cfg.OutputDir, "data"),
tmpDataPath,
)
}
}()
// Connect to the server and feed it data.
c, err := redis.Dial("tcp", ":9851")
if err != nil {
return err
}
defer c.Close()
// Store GeoJSON of countries.
genDataDir := filepath.Join(cfg.AssetsDir, "gen-data")
if err := storeGeoJSON(c, filepath.Join(genDataDir, "datahub", "countries.geojson")); err != nil {
return err
}
// Feed the server points-of-interest.
f, err := os.Open(filepath.Join(genDataDir, "geonames", "allCountries.txt"))
if err != nil {
return err
}
defer f.Close()
// allCountries.txt is a TSV file with a fixed number ofcolumns per row
// (line). What we need to pull out of it is a unique ID, and the
// coordinates for the point-of-interest.
const (
columnsPerLine = 19
idColumn = 0
latColumn = 4
lonColumn = 5
)
s := tsvScanner(f)
var item int
var obj geoObj
for s.Scan() {
// Each iteration of this loop is another cell in the
// TSV file.
switch item % columnsPerLine {
case idColumn:
i, err := strconv.ParseInt(s.Text(), 10, 64)
if err != nil {
return err
}
obj.id = i
case latColumn:
f, err := strconv.ParseFloat(s.Text(), 64)
if err != nil {
return err
}
obj.lat = f
case lonColumn:
f, err := strconv.ParseFloat(s.Text(), 64)
if err != nil {
return err
}
obj.lon = f
}
item++
// We finished off another row, which means obj
// should be correctly populated.
if item%columnsPerLine == 0 {
if err := storeGeoObj(c, &obj); err != nil {
return err
}
}
}
return s.Err()
}