Beispiel #1
0
func (s *BzrSuite) TestPush(c *gc.C) {
	b1 := bzr.New(c.MkDir())
	b2 := bzr.New(c.MkDir())
	b3 := bzr.New(c.MkDir())
	c.Assert(b1.Init(), gc.IsNil)
	c.Assert(b2.Init(), gc.IsNil)
	c.Assert(b3.Init(), gc.IsNil)

	// Create and add b1/file to the branch.
	f, err := os.Create(b1.Join("file"))
	c.Assert(err, gc.IsNil)
	f.Close()
	err = b1.Add("file")
	c.Assert(err, gc.IsNil)
	err = b1.Commit("added file")
	c.Assert(err, gc.IsNil)

	// Push file to b2.
	err = b1.Push(&bzr.PushAttr{Location: b2.Location()})
	c.Assert(err, gc.IsNil)

	// Push location should be set to b2.
	location, err := b1.PushLocation()
	c.Assert(err, gc.IsNil)
	c.Assert(location, gc.Equals, b2.Location())

	// Now push it to b3.
	err = b1.Push(&bzr.PushAttr{Location: b3.Location()})
	c.Assert(err, gc.IsNil)

	// Push location is still set to b2.
	location, err = b1.PushLocation()
	c.Assert(err, gc.IsNil)
	c.Assert(location, gc.Equals, b2.Location())

	// Push it again, this time with the remember flag set.
	err = b1.Push(&bzr.PushAttr{Location: b3.Location(), Remember: true})
	c.Assert(err, gc.IsNil)

	// Now the push location has shifted to b3.
	location, err = b1.PushLocation()
	c.Assert(err, gc.IsNil)
	c.Assert(location, gc.Equals, b3.Location())

	// Both b2 and b3 should have the file.
	_, err = os.Stat(b2.Join("file"))
	c.Assert(err, gc.IsNil)
	_, err = os.Stat(b3.Join("file"))
	c.Assert(err, gc.IsNil)
}
Beispiel #2
0
func (s *PublishSuite) TestFullPublish(c *gc.C) {
	addMeta(c, s.branch, "")

	digest, err := s.branch.RevisionId()
	c.Assert(err, gc.IsNil)

	pushBranch := bzr.New(c.MkDir())
	err = pushBranch.Init()
	c.Assert(err, gc.IsNil)

	cmd := &PublishCommand{}
	cmd.ChangePushLocation(func(location string) string {
		c.Assert(location, gc.Equals, "lp:~user/charms/precise/wordpress/trunk")
		return pushBranch.Location()
	})
	cmd.SetPollDelay(testing.ShortWait)

	var body string

	// The local digest isn't found.
	body = `{"cs:~user/precise/wordpress": {"kind": "", "errors": ["entry not found"]}}`
	testing.Server.Response(200, nil, []byte(body))

	// But the charm exists with an arbitrary non-matching digest.
	body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "other-digest"}}`
	testing.Server.Response(200, nil, []byte(body))

	// After the branch is pushed we fake the publishing delay.
	body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "other-digest"}}`
	testing.Server.Response(200, nil, []byte(body))

	// And finally report success.
	body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": %q, "revision": 42}}`
	testing.Server.Response(200, nil, []byte(fmt.Sprintf(body, digest)))

	ctx, err := testing.RunCommandInDir(c, cmd, []string{"cs:~user/precise/wordpress"}, s.dir)
	c.Assert(err, gc.IsNil)
	c.Assert(testing.Stdout(ctx), gc.Equals, "cs:~user/precise/wordpress-42\n")

	// Ensure the branch was actually pushed.
	pushDigest, err := pushBranch.RevisionId()
	c.Assert(err, gc.IsNil)
	c.Assert(pushDigest, gc.Equals, digest)

	// And that all the requests were sent with the proper data.
	req := testing.Server.WaitRequest()
	c.Assert(req.URL.Path, gc.Equals, "/charm-event")
	c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress@"+digest)

	for i := 0; i < 3; i++ {
		// The second request grabs tip to see the current state, and the
		// following requests are done after pushing to see when it changes.
		req = testing.Server.WaitRequest()
		c.Assert(req.URL.Path, gc.Equals, "/charm-event")
		c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress")
	}
}
Beispiel #3
0
func (s *BzrSuite) TestNewFindsRoot(c *gc.C) {
	err := os.Mkdir(s.b.Join("dir"), 0755)
	c.Assert(err, gc.IsNil)
	b := bzr.New(s.b.Join("dir"))
	// When bzr has to search for the root, it will expand any symlinks it
	// found along the way.
	path, err := filepath.EvalSymlinks(s.b.Location())
	c.Assert(err, gc.IsNil)
	c.Assert(b.Location(), gc.Equals, path)
}
Beispiel #4
0
func (s *PublishSuite) TestFullPublishRace(c *gc.C) {
	addMeta(c, s.branch, "")

	digest, err := s.branch.RevisionId()
	c.Assert(err, gc.IsNil)

	pushBranch := bzr.New(c.MkDir())
	err = pushBranch.Init()
	c.Assert(err, gc.IsNil)

	cmd := &PublishCommand{}
	cmd.ChangePushLocation(func(location string) string {
		c.Assert(location, gc.Equals, "lp:~user/charms/precise/wordpress/trunk")
		return pushBranch.Location()
	})
	cmd.SetPollDelay(pollDelay)

	var body string

	// The local digest isn't found.
	body = `{"cs:~user/precise/wordpress": {"kind": "", "errors": ["entry not found"]}}`
	testing.Server.Response(200, nil, []byte(body))

	// And tip isn't found either, meaning the charm was never published.
	testing.Server.Response(200, nil, []byte(body))

	// After the branch is pushed we fake the publishing delay.
	testing.Server.Response(200, nil, []byte(body))

	// But, surprisingly, the digest changed to something else entirely.
	body = `{"cs:~user/precise/wordpress": {"kind": "published", "digest": "surprising-digest", "revision": 42}}`
	testing.Server.Response(200, nil, []byte(body))

	_, err = testing.RunCommandInDir(c, cmd, []string{"cs:~user/precise/wordpress"}, s.dir)
	c.Assert(err, gc.ErrorMatches, `charm changed but not to local charm digest; publishing race\?`)

	// Ensure the branch was actually pushed.
	pushDigest, err := pushBranch.RevisionId()
	c.Assert(err, gc.IsNil)
	c.Assert(pushDigest, gc.Equals, digest)

	// And that all the requests were sent with the proper data.
	req := testing.Server.WaitRequest()
	c.Assert(req.URL.Path, gc.Equals, "/charm-event")
	c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress@"+digest)

	for i := 0; i < 3; i++ {
		// The second request grabs tip to see the current state, and the
		// following requests are done after pushing to see when it changes.
		req = testing.Server.WaitRequest()
		c.Assert(req.URL.Path, gc.Equals, "/charm-event")
		c.Assert(req.Form.Get("charms"), gc.Equals, "cs:~user/precise/wordpress")
	}
}
Beispiel #5
0
func (s *BzrSuite) SetUpTest(c *gc.C) {
	s.LoggingSuite.SetUpTest(c)
	bzrdir := c.MkDir()
	s.PatchEnvironment("BZR_HOME", bzrdir)
	err := os.Mkdir(filepath.Join(bzrdir, ".bazaar"), 0755)
	c.Assert(err, gc.IsNil)
	err = ioutil.WriteFile(
		filepath.Join(bzrdir, ".bazaar", "bazaar.conf"),
		[]byte(bzr_config), 0644)
	c.Assert(err, gc.IsNil)
	s.b = bzr.New(c.MkDir())
	c.Assert(s.b.Init(), gc.IsNil)
}
Beispiel #6
0
func (s *PublishSuite) SetUpTest(c *gc.C) {
	s.LoggingSuite.SetUpTest(c)
	s.HTTPSuite.SetUpTest(c)
	s.home = testing.MakeSampleHome(c, testing.TestFile{
		Name: ".bazaar/bazaar.conf",
		Data: "[DEFAULT]\nemail = Test <*****@*****.**>\n",
	})

	s.dir = c.MkDir()
	s.branch = bzr.New(s.dir)
	err := s.branch.Init()
	c.Assert(err, gc.IsNil)
}
Beispiel #7
0
func (s *BzrSuite) TestErrorHandling(c *gc.C) {
	err := bzr.New("/non/existent/path").Init()
	c.Assert(err, gc.ErrorMatches, `(?s)error running "bzr init":.*does not exist.*`)
}
Beispiel #8
0
func (s *BzrSuite) TestJoin(c *gc.C) {
	path := bzr.New("lp:foo").Join("baz", "bar")
	c.Assert(path, gc.Equals, "lp:foo/baz/bar")
}
Beispiel #9
0
func (c *PublishCommand) Run(ctx *cmd.Context) (err error) {
	branch := bzr.New(ctx.AbsPath(c.CharmPath))
	if _, err := os.Stat(branch.Join(".bzr")); err != nil {
		return fmt.Errorf("not a charm branch: %s", branch.Location())
	}
	if err := branch.CheckClean(); err != nil {
		return err
	}

	var curl *charm.URL
	if c.URL == "" {
		if err == nil {
			loc, err := branch.PushLocation()
			if err != nil {
				return fmt.Errorf("no charm URL provided and cannot infer from current directory (no push location)")
			}
			curl, err = charm.Store.CharmURL(loc)
			if err != nil {
				return fmt.Errorf("cannot infer charm URL from branch location: %q", loc)
			}
		}
	} else {
		curl, err = charm.InferURL(c.URL, "")
		if err != nil {
			return err
		}
	}

	pushLocation := charm.Store.BranchLocation(curl)
	if c.changePushLocation != nil {
		pushLocation = c.changePushLocation(pushLocation)
	}

	repo, err := charm.InferRepository(curl.Reference, "/not/important")
	if err != nil {
		return err
	}
	if repo != charm.Store {
		return fmt.Errorf("charm URL must reference the juju charm store")
	}

	localDigest, err := branch.RevisionId()
	if err != nil {
		return fmt.Errorf("cannot obtain local digest: %v", err)
	}
	logger.Infof("local digest is %s", localDigest)

	ch, err := charm.ReadDir(branch.Location())
	if err != nil {
		return err
	}
	if ch.Meta().Name != curl.Name {
		return fmt.Errorf("charm name in metadata must match name in URL: %q != %q", ch.Meta().Name, curl.Name)
	}

	oldEvent, err := charm.Store.Event(curl, localDigest)
	if _, ok := err.(*charm.NotFoundError); ok {
		oldEvent, err = charm.Store.Event(curl, "")
		if _, ok := err.(*charm.NotFoundError); ok {
			logger.Infof("charm %s is not yet in the store", curl)
			err = nil
		}
	}
	if err != nil {
		return fmt.Errorf("cannot obtain event details from the store: %s", err)
	}

	if oldEvent != nil && oldEvent.Digest == localDigest {
		return handleEvent(ctx, curl, oldEvent)
	}

	logger.Infof("sending charm to the charm store...")

	err = branch.Push(&bzr.PushAttr{Location: pushLocation, Remember: true})
	if err != nil {
		return err
	}
	logger.Infof("charm sent; waiting for it to be published...")
	for {
		time.Sleep(c.pollDelay)
		newEvent, err := charm.Store.Event(curl, "")
		if _, ok := err.(*charm.NotFoundError); ok {
			continue
		}
		if err != nil {
			return fmt.Errorf("cannot obtain event details from the store: %s", err)
		}
		if oldEvent != nil && oldEvent.Digest == newEvent.Digest {
			continue
		}
		if newEvent.Digest != localDigest {
			// TODO Check if the published digest is in the local history.
			return fmt.Errorf("charm changed but not to local charm digest; publishing race?")
		}
		return handleEvent(ctx, curl, newEvent)
	}
}