Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions internal/p4/depot.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ import (
"strings"
)

func (p *P4) GetDepotSpec(name string) (map[string]string, error) {
var sb strings.Builder
sb.Grow(1024)
err := p.sh.Cmdf(`%s -z tag depot -o %s`, p.cmd(), name).Out(&sb).RunErr()
if err != nil {
return nil, fmt.Errorf("error getting depot %s: %w", name, err)
}
return ParseSpec(sb.String()), nil
}

// CreateStreamDepot creates a depot with type "stream".
func (p *P4) CreateStreamDepot(name string) error {
// generate a depot spec
Expand Down
82 changes: 63 additions & 19 deletions internal/p4/p4.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package p4

import (
"bufio"
"errors"
"fmt"
"io"
"os"
Expand All @@ -22,7 +23,6 @@ type P4 struct {
sh *bsh.Bsh

streamMutex sync.Mutex
streamNameCache string // read/write requires mutex lock
streamDepthCache int // read/write requires mutex lock
}

Expand All @@ -44,42 +44,71 @@ func (p *P4) DisplayName() string {
func (p *P4) SetStreamName(stream string) error {
p.streamMutex.Lock()
defer p.streamMutex.Unlock()
depth, err := streamDepth(stream)
p.streamDepthCache = 0
return nil
}

func (p *P4) Depot() (string, error) {
spec, err := p.GetClientSpec()
if err != nil {
return err
return "", fmt.Errorf("error getting depot: %w", err)
}
p.streamNameCache = stream
p.streamDepthCache = depth
return nil

stream, exists := spec["Stream"]
if exists && len(stream) > 3 {
depotName, err := getDepotName(stream)
if err != nil {
return "", fmt.Errorf("error getting depot from stream %s: %w", stream, err)
}
return depotName, nil
}

for key, value := range spec {
if !strings.HasPrefix(key, "View") {
continue
}

depotName, err := getDepotName(value)
if err != nil {
return "", fmt.Errorf("error getting depot from mapping %s: %w", value, err)
}
return depotName, nil
}

return "", errors.New("could not find any View or Stream entries in client spec")
}

func (p *P4) StreamInfo() (string, int, error) {
func (p *P4) StreamDepth() (int, error) {
p.streamMutex.Lock()
defer p.streamMutex.Unlock()

if len(p.streamNameCache) > 0 {
return p.streamNameCache, p.streamDepthCache, nil
if p.streamDepthCache > 0 {
return p.streamDepthCache, nil
}

spec, err := p.GetClientSpec()
depot, err := p.Depot()
if err != nil {
return "", 0, fmt.Errorf("error getting stream name: %w", err)
return 0, err
}

stream, exists := spec["Stream"]
if !exists || len(stream) == 0 {
return "", 0, fmt.Errorf("client spec does not include Stream field")
depotSpec, err := p.GetDepotSpec(depot)
if err != nil {
return 0, err
}

depotDepthPath, exists := depotSpec["StreamDepth"]
if !exists {
return 0, fmt.Errorf("no StreamDepth field in depot spec for %s", depot)
}

depth, err := streamDepth(stream)
depth, err := streamDepth(depotDepthPath)
if err != nil {
return "", 0, err
return 0, err
}

p.streamNameCache = stream
p.streamDepthCache = depth

return stream, depth, nil
return depth, nil
}

func streamDepth(stream string) (int, error) {
Expand Down Expand Up @@ -167,7 +196,7 @@ func (p *P4) runAndParseDepotFiles(cmd string) ([]DepotFile, error) {
return nil, fmt.Errorf("missing '-z tag' in non-fstat cmd: %s", cmd)
}

_, streamDepth, err := p.StreamInfo()
streamDepth, err := p.StreamDepth()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -233,6 +262,21 @@ func (p *P4) runAndParseDepotFiles(cmd string) ([]DepotFile, error) {
return out, nil
}

// getDepotName returns the depot name given a depot path
// For example: ("//a/b/c/d:foo") would return "a"
func getDepotName(line string) (string, error) {
prefix, err := getDepotPrefix(line, 1)
if err != nil {
return "", err
}

if len(prefix) < 3 {
return "", fmt.Errorf("line '%s' does not have a full depot prefix", line)
}

return prefix[2:len(prefix)-1], nil
}

// getDepotPrefix returns the stream prefix given a line that includes the prefix and the stream depth
// For example: ("//a/b/c/d:foo", 2) would return "//a/b/"
func getDepotPrefix(line string, depth int) (string, error) {
Expand Down