Example #1
0
File: mllp.go Project: deoxxa/mllp
func (r Reader) ReadMessage() ([]byte, error) {
	c, err := r.b.ReadByte()
	if err != nil {
		return nil, stackerr.Wrap(err)
	}

	if c != byte(0x0b) {
		return nil, ErrInvalidHeader(stackerr.Newf("invalid header found; expected 0x0b but got %02x", c))
	}

	d, err := r.b.ReadBytes(byte(0x1c))
	if err != nil {
		return nil, stackerr.Wrap(err)
	}

	if len(d) < 2 {
		return nil, ErrInvalidContent(stackerr.Newf("content including boundary should be at least two bytes long; instead was %d", len(d)))
	}

	if d[len(d)-2] != 0x0d {
		return nil, ErrInvalidBoundary(stackerr.Newf("content should end with 0x0d; instead was %02x", d[len(d)-2]))
	}

	t, err := r.b.ReadByte()
	if err != nil {
		return nil, stackerr.Wrap(err)
	}
	if t != byte(0x0d) {
		return nil, ErrInvalidTrailer(stackerr.Newf("invalid trailer found; expected 0x0d but got %02x", t))
	}

	return d[0 : len(d)-2], nil
}
Example #2
0
func (u *updateCmd) updateCLI(e *env) (bool, error) {
	downloadURL, err := u.getDownloadURL(e)
	if err != nil {
		return false, err
	}
	if downloadURL == "" {
		return false, nil
	}
	exec, err := osext.Executable()
	if err != nil {
		return false, stackerr.Wrap(err)
	}

	fmt.Fprintf(e.Out, "Downloading binary from %s.\n", downloadURL)
	resp, err := http.Get(downloadURL)
	if err != nil {
		return false, stackerr.Newf("Update failed with error: %v", err)
	}
	defer resp.Body.Close()
	err = update.Apply(resp.Body, update.Options{TargetPath: exec})
	if err != nil {
		return false, stackerr.Newf("Update failed with error: %v", err)
	}
	fmt.Fprintf(e.Out, "Successfully updated binary at: %s\n", exec)
	return true, nil
}
Example #3
0
func (l *Login) AuthToken(e *Env, token string) (string, error) {
	req := &http.Request{
		Method: "POST",
		URL:    &url.URL{Path: "accountkey"},
		Body: ioutil.NopCloser(
			jsonpipe.Encode(
				map[string]string{
					"accountKey": token,
				},
			),
		),
	}

	res := &struct {
		Email string `json:"email"`
	}{}
	if response, err := e.ParseAPIClient.Do(req, nil, res); err != nil {
		if response != nil && response.StatusCode == http.StatusUnauthorized {
			return "", stackerr.Newf(tokenErrMsgf, Last4(token), keysURL)
		}
		return "", stackerr.Wrap(err)
	}

	if e.ParserEmail != "" && res.Email != e.ParserEmail {
		return "", stackerr.Newf("Account key %q does not belong to %q", Last4(token), e.ParserEmail)
	}
	return res.Email, nil
}
Example #4
0
func (g *Generator) genRootCA() error {
	certFileName := g.certFileName()
	keyFileName := g.keyFileName()

	if _, err := os.Stat(certFileName); !os.IsNotExist(err) {
		return stackerr.Newf("%s must not exist", certFileName)
	}
	if _, err := os.Stat(keyFileName); !os.IsNotExist(err) {
		return stackerr.Newf("%s must not exist", keyFileName)
	}

	priv, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return stackerr.Wrap(err)
	}

	now := time.Now()

	template := x509.Certificate{
		SerialNumber: new(big.Int).SetInt64(0),
		Subject: pkix.Name{
			CommonName: g.RootName,
		},
		NotBefore:             now.Add(-5 * time.Minute).UTC(),
		NotAfter:              now.Add(g.MaxAge),
		IsCA:                  true,
		SubjectKeyId:          []byte{1, 2, 3, 4},
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
		BasicConstraintsValid: true,
	}

	derBytes, err := x509.CreateCertificate(
		rand.Reader, &template, &template, &priv.PublicKey, priv)
	if err != nil {
		return stackerr.Wrap(err)
	}

	certOut, err := os.Create(certFileName)
	if err != nil {
		return stackerr.Wrap(err)
	}
	pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	certOut.Close()
	log.Print("Written " + certFileName + "\n")

	keyOut, err := os.OpenFile(keyFileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
	if err != nil {
		return stackerr.Wrap(err)
	}
	pem.Encode(keyOut, &pem.Block{
		Type:  "RSA PRIVATE KEY",
		Bytes: x509.MarshalPKCS1PrivateKey(priv),
	})
	keyOut.Close()
	log.Print("Written " + keyFileName + "\n")
	return nil
}
Example #5
0
func (c *ParseConfig) AddAlias(name, link string) error {
	if _, found := c.Applications[name]; found {
		return stackerr.Newf("App %q has already been added.", name)
	}
	if _, found := c.Applications[link]; !found {
		return stackerr.Newf("App %q wasn't found.", link)
	}
	c.Applications[name] = &ParseAppConfig{Link: link}
	return nil
}
Example #6
0
func (c *ParseConfig) App(name string) (AppConfig, error) {
	ac, found := c.Applications[name]
	if !found {
		if name == DefaultKey {
			return nil, stackerr.Newf("No default app configured.")
		}
		return nil, stackerr.Newf("App %q wasn't found.", name)
	}
	if ac.Link != "" {
		return c.App(ac.Link)
	}
	return ac, nil
}
Example #7
0
func (l *Login) GetTokenCredentials(e *Env, email string) (bool, *Credentials, error) {
	reader, err := l.getTokensReader()
	if err != nil {
		return false, nil, stackerr.Wrap(err)
	}
	tokens, err := netrc.Parse(reader)
	if err != nil {
		return false, nil, stackerr.Wrap(err)
	}
	server, err := getHostFromURL(e.Server, email)
	if err != nil {
		return false, nil, err
	}
	machine := tokens.FindMachine(server)
	if machine != nil {
		return true,
			&Credentials{
				Token: machine.Password,
			}, nil
	}

	if email == "" {
		return false, nil, stackerr.Newf("Could not find account key for %q", server)
	}

	// check for system default account key for the given server
	// since we could not find account key for the given account (email)
	server, err = getHostFromURL(e.Server, "")
	if err != nil {
		return false, nil, err
	}
	machine = tokens.FindMachine(server)
	if machine != nil {
		return false,
			&Credentials{
				Token: machine.Password,
			}, nil
	}
	return false,
		nil,
		stackerr.Newf(
			`Could not find account key for email: %q,
and default access key not configured for %q
`,
			email,
			e.Server,
		)
}
Example #8
0
func (manager *StateManager) Start() error {
	corelog.LogInfoMessage("starting manager")
	manager.Lock()
	defer manager.Unlock()
	var err error
	manager.currentReplicaSetState, err = manager.generateReplicaSetState()
	if err != nil {
		return err
		return errors.New(fmt.Sprintf("error starting statemanager, replicaset in flux: %v", err))
	}
	healthyAddrs := manager.currentReplicaSetState.Addrs()

	// Ensure we have at least one health address.
	if len(healthyAddrs) == 0 {
		return stackerr.Newf("no healthy primaries or secondaries: %s", manager.replicaSet.Addrs)
	}

	manager.addProxies(healthyAddrs...)

	for _, proxy := range manager.proxies {
		go manager.startProxy(proxy)
	}
	manager.refreshTime = time.Now()
	return nil
}
Example #9
0
func (g *gitInfo) isGitRepo(e *parsecli.Env) error {
	_, err := os.Lstat(filepath.Join(e.Root, ".git"))
	if os.IsNotExist(err) {
		return stackerr.Newf("%s is not a git repository. Please run 'git init'", e.Root)
	}
	return nil
}
Example #10
0
func selectHerokuApp(apps nameIDs, e *parsecli.Env) (*nameID, error) {
	fmt.Fprintf(e.Out, "Please select from the following Heroku apps: (Enter a number between 1 and %d)\n", len(apps))
	for i, app := range apps {
		w := new(tabwriter.Writer)
		w.Init(e.Out, 0, 8, 0, '\t', 0)
		fmt.Fprintf(w, "%d: %s\t\t(%s)\n", i+1, app.name, app.id)
		if err := w.Flush(); err != nil {
			return nil, stackerr.Wrap(err)
		}
	}
	fmt.Fprintf(e.Out, "Selection: ")
	var selection string
	fmt.Fscanf(e.In, "%s\n", &selection)

	n, err := strconv.Atoi(selection)
	if err != nil {
		return nil, err
	}

	lapps := len(apps)
	if n <= 0 || n > lapps {
		return nil, stackerr.Newf("Invalid selection: can only be in range 1..%d", lapps)
	}
	return &apps[n-1], nil
}
Example #11
0
func (s *symbolsCmd) run(e *env, c *context) error {
	android := &androidSymbolUploader{
		Path:     s.path,
		Apk:      s.apk,
		Manifest: s.manifest,
		AAPT:     s.aapt}
	ios := &iosSymbolUploader{
		Path:        s.path,
		SkipOsCheck: s.skipOsCheck}
	switch {
	case android.acceptsPath():
		if err := android.validate(); err != nil {
			return err
		}
		fmt.Fprintln(e.Out, "Uploading Android symbol files...")
		return android.uploadSymbols(e)
	case ios.acceptsPath():
		if err := ios.validate(); err != nil {
			return err
		}
		fmt.Fprintln(e.Out, "Uploading iOS symbol files...")
		return ios.uploadSymbols(e)
	default:
		if s.path == "" {
			return stackerr.New("Please specify path to symbol files")
		}
		return stackerr.Newf("Do not understand symbol files at : %s", s.path)
	}
}
Example #12
0
func (r *releasesCmd) printFiles(version string,
	releases []releasesResponse,
	e *env) error {
	var files string
	for _, release := range releases {
		if release.Version == version {
			files = release.UserFiles
			break
		}
	}
	if files == "" {
		return stackerr.Newf(`Unable to fetch files for release version: %s
Note that you can list files for all releases shown in "parse releases"`,
			version)
	}
	var versionFileNames userFiles
	if err := json.NewDecoder(
		strings.NewReader(files),
	).Decode(&versionFileNames); err != nil {
		return stackerr.Wrap(err)
	}
	if len(versionFileNames.Cloud) != 0 {
		fmt.Fprintf(e.Out, "Deployed cloud code files:\n")
		r.printFileNames(versionFileNames.Cloud, e)
	}
	if len(versionFileNames.Cloud) != 0 && len(versionFileNames.Public) != 0 {
		fmt.Fprintln(e.Out)
	}
	if len(versionFileNames.Public) != 0 {
		fmt.Fprintf(e.Out, "Deployed public hosting files:\n")
		r.printFileNames(versionFileNames.Public, e)
	}
	return nil
}
func (i *iosSymbolUploader) convertSymbols(e *env) ([]string, error) {
	homedir, err := homedir.Dir()
	if err != nil {
		return nil, stackerr.Wrap(err)
	}

	folderPath := filepath.Join(homedir, ".parse", "CrashReportingSymbols")
	if err := i.prepareSymbolsFolder(folderPath, e); err != nil {
		return nil, stackerr.Wrap(err)
	}

	conversionTool, err := i.symbolConversionTool(homedir, nil, e)
	if err != nil {
		return nil, stackerr.Wrap(err)
	}

	cmd := exec.Command(conversionTool, i.Path, folderPath)
	if out, err := cmd.CombinedOutput(); err != nil {
		return nil, stackerr.Newf("Symbol conversion failed with:\n%s", string(out))
	}

	filenames, err := readDirNames(folderPath)
	if err != nil {
		return nil, stackerr.Wrap(err)
	}
	return filenames, nil
}
Example #14
0
func (l *logsCmd) run(e *env, c *context) error {
	level := strings.ToUpper(l.level)
	if level != "INFO" && level != "ERROR" {
		return stackerr.Newf("invalid level: %q", l.level)
	}
	l.level = level
	numIsSet := true
	if l.num == 0 {
		numIsSet = false
		l.num = 10
	}

	lastTime, err := l.round(e, c, nil)
	if err != nil {
		return err
	}

	if !l.follow {
		return nil
	}
	if !numIsSet {
		l.num = 100 // force num to 100 for follow
	}

	ticker := e.Clock.Ticker(logFollowSleepDuration)
	defer ticker.Stop()
	for range ticker.C {
		lastTime, err = l.round(e, c, lastTime)
		if err != nil {
			return err
		}
	}
	return nil
}
Example #15
0
func (u *updateCmd) updateCLI(e *env) (bool, error) {
	downloadURL := unixCliDownloadURL
	switch runtime.GOOS {
	case "windows":
		downloadURL = windowsCliDownloadURL
	case "darwin":
		downloadURL = macCliDownloadURL
	}

	latestVersion, err := u.latestVersion(e, downloadURL)
	if err != nil {
		return false, stackerr.Wrap(err)
	}

	if latestVersion == "" || latestVersion == version {
		return false, nil
	}

	exec, err := osext.Executable()
	if err != nil {
		return false, stackerr.Wrap(err)
	}

	fmt.Fprintf(e.Out, "Downloading binary from %s.\n", downloadURL)
	if err, _ := update.New().Target(exec).FromUrl(downloadURL); err != nil {
		return false, stackerr.Newf("Update failed: %v", err)
	}
	fmt.Fprintf(e.Out, "Successfully updated binary at: %s\n", exec)
	return true, nil
}
Example #16
0
func (d *defaultCmd) run(e *env, args []string) error {
	var newDefault string
	if len(args) > 1 {
		return stackerr.Newf("unexpected arguments, only an optional app name is expected: %v", args)
	}
	if len(args) == 1 {
		newDefault = args[0]
	}

	config, err := configFromDir(e.Root)
	if err != nil {
		return err
	}

	if config.getNumApps() == 0 {
		return stackerr.New("No apps are associated with this project. You can add some with parse add")
	}

	defaultApp := config.getDefaultApp()

	switch newDefault {
	case "":
		return d.printDefault(e, defaultApp)
	default:
		return d.setDefault(e, newDefault, defaultApp, config)
	}
}
Example #17
0
func fetchAppKeys(e *env, appID string) (*app, error) {
	l := &login{}
	err := l.authUser(e)
	if err != nil {
		return nil, err
	}
	credentials := &l.credentials

	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: path.Join("apps", appID)},
		Header: getAuthHeaders(credentials, nil),
	}
	res := &app{}

	if response, err := e.ParseAPIClient.Do(req, nil, res); err != nil {
		if response.StatusCode == http.StatusUnauthorized {
			return nil, errAuth
		}
		return nil, err
	}
	if res == nil {
		return nil, stackerr.Newf("Unable to fetch keys for %s.", appID)
	}
	return res, nil
}
Example #18
0
func (a *apps) selectApp(apps []*app, msg string, e *env) (*app, error) {
	appNames := allApps(apps)
	appCount := len(apps)

	pos := -1
	var err error

	for {
		fmt.Fprintf(e.Out, "%s%s", selectionString(appNames), msg)

		var selected string
		fmt.Fscanf(e.In, "%s", &selected)
		if pos, err = strconv.Atoi(strings.TrimSpace(selected)); err != nil {
			pos = -1
			break
		}

		if pos > 0 && pos <= appCount {
			break
		} else {
			fmt.Fprintf(e.Out, "Invalid selection %d: must be between 1 and %d\n", pos, appCount)
			pos = -1
		}
	}

	if pos != -1 {
		appName := appNames[pos-1]
		for _, app := range apps {
			if app.Name == appName {
				return app, nil
			}
		}
	}
	return nil, stackerr.Newf("Please try again. Please select from among the listed apps.")
}
Example #19
0
func (d *daemon) validateFile() error {
	if d.fileName == "" {
		return stackerr.Newf("Invalid config file. File path cannot be empty.")
	}
	if !filepath.IsAbs(d.fileName) {
		return stackerr.Newf("Invalid config file: [%s]. File path must be absolute path.", d.fileName)
	}
	dir := filepath.Dir(d.fileName)
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		return stackerr.Newf("Invalid config file: [%s]. The enclosing directory [%s] does not exit.", d.fileName, dir)
	}

	if _, err := os.Stat(d.fileName); os.IsNotExist(err) {
		d.log.Printf("[INFO]: [%s] doesn't exist. Going to create a new one.", d.fileName)
	}
	return nil
}
Example #20
0
func (u *updateCmd) updateCLI(e *env) (bool, error) {
	ostype := runtime.GOOS
	arch := runtime.GOARCH

	latestVersion, err := u.latestVersion(e)
	if err != nil {
		return false, err
	}
	if latestVersion == "" || latestVersion == version {
		return false, nil
	}

	var downloadURL string
	switch ostype {
	case "darwin":
		downloadURL = fmt.Sprintf(downloadURLFormat, latestVersion, macDownload)
	case "windows":
		downloadURL = fmt.Sprintf(downloadURLFormat, latestVersion, windowsDownload)
	case "linux":
		if arch == "arm" {
			downloadURL = fmt.Sprintf(downloadURLFormat, latestVersion, linuxArmDownload)
		} else {
			downloadURL = fmt.Sprintf(downloadURLFormat, latestVersion, linuxDownload)
		}
	}

	exec, err := osext.Executable()
	if err != nil {
		return false, stackerr.Wrap(err)
	}

	fmt.Fprintf(e.Out, "Downloading binary from %s.\n", downloadURL)
	resp, err := http.Get(downloadURL)
	if err != nil {
		return false, stackerr.Newf("Update failed with error: %v", err)
	}
	defer resp.Body.Close()
	err = update.Apply(resp.Body, &update.Options{TargetPath: exec})
	if err != nil {
		return false, stackerr.Newf("Update failed with error: %v", err)
	}
	fmt.Fprintf(e.Out, "Successfully updated binary at: %s\n", exec)
	return true, nil
}
Example #21
0
func fetchHerokuAppInfo(e *parsecli.Env, appConfig *parsecli.HerokuAppConfig) (*heroku.App, error) {
	herokuAppInfo, err := e.HerokuAPIClient.AppInfo(appConfig.HerokuAppID)
	if err != nil {
		return nil, stackerr.Newf(
			"Unable to fetch app info for: %q from heroku.",
			appConfig.HerokuAppID,
		)
	}
	return herokuAppInfo, nil
}
Example #22
0
func (d *defaultCmd) setDefault(e *env, newDefault, defaultApp string, c config) error {
	if c.getProjectConfig().Type == legacy {
		p, ok := c.(*parseConfig)
		if !ok {
			return stackerr.New("Invalid Cloud Code config.")
		}
		return d.setParseDefault(e, newDefault, defaultApp, p)
	}
	return stackerr.Newf("Project type not configured.")
}
Example #23
0
func TestNewf(t *testing.T) {
	const fmtStr = "%s 42"
	const errStr = "foo bar baz"
	e := stackerr.Newf(fmtStr, errStr)
	matches := []string{
		fmt.Sprintf(fmtStr, errStr),
		"stackerr_test.go:26 +TestNewf$",
	}
	match(t, e.Error(), matches)
}
Example #24
0
func storeConfig(e *env, c config) error {
	projectType := c.getProjectConfig().Type
	switch projectType {
	case legacyParseFormat:
		pc, ok := (c).(*parseConfig)
		if !ok {
			return stackerr.Newf("Incorrect project type: 'legacy'.")
		}
		lconf := &legacyConfig{Applications: pc.Applications}
		lconf.Global.ParseVersion = pc.projectConfig.Parse.JSSDK
		return writeLegacyConfigFile(
			lconf,
			filepath.Join(e.Root, legacyConfigFile),
		)
	case parseFormat:
		return writeConfigFile(c, filepath.Join(e.Root, parseLocal))
	}
	return stackerr.Newf("Unknown project type: %d.", projectType)
}
Example #25
0
func (g *generateCmd) validateArgs() error {
	if _, ok := validTypes[g.generateType]; !ok {
		var buf bytes.Buffer
		for key := range validTypes {
			buf.WriteString(key)
			buf.WriteString(comma)
		}
		return stackerr.Newf("type can only be one of {%s}", buf.String())
	}
	return nil
}
Example #26
0
func (g *Generator) loadPem(filename string) (*pem.Block, error) {
	in, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, stackerr.Wrap(err)
	}
	b, _ := pem.Decode(in)
	if b == nil {
		return nil, stackerr.Newf("failed to pem decode %s", filename)
	}
	return b, nil
}
Example #27
0
func getHostFromURL(urlStr string) (string, error) {
	netURL, err := url.Parse(urlStr)
	if err != nil {
		return "", stackerr.Wrap(err)
	}
	server := regexp.MustCompile(`(.*):\d+$`).ReplaceAllString(netURL.Host, "$1")
	if server == "" {
		return "", stackerr.Newf("%s is not a valid url", urlStr)
	}
	return server, nil
}
Example #28
0
func newParseAPIClient(e *env) (*ParseAPIClient, error) {
	baseURL, err := url.Parse(e.Server)
	if err != nil {
		return nil, stackerr.Newf("invalid server URL %q: %s", e.Server, err)
	}
	return &ParseAPIClient{
		apiClient: &parse.Client{
			BaseURL: baseURL,
		},
	}, nil
}
Example #29
0
func AddSelectedParseApp(
	appName string,
	appConfig *parsecli.ParseAppConfig,
	args []string,
	makeDefault, verbose bool,
	e *parsecli.Env,
) error {
	config, err := parsecli.ConfigFromDir(e.Root)
	if err != nil {
		return err
	}
	parseConfig, ok := config.(*parsecli.ParseConfig)
	if !ok {
		return stackerr.New("Invalid Cloud Code config.")
	}

	// add app to config
	if _, ok := parseConfig.Applications[appName]; ok {
		return stackerr.Newf("App %s has already been added", appName)
	}

	parseConfig.Applications[appName] = appConfig

	if len(args) > 0 && args[0] != "" {
		alias := args[0]
		aliasConfig, ok := parseConfig.Applications[alias]
		if !ok {
			parseConfig.Applications[alias] = &parsecli.ParseAppConfig{Link: appName}
		}
		if ok && aliasConfig.GetLink() != "" {
			fmt.Fprintf(e.Out, "Overwriting alias: %q to point to %q\n", alias, appName)
			parseConfig.Applications[alias] = &parsecli.ParseAppConfig{Link: appName}
		}
	}

	if makeDefault {
		if _, ok := parseConfig.Applications[parsecli.DefaultKey]; ok {
			return stackerr.New(`Default key already set. To override default, use command "parse default"`)
		}
		parseConfig.Applications[parsecli.DefaultKey] = &parsecli.ParseAppConfig{Link: appName}
	}

	if err := parsecli.StoreConfig(e, parseConfig); err != nil {
		return err
	}
	if verbose {
		fmt.Fprintf(e.Out, "Written config for %q\n", appName)
		if makeDefault {
			fmt.Fprintf(e.Out, "Set %q as default\n", appName)
		}
	}

	return nil
}
Example #30
0
func configFromDir(dir string) (config, error) {
	l, err := readLegacyConfigFile(filepath.Join(dir, legacyConfigFile))
	if err != nil && !stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) {
		return nil, err
	}
	if l != nil { // legacy config format
		projectConfig := &projectConfig{
			Type: legacyParseFormat,
			Parse: &parseProjectConfig{
				JSSDK: l.Global.ParseVersion,
			},
			ParserEmail: l.Global.ParserEmail,
		}
		applications := l.Applications
		if applications == nil {
			applications = make(map[string]*parseAppConfig)
		}
		return &parseConfig{
			Applications:  applications,
			projectConfig: projectConfig,
		}, nil
	}

	canonicalize := func(err error) error {
		if err == nil {
			return nil
		}
		if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) {
			return stackerr.New("Command must be run inside a Parse project.")
		}
		return err
	}

	// current config format
	p, err := readProjectConfigFile(filepath.Join(dir, parseProject))
	if err != nil {
		return nil, canonicalize(err)
	}
	configFile := filepath.Join(dir, parseLocal)
	switch p.Type {
	case parseFormat:
		c, err := readParseConfigFile(configFile)
		if err != nil {
			return nil, canonicalize(err)
		}
		if c.Applications == nil {
			c.Applications = make(map[string]*parseAppConfig)
		}
		c.projectConfig = p
		return c, nil
	}

	return nil, stackerr.Newf("Unknown project type: %d.", p.Type)
}