From 634e6df8a2096c5dab7bc1d0e35ad8aed1b9c34e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=90?= Date: Tue, 9 Apr 2024 10:46:11 +0800 Subject: [PATCH] feat: pass context down to xorm (#65) * feat: pass context down to xorm * fix: update README --- README.md | 4 +- adapter.go | 36 ++++++++-- context_adapter.go | 86 ----------------------- context_adapter_test.go | 152 ---------------------------------------- go.mod | 2 - go.sum | 10 ++- 6 files changed, 41 insertions(+), 249 deletions(-) delete mode 100644 context_adapter.go delete mode 100644 context_adapter_test.go diff --git a/README.md b/README.md index 021066a..14f9510 100644 --- a/README.md +++ b/README.md @@ -106,11 +106,11 @@ func main() { `xormadapter` supports adapter with context, the following is a timeout control implemented using context ```go -ca, _ := NewContextAdapter("mysql", "root:@tcp(127.0.0.1:3306)/", "casbin") +a, _ := xormadapter.NewAdapter("mysql", "mysql_username:mysql_password@tcp(127.0.0.1:3306)/") // Your driver and data source. // Limited time 300s ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) defer cancel() -err := ca.AddPolicyCtx(ctx, "p", "p", []string{"alice", "data1", "read"}) +err := a.AddPolicyCtx(ctx, "p", "p", []string{"alice", "data1", "read"}) if err != nil { panic(err) } diff --git a/adapter.go b/adapter.go index 004f2f0..69c5ca5 100644 --- a/adapter.go +++ b/adapter.go @@ -15,6 +15,7 @@ package xormadapter import ( + "context" "errors" "log" "runtime" @@ -271,9 +272,14 @@ func loadPolicyLine(line *CasbinRule, model model.Model) { // LoadPolicy loads policy from database. func (a *Adapter) LoadPolicy(model model.Model) error { + return a.LoadPolicyCtx(context.Background(), model) +} + +// LoadPolicyCtx loads policy from database. +func (a *Adapter) LoadPolicyCtx(ctx context.Context, model model.Model) error { lines := make([]*CasbinRule, 0, 64) - if err := a.engine.Table(&CasbinRule{tableName: a.getFullTableName()}).Find(&lines); err != nil { + if err := a.engine.Context(ctx).Table(&CasbinRule{tableName: a.getFullTableName()}).Find(&lines); err != nil { return err } @@ -312,6 +318,11 @@ func (a *Adapter) genPolicyLine(ptype string, rule []string) *CasbinRule { // SavePolicy saves policy to database. func (a *Adapter) SavePolicy(model model.Model) error { + return a.SavePolicyCtx(context.Background(), model) +} + +// SavePolicyCtx saves policy to database. +func (a *Adapter) SavePolicyCtx(ctx context.Context, model model.Model) error { err := a.dropTable() if err != nil { return err @@ -342,15 +353,20 @@ func (a *Adapter) SavePolicy(model model.Model) error { return nil } - _, err = a.engine.Insert(&lines) + _, err = a.engine.Context(ctx).Insert(&lines) return err } // AddPolicy adds a policy rule to the storage. func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error { + return a.AddPolicyCtx(context.Background(), sec, ptype, rule) +} + +// AddPolicyCtx adds a policy rule to the storage. +func (a *Adapter) AddPolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error { line := a.genPolicyLine(ptype, rule) - _, err := a.engine.InsertOne(line) + _, err := a.engine.Context(ctx).InsertOne(line) return err } @@ -371,8 +387,13 @@ func (a *Adapter) AddPolicies(sec string, ptype string, rules [][]string) error // RemovePolicy removes a policy rule from the storage. func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error { + return a.RemovePolicyCtx(context.Background(), sec, ptype, rule) +} + +// RemovePolicyCtx removes a policy rule from the storage. +func (a *Adapter) RemovePolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error { line := a.genPolicyLine(ptype, rule) - _, err := a.engine.Delete(line) + _, err := a.engine.Context(ctx).Delete(line) return err } @@ -393,6 +414,11 @@ func (a *Adapter) RemovePolicies(sec string, ptype string, rules [][]string) err // RemoveFilteredPolicy removes policy rules that match the filter from the storage. func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error { + return a.RemoveFilteredPolicyCtx(context.Background(), sec, ptype, fieldIndex, fieldValues...) +} + +// RemoveFilteredPolicyCtx removes policy rules that match the filter from the storage. +func (a *Adapter) RemoveFilteredPolicyCtx(ctx context.Context, sec string, ptype string, fieldIndex int, fieldValues ...string) error { line := CasbinRule{Ptype: ptype, tableName: a.getFullTableName()} idx := fieldIndex + len(fieldValues) @@ -415,7 +441,7 @@ func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, line.V5 = fieldValues[5-fieldIndex] } - _, err := a.engine.Delete(&line) + _, err := a.engine.Context(ctx).Delete(&line) return err } diff --git a/context_adapter.go b/context_adapter.go deleted file mode 100644 index 7d2cb0b..0000000 --- a/context_adapter.go +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright 2023 The casbin Authors. All Rights Reserved. -// -// 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 xormadapter - -import ( - "context" - - "github.com/casbin/casbin/v2/model" -) - -type ContextAdapter struct { - *Adapter -} - -func NewContextAdapter(driverName string, dataSourceName string, dbSpecified ...bool) (*ContextAdapter, error) { - a, err := NewAdapter(driverName, dataSourceName, dbSpecified...) - return &ContextAdapter{ - a, - }, err -} - -// executeWithContext is a helper function to execute a function with context and return the result or error. -func executeWithContext(ctx context.Context, fn func() error) error { - done := make(chan error) - - go func() { - done <- fn() - }() - - select { - case <-ctx.Done(): - return ctx.Err() - case err := <-done: - return err - } -} - -// LoadPolicyCtx loads all policy rules from the storage with context. -func (ca *ContextAdapter) LoadPolicyCtx(ctx context.Context, model model.Model) error { - return executeWithContext(ctx, func() error { - return ca.LoadPolicy(model) - }) -} - -// SavePolicyCtx saves all policy rules to the storage with context. -func (ca *ContextAdapter) SavePolicyCtx(ctx context.Context, model model.Model) error { - return executeWithContext(ctx, func() error { - return ca.SavePolicy(model) - }) -} - -// AddPolicyCtx adds a policy rule to the storage with context. -// This is part of the Auto-Save feature. -func (ca *ContextAdapter) AddPolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error { - return executeWithContext(ctx, func() error { - return ca.AddPolicy(sec, ptype, rule) - }) -} - -// RemovePolicyCtx removes a policy rule from the storage with context. -// This is part of the Auto-Save feature. -func (ca *ContextAdapter) RemovePolicyCtx(ctx context.Context, sec string, ptype string, rule []string) error { - return executeWithContext(ctx, func() error { - return ca.RemovePolicy(sec, ptype, rule) - }) -} - -// RemoveFilteredPolicyCtx removes policy rules that match the filter from the storage with context. -// This is part of the Auto-Save feature. -func (ca *ContextAdapter) RemoveFilteredPolicyCtx(ctx context.Context, sec string, ptype string, fieldIndex int, fieldValues ...string) error { - return executeWithContext(ctx, func() error { - return ca.RemoveFilteredPolicy(sec, ptype, fieldIndex, fieldValues...) - }) -} diff --git a/context_adapter_test.go b/context_adapter_test.go deleted file mode 100644 index f64546a..0000000 --- a/context_adapter_test.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2023 The casbin Authors. All Rights Reserved. -// -// 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 xormadapter - -import ( - "context" - "testing" - "time" - - "github.com/agiledragon/gomonkey/v2" - "github.com/casbin/casbin/v2" - "github.com/stretchr/testify/assert" - "xorm.io/xorm" -) - -func mockExecuteWithContextTimeOut(ctx context.Context, fn func() error) error { - done := make(chan error) - go func() { - time.Sleep(500 * time.Microsecond) - done <- fn() - }() - - select { - case <-ctx.Done(): - return ctx.Err() - case err := <-done: - return err - } -} - -func clearDBPolicy() (*casbin.Enforcer, *ContextAdapter) { - ca, err := NewContextAdapter("mysql", "root:@tcp(127.0.0.1:3306)/") - if err != nil { - panic(err) - } - - e, err := casbin.NewEnforcer("examples/rbac_model.conf", ca) - if err != nil { - panic(err) - } - - e.ClearPolicy() - _ = e.SavePolicy() - - return e, ca - - return e, ca -} - -func TestContextAdapter_LoadPolicyCtx(t *testing.T) { - e, ca := clearDBPolicy() - - engine, _ := xorm.NewEngine("mysql", "root:@tcp(127.0.0.1:3306)/casbin") - policy := &CasbinRule{ - Ptype: "p", - V0: "alice", - V1: "data1", - V2: "read", - } - _, err := engine.Insert(policy) - if err != nil { - panic(err) - } - - assert.NoError(t, ca.LoadPolicyCtx(context.Background(), e.GetModel())) - e, _ = casbin.NewEnforcer(e.GetModel(), ca) - testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}}) - - var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut) - defer p.Reset() - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - - assert.EqualError(t, ca.LoadPolicyCtx(ctx, e.GetModel()), "context deadline exceeded") -} - -func TestContextAdapter_SavePolicyCtx(t *testing.T) { - e, ca := clearDBPolicy() - - e.EnableAutoSave(false) - _, _ = e.AddPolicy("alice", "data1", "read") - assert.NoError(t, ca.SavePolicyCtx(context.Background(), e.GetModel())) - _ = e.LoadPolicy() - testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}}) - - var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut) - defer p.Reset() - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - assert.EqualError(t, ca.SavePolicyCtx(ctx, e.GetModel()), "context deadline exceeded") - // Sleep, waiting for the completion of the transaction commit - time.Sleep(2 * time.Second) -} - -func TestContextAdapter_AddPolicyCtx(t *testing.T) { - e, ca := clearDBPolicy() - - assert.NoError(t, ca.AddPolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"})) - _ = e.LoadPolicy() - testGetPolicy(t, e, [][]string{{"alice", "data1", "read"}}) - - var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut) - defer p.Reset() - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - assert.EqualError(t, ca.AddPolicyCtx(ctx, "p", "p", []string{"alice", "data1", "read"}), "context deadline exceeded") -} - -func TestContextAdapter_RemovePolicyCtx(t *testing.T) { - e, ca := clearDBPolicy() - - _ = ca.AddPolicy("p", "p", []string{"alice", "data1", "read"}) - _ = ca.AddPolicy("p", "p", []string{"alice", "data2", "read"}) - assert.NoError(t, ca.RemovePolicyCtx(context.Background(), "p", "p", []string{"alice", "data1", "read"})) - _ = e.LoadPolicy() - testGetPolicy(t, e, [][]string{{"alice", "data2", "read"}}) - - var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut) - defer p.Reset() - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - assert.EqualError(t, ca.RemovePolicyCtx(ctx, "p", "p", []string{"alice", "data1", "read"}), "context deadline exceeded") -} - -func TestContextAdapter_RemoveFilteredPolicyCtx(t *testing.T) { - e, ca := clearDBPolicy() - - _ = ca.AddPolicy("p", "p", []string{"alice", "data1", "read"}) - _ = ca.AddPolicy("p", "p", []string{"alice", "data1", "write"}) - _ = ca.AddPolicy("p", "p", []string{"alice", "data2", "read"}) - assert.NoError(t, ca.RemoveFilteredPolicyCtx(context.Background(), "p", "p", 1, "data1")) - _ = e.LoadPolicy() - testGetPolicy(t, e, [][]string{{"alice", "data2", "read"}}) - - var p = gomonkey.ApplyFunc(executeWithContext, mockExecuteWithContextTimeOut) - defer p.Reset() - ctx, cancel := context.WithTimeout(context.Background(), 300*time.Microsecond) - defer cancel() - assert.EqualError(t, ca.RemoveFilteredPolicyCtx(ctx, "p", "p", 1, "data1"), "context deadline exceeded") -} diff --git a/go.mod b/go.mod index b899629..dc20432 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,8 @@ module github.com/casbin/xorm-adapter/v3 go 1.12 require ( - github.com/agiledragon/gomonkey/v2 v2.10.1 github.com/casbin/casbin/v2 v2.77.2 github.com/go-sql-driver/mysql v1.6.0 github.com/lib/pq v1.10.2 - github.com/stretchr/testify v1.7.0 xorm.io/xorm v1.3.2 ) diff --git a/go.sum b/go.sum index 1aae6b6..e15529d 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,6 @@ github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWX github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= -github.com/agiledragon/gomonkey/v2 v2.10.1 h1:FPJJNykD1957cZlGhr9X0zjr291/lbazoZ/dmc4mS4c= -github.com/agiledragon/gomonkey/v2 v2.10.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -54,6 +52,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -65,6 +64,7 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -94,6 +94,7 @@ github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= @@ -104,6 +105,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.5.3 h1:x95R7cp+rSeeqAMI2knLtQ0DKlaBhv2NrtrOvafPHRo= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= @@ -586,7 +588,9 @@ modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3 modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= modernc.org/ccgo/v3 v3.12.82 h1:wudcnJyjLj1aQQCXF3IM9Gz2X6UNjw+afIghzdtn0v8= modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= +modernc.org/ccorpus v1.11.1 h1:K0qPfpVG1MJh5BYazccnmhywH4zHuOgJXgbjzyp6dWA= modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= +modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q= @@ -638,9 +642,11 @@ modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE= modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/tcl v1.8.13 h1:V0sTNBw0Re86PvXZxuCub3oO9WrSTqALgrwNZNvLFGw= modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.2.19 h1:BGyRFWhDVn5LFS5OcX4Yd/MlpRTOc7hOPTdcIpCiUao= modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=