Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bufplugin package #3431

Merged
merged 13 commits into from
Nov 13, 2024
2 changes: 1 addition & 1 deletion private/bufpkg/bufcas/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (d DigestType) String() string {
//
// This reverses DigestType.String().
//
// Returns an error of type *ParseError if thie string could not be parsed.
// Returns an error of type *ParseError if the string could not be parsed.
func ParseDigestType(s string) (DigestType, error) {
d, ok := stringToDigestType[s]
if !ok {
Expand Down
2 changes: 1 addition & 1 deletion private/bufpkg/bufmodule/commit.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"time"
)

// Commit represents a Commit on the BSR.
// Commit represents a Commit for a Module on the BSR.
type Commit interface {
// ModuleKey returns the ModuleKey for the Commit.
ModuleKey() ModuleKey
Expand Down
5 changes: 3 additions & 2 deletions private/bufpkg/bufmodule/digest.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func (d DigestType) String() string {
//
// This reverses DigestType.String().
//
// Returns an error of type *ParseError if thie string could not be parsed.
// Returns an error of type *ParseError if the string could not be parsed.
func ParseDigestType(s string) (DigestType, error) {
doriable marked this conversation as resolved.
Show resolved Hide resolved
d, ok := stringToDigestType[s]
if !ok {
Expand All @@ -96,6 +96,7 @@ type Digest interface {
fmt.Stringer

// Type returns the type of digest.
//
// Always a valid value.
Type() DigestType
// Value returns the digest value.
Expand Down Expand Up @@ -127,7 +128,7 @@ func NewDigest(digestType DigestType, bufcasDigest bufcas.Digest) (Digest, error
// ParseDigest parses a Digest from its string representation.
//
// A Digest string is of the form typeString:hexValue.
// The string is expected to be non-empty, If not, an error is treutned.
// The string is expected to be non-empty, If not, an error is returned.
//
// This reverses Digest.String().
func ParseDigest(s string) (Digest, error) {
Expand Down
2 changes: 1 addition & 1 deletion private/bufpkg/bufmodule/file_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ func (c FileType) String() string {
//
// This reverses FileType.String().
//
// Returns an error of type *ParseError if thie string could not be parsed.
// Returns an error of type *ParseError if the string could not be parsed.
func ParseFileType(s string) (FileType, error) {
c, ok := stringToFileType[s]
if !ok {
Expand Down
2 changes: 0 additions & 2 deletions private/bufpkg/bufmodule/module_data.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,6 @@ func NewModuleData(

// *** PRIVATE ***

// moduleData

type moduleData struct {
moduleKey ModuleKey
getBucket func() (storage.ReadBucket, error)
Expand Down
15 changes: 15 additions & 0 deletions private/bufpkg/bufplugin/bufplugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bufplugin
72 changes: 72 additions & 0 deletions private/bufpkg/bufplugin/commit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bufplugin

import (
"sync"
"time"
)

// Commit represents a Commit for a Plugin on the BSR.
type Commit interface {
// PluginKey returns the PluginKey for the Commit.
PluginKey() PluginKey
// CreateTime returns the time the Commit was created on the BSR.
CreateTime() (time.Time, error)

isCommit()
}

// NewCommit returns a new Commit.
func NewCommit(
pluginKey PluginKey,
getCreateTime func() (time.Time, error),
) Commit {
return newCommit(
pluginKey,
getCreateTime,
)
}
doriable marked this conversation as resolved.
Show resolved Hide resolved

// *** PRIVATE ***

type commit struct {
pluginKey PluginKey
getCreateTime func() (time.Time, error)
}

func newCommit(
pluginKey PluginKey,
getCreateTime func() (time.Time, error),
) *commit {
return &commit{
pluginKey: pluginKey,
getCreateTime: sync.OnceValues(getCreateTime),
}
}

func (c *commit) PluginKey() PluginKey {
return c.pluginKey
}

func (c *commit) CreateTime() (time.Time, error) {
// This may invoke tamper-proofing per newCommit construction.
if _, err := c.pluginKey.Digest(); err != nil {
return time.Time{}, err
}
return c.getCreateTime()
}

func (*commit) isCommit() {}
211 changes: 211 additions & 0 deletions private/bufpkg/bufplugin/digest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
// Copyright 2020-2024 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package bufplugin

import (
"bytes"
"encoding/hex"
"errors"
"fmt"
"strconv"
"strings"

"github.com/bufbuild/buf/private/bufpkg/bufcas"
"github.com/bufbuild/buf/private/pkg/syserror"
)

const (
// DigestTypeP1 represents the p1 plugin digest type.
//
// The string value of this is "p1".
DigestTypeP1 DigestType = iota + 1
)

var (
// AllDigestTypes are all known DigestTypes.
AllDigestTypes = []DigestType{
DigestTypeP1,
}
digestTypeToString = map[DigestType]string{
DigestTypeP1: "p1",
}
stringToDigestType = map[string]DigestType{
"p1": DigestTypeP1,
}
)

// DigestType is a type of digest.
type DigestType int

// ParseDigestType parses a DigestType from its string representation.
//
// This reverses DigestType.String().
//
// Returns an error of type *ParseError if the string could not be parsed.
func ParseDigestType(s string) (DigestType, error) {
d, ok := stringToDigestType[s]
if !ok {
return 0, &ParseError{
typeString: "plugin digest type",
input: s,
err: fmt.Errorf("unknown type: %q", s),
}
}
return d, nil
}

// String prints the string representation of the DigestType.
func (d DigestType) String() string {
s, ok := digestTypeToString[d]
if !ok {
return strconv.Itoa(int(d))
}
return s
}

// Digest is a digest of some content.
//
// It consists of a DigestType and a digest value.
type Digest interface {
// String() prints typeString:hexValue.
fmt.Stringer

// Type returns the type of digest.
//
// Always a valid value.
Type() DigestType
// Value returns the digest value.
//
// Always non-empty.
Value() []byte

isDigest()
}

// NewDigest creates a new Digest.
func NewDigest(digestType DigestType, bufcasDigest bufcas.Digest) (Digest, error) {
switch digestType {
case DigestTypeP1:
if bufcasDigest.Type() != bufcas.DigestTypeShake256 {
return nil, syserror.Newf(
"trying to create a %v Digest for a cas Digest of type %v",
digestType,
bufcasDigest.Type(),
)
}
return newDigest(digestType, bufcasDigest), nil
default:
// This is a system error.
return nil, syserror.Newf("unknown DigestType: %v", digestType)
}
}

// ParseDigest parses a Digest from its string representation.
//
// A Digest string is of the form typeString:hexValue.
// The string is expected to be non-empty, If not, an error is returned.
//
// This reverses Digest.String().
func ParseDigest(s string) (Digest, error) {
if s == "" {
// This should be considered a system error.
return nil, errors.New("empty string passed to ParseDigest")
}
digestTypeString, hexValue, ok := strings.Cut(s, ":")
if !ok {
return nil, &ParseError{
typeString: "plugin digest",
input: s,
err: errors.New(`must be in the form "digest_type:digest_hex_value"`),
}
}
digestType, err := ParseDigestType(digestTypeString)
if err != nil {
return nil, &ParseError{
typeString: "plugin digest",
input: digestTypeString,
err: err,
}
}
value, err := hex.DecodeString(hexValue)
if err != nil {
return nil, &ParseError{
typeString: "plugin digest",
input: s,
err: errors.New(`could not parse hex: must in the form "digest_type:digest_hex_value"`),
}
}
switch digestType {
case DigestTypeP1:
bufcasDigest, err := bufcas.NewDigest(value)
if err != nil {
return nil, err
}
return NewDigest(digestType, bufcasDigest)
default:
return nil, syserror.Newf("unknown DigestType: %v", digestType)
}
}

// DigestEqual returns true if the given Digests are considered equal.
//
// If both Digests are nil, this returns true.
//
// This checks both the DigestType and Digest value.
func DigestEqual(a Digest, b Digest) bool {
if (a == nil) != (b == nil) {
return false
}
if a == nil {
return true
}
if a.Type() != b.Type() {
return false
}
return bytes.Equal(a.Value(), b.Value())
}

/// *** PRIVATE ***

type digest struct {
digestType DigestType
bufcasDigest bufcas.Digest
// Cache as we call String pretty often.
// We could do this lazily but not worth it.
stringValue string
}

// validation should occur outside of this function.
func newDigest(digestType DigestType, bufcasDigest bufcas.Digest) *digest {
return &digest{
digestType: digestType,
bufcasDigest: bufcasDigest,
stringValue: digestType.String() + ":" + hex.EncodeToString(bufcasDigest.Value()),
}
}

func (d *digest) Type() DigestType {
return d.digestType
}

func (d *digest) Value() []byte {
return d.bufcasDigest.Value()
}

func (d *digest) String() string {
return d.stringValue
}

func (*digest) isDigest() {}
Loading