github.com/bhameyie/otto@v0.2.1-0.20160406174117-16052efa52ec/builtin/app/ruby/app.go (about)

     1  package rubyapp
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/otto/app"
    10  	"github.com/hashicorp/otto/appfile"
    11  	rubySP "github.com/hashicorp/otto/builtin/scriptpack/ruby"
    12  	stdSP "github.com/hashicorp/otto/builtin/scriptpack/stdlib"
    13  	"github.com/hashicorp/otto/helper/bindata"
    14  	"github.com/hashicorp/otto/helper/compile"
    15  	"github.com/hashicorp/otto/helper/oneline"
    16  	"github.com/hashicorp/otto/helper/packer"
    17  	"github.com/hashicorp/otto/helper/schema"
    18  	"github.com/hashicorp/otto/helper/terraform"
    19  	"github.com/hashicorp/otto/helper/vagrant"
    20  	"github.com/hashicorp/otto/scriptpack"
    21  )
    22  
    23  //go:generate go-bindata -pkg=rubyapp -nomemcopy -nometadata ./data/...
    24  
    25  // App is an implementation of app.App
    26  type App struct{}
    27  
    28  func (a *App) Meta() (*app.Meta, error) {
    29  	return Meta, nil
    30  }
    31  
    32  func (a *App) Implicit(ctx *app.Context) (*appfile.File, error) {
    33  	// depMap is our mapping of gem to dependency URL
    34  	depMap := map[string]string{
    35  		"dalli": "github.com/hashicorp/otto/examples/memcached",
    36  		"pg":    "github.com/hashicorp/otto/examples/postgresql",
    37  		"redis": "github.com/hashicorp/otto/examples/redis",
    38  	}
    39  
    40  	// used keeps track of dependencies we've used so we don't
    41  	// double-up on dependencies
    42  	used := map[string]struct{}{}
    43  
    44  	// Get the path to the working directory
    45  	dir := filepath.Dir(ctx.Appfile.Path)
    46  	log.Printf("[DEBUG] app: implicit check path: %s", dir)
    47  
    48  	// If we have certain gems, add the dependencies
    49  	var deps []*appfile.Dependency
    50  	for k, v := range depMap {
    51  		// If we already used v, then don't do it
    52  		if _, ok := used[v]; ok {
    53  			continue
    54  		}
    55  
    56  		// If we don't have the gem, then nothing to do
    57  		log.Printf("[DEBUG] app: checking for Gem: %s", k)
    58  		ok, err := HasGem(dir, k)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  		if !ok {
    63  			log.Printf("[DEBUG] app: Gem not found: %s", k)
    64  			continue
    65  		}
    66  		log.Printf("[INFO] app: found Gem '%s', adding dep: %s", k, v)
    67  
    68  		// We have it! Add the implicit
    69  		deps = append(deps, &appfile.Dependency{
    70  			Source: v,
    71  		})
    72  		used[v] = struct{}{}
    73  	}
    74  
    75  	// Build an implicit Appfile if we have deps
    76  	var result *appfile.File
    77  	if len(deps) > 0 {
    78  		result = &appfile.File{
    79  			Application: &appfile.Application{
    80  				Dependencies: deps,
    81  			},
    82  		}
    83  	}
    84  
    85  	return result, nil
    86  }
    87  
    88  func (a *App) Compile(ctx *app.Context) (*app.CompileResult, error) {
    89  	var opts compile.AppOptions
    90  	custom := &customizations{Opts: &opts}
    91  	opts = compile.AppOptions{
    92  		Ctx: ctx,
    93  		Result: &app.CompileResult{
    94  			Version: 1,
    95  		},
    96  		Bindata: &bindata.Data{
    97  			Asset:    Asset,
    98  			AssetDir: AssetDir,
    99  			Context:  map[string]interface{}{},
   100  		},
   101  		ScriptPacks: []*scriptpack.ScriptPack{
   102  			&stdSP.ScriptPack,
   103  			&rubySP.ScriptPack,
   104  		},
   105  		Customization: (&compile.Customization{
   106  			Callback: custom.process,
   107  			Schema: map[string]*schema.FieldSchema{
   108  				"ruby_version": &schema.FieldSchema{
   109  					Type:        schema.TypeString,
   110  					Default:     "detect",
   111  					Description: "Ruby version to install",
   112  				},
   113  			},
   114  		}).Merge(compile.VagrantCustomizations(&opts)),
   115  	}
   116  
   117  	return compile.App(&opts)
   118  }
   119  
   120  func (a *App) Build(ctx *app.Context) error {
   121  	return packer.Build(ctx, &packer.BuildOptions{
   122  		InfraOutputMap: map[string]string{
   123  			"region":        "aws_region",
   124  			"vpc_id":        "aws_vpc_id",
   125  			"subnet_public": "aws_subnet_id",
   126  		},
   127  	})
   128  }
   129  
   130  func (a *App) Deploy(ctx *app.Context) error {
   131  	return terraform.Deploy(&terraform.DeployOptions{
   132  		InfraOutputMap: map[string]string{
   133  			"region":         "aws_region",
   134  			"subnet-private": "private_subnet_id",
   135  			"subnet-public":  "public_subnet_id",
   136  		},
   137  	}).Route(ctx)
   138  }
   139  
   140  func (a *App) Dev(ctx *app.Context) error {
   141  	var layered *vagrant.Layered
   142  
   143  	// We only setup a layered environment if we've recompiled since
   144  	// version 0. If we're still at version 0 then we have to use the
   145  	// non-layered dev environment.
   146  	if ctx.CompileResult.Version > 0 {
   147  		// Read the go version, since we use that for our layer
   148  		version, err := oneline.Read(filepath.Join(ctx.Dir, "dev", "ruby_version"))
   149  		if err != nil {
   150  			return err
   151  		}
   152  
   153  		// Setup layers
   154  		layered, err = vagrant.DevLayered(ctx, []*vagrant.Layer{
   155  			&vagrant.Layer{
   156  				ID:          fmt.Sprintf("ruby%s", version),
   157  				Vagrantfile: filepath.Join(ctx.Dir, "dev", "layer-base", "Vagrantfile"),
   158  			},
   159  		})
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	// Build the actual development environment
   166  	return vagrant.Dev(&vagrant.DevOptions{
   167  		Instructions: strings.TrimSpace(devInstructions),
   168  		Layer:        layered,
   169  	}).Route(ctx)
   170  }
   171  
   172  func (a *App) DevDep(dst, src *app.Context) (*app.DevDep, error) {
   173  	return vagrant.DevDep(dst, src, &vagrant.DevDepOptions{})
   174  }
   175  
   176  const devInstructions = `
   177  A development environment has been created for writing a generic
   178  Ruby-based app.
   179  
   180  Ruby is pre-installed. To work on your project, edit files locally on your
   181  own machine. The file changes will be synced to the development environment.
   182  
   183  When you're ready to build your project, run 'otto dev ssh' to enter
   184  the development environment. You'll be placed directly into the working
   185  directory where you can run 'bundle' and 'ruby' as you normally would.
   186  
   187  You can access any running web application using the IP above.
   188  `