예제 #1
0
func (s *SnapTestSuite) TestLocalSnapSimple(c *C) {
	snapYaml, err := s.makeInstalledMockSnap()
	c.Assert(err, IsNil)

	snap, err := NewInstalledSnapPart(snapYaml, testOrigin)
	c.Assert(err, IsNil)
	c.Assert(snap, NotNil)
	c.Check(snap.Name(), Equals, "hello-app")
	c.Check(snap.Version(), Equals, "1.10")
	c.Check(snap.IsActive(), Equals, false)
	c.Check(snap.Description(), Equals, "Hello")
	c.Check(snap.IsInstalled(), Equals, true)

	services := snap.ServiceYamls()
	c.Assert(services, HasLen, 1)
	c.Assert(services[0].Name, Equals, "svc1")

	// ensure we get valid Date()
	st, err := os.Stat(snap.basedir)
	c.Assert(err, IsNil)
	c.Assert(snap.Date(), Equals, st.ModTime())

	c.Assert(snap.basedir, Equals, filepath.Join(s.tempdir, "snaps", helloAppComposedName, "1.10"))
	c.Assert(snap.InstalledSize(), Not(Equals), -1)
}
예제 #2
0
func (s *SnapTestSuite) TestServicesWithPorts(c *C) {
	const packageHello = `name: hello-app
version: 1.10
icon: meta/hello.svg
binaries:
 - name: bin/hello
services:
 - name: svc1
   description: "Service #1"
   ports:
      external:
        ui:
          port: 8080/tcp
        nothing:
          port: 8081/tcp
          negotiable: yes
 - name: svc2
   description: "Service #2"
`

	yamlFile, err := makeInstalledMockSnap(s.tempdir, packageHello)
	c.Assert(err, IsNil)

	snap, err := NewInstalledSnapPart(yamlFile, testOrigin)
	c.Assert(err, IsNil)
	c.Assert(snap, NotNil)

	c.Assert(snap.Name(), Equals, "hello-app")
	c.Assert(snap.Origin(), Equals, testOrigin)
	c.Assert(snap.Version(), Equals, "1.10")
	c.Assert(snap.IsActive(), Equals, false)

	services := snap.ServiceYamls()
	c.Assert(services, HasLen, 2)

	c.Assert(services[0].Name, Equals, "svc1")
	c.Assert(services[0].Description, Equals, "Service #1")

	external1Ui, ok := services[0].Ports.External["ui"]
	c.Assert(ok, Equals, true)
	c.Assert(external1Ui.Port, Equals, "8080/tcp")
	c.Assert(external1Ui.Negotiable, Equals, false)

	external1Nothing, ok := services[0].Ports.External["nothing"]
	c.Assert(ok, Equals, true)
	c.Assert(external1Nothing.Port, Equals, "8081/tcp")
	c.Assert(external1Nothing.Negotiable, Equals, true)

	c.Assert(services[1].Name, Equals, "svc2")
	c.Assert(services[1].Description, Equals, "Service #2")

	// ensure we get valid Date()
	st, err := os.Stat(snap.basedir)
	c.Assert(err, IsNil)
	c.Assert(snap.Date(), Equals, st.ModTime())

	c.Assert(snap.basedir, Equals, filepath.Join(s.tempdir, "snaps", helloAppComposedName, "1.10"))
	c.Assert(snap.InstalledSize(), Not(Equals), -1)
}
예제 #3
0
파일: install.go 프로젝트: dholbach/snappy
func doInstall(name, channel string, flags InstallFlags, meter progress.Meter) (snapName string, err error) {
	defer func() {
		if err != nil {
			err = &ErrInstallFailed{Snap: name, OrigErr: err}
		}
	}()

	// consume local snaps
	if fi, err := os.Stat(name); err == nil && fi.Mode().IsRegular() {
		// we allow unauthenticated package when in developer
		// mode
		if provisioning.InDeveloperMode() {
			flags |= AllowUnauthenticated
		}

		snap, err := (&Overlord{}).Install(name, flags, meter)
		if err != nil {
			return "", err
		}

		return snap.Name(), nil
	}

	// check repos next
	mStore := NewConfiguredUbuntuStoreSnapRepository()
	installed, err := (&Overlord{}).Installed()
	if err != nil {
		return "", err
	}

	snap, err := mStore.Snap(name, channel, nil)
	if err != nil {
		return "", err
	}

	cur := FindSnapsByNameAndVersion(snap.Name(), snap.Version, installed)
	if len(cur) != 0 {
		return "", ErrAlreadyInstalled
	}
	if PackageNameActive(snap.Name()) {
		return "", ErrPackageNameAlreadyInstalled
	}

	return installRemote(mStore, snap, flags, meter)
}
예제 #4
0
// Search searches the repository for the given searchTerm
func (s *SnapUbuntuStoreRepository) Search(searchTerm string) (SharedNames, error) {
	u := *s.searchURI // make a copy, so we can mutate it
	q := u.Query()
	q.Set("q", searchTerm)
	u.RawQuery = q.Encode()
	req, err := http.NewRequest("GET", u.String(), nil)
	if err != nil {
		return nil, err
	}

	// set headers
	setUbuntuStoreHeaders(req)

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var searchData searchResults

	dec := json.NewDecoder(resp.Body)
	if err := dec.Decode(&searchData); err != nil {
		return nil, err
	}

	sharedNames := make(SharedNames, len(searchData.Payload.Packages))
	for _, pkg := range searchData.Payload.Packages {
		snap := NewRemoteSnapPart(pkg)
		pkgName := snap.Name()

		if _, ok := sharedNames[snap.Name()]; !ok {
			sharedNames[pkgName] = new(SharedName)
		}

		sharedNames[pkgName].Parts = append(sharedNames[pkgName].Parts, snap)
		if pkg.Alias != "" {
			sharedNames[pkgName].Alias = snap
		}
	}

	return sharedNames, nil
}
예제 #5
0
파일: info.go 프로젝트: dholbach/snappy
// FindSnapsByName returns all snaps with the given name in the "haystack"
// slice of snaps (useful for filtering)
func FindSnapsByName(needle string, haystack []*Snap) (res []*Snap) {
	name, developer := SplitDeveloper(needle)
	ignorens := developer == ""

	for _, snap := range haystack {
		if snap.Name() == name && (ignorens || snap.Developer() == developer) {
			res = append(res, snap)
		}
	}

	return res
}
예제 #6
0
파일: info.go 프로젝트: dholbach/snappy
// FindSnapsByNameAndRevision returns the snaps with the name/version in the
// given slice of snaps
func FindSnapsByNameAndRevision(needle string, revision int, haystack []*Snap) []*Snap {
	name, developer := SplitDeveloper(needle)
	ignorens := developer == ""
	var found []*Snap

	for _, snap := range haystack {
		if snap.Name() == name && snap.Revision() == revision && (ignorens || snap.Developer() == developer) {
			found = append(found, snap)
		}
	}

	return found
}
예제 #7
0
func (s *SnapTestSuite) TestLocalSnapInstallWithBlessedMetadataOverridingName(c *C) {
	snapPath := makeTestSnapPackage(c, "")

	si := &snap.SideInfo{
		OfficialName: "bar",
		Revision:     55,
	}

	snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
	c.Assert(err, IsNil)
	c.Check(snap.Name(), Equals, "bar")
	c.Check(snap.Revision, Equals, 55)

	baseDir := filepath.Join(dirs.SnapSnapsDir, "bar", "55")
	c.Assert(osutil.FileExists(baseDir), Equals, true)
}
예제 #8
0
파일: info.go 프로젝트: dholbach/snappy
// ActiveSnapByName returns all active snaps with the given name
func ActiveSnapByName(needle string) *Snap {
	installed, err := (&Overlord{}).Installed()
	if err != nil {
		return nil
	}
	for _, snap := range installed {
		if !snap.IsActive() {
			continue
		}
		if snap.Name() == needle {
			return snap
		}
	}

	return nil
}
예제 #9
0
파일: install.go 프로젝트: dholbach/snappy
// FIXME: This needs to go (and will go). We will have something
//        like:
//           remoteSnapType = GetUpdatesFromServer()
//           localSnapType = DoUpdate(remoteSnaps)
//           ShowUpdates(localSnaps)
//        By using the different types (instead of the same interface)
//        it will not be possilbe to pass remote snaps into the
//        ShowUpdates() output.
//
//
// convertToInstalledSnaps takes a slice of remote snaps that got
// updated and returns the corresponding local snaps
func convertToInstalledSnaps(remoteUpdates []*snap.Info) ([]*Snap, error) {
	installed, err := (&Overlord{}).Installed()
	if err != nil {
		return nil, err
	}

	installedUpdates := make([]*Snap, 0, len(remoteUpdates))
	for _, snap := range remoteUpdates {
		for _, installed := range installed {
			if snap.Name() == installed.Name() && snap.Version == installed.Version() {
				installedUpdates = append(installedUpdates, installed)
			}
		}
	}

	return installedUpdates, nil
}
예제 #10
0
func (s *SnapTestSuite) TestLocalSnapInstall(c *C) string {
	snapPath := makeTestSnapPackage(c, "")
	// revision will be 0
	snap, err := (&Overlord{}).Install(snapPath, 0, nil)
	c.Assert(err, IsNil)
	c.Check(snap.Name(), Equals, "foo")

	baseDir := filepath.Join(dirs.SnapSnapsDir, fooComposedName, "0")
	c.Assert(osutil.FileExists(baseDir), Equals, true)

	snapEntries := listDir(c, filepath.Join(dirs.SnapSnapsDir, fooComposedName))
	c.Check(snapEntries, DeepEquals, []string{"0", "current"})

	snapDataEntries := listDir(c, filepath.Join(dirs.SnapDataDir, fooComposedName))
	c.Check(snapDataEntries, DeepEquals, []string{"0", "current"})

	return snapPath
}
예제 #11
0
func (s *SnapTestSuite) TestServicesWithPorts(c *C) {
	const packageHello = `name: hello-snap
version: 1.10
apps:
 hello:
  command: bin/hello
 svc1:
   command: svc1
   type: forking
   description: "Service #1"
   ports:
      external:
        ui:
          port: 8080/tcp
        nothing:
          port: 8081/tcp
          negotiable: yes
 svc2:
   command: svc2
   type: forking
   description: "Service #2"
`

	yamlFile, err := makeInstalledMockSnap(packageHello, 11)
	c.Assert(err, IsNil)

	snap, err := NewInstalledSnap(yamlFile)
	c.Assert(err, IsNil)
	c.Assert(snap, NotNil)

	c.Assert(snap.Name(), Equals, "hello-snap")
	c.Assert(snap.Developer(), Equals, testDeveloper)
	c.Assert(snap.Version(), Equals, "1.10")
	c.Assert(snap.IsActive(), Equals, false)

	apps := snap.Info().Apps
	c.Assert(apps, HasLen, 3)

	c.Assert(apps["svc1"].Name, Equals, "svc1")

	c.Assert(apps["svc2"].Name, Equals, "svc2")
}
예제 #12
0
func (s *SnapTestSuite) TestLocalSnapSimple(c *C) {
	snapYaml, err := makeInstalledMockSnap("", 15)
	c.Assert(err, IsNil)

	snap, err := NewInstalledSnap(snapYaml)
	c.Assert(err, IsNil)
	c.Assert(snap, NotNil)
	c.Check(snap.Name(), Equals, "hello-snap")
	c.Check(snap.Version(), Equals, "1.10")
	c.Check(snap.IsActive(), Equals, false)
	c.Check(snap.Info().Summary(), Equals, "hello in summary")
	c.Check(snap.Info().Description(), Equals, "Hello...")
	c.Check(snap.Info().Revision, Equals, 15)

	mountDir := snap.Info().MountDir()
	_, err = os.Stat(mountDir)
	c.Assert(err, IsNil)

	c.Assert(mountDir, Equals, filepath.Join(dirs.SnapSnapsDir, helloSnapComposedName, "15"))
}
예제 #13
0
파일: install.go 프로젝트: dholbach/snappy
// UpdateAll the installed snappy packages, it returns the updated Snaps
// if updates where available and an error and nil if any of the updates
// fail to apply.
func UpdateAll(flags InstallFlags, meter progress.Meter) ([]*Snap, error) {
	mStore := NewConfiguredUbuntuStoreSnapRepository()
	updates, err := snapUpdates(mStore)
	if err != nil {
		return nil, err
	}

	for _, snap := range updates {
		meter.Notify(fmt.Sprintf("Updating %s (%s)", snap.Name(), snap.Version))
		if err := doUpdate(mStore, snap, flags, meter); err != nil {
			return nil, err
		}
	}

	installedUpdates, err := convertToInstalledSnaps(updates)
	if err != nil {
		return nil, err
	}

	return installedUpdates, nil
}
예제 #14
0
func (s *SnapTestSuite) TestLocalSnapInstallWithBlessedMetadata(c *C) {
	snapPath := makeTestSnapPackage(c, "")

	si := &snap.SideInfo{
		OfficialName: "foo",
		Revision:     40,
	}

	snap, err := (&Overlord{}).InstallWithSideInfo(snapPath, si, 0, nil)
	c.Assert(err, IsNil)
	c.Check(snap.Name(), Equals, "foo")
	c.Check(snap.Revision, Equals, 40)

	baseDir := filepath.Join(dirs.SnapSnapsDir, fooComposedName, "40")
	c.Assert(osutil.FileExists(baseDir), Equals, true)

	snapEntries := listDir(c, filepath.Join(dirs.SnapSnapsDir, fooComposedName))
	c.Check(snapEntries, DeepEquals, []string{"40", "current"})

	snapDataEntries := listDir(c, filepath.Join(dirs.SnapDataDir, fooComposedName))
	c.Check(snapDataEntries, DeepEquals, []string{"40", "current"})
}
예제 #15
0
func (s *SquashfsTestSuite) TestName(c *C) {
	snap := New("/path/to/foo.snap")
	c.Assert(snap.Name(), Equals, "foo.snap")
}
예제 #16
0
파일: api.go 프로젝트: dholbach/snappy
// plural!
func getSnapsInfo(c *Command, r *http.Request) Response {
	route := c.d.router.Get(snapCmd.Path)
	if route == nil {
		return InternalError("router can't find route for snaps")
	}

	sources := make([]string, 0, 2)
	query := r.URL.Query()

	var includeStore, includeLocal bool
	if len(query["sources"]) > 0 {
		for _, v := range strings.Split(query["sources"][0], ",") {
			if v == "store" {
				includeStore = true
			} else if v == "local" {
				includeLocal = true
			}
		}
	} else {
		includeStore = true
		includeLocal = true
	}

	searchTerm := query.Get("q")

	var includeTypes []string
	if len(query["types"]) > 0 {
		includeTypes = strings.Split(query["types"][0], ",")
	}

	var aboutSnaps []aboutSnap
	var remoteSnapMap map[string]*snap.Info

	if includeLocal {
		sources = append(sources, "local")
		aboutSnaps, _ = allLocalSnapInfos(c.d.overlord.State())
	}

	var suggestedCurrency string

	if includeStore {
		remoteSnapMap = make(map[string]*snap.Info)

		remoteRepo := newRemoteRepo()

		auther, err := c.d.auther(r)
		if err != nil && err != auth.ErrInvalidAuth {
			return InternalError("%v", err)
		}

		// repo.Find("") finds all
		//
		// TODO: Instead of ignoring the error from Find:
		//   * if there are no results, return an error response.
		//   * If there are results at all (perhaps local), include a
		//     warning in the response
		found, _ := remoteRepo.FindSnaps(searchTerm, "", auther)
		suggestedCurrency = remoteRepo.SuggestedCurrency()

		sources = append(sources, "store")

		for _, snap := range found {
			remoteSnapMap[snap.Name()] = snap
		}
	}

	seen := make(map[string]bool)
	results := make([]*json.RawMessage, 0, len(aboutSnaps)+len(remoteSnapMap))

	addResult := func(name string, m map[string]interface{}) {
		if seen[name] {
			return
		}
		seen[name] = true

		// TODO Search the store for "content" with multiple values. See:
		//      https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex#Search
		if len(includeTypes) > 0 && !resultHasType(m, includeTypes) {
			return
		}

		resource := ""
		url, err := route.URL("name", name)
		if err == nil {
			resource = url.String()
		}

		data, err := json.Marshal(webify(m, resource))
		if err != nil {
			return
		}
		raw := json.RawMessage(data)
		results = append(results, &raw)
	}

	for _, about := range aboutSnaps {
		info := about.info
		name := info.Name()
		// strings.Contains(name, "") is true
		if strings.Contains(name, searchTerm) {
			active := about.snapst.Active
			addResult(name, mapSnap(info, active, remoteSnapMap[name]))
		}
	}

	for name, remoteSnap := range remoteSnapMap {
		addResult(name, mapSnap(nil, false, remoteSnap))
	}

	meta := &Meta{
		Sources: sources,
		Paging: &Paging{
			Page:  1,
			Pages: 1,
		},
		SuggestedCurrency: suggestedCurrency,
	}
	return SyncResponse(results, meta)
}