1
// Package bzr offers an interface to manage branches of the Bazaar VCS.
13
// Branch represents a Bazaar branch.
18
// New returns a new Branch for the Bazaar branch at location.
19
func New(location string) (*Branch, error) {
20
b := &Branch{location}
21
if _, err := os.Stat(location); err == nil {
22
stdout, _, err := b.bzr("root")
24
b.location = strings.TrimRight(string(stdout), "\n")
25
} else if !strings.Contains(err.Error(), "Not a branch") {
32
// Location returns the location of branch b.
33
func (b *Branch) Location() string {
37
// Join returns b's location with parts appended as path components.
38
// In other words, if b's location is "lp:foo", and parts is {"bar, baz"},
39
// Join returns "lp:foo/bar/baz".
40
func (b *Branch) Join(parts ...string) string {
41
return path.Join(append([]string{b.location}, parts...)...)
44
func (b *Branch) bzr(args ...string) (stdout, stderr []byte, err error) {
46
panic("no point in runing bzr without arguments here")
48
cmd := exec.Command("bzr", args...)
49
if _, err := os.Stat(b.location); err == nil {
52
errbuf := &bytes.Buffer{}
54
stdout, err = cmd.Output()
55
// Some commands fail with exit status 0 (e.g. bzr root). :-(
56
if err != nil || bytes.Contains(errbuf.Bytes(), []byte("ERROR")) {
61
return nil, nil, fmt.Errorf(`error running "bzr %s": %s%s%s`, args[0], stdout, errbuf.Bytes(), errmsg)
63
return stdout, errbuf.Bytes(), err
66
// Init intializes a new branch at b's location.
67
func (b *Branch) Init() error {
68
_, _, err := b.bzr("init", b.location)
72
// Add adds to b the path resultant from calling b.Join(parts...).
73
func (b *Branch) Add(parts ...string) error {
74
_, _, err := b.bzr("add", b.Join(parts...))
78
// Commit commits pending changes into b.
79
func (b *Branch) Commit(message string) error {
80
_, _, err := b.bzr("commit", "-q", "-m", message)
84
// RevisionId returns the Bazaar revision id for the tip of b.
85
func (b *Branch) RevisionId() (string, error) {
86
stdout, stderr, err := b.bzr("revision-info", "-d", b.location)
90
pair := bytes.Fields(stdout)
92
return "", fmt.Errorf(`invalid output from "bzr revision-info": %s%s`, stdout, stderr)
96
return "", fmt.Errorf("branch has no content")
101
// PushLocation returns the default push location for b.
102
func (b *Branch) PushLocation() (string, error) {
103
stdout, _, err := b.bzr("info", b.location)
107
if i := bytes.Index(stdout, []byte("push branch:")); i >= 0 {
108
return string(stdout[i+13 : i+bytes.IndexAny(stdout[i:], "\r\n")]), nil
110
return "", fmt.Errorf("no push branch location defined")
113
// PushAttr holds options for the Branch.Push method.
114
type PushAttr struct {
115
Location string // Location to push to. Use the default push location if empty.
116
Remember bool // Whether to remember the location being pushed to as the default.
119
// Push pushes any new revisions in b to attr.Location if that's
120
// provided, or to the default push location otherwise.
121
// See PushAttr for other options.
122
func (b *Branch) Push(attr *PushAttr) error {
123
args := []string{"push"}
126
args = append(args, "--remember")
128
if attr.Location != "" {
129
args = append(args, attr.Location)
132
_, _, err := b.bzr(args...)