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) }
func TestApplyWithExistingRemoveError(t *testing.T) { const image = "x" givenErr := errors.New("") container := &Container{ containerConfig: &dockerclient.ContainerConfig{ Image: image, }, removeExisting: true, } client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return &dockerclient.ContainerInfo{ Id: "y", Image: "z", }, nil }, listImages: func() ([]*dockerclient.Image, error) { return []*dockerclient.Image{ { RepoTags: []string{image}, Id: "y", }, }, nil }, removeContainer: func(id string, force, volumes bool) error { return givenErr }, } err := container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func main() { rx := regexp.MustCompile(os.Args[1]) r := mllp.NewReader(os.Stdin) w := mllp.NewWriter(os.Stdout) i := 0 for { m, err := r.ReadMessage() if err != nil { if stackerr.HasUnderlying(err, stackerr.Equals(io.EOF)) { break } panic(err) } if rx.Match(m) { if err := w.WriteMessage(m); err != nil { panic(err) } } i++ } }
func TestApplyStartError(t *testing.T) { givenErr := errors.New("") const image = "x" const id = "y" container := &Container{ containerConfig: &dockerclient.ContainerConfig{ Image: image, }, } client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return &dockerclient.ContainerInfo{ Id: "a", Image: id, Config: &dockerclient.ContainerConfig{}, }, nil }, listImages: func() ([]*dockerclient.Image, error) { return []*dockerclient.Image{ { RepoTags: []string{image}, Id: id, }, }, nil }, startContainer: func(id string, config *dockerclient.HostConfig) error { return givenErr }, } err := container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func TestApplyInitialInspectError(t *testing.T) { givenErr := errors.New("") container := &Container{ containerConfig: &dockerclient.ContainerConfig{ Image: "x", }, } client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return nil, givenErr }, } err := container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func TestApplyGraphApplyError(t *testing.T) { givenErr := errors.New("") containers := []*Container{ { name: "n1", containerConfig: &dockerclient.ContainerConfig{Image: "in1"}, }, } client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return nil, givenErr }, } err := ApplyGraph(client, containers) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func TestApplyInspectAfterCreateError(t *testing.T) { container, err := NewContainer( ContainerName("x"), ContainerConfig(&dockerclient.ContainerConfig{Image: "foo"}), ) ensure.Nil(t, err) client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return nil, dockerclient.ErrNotFound }, createContainer: func(config *dockerclient.ContainerConfig, name string) (string, error) { return "baz", nil }, } err = container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(dockerclient.ErrNotFound))) }
func TestCheckExistingImageIdentifyError(t *testing.T) { givenErr := errors.New("") const image = "x" container := &Container{ containerConfig: &dockerclient.ContainerConfig{ Image: image, }, } client := &mockClient{ listImages: func() ([]*dockerclient.Image, error) { return nil, givenErr }, } ok, err := container.checkExisting(client, &dockerclient.ContainerInfo{Image: "z"}) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) ensure.False(t, ok) }
func (c *HerokuConfig) PrettyPrintApps(e *Env) { apps := c.Applications defaultApp := c.GetDefaultApp() var appNames []string for appName := range apps { appNames = append(appNames, appName) } sort.Strings(appNames) if len(appNames) == 0 { return } fmt.Fprintln( e.Out, "The following apps are associated with cloud code in the current directory:", ) for _, appName := range appNames { if appName == DefaultKey { continue } if defaultApp == appName { fmt.Fprint(e.Out, "* ") } else { fmt.Fprint(e.Out, " ") } fmt.Fprintf(e.Out, "%s", appName) config, _ := apps[appName] if config.GetLink() != "" { fmt.Fprintf(e.Out, " -> %s", config.GetLink()) } herokuAppName, err := FetchHerokuAppName(config.HerokuAppID, e) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(HerokuAppNotFound)) { herokuAppName = "" } else { herokuAppName = config.HerokuAppID } } fmt.Fprintf(e.Out, " (%q)\n", herokuAppName) } }
func (l *login) authUser(e *env) error { _, err := l.authUserWithToken(e) if err == nil { return nil } // user never created an account key: educate them if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { fmt.Fprintln( e.Out, `We've changed the way the CLI works. To save time logging in, you should create an account key. `) } apps := &apps{} fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/js/guide#command-line-account-keys Please login to Parse using your email and password.`, ) for i := 0; i < numRetries; i++ { err := l.populateCreds(e) if err != nil { return err } apps.login.credentials = l.credentials _, err = apps.restFetchApps(e) if err == nil { return nil } if i == numRetries-1 && err != nil { return err } if err != errAuth { fmt.Fprintf(e.Err, "Got error: %s", errorString(e, err)) } fmt.Fprintf(e.Err, "%s\nPlease try again...\n", err) l.credentials.password = "" } return errAuth }
func TestApplyRemovesExistingWithoutDesiredImageError(t *testing.T) { givenErr := errors.New("") container := &Container{ containerConfig: &dockerclient.ContainerConfig{ Image: "x", }, } client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return &dockerclient.ContainerInfo{Id: "y", Image: "a"}, nil }, listImages: func() ([]*dockerclient.Image, error) { return nil, givenErr }, } err := container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func (l *login) authUserWithToken(e *env) (string, error) { _, tokenCredentials, err := l.getTokenCredentials(e, e.ParserEmail) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(accessKeyNotFound)) { fmt.Fprintln(e.Err, errorString(e, err)) } return "", err } email, err := l.authToken(e, tokenCredentials.token) if err != nil { fmt.Fprintf(e.Err, "Account key could not be used.\nError: %s\n\n", errorString(e, err)) return "", err } l.credentials = *tokenCredentials return email, nil }
func main() { r := mllp.NewReader(os.Stdin) i := 0 for { if _, err := r.ReadMessage(); err != nil { if stackerr.HasUnderlying(err, stackerr.Equals(io.EOF)) { break } panic(err) } i++ } fmt.Printf("total messages: %d\n", i) }
func TestApplyForceRemoveExistingError(t *testing.T) { container, err := NewContainer( ContainerName("x"), ContainerConfig(&dockerclient.ContainerConfig{Image: "foo"}), ContainerForceRemoveExisting(), ) ensure.Nil(t, err) givenErr := errors.New("") client := &mockClient{ removeContainer: func(id string, force, volumes bool) error { return givenErr }, inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { return &dockerclient.ContainerInfo{Id: "x"}, nil }, } err = container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) }
func (l *Login) AuthUser(e *Env, strict bool) error { _, err := l.AuthUserWithToken(e, strict) if err == nil { return nil } if strict { return err } if !stackerr.HasUnderlying(err, stackerr.MatcherFunc(accountKeyNotConfigured)) { fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/cloudcode/guide#command-line-account-keys Please login to Parse using your email and password.`, ) } apps := &Apps{} for i := 0; i < numRetries; i++ { err := l.populateCreds(e) if err != nil { return err } apps.Login.Credentials = l.Credentials _, err = apps.RestFetchApps(e) if err == nil { return nil } if i == numRetries-1 && err != nil { return err } if err != errAuth { fmt.Fprintf(e.Err, "Got error: %s", ErrorString(e, err)) } fmt.Fprintf(e.Err, "%s\nPlease try again...\n", err) l.Credentials.Password = "" } return errAuth }
func (h *herokuLink) herokuAppNames(ids []string, e *parsecli.Env) (nameIDs, []string, error) { var wg errgroup.Group wg.Add(len(ids)) maxParallel := make(chan struct{}, maxRequests) var ( ret nameIDs deletedLinks []string retMutex sync.Mutex deletedLinksMutex sync.Mutex ) getAppName := func(id string) { defer func() { wg.Done() <-maxParallel }() appName, err := parsecli.FetchHerokuAppName(id, e) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(parsecli.HerokuAppNotFound)) { deletedLinksMutex.Lock() defer deletedLinksMutex.Unlock() deletedLinks = append(deletedLinks, id) return } wg.Error(err) // ignore error if corresponding heroku app was deleted return } retMutex.Lock() defer retMutex.Unlock() ret = append(ret, nameID{id: id, name: appName}) } for _, id := range ids { go getAppName(id) } err := wg.Wait() sort.Sort(ret) return ret, deletedLinks, stackerr.Wrap(err) }
func configFromDir(dir string) (config, error) { l, err := readLegacyConfigFile(filepath.Join(dir, legacyConfigFile)) if err != nil { if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { return nil, stackerr.New("Command must be run in a directory containing a Parse project.") } return nil, err } projectConfig := &projectConfig{ Type: legacy, Parse: &parseProjectConfig{JSSDK: l.Global.ParseVersion}, } applications := l.Applications if applications == nil { applications = make(map[string]*parseAppConfig) } return &parseConfig{ Applications: applications, projectConfig: projectConfig, }, nil }
func (l *Login) AuthUserWithToken(e *Env, strict bool) (string, error) { _, tokenCredentials, err := l.GetTokenCredentials(e, e.ParserEmail) if err != nil { // user never created an account key: educate them if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) { if strict { fmt.Fprintln( e.Out, `To proceed further, you must configure an account key. `, ) } else { fmt.Fprintln( e.Out, `We've changed the way the CLI works. To save time logging in, you should create an account key. `, ) } fmt.Fprintln( e.Out, `Type "parse configure accountkey" to create a new account key. Read more at: https://parse.com/docs/cloudcode/guide#command-line-account-keys`) return "", stackerr.New("Account key not configured") } return "", err } email, err := l.AuthToken(e, tokenCredentials.Token) if err != nil { fmt.Fprintf(e.Err, "Account key could not be used.\nError: %s\n\n", ErrorString(e, err)) return "", err } l.Credentials = *tokenCredentials return email, nil }
func TestApplyAfterCreateError(t *testing.T) { givenErr := errors.New("") const givenName = "x" const givenID = "y" var inspectCalls, removeCalls int container, err := NewContainer( ContainerName(givenName), ContainerConfig(&dockerclient.ContainerConfig{Image: "foo"}), ContainerAfterCreate(func(string) error { return givenErr }), ) ensure.Nil(t, err) client := &mockClient{ inspectContainer: func(name string) (*dockerclient.ContainerInfo, error) { inspectCalls++ switch inspectCalls { case 1: return nil, dockerclient.ErrNotFound case 2: return &dockerclient.ContainerInfo{Id: givenID}, nil } panic("not reached") }, createContainer: func(config *dockerclient.ContainerConfig, name string) (string, error) { return "", nil }, startContainer: func(id string, config *dockerclient.HostConfig) error { return nil }, removeContainer: func(id string, force, volumes bool) error { removeCalls++ ensure.DeepEqual(t, id, givenID) return nil }, } err = container.Apply(client) ensure.True(t, stackerr.HasUnderlying(err, stackerr.Equals(givenErr))) ensure.DeepEqual(t, removeCalls, 1) }
func (c *configureCmd) accountKey(e *env) error { token, err := c.login.helpCreateToken(e) if err != nil { return err } email, err := c.login.authToken(e, token) if err != nil { fmt.Fprintln(e.Err, "Could not store credentials. Please try again.\n") return err } if c.isDefault { email = "" } var l login if c.tokenReader != nil { l.tokenReader = c.tokenReader } foundEmail, creds, err := l.getTokenCredentials(e, email) if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) && !c.isDefault { fmt.Fprintln( e.Out, ` Looks like you have not configured the default account key yet. Note that "parse new" and "parse list" can automatically pick up a default key if present. Otherwise, you'll have to explicitly set the PARSER_EMAIL environment variable for it to know which account key to use. Further, if the command line tool cannot find an account key for a configured email it will try to use the default account key To configure the default account key use: "parse configure accountkey -d"`, ) } if creds != nil { if c.isDefault { fmt.Fprintln( e.Err, "Note: this operation will overwrite the default account key", ) } else if foundEmail { fmt.Fprintf( e.Err, `Note: this operation will overwrite the account key: %q for email: %q `, last4(token), email, ) } } err = c.login.storeCredentials(e, email, &credentials{token: token}) if err == nil { if c.isDefault { fmt.Fprintln(e.Out, "Successfully stored default account key.") } else { fmt.Fprintf(e.Out, "Successfully stored account key for: %q.\n", email) } } return stackerr.Wrap(err) }
func GetLinkedHerokuAppConfig(app *parsecli.App, e *parsecli.Env) (bool, *parsecli.HerokuAppConfig, error) { h := &herokuLink{parseAppID: app.ApplicationID} apps, err := h.getAppLinks(e) if err != nil { return false, nil, err } if len(apps) == 0 { randomName := getRandomAppName(app) appName := randomName for i := 0; i < 3; i++ { if appName == randomName { fmt.Fprintf(e.Out, `Let's create a new Heroku app in which server code will be run. The Heroku app will be named: %q Note that this can be changed later using Heroku API or Dashboard. `, randomName, ) } else { appName = h.getHerokuAppName(e) } id, err := h.createNewLink(e, appName) if err == nil { return true, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: id, }, nil } if i == 2 { return false, nil, err } switch { case stackerr.HasUnderlying(err, stackerr.MatcherFunc(herokuAppNameTaken)): fmt.Fprintf(e.Err, "App name %s already taken.\nPlease try again...\n\n", appName) appName = "" case stackerr.HasUnderlying(err, stackerr.MatcherFunc(herokuAccountNotLinked)): fmt.Fprintf(e.Err, `Looks like you have not yet linked your Heroku Account to your Parse account. Trying to open %q in the browser. Please click "Link Heroku" button at the bottom. `, linkHerokuURL, ) appName = randomName err := open.Run(linkHerokuURL) if err != nil { fmt.Fprintf(e.Err, `Sorry, we couldn’t open the browser for you. Go to %q and click the "Link Heroku" button to link your Heroku account to Parse. `, linkHerokuURL, ) } fmt.Fprintf(e.Out, "Press ENTER when you are done linking your Heroku account to Parse: ") var discard string fmt.Fscanf(e.In, "%s\n", &discard) default: return false, nil, err } } } if len(apps) == 1 { return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: apps[0].id, }, nil } // NOTE: this part of code will not be used for now for r := 0; r < 3; r++ { selected, err := selectHerokuApp(apps, e) if err != nil { fmt.Fprintf(e.Err, "error: %s.\nPlease try again...\n", parsecli.ErrorString(e, err)) continue } if selected.id != "" { return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: selected.id, }, nil } id, err := h.createNewLink(e, selected.name) if err != nil { return false, nil, err } return false, &parsecli.HerokuAppConfig{ ParseAppID: app.ApplicationID, HerokuAppID: id, }, nil } return false, nil, stackerr.New("failed to selected an heroku app in 3 attempts") }
func (c *configureCmd) accountKey(e *parsecli.Env) error { token, err := c.login.HelpCreateToken(e) if err != nil { return err } email, err := c.login.AuthToken(e, token) if err != nil { fmt.Fprintln(e.Err, "Could not store credentials. Please try again.\n") return err } if c.isDefault { email = "" } var l parsecli.Login if c.tokenReader != nil { l.TokenReader = c.tokenReader } foundEmail, creds, err := l.GetTokenCredentials(e, email) firstEverConfigure := false if stackerr.HasUnderlying(err, stackerr.MatcherFunc(os.IsNotExist)) && !c.isDefault { firstEverConfigure = true } if creds != nil { if c.isDefault { fmt.Fprintln( e.Err, "Note: this operation will overwrite the default account key", ) } else if foundEmail { fmt.Fprintf( e.Err, `Note: this operation will overwrite the account key: %q for email: %q `, parsecli.Last4(token), email, ) } } err = c.login.StoreCredentials(e, email, &parsecli.Credentials{Token: token}) if err == nil { if c.isDefault { fmt.Fprintln(e.Out, "Successfully stored default account key.") } else { fmt.Fprintf(e.Out, "Successfully stored account key for: %q.\n", email) } } if err != nil { fmt.Fprintln(e.Err, "Could not save account key.") return stackerr.Wrap(err) } if firstEverConfigure { fmt.Fprintln( e.Out, ` Looks like this is the first time you have configured an account key. Note that "parse new" and "parse list" can automatically pick up a default key if present. Otherwise, you'll have to explicitly set the PARSER_EMAIL common.Environment variable for them to pick the correct account key. Further, if the command line tool cannot find an account key for a configured email it will try to use the default account key. Hence, we are automatically configuring the default account key to be the same as current account key. `, ) err = c.login.StoreCredentials(e, "", &parsecli.Credentials{Token: token}) if err != nil { fmt.Fprintln(e.Err, "Could not save account key.") return stackerr.Wrap(err) } fmt.Fprintln(e.Out, `Successfully configured the default account key. To change the default account key in future use: "parse configure accountkey -d" `) } return nil }