func (s *copydataSuite) populateData(c *C, revision snap.Revision) { datadir := filepath.Join(dirs.SnapDataDir, "hello", revision.String()) subdir := filepath.Join(datadir, "random-subdir") err := os.MkdirAll(subdir, 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(filepath.Join(subdir, "canary"), []byte(fmt.Sprintln(revision)), 0644) c.Assert(err, IsNil) }
func (s copydataSuite) populateHomeData(c *C, user string, revision snap.Revision) (homedir string) { homedir = filepath.Join(s.tempdir, "home", user, "snap") homeData := filepath.Join(homedir, "hello", revision.String()) err := os.MkdirAll(homeData, 0755) c.Assert(err, IsNil) err = ioutil.WriteFile(filepath.Join(homeData, "canary.home"), []byte(fmt.Sprintln(revision)), 0644) c.Assert(err, IsNil) return }
// Info returns the information about the snap with given name and revision. // Works also for a mounted candidate snap in the process of being installed. func Info(s *state.State, name string, revision snap.Revision) (*snap.Info, error) { var snapst SnapState err := Get(s, name, &snapst) if err == state.ErrNoState { return nil, fmt.Errorf("cannot find snap %q", name) } if err != nil { return nil, err } for i := len(snapst.Sequence) - 1; i >= 0; i-- { if si := snapst.Sequence[i]; si.Revision == revision { return readInfo(name, si) } } return nil, fmt.Errorf("cannot find snap %q at revision %s", name, revision.String()) }
func runHookAndWait(snapName string, revision snap.Revision, hookName, hookContext string, tomb *tomb.Tomb) ([]byte, error) { command := exec.Command("snap", "run", "--hook", hookName, "-r", revision.String(), snapName) // Make sure the hook has its context defined so it can communicate via the // REST API. command.Env = append(os.Environ(), fmt.Sprintf("SNAP_CONTEXT=%s", hookContext)) // Make sure we can obtain stdout and stderror. Same buffer so they're // combined. buffer := bytes.NewBuffer(nil) command.Stdout = buffer command.Stderr = buffer // Actually run the hook. if err := command.Start(); err != nil { return nil, err } hookCompleted := make(chan struct{}) var hookError error go func() { // Wait for hook to complete hookError = command.Wait() close(hookCompleted) }() select { // Hook completed; it may or may not have been successful. case <-hookCompleted: return buffer.Bytes(), hookError // Hook was aborted. case <-tomb.Dying(): if err := command.Process.Kill(); err != nil { return nil, fmt.Errorf("cannot abort hook %q: %s", hookName, err) } return nil, fmt.Errorf("hook %q aborted", hookName) } }
// Snap returns the snap.Info for the store hosted snap with the given name or an error. func (s *Store) Snap(name, channel string, devmode bool, revision snap.Revision, user *auth.UserState) (*snap.Info, error) { u, err := s.detailsURI.Parse(name) if err != nil { return nil, err } query := u.Query() query.Set("channel", channel) if !revision.Unset() { query.Set("revision", revision.String()) query.Set("channel", "") } // if devmode then don't restrict by confinement as either is fine // XXX: what we really want to do is have the store not specify // devmode, and have the business logic wrt what to do with // unwanted devmode further up if !devmode { query.Set("confinement", string(snap.StrictConfinement)) } u.RawQuery = query.Encode() reqOptions := &requestOptions{ Method: "GET", URL: u, Accept: halJsonContentType, } var remote snapDetails resp, err := s.retryRequestDecodeJSON(context.TODO(), s.client, reqOptions, user, &remote, nil) if err != nil { return nil, err } // check statusCode switch resp.StatusCode { case http.StatusOK: // OK case http.StatusNotFound: return nil, ErrSnapNotFound default: msg := fmt.Sprintf("get details for snap %q in channel %q", name, channel) return nil, respToError(resp, msg) } info := infoFromRemote(remote) // only get the channels when it makes sense as part of the reply if info.SnapID != "" && channel == "" && revision.Unset() { channels, err := s.fakeChannels(info.SnapID, user) if err != nil { logger.Noticef("cannot get channels: %v", err) } else { info.Channels = channels } } err = s.decorateOrders([]*snap.Info{info}, channel, user) if err != nil { logger.Noticef("cannot get user orders: %v", err) } s.extractSuggestedCurrency(resp) return info, nil }
// Snap returns the snap.Info for the store hosted snap with the given name or an error. func (s *Store) Snap(name, channel string, devmode bool, revision snap.Revision, user *auth.UserState) (*snap.Info, error) { u, err := s.detailsURI.Parse(name) if err != nil { return nil, err } query := u.Query() if !revision.Unset() { query.Set("revision", revision.String()) query.Set("channel", "") // sidestep the channel map } else if channel != "" { query.Set("channel", channel) } // if devmode then don't restrict by confinement as either is fine // XXX: what we really want to do is have the store not specify // devmode, and have the business logic wrt what to do with // unwanted devmode further up if !devmode { query.Set("confinement", string(snap.StrictConfinement)) } u.RawQuery = query.Encode() reqOptions := &requestOptions{ Method: "GET", URL: u, Accept: halJsonContentType, } resp, err := s.doRequest(s.client, reqOptions, user) if err != nil { return nil, err } defer resp.Body.Close() // check statusCode switch resp.StatusCode { case http.StatusOK: // OK case http.StatusNotFound: return nil, ErrSnapNotFound default: msg := fmt.Sprintf("get details for snap %q in channel %q", name, channel) return nil, respToError(resp, msg) } // and decode json var remote snapDetails dec := json.NewDecoder(resp.Body) if err := dec.Decode(&remote); err != nil { return nil, err } info := infoFromRemote(remote) err = s.decorateOrders([]*snap.Info{info}, channel, user) if err != nil { logger.Noticef("cannot get user orders: %v", err) } s.extractSuggestedCurrency(resp) return info, nil }