diff --git a/Makefile b/Makefile index ce813eaa..3a25b590 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ release: release/cached_linux_amd64 release/cached_macos_amd64 release/cached_ma release: release/migrations.tar.gz prerelease: build +prerelease: build-js prerelease: ifndef tag $(error tag variable must be set) diff --git a/cmd/fuzz-test/main.go b/cmd/fuzz-test/main.go index 677e14eb..091f532e 100644 --- a/cmd/fuzz-test/main.go +++ b/cmd/fuzz-test/main.go @@ -403,7 +403,7 @@ func runIteration(ctx context.Context, client *dlc.Client, project int64, operat return -1, fmt.Errorf("failed to apply operation %s: %w", operation.String(), err) } - version, _, err := client.Update(ctx, project, dirs.Base(project)) + version, _, err := client.Update(ctx, project, dirs.Base(project), nil) if err != nil { return -1, fmt.Errorf("failed to update project %d: %w", project, err) } @@ -414,12 +414,12 @@ func runIteration(ctx context.Context, client *dlc.Client, project int64, operat return -1, fmt.Errorf("failed to create reset dir %s: %w", dirs.Reset(project), err) } - _, err = client.Rebuild(ctx, project, "", nil, dirs.Reset(project), nil, "", nil, false) + _, err = client.Rebuild(ctx, project, "", nil, dirs.Reset(project), nil, nil, "", nil, false) if err != nil { return -1, fmt.Errorf("failed to rebuild reset project %d: %w", project, err) } - _, err = client.Rebuild(ctx, project, "", nil, dirs.OneStep(project), nil, "", nil, false) + _, err = client.Rebuild(ctx, project, "", nil, dirs.OneStep(project), nil, nil, "", nil, false) if err != nil { return -1, fmt.Errorf("failed to rebuild continue project %d: %w", project, err) } @@ -430,11 +430,11 @@ func runIteration(ctx context.Context, client *dlc.Client, project int64, operat } randomStepVersion := int64(rand.Intn(int(version))) - _, err = client.Rebuild(ctx, project, "", &randomStepVersion, dirs.RandomStep(project), nil, "", nil, false) + _, err = client.Rebuild(ctx, project, "", &randomStepVersion, dirs.RandomStep(project), nil, nil, "", nil, false) if err != nil { return -1, fmt.Errorf("failed to rebuild step project %d: %w", project, err) } - _, err = client.Rebuild(ctx, project, "", &version, dirs.RandomStep(project), nil, "", nil, false) + _, err = client.Rebuild(ctx, project, "", &version, dirs.RandomStep(project), nil, nil, "", nil, false) if err != nil { return -1, fmt.Errorf("failed to rebuild step project %d: %w", project, err) } diff --git a/internal/db/queryBuilder.go b/internal/db/queryBuilder.go index c211d1a3..c5223a9f 100644 --- a/internal/db/queryBuilder.go +++ b/internal/db/queryBuilder.go @@ -80,6 +80,7 @@ func (qb *queryBuilder) updatedObjectsCTE() string { AND (o.stop_version IS NULL OR o.stop_version > __stop_version__) %s %s + %s ORDER BY o.path ` @@ -105,7 +106,12 @@ func (qb *queryBuilder) updatedObjectsCTE() string { ignoresPredicate = "AND o.path NOT LIKE ALL(__ignores__::text[])" } - return fmt.Sprintf(template, isCachedSelector, cacheJoin, pathPredicate, ignoresPredicate) + subpathsPredicate := "" + if len(qb.objectQuery.Subpaths) > 0 { + subpathsPredicate = "AND o.path LIKE ALL(__subpaths__::text[])" + } + + return fmt.Sprintf(template, isCachedSelector, cacheJoin, pathPredicate, ignoresPredicate, subpathsPredicate) } func (qb *queryBuilder) removedObjectsCTE() string { @@ -117,6 +123,7 @@ func (qb *queryBuilder) removedObjectsCTE() string { AND o.stop_version > __start_version__ AND o.stop_version <= __stop_version__ %s + %s AND NOT ( -- Skip removing files if they are in the updated_objects list (RIGHT(o.path, 1) != '/' AND o.path IN (SELECT path FROM updated_objects)) @@ -135,7 +142,12 @@ func (qb *queryBuilder) removedObjectsCTE() string { ignoresPredicate = "AND o.path NOT LIKE ALL(__ignores__::text[])" } - return fmt.Sprintf(template, ignoresPredicate) + subpathsPredicate := "" + if len(qb.objectQuery.Subpaths) > 0 { + subpathsPredicate = "AND o.path LIKE ALL(__subpaths__::text[])" + } + + return fmt.Sprintf(template, ignoresPredicate, subpathsPredicate) } func (qb *queryBuilder) cachedObjectHashesCTE() string { @@ -225,6 +237,15 @@ func (qb *queryBuilder) replaceQueryArgs(query string) (string, []any) { args = append(args, ignorePatterns) } + if len(qb.objectQuery.Subpaths) > 0 { + argNames = append(argNames, "__subpaths__") + subpathPatterns := []string{} + for _, subPath := range qb.objectQuery.Subpaths { + subpathPatterns = append(subpathPatterns, fmt.Sprintf("%s%%", subPath)) + } + args = append(args, subpathPatterns) + } + if len(qb.cacheVersions) > 0 { argNames = append(argNames, "__cache_versions__") args = append(args, qb.cacheVersions) diff --git a/internal/pb/fs.pb.go b/internal/pb/fs.pb.go index 7fdfce45..9fb43476 100644 --- a/internal/pb/fs.pb.go +++ b/internal/pb/fs.pb.go @@ -520,6 +520,7 @@ type ObjectQuery struct { Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` IsPrefix bool `protobuf:"varint,2,opt,name=is_prefix,json=isPrefix,proto3" json:"is_prefix,omitempty"` Ignores []string `protobuf:"bytes,4,rep,name=ignores,proto3" json:"ignores,omitempty"` + Subpaths []string `protobuf:"bytes,5,rep,name=subpaths,proto3" json:"subpaths,omitempty"` } func (x *ObjectQuery) Reset() { @@ -575,6 +576,13 @@ func (x *ObjectQuery) GetIgnores() []string { return nil } +func (x *ObjectQuery) GetSubpaths() []string { + if x != nil { + return x.Subpaths + } + return nil +} + type GetRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2044,231 +2052,233 @@ var file_internal_pb_fs_proto_rawDesc = []byte{ 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x1d, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x88, 0x01, 0x01, - 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x6c, 0x0a, 0x0b, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x70, - 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, - 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x18, 0x0a, 0x07, - 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x69, - 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x52, 0x0c, 0x77, 0x69, - 0x74, 0x68, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xbd, 0x01, 0x0a, 0x0a, 0x47, - 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, - 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x74, - 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, - 0x01, 0x52, 0x09, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, - 0x29, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, - 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, - 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4b, 0x0a, 0x0b, 0x47, 0x65, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x12, 0x22, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, - 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xff, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, - 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, - 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, - 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, - 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, - 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, - 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, - 0x38, 0x0a, 0x18, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x63, - 0x68, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, - 0x03, 0x52, 0x16, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, - 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, - 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, - 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc3, 0x01, 0x0a, 0x13, 0x47, 0x65, + 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0x88, 0x01, 0x0a, + 0x0b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, + 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x73, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x73, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x18, 0x0a, + 0x07, 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x69, 0x67, 0x6e, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x75, 0x62, 0x70, 0x61, + 0x74, 0x68, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x73, 0x75, 0x62, 0x70, 0x61, + 0x74, 0x68, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x52, 0x0c, 0x77, 0x69, 0x74, 0x68, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x22, 0xbd, 0x01, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x09, + 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x07, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, + 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x6f, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4b, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x22, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x22, 0xff, 0x01, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, + 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, + 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, + 0x0a, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x48, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, + 0x01, 0x12, 0x29, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x12, 0x38, 0x0a, 0x18, + 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x03, 0x52, 0x16, + 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x6f, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xc3, 0x01, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x36, 0x0a, 0x06, 0x66, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, - 0x6d, 0x61, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, 0x63, - 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, - 0x70, 0x61, 0x63, 0x6b, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x22, 0x14, 0x0a, 0x06, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x32, 0x5f, 0x54, 0x41, 0x52, 0x10, - 0x00, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x22, - 0xc2, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, - 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x07, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, - 0x72, 0x69, 0x65, 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x52, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, - 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x4d, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, - 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2a, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x22, 0x45, 0x0a, 0x0f, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, + 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, + 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, + 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x12, 0x20, 0x0a, 0x09, 0x70, 0x61, 0x63, 0x6b, 0x5f, 0x70, + 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x70, 0x61, 0x63, + 0x6b, 0x50, 0x61, 0x74, 0x68, 0x88, 0x01, 0x01, 0x22, 0x14, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x32, 0x5f, 0x54, 0x41, 0x52, 0x10, 0x00, 0x42, 0x0c, + 0x0a, 0x0a, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x22, 0xc2, 0x01, 0x0a, + 0x0f, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, + 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, + 0x01, 0x01, 0x12, 0x22, 0x0a, 0x0a, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x01, 0x52, 0x09, 0x74, 0x6f, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x29, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, + 0x73, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x74, 0x6f, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x52, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x24, 0x0a, 0x07, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, 0x07, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x4d, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x22, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0a, 0x2e, 0x70, 0x62, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x6b, 0x74, 0x52, 0x06, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x22, 0x2a, 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x22, 0x45, 0x0a, 0x0f, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x6f, 0x6c, 0x6c, 0x62, + 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, 0x0a, 0x0e, 0x49, + 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, + 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x49, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, + 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x2c, 0x0a, 0x12, + 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x69, 0x76, 0x65, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, 0x13, 0x74, 0x6f, + 0x74, 0x61, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x11, 0x0a, 0x0f, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x3b, 0x0a, + 0x10, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x27, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x37, 0x0a, 0x0c, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x08, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, + 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x10, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6b, 0x65, 0x65, 0x70, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, + 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, + 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x43, 0x0a, 0x11, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x8f, 0x01, 0x0a, 0x17, 0x47, 0x63, 0x52, 0x61, 0x6e, + 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x02, 0x52, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6b, 0x65, + 0x65, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4c, 0x0a, 0x18, 0x47, 0x63, 0x52, 0x61, + 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x08, 0x70, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x2b, 0x0a, 0x11, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x22, 0x2a, 0x0a, 0x12, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, + 0x61, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x12, 0x0a, 0x10, 0x52, 0x6f, - 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2a, - 0x0a, 0x0e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xb0, 0x01, 0x0a, 0x0f, 0x49, - 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, - 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x2c, 0x0a, 0x12, 0x6c, 0x69, 0x76, 0x65, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x5f, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x6c, 0x69, 0x76, - 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x2e, 0x0a, - 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x5f, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x11, 0x0a, - 0x0f, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x3b, 0x0a, 0x10, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x37, 0x0a, - 0x0c, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x0b, 0x2e, 0x70, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x08, 0x70, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x10, 0x47, 0x63, 0x50, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x70, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x76, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6b, - 0x65, 0x65, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x66, - 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x11, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x07, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x8f, 0x01, 0x0a, 0x17, 0x47, 0x63, - 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0c, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, - 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x72, 0x6f, 0x6d, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0f, 0x0a, 0x0d, 0x5f, 0x66, - 0x72, 0x6f, 0x6d, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x4c, 0x0a, 0x18, 0x47, - 0x63, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, - 0x08, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x22, 0x2b, 0x0a, 0x11, 0x47, 0x63, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, - 0x0a, 0x06, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x02, 0x52, 0x06, - 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x22, 0x2a, 0x0a, 0x12, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x63, 0x6f, 0x75, - 0x6e, 0x74, 0x22, 0x61, 0x0a, 0x15, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, 0x6f, - 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, - 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0x3f, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, - 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x25, 0x0a, 0x0e, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, - 0x68, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x10, 0x47, 0x65, - 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, - 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, - 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x14, 0x0a, - 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, - 0x74, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x22, 0x14, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, - 0x74, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x32, 0x5f, 0x54, 0x41, 0x52, 0x10, 0x00, 0x32, 0xb8, 0x07, - 0x0a, 0x02, 0x46, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x4e, - 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x44, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, - 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, - 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, - 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, - 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x03, 0x47, 0x65, - 0x74, 0x12, 0x0e, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0f, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x30, 0x01, 0x12, 0x40, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, - 0x65, 0x73, 0x73, 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, - 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, - 0x72, 0x79, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, - 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, - 0x06, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, - 0x12, 0x35, 0x0a, 0x08, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x13, 0x2e, 0x70, - 0x62, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x70, 0x65, - 0x63, 0x74, 0x12, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x73, 0x70, - 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x53, - 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x6e, 0x61, - 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, - 0x62, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x10, 0x2e, 0x70, 0x62, - 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, - 0x70, 0x62, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x38, 0x0a, 0x09, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x14, 0x2e, - 0x70, 0x62, 0x2e, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x10, 0x47, 0x63, - 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, - 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, - 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x62, + 0x03, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x74, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x22, 0x3f, 0x0a, 0x16, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x0e, + 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6c, 0x61, 0x74, 0x65, 0x73, 0x74, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x22, 0x11, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x76, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x33, 0x0a, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, + 0x63, 0x68, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x6d, + 0x61, 0x74, 0x52, 0x06, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, + 0x74, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, + 0x68, 0x61, 0x73, 0x68, 0x22, 0x14, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x12, 0x0a, + 0x0a, 0x06, 0x53, 0x32, 0x5f, 0x54, 0x41, 0x52, 0x10, 0x00, 0x32, 0xb8, 0x07, 0x0a, 0x02, 0x46, + 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x4e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x77, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x4e, 0x65, 0x77, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x44, + 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x18, 0x2e, 0x70, 0x62, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, + 0x65, 0x63, 0x74, 0x73, 0x12, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, + 0x70, 0x62, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x0e, + 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0f, + 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, + 0x01, 0x12, 0x40, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, + 0x12, 0x16, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x30, 0x01, 0x12, 0x35, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x12, + 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, 0x72, 0x79, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x61, + 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x31, 0x0a, 0x06, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x11, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x12, 0x35, 0x0a, + 0x08, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x52, + 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, + 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x6f, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x07, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x12, + 0x12, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x49, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x53, 0x6e, 0x61, 0x70, + 0x73, 0x68, 0x6f, 0x74, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x53, + 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x2c, 0x0a, 0x05, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x10, 0x2e, 0x70, 0x62, 0x2e, 0x52, 0x65, + 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x70, 0x62, 0x2e, + 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x0a, + 0x09, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x14, 0x2e, 0x70, 0x62, 0x2e, + 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4d, 0x0a, 0x10, 0x47, 0x63, 0x52, 0x61, 0x6e, + 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x47, 0x63, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, - 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, - 0x6f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, - 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, - 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x37, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x62, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x14, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x64, 0x67, 0x65, 0x74, 0x2d, 0x69, 0x6e, - 0x63, 0x2f, 0x64, 0x61, 0x74, 0x65, 0x69, 0x6c, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, - 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, + 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3b, 0x0a, 0x0a, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x15, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x70, 0x62, + 0x2e, 0x47, 0x63, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x19, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, + 0x54, 0x6f, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x70, 0x62, 0x2e, 0x43, 0x6c, 0x6f, 0x6e, 0x65, 0x54, 0x6f, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x08, + 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x12, 0x13, 0x2e, 0x70, 0x62, 0x2e, 0x47, 0x65, + 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, + 0x70, 0x62, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x61, 0x63, 0x68, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x29, 0x5a, 0x27, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x64, 0x67, 0x65, 0x74, 0x2d, 0x69, 0x6e, 0x63, 0x2f, 0x64, + 0x61, 0x74, 0x65, 0x69, 0x6c, 0x61, 0x67, 0x65, 0x72, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x70, 0x62, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/pb/fs.proto b/internal/pb/fs.proto index 5e7be915..2c5ba24c 100644 --- a/internal/pb/fs.proto +++ b/internal/pb/fs.proto @@ -81,6 +81,7 @@ message ObjectQuery { string path = 1; bool is_prefix = 2; repeated string ignores = 4; + repeated string subpaths = 5; } message GetRequest { diff --git a/js/src/binary-client.ts b/js/src/binary-client.ts index a2c649cc..33d6154a 100644 --- a/js/src/binary-client.ts +++ b/js/src/binary-client.ts @@ -157,13 +157,14 @@ export class DateiLagerBinaryClient { /** * Update objects in a project based on the differences in a local directory. - * @param project The id of the project. - * @param directory The path of the directory to send updates from. - * @param options Object of options. - * @param options.timeout Number of milliseconds to wait before terminating the process. - * @returns The latest project version or `null` if something went wrong. + * @param project The id of the project. + * @param directory The path of the directory to send updates from. + * @param options Object of options. + * @param options.timeout Number of milliseconds to wait before terminating the process. + * @param options.subpaths The paths to include when updating the FS. + * @returns The latest project version or `null` if something went wrong. */ - public async update(project: bigint, directory: string, options?: { timeout?: number }): Promise { + public async update(project: bigint, directory: string, options?: { timeout?: number; subpaths?: string[] }): Promise { return await trace( "dateilager-binary-client.update", { @@ -174,6 +175,9 @@ export class DateiLagerBinaryClient { }, async () => { const args = ["--dir", String(directory), "--project", String(project)]; + if (options?.subpaths) { + args.push(`--subpaths=${options.subpaths.join(",")}`); + } const result = await this._call("update", args, directory, options); if (result.stdout == "-1") { @@ -193,6 +197,7 @@ export class DateiLagerBinaryClient { * @param options Object of options. * @param options.timeout Number of milliseconds to wait before terminating the process. * @param options.ignores The paths to ignore when rebuilding the FS. + * @param options.subpaths The paths to include when rebuilding the FS. * @param options.summarize Should produce the summary file after rebuilding. * @param options.cacheDir Path where the cache directory is mounted. * @param options.matchInclude Set fileMatch to true if the written files are matched by this glob pattern @@ -206,6 +211,7 @@ export class DateiLagerBinaryClient { options?: { timeout?: number; ignores?: string[]; + subpaths?: string[]; summarize?: boolean; cacheDir?: string; matchInclude?: string; @@ -249,6 +255,10 @@ export class DateiLagerBinaryClient { args.push(`--matchexclude=${options.matchExclude}`); } + if (options?.subpaths) { + args.push(`--subpaths=${options.subpaths.join(",")}`); + } + args.push("--project", String(project), "--dir", directory); const result = await this._call("rebuild", args, directory, options); const parsed = JSON.parse(result.stdout) as { version: number; count: number; fileMatch: boolean }; @@ -263,6 +273,7 @@ export class DateiLagerBinaryClient { * @param from Where to start cleanup * @param options dict options passed * @param options.timeout timeout limit for the request + * @returns The number of records garbage collected */ public async gcRandomProjects(sample: number, keep: number, from?: number, options?: { timeout?: number }): Promise { return await trace( @@ -294,6 +305,7 @@ export class DateiLagerBinaryClient { * @param from Where to start cleanup * @param options dict options passed * @param options.timeout timeout limit for the request + * @returns The number of records garbage collected */ public async gcProject(project: number, keep: number, from?: number, options?: { timeout?: number }): Promise { return await trace( @@ -322,6 +334,7 @@ export class DateiLagerBinaryClient { * @param sample sample size of cleanup * @param options dict options passed * @param options.timeout timeout limit for the request + * @returns The number of records garbage collected */ public async gcContents(sample: number, options?: { timeout?: number }): Promise { return await trace( diff --git a/js/src/grpc-client.ts b/js/src/grpc-client.ts index a1e2fe31..6a5f3b7f 100644 --- a/js/src/grpc-client.ts +++ b/js/src/grpc-client.ts @@ -200,6 +200,7 @@ export class DateiLagerGrpcClient { path, ignores, isPrefix: true, + subpaths: [], }, ], }, @@ -248,7 +249,7 @@ export class DateiLagerGrpcClient { }, async () => { const call = this._client.getUnary( - { project, fromVersion: from, toVersion: to, queries: [{ path, ignores, isPrefix: true }] }, + { project, fromVersion: from, toVersion: to, queries: [{ path, ignores, isPrefix: true, subpaths: [] }] }, this._rpcOptions() ); return await call.response; @@ -286,6 +287,7 @@ export class DateiLagerGrpcClient { path, isPrefix: false, ignores: [], + subpaths: [], }, ], }, diff --git a/pkg/cli/rebuild.go b/pkg/cli/rebuild.go index 3bb07610..0b4b96e2 100644 --- a/pkg/cli/rebuild.go +++ b/pkg/cli/rebuild.go @@ -19,6 +19,7 @@ func NewCmdRebuild() *cobra.Command { prefix string dir string ignores string + subpaths string summarize bool cacheDir string fileMatchInclude string @@ -40,12 +41,17 @@ func NewCmdRebuild() *cobra.Command { ignoreList = strings.Split(ignores, ",") } + var subpathList []string + if len(subpaths) > 0 { + subpathList = strings.Split(subpaths, ",") + } + matcher, err := files.NewFileMatcher(fileMatchInclude, fileMatchExclude) if err != nil { return err } - result, err := client.Rebuild(ctx, project, prefix, to, dir, ignoreList, cacheDir, matcher, summarize) + result, err := client.Rebuild(ctx, project, prefix, to, dir, ignoreList, subpathList, cacheDir, matcher, summarize) if err != nil { return fmt.Errorf("could not rebuild project: %w", err) } @@ -73,6 +79,7 @@ func NewCmdRebuild() *cobra.Command { cmd.Flags().StringVar(&prefix, "prefix", "", "Search prefix") cmd.Flags().StringVar(&dir, "dir", "", "Output directory") cmd.Flags().StringVar(&ignores, "ignores", "", "Comma separated list of ignore paths") + cmd.Flags().StringVar(&subpaths, "subpaths", "", "Comma separated list of subpaths to include") cmd.Flags().BoolVar(&summarize, "summarize", true, "Should include the summary file (required for future updates)") cmd.Flags().StringVar(&cacheDir, "cachedir", "", "Path where the cache folder is mounted") cmd.Flags().StringVar(&fileMatchInclude, "matchinclude", "", "Set fileMatch to true if the written files are matched by this glob pattern") diff --git a/pkg/cli/update.go b/pkg/cli/update.go index 62921cea..5ad67048 100644 --- a/pkg/cli/update.go +++ b/pkg/cli/update.go @@ -11,8 +11,9 @@ import ( func NewCmdUpdate() *cobra.Command { var ( - project int64 - dir string + project int64 + dir string + subpaths []string ) cmd := &cobra.Command{ @@ -22,7 +23,7 @@ func NewCmdUpdate() *cobra.Command { client := client.FromContext(ctx) - version, count, err := client.Update(ctx, project, dir) + version, count, err := client.Update(ctx, project, dir, subpaths) if err != nil { return fmt.Errorf("update objects: %w", err) } @@ -40,7 +41,7 @@ func NewCmdUpdate() *cobra.Command { cmd.Flags().Int64Var(&project, "project", -1, "Project ID (required)") cmd.Flags().StringVar(&dir, "dir", "", "Directory containing updated files") - + cmd.Flags().StringSliceVar(&subpaths, "subpaths", nil, "Subpaths to update") _ = cmd.MarkFlagRequired("project") return cmd diff --git a/pkg/client/client.go b/pkg/client/client.go index 05e4b6c7..ccf864af 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -358,7 +358,7 @@ func (t *rebuildResultTracker) result() RebuildResult { } } -func (c *Client) Rebuild(ctx context.Context, project int64, prefix string, toVersion *int64, dir string, ignores []string, cacheDir string, matcher *files.FileMatcher, summarize bool) (RebuildResult, error) { +func (c *Client) Rebuild(ctx context.Context, project int64, prefix string, toVersion *int64, dir string, ignores []string, subpaths []string, cacheDir string, matcher *files.FileMatcher, summarize bool) (RebuildResult, error) { ctx, span := telemetry.Start(ctx, "client.rebuild", trace.WithAttributes( key.Project.Attribute(project), key.Prefix.Attribute(prefix), @@ -381,6 +381,7 @@ func (c *Client) Rebuild(ctx context.Context, project int64, prefix string, toVe Path: prefix, IsPrefix: true, Ignores: ignores, + Subpaths: subpaths, } availableCacheVersions := ReadCacheVersionFile(cacheDir) @@ -504,7 +505,7 @@ func (c *Client) Rebuild(ctx context.Context, project int64, prefix string, toVe return result, nil } -func (c *Client) Update(rootCtx context.Context, project int64, dir string) (int64, uint32, error) { +func (c *Client) Update(rootCtx context.Context, project int64, dir string, subpaths []string) (int64, uint32, error) { rootCtx, span := telemetry.Start(rootCtx, "client.update", trace.WithAttributes( key.Project.Attribute(project), key.Directory.Attribute(dir), @@ -525,6 +526,19 @@ func (c *Client) Update(rootCtx context.Context, project int64, dir string) (int return fromVersion, 0, nil } + if len(subpaths) > 0 { + filteredUpdates := make([]*fsdiff_pb.Update, 0, len(diff.Updates)) + for _, update := range diff.Updates { + for _, subpath := range subpaths { + if strings.HasPrefix(update.Path, subpath) { + filteredUpdates = append(filteredUpdates, update) + break + } + } + } + diff.Updates = filteredUpdates + } + toVersion := int64(-1) updateChan := make(chan *fsdiff_pb.Update, len(diff.Updates)) @@ -642,7 +656,7 @@ func (c *Client) Update(rootCtx context.Context, project int64, dir string) (int return -1, updateCount, err } } else { - result, err := c.Rebuild(rootCtx, project, "", nil, dir, nil, "", nil, true) + result, err := c.Rebuild(rootCtx, project, "", nil, dir, nil, nil, "", nil, true) if err != nil { return -1, updateCount, err } diff --git a/test/client_combined_test.go b/test/client_combined_test.go index 46b8e07b..d33725be 100644 --- a/test/client_combined_test.go +++ b/test/client_combined_test.go @@ -29,7 +29,7 @@ func TestCombined(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a": {content: "a v1"}, @@ -47,7 +47,7 @@ func TestCombined(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a": {content: "a v2"}, @@ -74,7 +74,7 @@ func TestCombinedWithIdenticalObjects(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a": {content: "a v1"}, @@ -94,7 +94,7 @@ func TestCombinedWithIdenticalObjects(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 2, count: 3, - }) + }, nil) // Reset the tmpdir to remove all state and updates os.RemoveAll(tmpDir) @@ -104,12 +104,12 @@ func TestCombinedWithIdenticalObjects(t *testing.T) { rebuild(tc, c, 1, i(1), tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, // Only one file should be updated since /a and /b were identical but had new mod times - }) + }, nil) } func TestCombinedWithEmptyDirectories(t *testing.T) { @@ -130,7 +130,7 @@ func TestCombinedWithEmptyDirectories(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/": {content: "", fileType: typeDirectory}, @@ -144,7 +144,7 @@ func TestCombinedWithEmptyDirectories(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 2, count: 2, - }) + }, nil) stream := &mockGetServer{ctx: tc.Context()} err := fs.Get(prefixQuery(1, nil, ""), stream) @@ -175,7 +175,7 @@ func TestCombinedWithChangingObjectTypes(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a": {content: "a v1"}, @@ -195,7 +195,7 @@ func TestCombinedWithChangingObjectTypes(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a/": {fileType: typeDirectory}, @@ -220,7 +220,7 @@ func TestCombinedNonEmptyDirectoryIntoFile(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "foo/bar": {content: "file contents"}, @@ -236,7 +236,7 @@ func TestCombinedNonEmptyDirectoryIntoFile(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "foo": {content: "content"}, @@ -259,7 +259,7 @@ func TestCombinedNonEmptyDirectoryIntoSymlink(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "foo/bar": {content: "file contents"}, @@ -276,7 +276,7 @@ func TestCombinedNonEmptyDirectoryIntoSymlink(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "target": {content: "content"}, @@ -300,7 +300,7 @@ func TestCombinedFileIntoNonEmptyDirectory(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "foo": {content: "file contents"}, @@ -316,7 +316,7 @@ func TestCombinedFileIntoNonEmptyDirectory(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "foo/bar": {content: "content"}, @@ -339,7 +339,7 @@ func TestCombinedFileIntoEmptyDirectory(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "foo": {content: "file contents"}, @@ -355,7 +355,7 @@ func TestCombinedFileIntoEmptyDirectory(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "foo/": {fileType: typeDirectory}, @@ -383,7 +383,7 @@ func TestCombinedWithPacked(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 4, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/c": {content: "a/c v1"}, @@ -406,7 +406,7 @@ func TestCombinedWithPacked(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 3, // We updated a pack so all of them were rebuilt - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a/c": {content: "a/c v2"}, @@ -438,7 +438,7 @@ func TestCombinedWithPackedSymlinks(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 6, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/c": {content: "a/c v1"}, @@ -462,7 +462,7 @@ func TestCombinedWithPackedSymlinks(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 6, // We updated one file in a pack so all of them were rebuilt - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a/c": {content: "a/c v2"}, @@ -494,7 +494,7 @@ func TestCombinedWithPackAsASymlink(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/c": {content: "a/c v1"}, @@ -515,7 +515,7 @@ func TestCombinedWithPackAsASymlink(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 4, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a/c": {content: "a/c v2"}, @@ -546,7 +546,7 @@ func TestCombinedWithIdenticalPackedObjects(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/c": {content: "a/c v1"}, @@ -566,7 +566,7 @@ func TestCombinedWithIdenticalPackedObjects(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 2, count: 3, - }) + }, nil) os.RemoveAll(tmpDir) err = os.Mkdir(tmpDir, 0775) @@ -575,12 +575,12 @@ func TestCombinedWithIdenticalPackedObjects(t *testing.T) { rebuild(tc, c, 1, i(1), tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, // Only one file should be updated since /a and /b were identical but with a new mod times - }) + }, nil) } func TestCombinedWithPrefixDirectoryBug(t *testing.T) { @@ -599,7 +599,7 @@ func TestCombinedWithPrefixDirectoryBug(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/": {content: "", fileType: typeDirectory}, @@ -610,7 +610,7 @@ func TestCombinedWithPrefixDirectoryBug(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 2, count: 1, - }) + }, nil) stream := &mockGetServer{ctx: tc.Context()} err := fs.Get(prefixQuery(1, nil, ""), stream) @@ -621,3 +621,50 @@ func TestCombinedWithPrefixDirectoryBug(t *testing.T) { "abc": {content: "abc v2"}, }) } + +func TestRebuildUpdateWithSubpaths(t *testing.T) { + tc := util.NewTestCtx(t, auth.Project, 1) + defer tc.Close() + + writeProject(tc, 1, 1) + writeObject(tc, 1, 1, nil, "ab", "ab v1") + writePackedFiles(tc, 1, 1, nil, "pack/a") + writePackedFiles(tc, 1, 1, nil, "pack/sub/b") + writePackedFiles(tc, 1, 1, nil, "pack/sub/c") + + c, _, close := createTestClient(tc) + defer close() + + tmpDir := emptyTmpDir(t) + defer os.RemoveAll(tmpDir) + + rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ + version: 1, + count: 4, + }, []string{"pack/sub"}) + + // Should only have the objects under the subpath + verifyDir(t, tmpDir, 1, map[string]expectedFile{ + "pack/sub/b/1": {content: "pack/sub/b/1 v1"}, + "pack/sub/b/2": {content: "pack/sub/b/2 v1"}, + "pack/sub/c/1": {content: "pack/sub/c/1 v1"}, + "pack/sub/c/2": {content: "pack/sub/c/2 v1"}, + }) + + writeFile(t, tmpDir, "pack/sub/c/1", "pack/sub/c/1 v2") + writeFile(t, tmpDir, "pack/a/1", "pack/a/1 v2") + + // Should only update pack/sub/c which is part of the subpaths + update(tc, c, 1, tmpDir, expectedResponse{ + version: 2, + count: 1, + }, []string{"pack/sub"}) + + verifyDir(t, tmpDir, 2, map[string]expectedFile{ + "pack/a/1": {content: "pack/a/1 v2"}, + "pack/sub/b/1": {content: "pack/sub/b/1 v1"}, + "pack/sub/b/2": {content: "pack/sub/b/2 v1"}, + "pack/sub/c/1": {content: "pack/sub/c/1 v2"}, + "pack/sub/c/2": {content: "pack/sub/c/2 v1"}, + }) +} diff --git a/test/client_new_test.go b/test/client_new_test.go index d85b01a3..9c00df50 100644 --- a/test/client_new_test.go +++ b/test/client_new_test.go @@ -28,7 +28,7 @@ func TestClientNewProjectEmptyPackPattern(t *testing.T) { require.NoError(t, err, "fs.Update") stream := &mockGetCompressServer{ctx: tc.Context()} - err = fs.GetCompress(buildCompressRequest(1, nil, nil, ""), stream) + err = fs.GetCompress(buildCompressRequest(1, nil, nil, nil, ""), stream) require.NoError(t, err, "fs.GetCompress") // If the objects were marked as packed they would be returned as more than 1 TAR diff --git a/test/client_rebuild_test.go b/test/client_rebuild_test.go index fd13b03d..6294cab2 100644 --- a/test/client_rebuild_test.go +++ b/test/client_rebuild_test.go @@ -36,7 +36,7 @@ func TestRebuild(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a": {content: "a v1"}, @@ -72,7 +72,7 @@ func TestRebuildWithOverwritesAndDeletes(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 4, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a": {content: "a v2"}, @@ -102,7 +102,7 @@ func TestRebuildWithEmptyDirAndSymlink(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 5, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a": {content: "a v1"}, @@ -130,7 +130,7 @@ func TestRebuildWithUpdatedEmptyDirectories(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a/": {content: "", fileType: typeDirectory}, @@ -147,7 +147,7 @@ func TestRebuildWithUpdatedEmptyDirectories(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 2, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a/c": {content: "a/c v2"}, @@ -179,7 +179,7 @@ func TestRebuildWithManyObjects(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 500, - }) + }, nil) verifyDir(t, tmpDir, 1, expectedFiles) } @@ -204,7 +204,7 @@ func TestRebuildWithUpdatedObjectToDirectory(t *testing.T) { rebuild(tc, c, 1, i(1), tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a": {content: "a v1"}, @@ -213,7 +213,7 @@ func TestRebuildWithUpdatedObjectToDirectory(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 4, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 4, map[string]expectedFile{ "a": {content: "a v1"}, @@ -239,7 +239,7 @@ func TestRebuildWithPackedObjects(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 4, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "pack/a/1": {content: "pack/a/1 v1"}, @@ -275,7 +275,7 @@ func TestRebuildWithCache(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, &cacheDir, expectedResponse{ version: 1, count: 2, - }) + }, nil) aCachePath := filepath.Join(client.CacheObjectsDir(cacheDir), ha, "pack/a") bCachePath := filepath.Join(client.CacheObjectsDir(cacheDir), hb, "pack/b") @@ -319,7 +319,7 @@ func TestRebuildWithInexistantCacheDir(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, &badPath, expectedResponse{ version: 1, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "pack/a/1": {content: "pack/a/1 v1"}, @@ -474,7 +474,7 @@ func TestRebuildWithMissingMetadataDir(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "ab": {content: "ab v1"}, @@ -487,7 +487,7 @@ func TestRebuildWithMissingMetadataDir(t *testing.T) { rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ version: 1, count: 3, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "ab": {content: "ab v1"}, @@ -513,7 +513,7 @@ func TestRebuildFileBecomesADir(t *testing.T) { rebuild(tc, c, 1, i(1), tmpDir, nil, expectedResponse{ version: 1, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 1, map[string]expectedFile{ "a.html": {content: "a v1"}, @@ -522,9 +522,39 @@ func TestRebuildFileBecomesADir(t *testing.T) { rebuild(tc, c, 1, i(2), tmpDir, nil, expectedResponse{ version: 2, count: 1, - }) + }, nil) verifyDir(t, tmpDir, 2, map[string]expectedFile{ "a.html/foo": {content: "a v2"}, }) } + +func TestRebuildWithSubpaths(t *testing.T) { + tc := util.NewTestCtx(t, auth.Project, 1) + defer tc.Close() + + writeProject(tc, 1, 1) + writeObject(tc, 1, 1, nil, "ab", "ab v1") + writePackedFiles(tc, 1, 1, nil, "pack/a") + writePackedFiles(tc, 1, 1, nil, "pack/sub/b") + writePackedFiles(tc, 1, 1, nil, "pack/sub/c") + + c, _, close := createTestClient(tc) + defer close() + + tmpDir := emptyTmpDir(t) + defer os.RemoveAll(tmpDir) + + rebuild(tc, c, 1, nil, tmpDir, nil, expectedResponse{ + version: 1, + count: 4, + }, []string{"pack/sub"}) + + // Should only have the objects under the subpath + verifyDir(t, tmpDir, 1, map[string]expectedFile{ + "pack/sub/b/1": {content: "pack/sub/b/1 v1"}, + "pack/sub/b/2": {content: "pack/sub/b/2 v1"}, + "pack/sub/c/1": {content: "pack/sub/c/1 v1"}, + "pack/sub/c/2": {content: "pack/sub/c/2 v1"}, + }) +} diff --git a/test/client_update_test.go b/test/client_update_test.go index 468813d6..a06b14ea 100644 --- a/test/client_update_test.go +++ b/test/client_update_test.go @@ -41,7 +41,7 @@ func TestUpdateObjects(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 2, count: 3, - }) + }, nil) objects, err := c.Get(tc.Context(), 1, "", nil, emptyVersionRange) require.NoError(t, err, "client.GetLatest after update") @@ -71,7 +71,7 @@ func TestUpdatePackedObjectsConsistentHashing(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 1, count: 3, - }) + }, nil) var baseH1, baseH2 []byte @@ -102,7 +102,7 @@ func TestUpdatePackedObjectsConsistentHashing(t *testing.T) { update(tc, c, int64(idx), tmpDir, expectedResponse{ version: 1, count: 3, - }) + }, nil) var newH1, newH2 []byte @@ -151,7 +151,7 @@ func TestUpdateWithManyObjects(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 1, count: 500, - }) + }, nil) objects, err := c.Get(tc.Context(), 1, "", nil, emptyVersionRange) require.NoError(t, err, "client.GetLatest after update") @@ -192,7 +192,7 @@ func TestConcurrentUpdatesSetsCorrectMetadata(t *testing.T) { update(tc, c, 1, tmpDir, expectedResponse{ version: 3, count: 2, - }) + }, nil) verifyDir(t, tmpDir, 3, map[string]expectedFile{ "a": {content: "a v3"}, @@ -220,7 +220,48 @@ func TestUpdateFailsWithTooLargeObject(t *testing.T) { } writeFile(t, tmpDir, "a", sb.String()) - _, _, err := c.Update(tc.Context(), 1, tmpDir) + _, _, err := c.Update(tc.Context(), 1, tmpDir, nil) assert.Error(tc.T(), err) } + +func TestUpdateWithSubpaths(t *testing.T) { + tc := util.NewTestCtx(t, auth.Project, 1) + defer tc.Close() + + writeProject(tc, 1, 1) + writePackedFiles(tc, 1, 1, nil, "pack/a") + writePackedFiles(tc, 1, 1, nil, "pack/sub/b") + writePackedFiles(tc, 1, 1, nil, "pack/sub/c") + + c, _, close := createTestClient(tc) + defer close() + + tmpDir := writeTmpFiles(t, 1, map[string]string{ + "pack/a/1": "pack/a/1 v1", + "pack/a/2": "pack/a/2 v1", + "pack/sub/b/1": "pack/sub/b/1 v1", + "pack/sub/b/2": "pack/sub/b/2 v1", + "pack/sub/c/1": "pack/sub/c/1 v1", + "pack/sub/c/2": "pack/sub/c/2 v1", + }) + defer os.RemoveAll(tmpDir) + + writeFile(t, tmpDir, "pack/sub/c/1", "pack/sub/c/1 v2") + writeFile(t, tmpDir, "pack/a/1", "pack/a/1 v2") + + // Should only update pack/sub/c which is part of the subpaths + update(tc, c, 1, tmpDir, expectedResponse{ + version: 2, + count: 1, + }, []string{"pack/sub"}) + + verifyDir(t, tmpDir, 2, map[string]expectedFile{ + "pack/a/1": {content: "pack/a/1 v2"}, + "pack/a/2": {content: "pack/a/2 v1"}, + "pack/sub/b/1": {content: "pack/sub/b/1 v1"}, + "pack/sub/b/2": {content: "pack/sub/b/2 v1"}, + "pack/sub/c/1": {content: "pack/sub/c/1 v2"}, + "pack/sub/c/2": {content: "pack/sub/c/2 v1"}, + }) +} diff --git a/test/db_test.go b/test/db_test.go index c7feed9b..f9e94025 100644 --- a/test/db_test.go +++ b/test/db_test.go @@ -193,3 +193,69 @@ func TestGetCacheWithMultipleVersions(t *testing.T) { } assert.Equal(t, []string{"pack/a", "pack/b"}, paths) } + +func TestGetCacheWithSubpaths(t *testing.T) { + tc := util.NewTestCtx(t, auth.Admin) + defer tc.Close() + + writeProject(tc, 1, 3, "pack/") + writePackedFiles(tc, 1, 1, nil, "pack/a") + writePackedFiles(tc, 1, 1, nil, "pack/sub/a") + writePackedFiles(tc, 1, 1, nil, "pack/sub/b") + writePackedFiles(tc, 1, 1, nil, "pack/sub/c") + + firstVersion, err := db.CreateCache(tc.Context(), tc.Connect(), "pack/", 100) + require.NoError(t, err) + + version, hashes := latestCacheVersionHashes(tc) + assert.Equal(t, firstVersion, version, "latest cache version matches newly created cache") + assert.Equal(t, 4, len(hashes), "cache hash count") + + vrange, err := db.NewVersionRange(tc.Context(), tc.Connect(), 1, i(0), i(1)) + require.NoError(t, err) + + availableVersions := []int64{firstVersion} + + query := &pb.ObjectQuery{ + Path: "pack", + IsPrefix: true, + Subpaths: []string{"pack/sub"}, + Ignores: []string{"pack/sub/c"}, + } + + tars, err := db.GetTars(tc.Context(), tc.Connect(), tc.ContentLookup(), 1, availableVersions, vrange, query) + require.NoError(t, err) + + var paths []string + + for { + tar, _, err := tars() + if err == io.EOF { + break + } + if err == db.SKIP { + continue + } + tarReader := db.NewTarReader() + tarReader.FromBytes(tar) + + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + require.NoError(t, err) + + content, err := tarReader.ReadContent() + require.NoError(t, err) + + assert.Equal(t, pb.TarCached, int32(header.Typeflag)) + + hexContent := hex.EncodeToString(content) + assert.Regexp(t, regexp.MustCompile("[0-9a-f]{64}"), hexContent) + + paths = append(paths, header.Name) + } + } + assert.Equal(t, []string{"pack/sub/a", "pack/sub/b"}, paths) +} diff --git a/test/fs_test.go b/test/fs_test.go index f8520e4a..432ec640 100644 --- a/test/fs_test.go +++ b/test/fs_test.go @@ -3,9 +3,8 @@ package test import ( "testing" - "github.com/gadget-inc/dateilager/internal/db" - "github.com/gadget-inc/dateilager/internal/auth" + "github.com/gadget-inc/dateilager/internal/db" "github.com/gadget-inc/dateilager/internal/pb" util "github.com/gadget-inc/dateilager/internal/testutil" "github.com/stretchr/testify/assert" @@ -351,7 +350,7 @@ func TestGetCompress(t *testing.T) { fs := tc.FsApi() stream := &mockGetCompressServer{ctx: tc.Context()} - err := fs.GetCompress(buildCompressRequest(1, nil, nil, ""), stream) + err := fs.GetCompress(buildCompressRequest(1, nil, nil, nil, ""), stream) require.NoError(t, err, "fs.GetCompress") assert.Equal(t, 1, len(stream.results), "expected 1 TAR files") @@ -374,7 +373,7 @@ func TestGetCompressWithIgnorePattern(t *testing.T) { fs := tc.FsApi() stream := &mockGetCompressServer{ctx: tc.Context()} - err := fs.GetCompress(buildCompressRequest(1, nil, nil, "", "/a/e"), stream) + err := fs.GetCompress(buildCompressRequest(1, nil, nil, nil, "", "/a/e"), stream) require.NoError(t, err, "fs.GetCompress") assert.Equal(t, 1, len(stream.results), "expected 1 TAR files") @@ -471,7 +470,7 @@ func TestGetCompressReturnsPackedObjectsWithoutRepacking(t *testing.T) { fs := tc.FsApi() stream := &mockGetCompressServer{ctx: tc.Context()} - err := fs.GetCompress(buildCompressRequest(1, nil, nil, ""), stream) + err := fs.GetCompress(buildCompressRequest(1, nil, nil, nil, ""), stream) require.NoError(t, err, "fs.GetCompress") assert.Equal(t, 2, len(stream.results), "expected 2 TAR files") @@ -502,7 +501,7 @@ func TestGetCompressWithCacheVersions(t *testing.T) { fs := tc.FsApi() stream := &mockGetCompressServer{ctx: tc.Context()} - request := buildCompressRequest(1, nil, nil, "") + request := buildCompressRequest(1, nil, nil, nil, "") request.AvailableCacheVersions = []int64{cacheVersion} err = fs.GetCompress(request, stream) diff --git a/test/shared_test.go b/test/shared_test.go index 317c7539..05ffabb1 100644 --- a/test/shared_test.go +++ b/test/shared_test.go @@ -477,14 +477,14 @@ func createTestCachedClient(tc util.TestCtx) (*client.CachedClient, *api.Cached, return cachedClient, cached, func() { cachedClient.Close(); closeClient(); s.Stop() } } -func rebuild(tc util.TestCtx, c *client.Client, project int64, toVersion *int64, dir string, cacheDir *string, expected expectedResponse) { +func rebuild(tc util.TestCtx, c *client.Client, project int64, toVersion *int64, dir string, cacheDir *string, expected expectedResponse, subpaths []string) { if cacheDir == nil { newCacheDir := emptyTmpDir(tc.T()) defer os.RemoveAll(newCacheDir) cacheDir = &newCacheDir } - result, err := c.Rebuild(tc.Context(), project, "", toVersion, dir, nil, *cacheDir, nil, true) + result, err := c.Rebuild(tc.Context(), project, "", toVersion, dir, nil, subpaths, *cacheDir, nil, true) require.NoError(tc.T(), err, "client.Rebuild") assert.Equal(tc.T(), expected.version, result.Version, "mismatch rebuild version") @@ -495,7 +495,7 @@ func rebuildWithMatcher(tc util.TestCtx, c *client.Client, project int64, toVers newCacheDir := emptyTmpDir(tc.T()) defer os.RemoveAll(newCacheDir) - result, err := c.Rebuild(tc.Context(), project, "", toVersion, dir, nil, newCacheDir, matcher, true) + result, err := c.Rebuild(tc.Context(), project, "", toVersion, dir, nil, nil, newCacheDir, matcher, true) require.NoError(tc.T(), err, "client.Rebuild") assert.Equal(tc.T(), expected.version, result.Version, "mismatch rebuild version") @@ -503,8 +503,8 @@ func rebuildWithMatcher(tc util.TestCtx, c *client.Client, project int64, toVers assert.Equal(tc.T(), expectedMatch, result.FileMatch, "unexpected file match") } -func update(tc util.TestCtx, c *client.Client, project int64, dir string, expected expectedResponse) { - version, count, err := c.Update(tc.Context(), project, dir) +func update(tc util.TestCtx, c *client.Client, project int64, dir string, expected expectedResponse, subpaths []string) { + version, count, err := c.Update(tc.Context(), project, dir, subpaths) require.NoError(tc.T(), err, "client.Update") assert.Equal(tc.T(), expected.version, version, "mismatch update version") @@ -642,13 +642,18 @@ func rangeQuery(project int64, fromVersion, toVersion *int64, paths ...string) * return buildRequest(project, fromVersion, toVersion, true, paths...) } -func buildCompressRequest(project int64, fromVersion, toVersion *int64, paths ...string) *pb.GetCompressRequest { +func buildCompressRequest(project int64, fromVersion, toVersion *int64, subpaths []string, paths ...string) *pb.GetCompressRequest { path, ignores := paths[0], paths[1:] + if subpaths == nil { + subpaths = []string{} + } + query := &pb.ObjectQuery{ Path: path, IsPrefix: true, Ignores: ignores, + Subpaths: subpaths, } return &pb.GetCompressRequest{