diff --git a/cli/internal/ffi/bindings.h b/cli/internal/ffi/bindings.h index 53f9bd0d86f2f..8c6d63d7d889e 100644 --- a/cli/internal/ffi/bindings.h +++ b/cli/internal/ffi/bindings.h @@ -18,4 +18,8 @@ struct Buffer previous_content(struct Buffer buffer); struct Buffer transitive_closure(struct Buffer buf); -struct Buffer npm_subgraph(struct Buffer buf); +struct Buffer subgraph(struct Buffer buf); + +struct Buffer patches(struct Buffer buf); + +struct Buffer global_change(struct Buffer buf); diff --git a/cli/internal/ffi/ffi.go b/cli/internal/ffi/ffi.go index 82646b19a0836..7bb9518fdb50f 100644 --- a/cli/internal/ffi/ffi.go +++ b/cli/internal/ffi/ffi.go @@ -169,7 +169,11 @@ func PreviousContent(gitRoot, fromCommit, filePath string) ([]byte, error) { } // TransitiveDeps returns the transitive external deps for all provided workspaces -func TransitiveDeps(content []byte, packageManager string, workspaces map[string]map[string]string) (map[string]*ffi_proto.LockfilePackageList, error) { +func TransitiveDeps(content []byte, packageManager string, workspaces map[string]map[string]string, resolutions map[string]string) (map[string]*ffi_proto.LockfilePackageList, error) { + var additionalData *ffi_proto.AdditionalBerryData + if resolutions != nil { + additionalData = &ffi_proto.AdditionalBerryData{Resolutions: resolutions} + } flatWorkspaces := make(map[string]*ffi_proto.PackageDependencyList) for workspace, deps := range workspaces { packageDependencyList := make([]*ffi_proto.PackageDependency, len(deps)) @@ -187,6 +191,7 @@ func TransitiveDeps(content []byte, packageManager string, workspaces map[string Contents: content, PackageManager: toPackageManager(packageManager), Workspaces: flatWorkspaces, + Resolutions: additionalData, } reqBuf := Marshal(&req) resBuf := C.transitive_closure(reqBuf) @@ -209,20 +214,28 @@ func toPackageManager(packageManager string) ffi_proto.PackageManager { switch packageManager { case "npm": return ffi_proto.PackageManager_NPM + case "berry": + return ffi_proto.PackageManager_BERRY default: panic(fmt.Sprintf("Invalid package manager string: %s", packageManager)) } } -// NpmSubgraph returns the contents of a npm lockfile subgraph -func NpmSubgraph(content []byte, workspaces []string, packages []string) ([]byte, error) { +// Subgraph returns the contents of a lockfile subgraph +func Subgraph(packageManager string, content []byte, workspaces []string, packages []string, resolutions map[string]string) ([]byte, error) { + var additionalData *ffi_proto.AdditionalBerryData + if resolutions != nil { + additionalData = &ffi_proto.AdditionalBerryData{Resolutions: resolutions} + } req := ffi_proto.SubgraphRequest{ - Contents: content, - Workspaces: workspaces, - Packages: packages, + Contents: content, + Workspaces: workspaces, + Packages: packages, + PackageManager: toPackageManager(packageManager), + Resolutions: additionalData, } reqBuf := Marshal(&req) - resBuf := C.npm_subgraph(reqBuf) + resBuf := C.subgraph(reqBuf) reqBuf.Free() resp := ffi_proto.SubgraphResponse{} @@ -236,3 +249,45 @@ func NpmSubgraph(content []byte, workspaces []string, packages []string) ([]byte return resp.GetContents(), nil } + +// Patches returns all patch files referenced in the lockfile +func Patches(content []byte, packageManager string) []string { + req := ffi_proto.PatchesRequest{ + Contents: content, + PackageManager: toPackageManager(packageManager), + } + reqBuf := Marshal(&req) + resBuf := C.patches(reqBuf) + reqBuf.Free() + + resp := ffi_proto.PatchesResponse{} + if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil { + panic(err) + } + + if err := resp.GetError(); err != "" { + panic(err) + } + + return resp.GetPatches().GetPatches() +} + +// GlobalChange checks if there are any differences between lockfiles that would completely invalidate +// the cache. +func GlobalChange(packageManager string, prevContents []byte, currContents []byte) bool { + req := ffi_proto.GlobalChangeRequest{ + PackageManager: toPackageManager(packageManager), + PrevContents: prevContents, + CurrContents: currContents, + } + reqBuf := Marshal(&req) + resBuf := C.patches(reqBuf) + reqBuf.Free() + + resp := ffi_proto.GlobalChangeResponse{} + if err := Unmarshal(resBuf, resp.ProtoReflect().Interface()); err != nil { + panic(err) + } + + return resp.GetGlobalChange() +} diff --git a/cli/internal/ffi/proto/messages.pb.go b/cli/internal/ffi/proto/messages.pb.go index 68a155a44eca1..6b051e4013473 100644 --- a/cli/internal/ffi/proto/messages.pb.go +++ b/cli/internal/ffi/proto/messages.pb.go @@ -23,16 +23,19 @@ const ( type PackageManager int32 const ( - PackageManager_NPM PackageManager = 0 + PackageManager_NPM PackageManager = 0 + PackageManager_BERRY PackageManager = 1 ) // Enum value maps for PackageManager. var ( PackageManager_name = map[int32]string{ 0: "NPM", + 1: "BERRY", } PackageManager_value = map[string]int32{ - "NPM": 0, + "NPM": 0, + "BERRY": 1, } ) @@ -806,6 +809,7 @@ type TransitiveDepsRequest struct { Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"` PackageManager PackageManager `protobuf:"varint,2,opt,name=package_manager,json=packageManager,proto3,enum=PackageManager" json:"package_manager,omitempty"` Workspaces map[string]*PackageDependencyList `protobuf:"bytes,3,rep,name=workspaces,proto3" json:"workspaces,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Resolutions *AdditionalBerryData `protobuf:"bytes,4,opt,name=resolutions,proto3,oneof" json:"resolutions,omitempty"` } func (x *TransitiveDepsRequest) Reset() { @@ -861,6 +865,13 @@ func (x *TransitiveDepsRequest) GetWorkspaces() map[string]*PackageDependencyLis return nil } +func (x *TransitiveDepsRequest) GetResolutions() *AdditionalBerryData { + if x != nil { + return x.Resolutions + } + return nil +} + type TransitiveDepsResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -941,6 +952,53 @@ func (*TransitiveDepsResponse_Dependencies) isTransitiveDepsResponse_Response() func (*TransitiveDepsResponse_Error) isTransitiveDepsResponse_Response() {} +type AdditionalBerryData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Resolutions map[string]string `protobuf:"bytes,1,rep,name=resolutions,proto3" json:"resolutions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *AdditionalBerryData) Reset() { + *x = AdditionalBerryData{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AdditionalBerryData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AdditionalBerryData) ProtoMessage() {} + +func (x *AdditionalBerryData) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AdditionalBerryData.ProtoReflect.Descriptor instead. +func (*AdditionalBerryData) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{14} +} + +func (x *AdditionalBerryData) GetResolutions() map[string]string { + if x != nil { + return x.Resolutions + } + return nil +} + type LockfilePackage struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -954,7 +1012,7 @@ type LockfilePackage struct { func (x *LockfilePackage) Reset() { *x = LockfilePackage{} if protoimpl.UnsafeEnabled { - mi := &file_turborepo_ffi_messages_proto_msgTypes[14] + mi := &file_turborepo_ffi_messages_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -967,7 +1025,7 @@ func (x *LockfilePackage) String() string { func (*LockfilePackage) ProtoMessage() {} func (x *LockfilePackage) ProtoReflect() protoreflect.Message { - mi := &file_turborepo_ffi_messages_proto_msgTypes[14] + mi := &file_turborepo_ffi_messages_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -980,7 +1038,7 @@ func (x *LockfilePackage) ProtoReflect() protoreflect.Message { // Deprecated: Use LockfilePackage.ProtoReflect.Descriptor instead. func (*LockfilePackage) Descriptor() ([]byte, []int) { - return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{14} + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{15} } func (x *LockfilePackage) GetKey() string { @@ -1015,7 +1073,7 @@ type LockfilePackageList struct { func (x *LockfilePackageList) Reset() { *x = LockfilePackageList{} if protoimpl.UnsafeEnabled { - mi := &file_turborepo_ffi_messages_proto_msgTypes[15] + mi := &file_turborepo_ffi_messages_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1028,7 +1086,7 @@ func (x *LockfilePackageList) String() string { func (*LockfilePackageList) ProtoMessage() {} func (x *LockfilePackageList) ProtoReflect() protoreflect.Message { - mi := &file_turborepo_ffi_messages_proto_msgTypes[15] + mi := &file_turborepo_ffi_messages_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1041,7 +1099,7 @@ func (x *LockfilePackageList) ProtoReflect() protoreflect.Message { // Deprecated: Use LockfilePackageList.ProtoReflect.Descriptor instead. func (*LockfilePackageList) Descriptor() ([]byte, []int) { - return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{15} + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{16} } func (x *LockfilePackageList) GetList() []*LockfilePackage { @@ -1056,16 +1114,17 @@ type SubgraphRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"` - PackageManager string `protobuf:"bytes,2,opt,name=package_manager,json=packageManager,proto3" json:"package_manager,omitempty"` - Workspaces []string `protobuf:"bytes,3,rep,name=workspaces,proto3" json:"workspaces,omitempty"` - Packages []string `protobuf:"bytes,4,rep,name=packages,proto3" json:"packages,omitempty"` + Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"` + PackageManager PackageManager `protobuf:"varint,2,opt,name=package_manager,json=packageManager,proto3,enum=PackageManager" json:"package_manager,omitempty"` + Workspaces []string `protobuf:"bytes,3,rep,name=workspaces,proto3" json:"workspaces,omitempty"` + Packages []string `protobuf:"bytes,4,rep,name=packages,proto3" json:"packages,omitempty"` + Resolutions *AdditionalBerryData `protobuf:"bytes,5,opt,name=resolutions,proto3,oneof" json:"resolutions,omitempty"` } func (x *SubgraphRequest) Reset() { *x = SubgraphRequest{} if protoimpl.UnsafeEnabled { - mi := &file_turborepo_ffi_messages_proto_msgTypes[16] + mi := &file_turborepo_ffi_messages_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1078,7 +1137,7 @@ func (x *SubgraphRequest) String() string { func (*SubgraphRequest) ProtoMessage() {} func (x *SubgraphRequest) ProtoReflect() protoreflect.Message { - mi := &file_turborepo_ffi_messages_proto_msgTypes[16] + mi := &file_turborepo_ffi_messages_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1091,7 +1150,7 @@ func (x *SubgraphRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubgraphRequest.ProtoReflect.Descriptor instead. func (*SubgraphRequest) Descriptor() ([]byte, []int) { - return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{16} + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{17} } func (x *SubgraphRequest) GetContents() []byte { @@ -1101,11 +1160,11 @@ func (x *SubgraphRequest) GetContents() []byte { return nil } -func (x *SubgraphRequest) GetPackageManager() string { +func (x *SubgraphRequest) GetPackageManager() PackageManager { if x != nil { return x.PackageManager } - return "" + return PackageManager_NPM } func (x *SubgraphRequest) GetWorkspaces() []string { @@ -1122,6 +1181,13 @@ func (x *SubgraphRequest) GetPackages() []string { return nil } +func (x *SubgraphRequest) GetResolutions() *AdditionalBerryData { + if x != nil { + return x.Resolutions + } + return nil +} + type SubgraphResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1136,7 +1202,7 @@ type SubgraphResponse struct { func (x *SubgraphResponse) Reset() { *x = SubgraphResponse{} if protoimpl.UnsafeEnabled { - mi := &file_turborepo_ffi_messages_proto_msgTypes[17] + mi := &file_turborepo_ffi_messages_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1149,7 +1215,7 @@ func (x *SubgraphResponse) String() string { func (*SubgraphResponse) ProtoMessage() {} func (x *SubgraphResponse) ProtoReflect() protoreflect.Message { - mi := &file_turborepo_ffi_messages_proto_msgTypes[17] + mi := &file_turborepo_ffi_messages_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1162,7 +1228,7 @@ func (x *SubgraphResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SubgraphResponse.ProtoReflect.Descriptor instead. func (*SubgraphResponse) Descriptor() ([]byte, []int) { - return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{17} + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{18} } func (m *SubgraphResponse) GetResponse() isSubgraphResponse_Response { @@ -1202,6 +1268,298 @@ func (*SubgraphResponse_Contents) isSubgraphResponse_Response() {} func (*SubgraphResponse_Error) isSubgraphResponse_Response() {} +type PatchesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Contents []byte `protobuf:"bytes,1,opt,name=contents,proto3" json:"contents,omitempty"` + PackageManager PackageManager `protobuf:"varint,2,opt,name=package_manager,json=packageManager,proto3,enum=PackageManager" json:"package_manager,omitempty"` +} + +func (x *PatchesRequest) Reset() { + *x = PatchesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PatchesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PatchesRequest) ProtoMessage() {} + +func (x *PatchesRequest) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PatchesRequest.ProtoReflect.Descriptor instead. +func (*PatchesRequest) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{19} +} + +func (x *PatchesRequest) GetContents() []byte { + if x != nil { + return x.Contents + } + return nil +} + +func (x *PatchesRequest) GetPackageManager() PackageManager { + if x != nil { + return x.PackageManager + } + return PackageManager_NPM +} + +type PatchesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Response: + // *PatchesResponse_Patches + // *PatchesResponse_Error + Response isPatchesResponse_Response `protobuf_oneof:"response"` +} + +func (x *PatchesResponse) Reset() { + *x = PatchesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PatchesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PatchesResponse) ProtoMessage() {} + +func (x *PatchesResponse) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PatchesResponse.ProtoReflect.Descriptor instead. +func (*PatchesResponse) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{20} +} + +func (m *PatchesResponse) GetResponse() isPatchesResponse_Response { + if m != nil { + return m.Response + } + return nil +} + +func (x *PatchesResponse) GetPatches() *Patches { + if x, ok := x.GetResponse().(*PatchesResponse_Patches); ok { + return x.Patches + } + return nil +} + +func (x *PatchesResponse) GetError() string { + if x, ok := x.GetResponse().(*PatchesResponse_Error); ok { + return x.Error + } + return "" +} + +type isPatchesResponse_Response interface { + isPatchesResponse_Response() +} + +type PatchesResponse_Patches struct { + Patches *Patches `protobuf:"bytes,1,opt,name=patches,proto3,oneof"` +} + +type PatchesResponse_Error struct { + Error string `protobuf:"bytes,2,opt,name=error,proto3,oneof"` +} + +func (*PatchesResponse_Patches) isPatchesResponse_Response() {} + +func (*PatchesResponse_Error) isPatchesResponse_Response() {} + +type Patches struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Patches []string `protobuf:"bytes,1,rep,name=patches,proto3" json:"patches,omitempty"` +} + +func (x *Patches) Reset() { + *x = Patches{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Patches) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Patches) ProtoMessage() {} + +func (x *Patches) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Patches.ProtoReflect.Descriptor instead. +func (*Patches) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{21} +} + +func (x *Patches) GetPatches() []string { + if x != nil { + return x.Patches + } + return nil +} + +type GlobalChangeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PackageManager PackageManager `protobuf:"varint,1,opt,name=package_manager,json=packageManager,proto3,enum=PackageManager" json:"package_manager,omitempty"` + PrevContents []byte `protobuf:"bytes,2,opt,name=prev_contents,json=prevContents,proto3" json:"prev_contents,omitempty"` + CurrContents []byte `protobuf:"bytes,3,opt,name=curr_contents,json=currContents,proto3" json:"curr_contents,omitempty"` +} + +func (x *GlobalChangeRequest) Reset() { + *x = GlobalChangeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GlobalChangeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GlobalChangeRequest) ProtoMessage() {} + +func (x *GlobalChangeRequest) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GlobalChangeRequest.ProtoReflect.Descriptor instead. +func (*GlobalChangeRequest) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{22} +} + +func (x *GlobalChangeRequest) GetPackageManager() PackageManager { + if x != nil { + return x.PackageManager + } + return PackageManager_NPM +} + +func (x *GlobalChangeRequest) GetPrevContents() []byte { + if x != nil { + return x.PrevContents + } + return nil +} + +func (x *GlobalChangeRequest) GetCurrContents() []byte { + if x != nil { + return x.CurrContents + } + return nil +} + +type GlobalChangeResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + GlobalChange bool `protobuf:"varint,1,opt,name=global_change,json=globalChange,proto3" json:"global_change,omitempty"` +} + +func (x *GlobalChangeResponse) Reset() { + *x = GlobalChangeResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_turborepo_ffi_messages_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GlobalChangeResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GlobalChangeResponse) ProtoMessage() {} + +func (x *GlobalChangeResponse) ProtoReflect() protoreflect.Message { + mi := &file_turborepo_ffi_messages_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GlobalChangeResponse.ProtoReflect.Descriptor instead. +func (*GlobalChangeResponse) Descriptor() ([]byte, []int) { + return file_turborepo_ffi_messages_proto_rawDescGZIP(), []int{23} +} + +func (x *GlobalChangeResponse) GetGlobalChange() bool { + if x != nil { + return x.GlobalChange + } + return false +} + var File_turborepo_ffi_messages_proto protoreflect.FileDescriptor var file_turborepo_ffi_messages_proto_rawDesc = []byte{ @@ -1278,7 +1636,7 @@ var file_turborepo_ffi_messages_proto_rawDesc = []byte{ 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x8c, 0x02, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, + 0x38, 0x01, 0x22, 0xd9, 0x02, 0x0a, 0x15, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, @@ -1289,47 +1647,97 @@ var file_turborepo_ffi_messages_proto_rawDesc = []byte{ 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x1a, 0x55, 0x0a, 0x0f, 0x57, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, - 0x63, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x7a, 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, - 0x65, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x64, - 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x16, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53, 0x0a, - 0x0f, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, - 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x75, - 0x6e, 0x64, 0x22, 0x3b, 0x0a, 0x13, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x6c, 0x69, 0x73, - 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, - 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, - 0x92, 0x01, 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, - 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, - 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, - 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x73, 0x22, 0x54, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, + 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x14, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x65, 0x72, 0x72, + 0x79, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, 0x1a, 0x55, 0x0a, 0x0f, 0x57, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x50, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0e, + 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7a, + 0x0a, 0x16, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x44, 0x65, 0x70, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x0c, 0x64, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x0a, - 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x19, 0x0a, 0x0e, 0x50, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x07, 0x0a, 0x03, - 0x4e, 0x50, 0x4d, 0x10, 0x00, 0x42, 0x0b, 0x5a, 0x09, 0x66, 0x66, 0x69, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x13, 0x41, + 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x65, 0x72, 0x72, 0x79, 0x44, 0x61, + 0x74, 0x61, 0x12, 0x47, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x65, 0x72, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x52, 0x65, + 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, + 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3e, 0x0a, 0x10, 0x52, + 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x53, 0x0a, 0x0f, 0x4c, + 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6f, + 0x75, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x66, 0x6f, 0x75, 0x6e, 0x64, + 0x22, 0x3b, 0x0a, 0x13, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x4c, 0x6f, 0x63, 0x6b, 0x66, 0x69, 0x6c, 0x65, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x22, 0xf0, 0x01, + 0x0a, 0x0f, 0x53, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x38, 0x0a, + 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, + 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x41, 0x64, 0x64, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x42, 0x65, 0x72, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x48, 0x00, + 0x52, 0x0b, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x88, 0x01, 0x01, + 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x22, 0x54, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x67, 0x72, 0x61, 0x70, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x66, 0x0a, 0x0e, 0x50, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x63, 0x6f, 0x6e, 0x74, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x38, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x5f, + 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, + 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x52, 0x0e, + 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x22, 0x5b, + 0x0a, 0x0f, 0x50, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x24, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x50, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x48, 0x00, 0x52, 0x07, + 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, + 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x23, 0x0a, 0x07, 0x50, + 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, + 0x22, 0x99, 0x01, 0x0a, 0x13, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0f, 0x70, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x5f, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x0f, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x52, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, + 0x65, 0x72, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x65, 0x76, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x70, 0x72, 0x65, 0x76, 0x43, + 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x75, 0x72, 0x72, 0x5f, + 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, + 0x63, 0x75, 0x72, 0x72, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x3b, 0x0a, 0x14, + 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x67, 0x6c, 0x6f, + 0x62, 0x61, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x2a, 0x24, 0x0a, 0x0e, 0x50, 0x61, 0x63, + 0x6b, 0x61, 0x67, 0x65, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x07, 0x0a, 0x03, 0x4e, + 0x50, 0x4d, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x42, 0x45, 0x52, 0x52, 0x59, 0x10, 0x01, 0x42, + 0x0b, 0x5a, 0x09, 0x66, 0x66, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1345,7 +1753,7 @@ func file_turborepo_ffi_messages_proto_rawDescGZIP() []byte { } var file_turborepo_ffi_messages_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_turborepo_ffi_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 20) +var file_turborepo_ffi_messages_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_turborepo_ffi_messages_proto_goTypes = []interface{}{ (PackageManager)(0), // 0: PackageManager (*TurboDataDirResp)(nil), // 1: TurboDataDirResp @@ -1362,29 +1770,43 @@ var file_turborepo_ffi_messages_proto_goTypes = []interface{}{ (*WorkspaceDependencies)(nil), // 12: WorkspaceDependencies (*TransitiveDepsRequest)(nil), // 13: TransitiveDepsRequest (*TransitiveDepsResponse)(nil), // 14: TransitiveDepsResponse - (*LockfilePackage)(nil), // 15: LockfilePackage - (*LockfilePackageList)(nil), // 16: LockfilePackageList - (*SubgraphRequest)(nil), // 17: SubgraphRequest - (*SubgraphResponse)(nil), // 18: SubgraphResponse - nil, // 19: WorkspaceDependencies.DependenciesEntry - nil, // 20: TransitiveDepsRequest.WorkspacesEntry + (*AdditionalBerryData)(nil), // 15: AdditionalBerryData + (*LockfilePackage)(nil), // 16: LockfilePackage + (*LockfilePackageList)(nil), // 17: LockfilePackageList + (*SubgraphRequest)(nil), // 18: SubgraphRequest + (*SubgraphResponse)(nil), // 19: SubgraphResponse + (*PatchesRequest)(nil), // 20: PatchesRequest + (*PatchesResponse)(nil), // 21: PatchesResponse + (*Patches)(nil), // 22: Patches + (*GlobalChangeRequest)(nil), // 23: GlobalChangeRequest + (*GlobalChangeResponse)(nil), // 24: GlobalChangeResponse + nil, // 25: WorkspaceDependencies.DependenciesEntry + nil, // 26: TransitiveDepsRequest.WorkspacesEntry + nil, // 27: AdditionalBerryData.ResolutionsEntry } var file_turborepo_ffi_messages_proto_depIdxs = []int32{ 4, // 0: GlobResp.files:type_name -> GlobRespList 7, // 1: ChangedFilesResp.files:type_name -> ChangedFilesList 10, // 2: PackageDependencyList.list:type_name -> PackageDependency - 19, // 3: WorkspaceDependencies.dependencies:type_name -> WorkspaceDependencies.DependenciesEntry + 25, // 3: WorkspaceDependencies.dependencies:type_name -> WorkspaceDependencies.DependenciesEntry 0, // 4: TransitiveDepsRequest.package_manager:type_name -> PackageManager - 20, // 5: TransitiveDepsRequest.workspaces:type_name -> TransitiveDepsRequest.WorkspacesEntry - 12, // 6: TransitiveDepsResponse.dependencies:type_name -> WorkspaceDependencies - 15, // 7: LockfilePackageList.list:type_name -> LockfilePackage - 16, // 8: WorkspaceDependencies.DependenciesEntry.value:type_name -> LockfilePackageList - 11, // 9: TransitiveDepsRequest.WorkspacesEntry.value:type_name -> PackageDependencyList - 10, // [10:10] is the sub-list for method output_type - 10, // [10:10] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 26, // 5: TransitiveDepsRequest.workspaces:type_name -> TransitiveDepsRequest.WorkspacesEntry + 15, // 6: TransitiveDepsRequest.resolutions:type_name -> AdditionalBerryData + 12, // 7: TransitiveDepsResponse.dependencies:type_name -> WorkspaceDependencies + 27, // 8: AdditionalBerryData.resolutions:type_name -> AdditionalBerryData.ResolutionsEntry + 16, // 9: LockfilePackageList.list:type_name -> LockfilePackage + 0, // 10: SubgraphRequest.package_manager:type_name -> PackageManager + 15, // 11: SubgraphRequest.resolutions:type_name -> AdditionalBerryData + 0, // 12: PatchesRequest.package_manager:type_name -> PackageManager + 22, // 13: PatchesResponse.patches:type_name -> Patches + 0, // 14: GlobalChangeRequest.package_manager:type_name -> PackageManager + 17, // 15: WorkspaceDependencies.DependenciesEntry.value:type_name -> LockfilePackageList + 11, // 16: TransitiveDepsRequest.WorkspacesEntry.value:type_name -> PackageDependencyList + 17, // [17:17] is the sub-list for method output_type + 17, // [17:17] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_turborepo_ffi_messages_proto_init() } @@ -1562,7 +1984,7 @@ func file_turborepo_ffi_messages_proto_init() { } } file_turborepo_ffi_messages_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LockfilePackage); i { + switch v := v.(*AdditionalBerryData); i { case 0: return &v.state case 1: @@ -1574,7 +1996,7 @@ func file_turborepo_ffi_messages_proto_init() { } } file_turborepo_ffi_messages_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LockfilePackageList); i { + switch v := v.(*LockfilePackage); i { case 0: return &v.state case 1: @@ -1586,7 +2008,7 @@ func file_turborepo_ffi_messages_proto_init() { } } file_turborepo_ffi_messages_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubgraphRequest); i { + switch v := v.(*LockfilePackageList); i { case 0: return &v.state case 1: @@ -1598,6 +2020,18 @@ func file_turborepo_ffi_messages_proto_init() { } } file_turborepo_ffi_messages_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubgraphRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_turborepo_ffi_messages_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SubgraphResponse); i { case 0: return &v.state @@ -1609,6 +2043,66 @@ func file_turborepo_ffi_messages_proto_init() { return nil } } + file_turborepo_ffi_messages_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PatchesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_turborepo_ffi_messages_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PatchesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_turborepo_ffi_messages_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Patches); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_turborepo_ffi_messages_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GlobalChangeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_turborepo_ffi_messages_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GlobalChangeResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_turborepo_ffi_messages_proto_msgTypes[2].OneofWrappers = []interface{}{ (*GlobResp_Files)(nil), @@ -1623,21 +2117,27 @@ func file_turborepo_ffi_messages_proto_init() { (*PreviousContentResp_Content)(nil), (*PreviousContentResp_Error)(nil), } + file_turborepo_ffi_messages_proto_msgTypes[12].OneofWrappers = []interface{}{} file_turborepo_ffi_messages_proto_msgTypes[13].OneofWrappers = []interface{}{ (*TransitiveDepsResponse_Dependencies)(nil), (*TransitiveDepsResponse_Error)(nil), } - file_turborepo_ffi_messages_proto_msgTypes[17].OneofWrappers = []interface{}{ + file_turborepo_ffi_messages_proto_msgTypes[17].OneofWrappers = []interface{}{} + file_turborepo_ffi_messages_proto_msgTypes[18].OneofWrappers = []interface{}{ (*SubgraphResponse_Contents)(nil), (*SubgraphResponse_Error)(nil), } + file_turborepo_ffi_messages_proto_msgTypes[20].OneofWrappers = []interface{}{ + (*PatchesResponse_Patches)(nil), + (*PatchesResponse_Error)(nil), + } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_turborepo_ffi_messages_proto_rawDesc, NumEnums: 1, - NumMessages: 20, + NumMessages: 27, NumExtensions: 0, NumServices: 0, }, diff --git a/cli/internal/lockfile/berry_lockfile.go b/cli/internal/lockfile/berry_lockfile.go index e76f230d7209e..ce6bbaae4faef 100644 --- a/cli/internal/lockfile/berry_lockfile.go +++ b/cli/internal/lockfile/berry_lockfile.go @@ -1,82 +1,16 @@ package lockfile import ( - "bytes" - "encoding/json" - "fmt" "io" - "reflect" - "regexp" - "sort" - "strconv" - "strings" - "github.com/Masterminds/semver" - "github.com/andybalholm/crlf" - "github.com/pkg/errors" + "github.com/vercel/turbo/cli/internal/ffi" "github.com/vercel/turbo/cli/internal/turbopath" - "github.com/vercel/turbo/cli/internal/yaml" ) -var _multipleKeyRegex = regexp.MustCompile(" *, *") - -// A tag cannot start with a "v" -var _tagRegex = regexp.MustCompile("^[a-zA-Z0-9.-_-[v]][a-zA-Z0-9._-]*$") - -var _metadataKey = "__metadata" - -type _void struct{} - -// BerryLockfileEntry package information from yarn lockfile -// Full Definition at https://github.com/yarnpkg/berry/blob/master/packages/yarnpkg-core/sources/Manifest.ts -// Only a subset of full definition are written to the lockfile -type BerryLockfileEntry struct { - Version string `yaml:"version"` - LanguageName string `yaml:"languageName,omitempty"` - - Dependencies map[string]string `yaml:"dependencies,omitempty"` - PeerDependencies map[string]string `yaml:"peerDependencies,omitempty"` - - DependenciesMeta map[string]BerryDependencyMetaEntry `yaml:"dependenciesMeta,omitempty"` - PeerDependenciesMeta map[string]BerryDependencyMetaEntry `yaml:"peerDependenciesMeta,omitempty"` - - Bin map[string]string `yaml:"bin,omitempty"` - - LinkType string `yaml:"linkType,omitempty"` - Resolution string `yaml:"resolution,omitempty"` - Checksum string `yaml:"checksum,omitempty"` - Conditions string `yaml:"conditions,omitempty"` - - // Only used for metadata entry - CacheKey string `yaml:"cacheKey,omitempty"` -} - -// Return a list of descriptors that this entry possibly uses -func (b *BerryLockfileEntry) possibleDescriptors() []_Descriptor { - descriptors := []_Descriptor{} - addDescriptor := func(name, version string) { - descriptors = append(descriptors, berryPossibleKeys(name, version)...) - } - - for dep, version := range b.Dependencies { - addDescriptor(dep, version) - } - - return descriptors -} - // BerryLockfile representation of berry lockfile type BerryLockfile struct { - packages map[_Locator]*BerryLockfileEntry - version int - cacheKey string - // Mapping descriptors (lodash@npm:^4.17.21) to their resolutions (lodash@npm:4.17.21) - descriptors map[_Descriptor]_Locator - // Mapping regular package locators to patched package locators - patches map[_Locator]_Locator - // Descriptors that are only used by package extensions - packageExtensions map[_Descriptor]_void - hasCRLF bool + contents []byte + resolutions map[string]string } // BerryDependencyMetaEntry Structure for holding if a package is optional or not @@ -89,621 +23,58 @@ var _ Lockfile = (*BerryLockfile)(nil) // ResolvePackage Given a package and version returns the key, resolved version, and if it was found func (l *BerryLockfile) ResolvePackage(_workspace turbopath.AnchoredUnixPath, name string, version string) (Package, error) { - for _, key := range berryPossibleKeys(name, version) { - if locator, ok := l.descriptors[key]; ok { - entry := l.packages[locator] - return Package{ - Found: true, - Key: locator.String(), - Version: entry.Version, - }, nil - } - } - - return Package{}, nil + panic("Should use Rust implementation") } // AllDependencies Given a lockfile key return all (dev/optional/peer) dependencies of that package func (l *BerryLockfile) AllDependencies(key string) (map[string]string, bool) { - deps := map[string]string{} - var locator _Locator - if err := locator.parseLocator(key); err != nil { - // We should never hit this as we have already vetted all entries in the lockfile - // during the creation of the lockfile struct - panic(fmt.Sprintf("invalid locator string: %s", key)) - } - entry, ok := l.packages[locator] - if !ok { - return deps, false - } - - for name, version := range entry.Dependencies { - deps[name] = version - } - - return deps, true + panic("Should use Rust implementation") } // Subgraph Given a list of lockfile keys returns a Lockfile based off the original one that only contains the packages given func (l *BerryLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, packages []string) (Lockfile, error) { - prunedPackages := make(map[_Locator]*BerryLockfileEntry, len(packages)) - prunedDescriptors := make(map[_Descriptor]_Locator, len(prunedPackages)) - patches := make(map[_Locator]_Locator, len(l.patches)) - reverseLookup := l.locatorToDescriptors() - - // add workspace package entries - for locator, pkg := range l.packages { - if locator.reference == "workspace:." { - prunedPackages[locator] = pkg - descriptor := _Descriptor{locator._Ident, locator.reference} - prunedDescriptors[descriptor] = locator - for desc := range reverseLookup[locator] { - prunedDescriptors[desc] = locator - } - } - } - for _, workspacePackage := range workspacePackages { - expectedReference := fmt.Sprintf("workspace:%s", workspacePackage.ToUnixPath().ToString()) - for locator, pkg := range l.packages { - if locator.reference == expectedReference { - prunedPackages[locator] = pkg - descriptor := _Descriptor{locator._Ident, locator.reference} - prunedDescriptors[descriptor] = locator - } - } - } - - for _, key := range packages { - var locator _Locator - if err := locator.parseLocator(key); err != nil { - // We should never hit this as we have already vetted all entries in the lockfile - // during the creation of the lockfile struct - panic(fmt.Sprintf("invalid locator string: %s", key)) - } - entry, ok := l.packages[locator] - if ok { - prunedPackages[locator] = entry - } - // If a package has a patch it should be included in the subgraph - patchLocator, ok := l.patches[locator] - if ok { - patches[locator] = patchLocator - prunedPackages[patchLocator] = l.packages[patchLocator] - } - } - - for _, entry := range prunedPackages { - for _, desc := range entry.possibleDescriptors() { - locator, ok := l.descriptors[desc] - if ok { - prunedDescriptors[desc] = locator - } - } - } - - // For each patch we find all descriptors for the primary package and patched package - for primaryLocator, patchLocator := range patches { - primaryDescriptors := reverseLookup[primaryLocator] - patchDescriptors := reverseLookup[patchLocator] - - // For each patch descriptor we extract the primary descriptor that each patch descriptor targets - // and check if that descriptor is present in the pruned map and add it if it is present - for patch := range patchDescriptors { - primaryVersion, _ := patch.primaryVersion() - primaryDescriptor := _Descriptor{patch._Ident, primaryVersion} - _, isPresent := primaryDescriptors[primaryDescriptor] - if !isPresent { - panic(fmt.Sprintf("Unable to find primary descriptor %s", &primaryDescriptor)) - } - - _, ok := prunedDescriptors[primaryDescriptor] - if ok { - if !ok { - panic(fmt.Sprintf("Unable to find patch for %s", &patchLocator)) - } - prunedDescriptors[patch] = patchLocator - } - } - } - - // Add any descriptors used by package extensions - for descriptor := range l.packageExtensions { - locator := l.descriptors[descriptor] - _, ok := prunedPackages[locator] - if ok { - prunedDescriptors[descriptor] = locator - } + workspaces := make([]string, len(workspacePackages)) + for i, workspace := range workspacePackages { + workspaces[i] = workspace.ToUnixPath().ToString() } - - // berry only includes a cache key in the lockfile if there are entries with a checksum - cacheKey := "" - for _, entry := range prunedPackages { - if entry.Checksum != "" { - cacheKey = l.cacheKey - break - } + contents, err := ffi.Subgraph("berry", l.contents, workspaces, packages, l.resolutions) + if err != nil { + return nil, err } - - return &BerryLockfile{ - packages: prunedPackages, - version: l.version, - cacheKey: cacheKey, - descriptors: prunedDescriptors, - patches: patches, - packageExtensions: l.packageExtensions, - hasCRLF: l.hasCRLF, - }, nil + return &BerryLockfile{contents: contents, resolutions: l.resolutions}, nil } // Encode encode the lockfile representation and write it to the given writer func (l *BerryLockfile) Encode(w io.Writer) error { - // Map all resolved packages to the descriptors that match them - reverseLookup := l.locatorToDescriptors() - - lockfile := make(map[string]*BerryLockfileEntry, len(l.packages)) - - lockfile[_metadataKey] = &BerryLockfileEntry{ - Version: fmt.Sprintf("%d", l.version), - CacheKey: l.cacheKey, - } - - for locator, descriptors := range reverseLookup { - sortedDescriptors := make([]string, len(descriptors)) - i := 0 - for descriptor := range descriptors { - sortedDescriptors[i] = descriptor.String() - i++ - } - sort.Strings(sortedDescriptors) - - key := strings.Join(sortedDescriptors, ", ") - - entry, ok := l.packages[locator] - if !ok { - return fmt.Errorf("Unable to find entry for %s", &locator) - } - - lockfile[key] = entry - } - - if l.hasCRLF { - w = crlf.NewWriter(w) - } - - _, err := io.WriteString(w, `# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! -`) - if err != nil { - return errors.Wrap(err, "unable to write header to lockfile") - } - - return _writeBerryLockfile(w, lockfile) -} - -// Invert the descriptor to locator map -func (l *BerryLockfile) locatorToDescriptors() map[_Locator]map[_Descriptor]_void { - reverseLookup := make(map[_Locator]map[_Descriptor]_void, len(l.packages)) - for descriptor, locator := range l.descriptors { - descriptors, ok := reverseLookup[locator] - if !ok { - reverseLookup[locator] = map[_Descriptor]_void{descriptor: {}} - } else { - descriptors[descriptor] = _void{} - } - } - - return reverseLookup + _, err := w.Write(l.contents) + return err } // Patches return a list of patches used in the lockfile func (l *BerryLockfile) Patches() []turbopath.AnchoredUnixPath { - patches := []turbopath.AnchoredUnixPath{} - - for _, patchLocator := range l.patches { - patchPath, isPatch := patchLocator.patchPath() - - if isPatch && !strings.HasPrefix(patchPath, "~") && !_builtinRegexp.MatchString(patchPath) { - patches = append(patches, turbopath.AnchoredUnixPath(patchPath)) - } - } - - if len(patches) == 0 { + rawPatches := ffi.Patches(l.contents, "berry") + if len(rawPatches) == 0 { return nil } - + patches := make([]turbopath.AnchoredUnixPath, len(rawPatches)) + for i, patch := range rawPatches { + patches[i] = turbopath.AnchoredUnixPath(patch) + } return patches } // DecodeBerryLockfile Takes the contents of a berry lockfile and returns a struct representation -func DecodeBerryLockfile(contents []byte) (*BerryLockfile, error) { - var packages map[string]*BerryLockfileEntry - - hasCRLF := bytes.HasSuffix(contents, _crlfLiteral) - err := yaml.Unmarshal(contents, &packages) - if err != nil { - return &BerryLockfile{}, fmt.Errorf("could not unmarshal lockfile: %w", err) - } - - metadata, ok := packages[_metadataKey] - if !ok { - return nil, errors.New("No __metadata entry found when decoding yarn.lock") - } - version, err := strconv.Atoi(metadata.Version) - if err != nil { - return nil, errors.Wrap(err, "yarn lockfile version isn't valid integer") - } - delete(packages, _metadataKey) - - locatorToPackage := map[_Locator]*BerryLockfileEntry{} - descriptorToLocator := map[_Descriptor]_Locator{} - // A map from packages to their patch entries - patches := map[_Locator]_Locator{} - - for key, data := range packages { - var locator _Locator - if err := locator.parseLocator(data.Resolution); err != nil { - return nil, errors.Wrap(err, "unable to parse entry") - } - - if _, isPatch := locator.patchPath(); isPatch { - // A patch will have the same identifier and version allowing us to construct the non-patch entry - originalLocator := _Locator{locator._Ident, fmt.Sprintf("npm:%s", data.Version)} - patches[originalLocator] = locator - } - - // Before storing cacheKey set it to "" so we know it's invalid - data.CacheKey = "" - - locatorToPackage[locator] = data - - // All descriptors that resolve to a single locator are grouped into a single key - for _, entry := range _multipleKeyRegex.Split(key, -1) { - descriptor := _Descriptor{} - if err := descriptor.parseDescriptor(entry); err != nil { - return nil, errors.Wrap(err, "Bad entry key found") - } - - // Before lockfile version 6 descriptors could be missing the npm protocol - if version <= 6 && descriptor.versionRange != "*" { - _, err := semver.NewConstraint(descriptor.versionRange) - if err == nil || _tagRegex.MatchString(descriptor.versionRange) { - descriptor.versionRange = fmt.Sprintf("npm:%s", descriptor.versionRange) - } - } - - descriptorToLocator[descriptor] = locator - } - } - - // Build up list of all descriptors in the file - packageExtensions := make(map[_Descriptor]_void, len(descriptorToLocator)) - for descriptor := range descriptorToLocator { - if descriptor.protocol() == "npm" { - packageExtensions[descriptor] = _void{} - } - } - // Remove any that are found in the lockfile entries - for _, entry := range packages { - for _, descriptor := range entry.possibleDescriptors() { - delete(packageExtensions, descriptor) - } - } - - lockfile := BerryLockfile{ - packages: locatorToPackage, - version: version, - cacheKey: metadata.CacheKey, - descriptors: descriptorToLocator, - patches: patches, - packageExtensions: packageExtensions, - hasCRLF: hasCRLF, - } - return &lockfile, nil +func DecodeBerryLockfile(contents []byte, resolutions map[string]string) (*BerryLockfile, error) { + return &BerryLockfile{contents: contents, resolutions: resolutions}, nil } // GlobalChange checks if there are any differences between lockfiles that would completely invalidate // the cache. func (l *BerryLockfile) GlobalChange(other Lockfile) bool { - otherBerry, ok := other.(*BerryLockfile) - return !ok || - l.cacheKey != otherBerry.cacheKey || - l.version != otherBerry.version || - // This is probably overly cautious, but getting it correct will be hard - !reflect.DeepEqual(l.patches, otherBerry.patches) -} - -// Fields shared between _Locator and _Descriptor -type _Ident struct { - // Scope of package without leading @ - scope string - // Name of package - name string -} - -type _Locator struct { - _Ident - // Resolved version e.g. 1.2.3 - reference string -} - -type _Descriptor struct { - _Ident - // Version range e.g. ^1.0.0 - // Can be prefixed with the protocol e.g. npm, workspace, patch, - versionRange string -} - -func (i _Ident) String() string { - if i.scope == "" { - return i.name - } - return fmt.Sprintf("@%s/%s", i.scope, i.name) -} - -var _locatorRegexp = regexp.MustCompile("^(?:@([^/]+?)/)?([^/]+?)(?:@(.+))$") - -func (l *_Locator) parseLocator(data string) error { - matches := _locatorRegexp.FindStringSubmatch(data) - if len(matches) != 4 { - return fmt.Errorf("%s is not a valid locator string", data) - } - l.scope = matches[1] - l.name = matches[2] - l.reference = matches[3] - - return nil -} - -func (l *_Locator) String() string { - if l.scope == "" { - return fmt.Sprintf("%s@%s", l.name, l.reference) - } - return fmt.Sprintf("@%s/%s@%s", l.scope, l.name, l.reference) -} - -var _builtinRegexp = regexp.MustCompile("^builtin<([^>]+)>$") - -func (l *_Locator) patchPath() (string, bool) { - if strings.HasPrefix(l.reference, "patch:") { - patchFileIndex := strings.Index(l.reference, "#") - paramIndex := strings.LastIndex(l.reference, "::") - if patchFileIndex == -1 || paramIndex == -1 { - // Better error handling - panic("Unable to extract patch file path from lockfile entry") - } - patchPath := strings.TrimPrefix(l.reference[patchFileIndex+1:paramIndex], "./") - - return patchPath, true - } - - return "", false -} - -var _descriptorRegexp = regexp.MustCompile("^(?:@([^/]+?)/)?([^/]+?)(?:@(.+))?$") - -func (d *_Descriptor) parseDescriptor(data string) error { - matches := _descriptorRegexp.FindStringSubmatch(data) - if len(matches) != 4 { - return fmt.Errorf("%s is not a valid descriptor string", data) - } - - d.scope = matches[1] - d.name = matches[2] - d.versionRange = matches[3] - - return nil -} - -// If the descriptor is for a patch it will return the primary descriptor that it patches -func (d *_Descriptor) primaryVersion() (string, bool) { - if !strings.HasPrefix(d.versionRange, "patch:") { - return "", false - } - patchFileIndex := strings.Index(d.versionRange, "#") - versionRangeIndex := strings.Index(d.versionRange, "@") - if patchFileIndex < 0 || versionRangeIndex < 0 { - panic("Patch reference is missing required markers") - } - // The ':' following npm protocol gets encoded as '%3A' in the patch string - version := strings.Replace(d.versionRange[versionRangeIndex+1:patchFileIndex], "%3A", ":", 1) - if !strings.HasPrefix(version, "npm:") { - version = fmt.Sprintf("npm:%s", version) - } - - return version, true -} - -// Returns the protocol of the descriptor -func (d *_Descriptor) protocol() string { - if index := strings.Index(d.versionRange, ":"); index > 0 { - return d.versionRange[:index] - } - return "" -} - -func (d *_Descriptor) String() string { - if d.scope == "" { - return fmt.Sprintf("%s@%s", d.name, d.versionRange) - } - return fmt.Sprintf("@%s/%s@%s", d.scope, d.name, d.versionRange) -} - -func berryPossibleKeys(name string, version string) []_Descriptor { - makeDescriptor := func(protocol string) _Descriptor { - descriptorString := fmt.Sprintf("%s@%s%s", name, protocol, version) - var descriptor _Descriptor - if err := descriptor.parseDescriptor(descriptorString); err != nil { - panic("Generated invalid descriptor") - } - return descriptor - } - return []_Descriptor{ - makeDescriptor(""), - makeDescriptor("npm:"), - makeDescriptor("file:"), - makeDescriptor("workspace:"), - makeDescriptor("yarn:"), - } -} - -func _writeBerryLockfile(w io.Writer, lockfile map[string]*BerryLockfileEntry) error { - keys := make([]string, len(lockfile)) - i := 0 - for key := range lockfile { - keys[i] = key - i++ - } - - // The __metadata key gets hoisted to the top - sort.Slice(keys, func(i, j int) bool { - if keys[i] == _metadataKey { - return true - } else if keys[j] == _metadataKey { - return false - } - return keys[i] < keys[j] - }) - - for _, key := range keys { - value, ok := lockfile[key] - if !ok { - panic(fmt.Sprintf("Unable to find entry for %s", key)) - } - - wrappedKey := _wrapString(key) - wrappedValue := _stringifyEntry(*value, 1) - - var keyPart string - if len(wrappedKey) > 1024 { - keyPart = fmt.Sprintf("? %s\n:", keyPart) - } else { - keyPart = fmt.Sprintf("%s:", wrappedKey) - } - - _, err := io.WriteString(w, fmt.Sprintf("\n%s\n%s\n", keyPart, wrappedValue)) - if err != nil { - return errors.Wrap(err, "unable to write to lockfile") - } - } - - return nil -} - -var _simpleStringPattern = regexp.MustCompile("^[^-?:,\\][{}#&*!|>'\"%@` \t\r\n]([ \t]*[^,\\][{}:# \t\r\n])*$") - -func _wrapString(str string) string { - if !_simpleStringPattern.MatchString(str) { - var b bytes.Buffer - encoder := json.NewEncoder(&b) - encoder.SetEscapeHTML(false) - err := encoder.Encode(str) - if err != nil { - panic("Unexpected error wrapping key") - } - - return strings.TrimRight(b.String(), "\n") - } - return str -} - -func _stringifyEntry(entry BerryLockfileEntry, indentLevel int) string { - lines := []string{} - addLine := func(field, value string, inline bool) { - var line string - if inline { - line = fmt.Sprintf(" %s: %s", field, value) - } else { - line = fmt.Sprintf(" %s:\n%s", field, value) - } - lines = append(lines, line) - } - - if entry.Version != "" { - addLine("version", _wrapString(entry.Version), true) - } - if entry.Resolution != "" { - addLine("resolution", _wrapString(entry.Resolution), true) - } - if len(entry.Dependencies) > 0 { - addLine("dependencies", _stringifyDeps(entry.Dependencies), false) - } - if len(entry.PeerDependencies) > 0 { - addLine("peerDependencies", _stringifyDeps(entry.PeerDependencies), false) - } - if len(entry.DependenciesMeta) > 0 { - addLine("dependenciesMeta", _stringifyDepsMeta(entry.DependenciesMeta), false) - } - if len(entry.PeerDependenciesMeta) > 0 { - addLine("peerDependenciesMeta", _stringifyDepsMeta(entry.PeerDependenciesMeta), false) - } - - if len(entry.Bin) > 0 { - addLine("bin", _stringifyDeps(entry.Bin), false) - } - if entry.Checksum != "" { - addLine("checksum", _wrapString(entry.Checksum), true) - } - if entry.Conditions != "" { - addLine("conditions", _wrapString(entry.Conditions), true) - } - if entry.LanguageName != "" { - addLine("languageName", _wrapString(entry.LanguageName), true) - } - if entry.LinkType != "" { - addLine("linkType", _wrapString(entry.LinkType), true) - } - if entry.CacheKey != "" { - addLine("cacheKey", _wrapString(entry.CacheKey), true) - } - - return strings.Join(lines, "\n") -} - -func _stringifyDeps(deps map[string]string) string { - keys := make([]string, len(deps)) - i := 0 - for key := range deps { - keys[i] = key - i++ - } - sort.Strings(keys) - - lines := make([]string, 0, len(deps)) - addLine := func(name, version string) { - lines = append(lines, fmt.Sprintf(" %s: %s", _wrapString(name), _wrapString(version))) - } - - for _, name := range keys { - version := deps[name] - addLine(name, version) - } - - return strings.Join(lines, "\n") -} - -func _stringifyDepsMeta(meta map[string]BerryDependencyMetaEntry) string { - keys := make([]string, len(meta)) - i := 0 - for key := range meta { - keys[i] = key - i++ - } - sort.Strings(keys) - - lines := make([]string, 0, len(meta)) - addLine := func(name string, key string) { - lines = append(lines, fmt.Sprintf(" %s:\n %s: true", _wrapString(name), key)) - } - - for _, name := range keys { - optional := meta[name] - if optional.Optional { - addLine(name, "optional") - } - if optional.Unplugged { - addLine(name, "unplugged") - } + o, ok := other.(*BerryLockfile) + if !ok { + return true } - return strings.Join(lines, "\n") + return ffi.GlobalChange("berry", o.contents, l.contents) } diff --git a/cli/internal/lockfile/berry_lockfile_test.go b/cli/internal/lockfile/berry_lockfile_test.go index afcbe46b20623..66e6894f04f43 100644 --- a/cli/internal/lockfile/berry_lockfile_test.go +++ b/cli/internal/lockfile/berry_lockfile_test.go @@ -1,273 +1,47 @@ package lockfile import ( - "bytes" "testing" "github.com/vercel/turbo/cli/internal/turbopath" "gotest.tools/v3/assert" ) -func getBerryLockfile(t *testing.T, filename string) *BerryLockfile { - content, err := getFixture(t, filename) - if err != nil { - t.Error(err) - } - lockfile, err := DecodeBerryLockfile(content) - if err != nil { - t.Error(err) - } - return lockfile -} - -func Test_DecodingBerryLockfile(t *testing.T) { - lockfile := getBerryLockfile(t, "berry.lock") - assert.Equal(t, lockfile.version, 6) - assert.Equal(t, lockfile.cacheKey, "8c0") -} - -func Test_ResolvePackage(t *testing.T) { - lockfile := getBerryLockfile(t, "berry.lock") - - type Case struct { - name string - semver string - key string - version string - found bool - } - - cases := map[string]Case{ - "can resolve '||' semver syntax": { - name: "js-tokens", - semver: "^3.0.0 || ^4.0.0", - key: "js-tokens@npm:4.0.0", - version: "4.0.0", - found: true, - }, - "handles packages with multiple descriptors": { - name: "js-tokens", - semver: "^4.0.0", - key: "js-tokens@npm:4.0.0", - version: "4.0.0", - found: true, - }, - "doesn't find nonexistent descriptors": { - name: "@babel/code-frame", - semver: "^7.12.11", - found: false, - }, - "handles workspace packages": { - name: "eslint-config-custom", - semver: "*", - key: "eslint-config-custom@workspace:packages/eslint-config-custom", - version: "0.0.0-use.local", - found: true, - }, - } - - for testName, testCase := range cases { - pkg, err := lockfile.ResolvePackage("some-pkg", testCase.name, testCase.semver) - assert.NilError(t, err) - if testCase.found { - assert.Equal(t, pkg.Key, testCase.key, testName) - assert.Equal(t, pkg.Version, testCase.version, testName) - } - assert.Equal(t, pkg.Found, testCase.found, testName) - } -} - -func Test_AllDependencies(t *testing.T) { - lockfile := getBerryLockfile(t, "berry.lock") - - pkg, err := lockfile.ResolvePackage("some-pkg", "react-dom", "18.2.0") +func Test_BerryPatches(t *testing.T) { + contents := getRustFixture(t, "berry.lock") + lf, err := DecodeBerryLockfile(contents, nil) assert.NilError(t, err) - assert.Assert(t, pkg.Found, "expected to find react-dom") - deps, found := lockfile.AllDependencies(pkg.Key) - assert.Assert(t, found, "expected lockfile key for react-dom to be present") - assert.Equal(t, len(deps), 2, "expected to find all react-dom direct dependencies") - for pkgName, version := range deps { - pkg, err := lockfile.ResolvePackage("some-pkg", pkgName, version) - assert.NilError(t, err, "error finding %s@%s", pkgName, version) - assert.Assert(t, pkg.Found, "expected to find lockfile entry for %s@%s", pkgName, version) - } -} - -func Test_BerryPatchList(t *testing.T) { - lockfile := getBerryLockfile(t, "berry.lock") - - var locator _Locator - if err := locator.parseLocator("resolve@npm:2.0.0-next.4"); err != nil { - t.Error(err) - } - - patchLocator, ok := lockfile.patches[locator] - assert.Assert(t, ok, "Expected to find patch locator") - patch, ok := lockfile.packages[patchLocator] - assert.Assert(t, ok, "Expected to find patch") - assert.Equal(t, patch.Version, "2.0.0-next.4") -} - -func Test_PackageExtensions(t *testing.T) { - lockfile := getBerryLockfile(t, "berry.lock") - - expectedExtensions := map[_Descriptor]_void{} - for _, extension := range []string{"@babel/types@npm:^7.8.3", "lodash@npm:4.17.21"} { - var extensionDescriptor _Descriptor - if err := extensionDescriptor.parseDescriptor(extension); err != nil { - t.Error(err) - } - expectedExtensions[extensionDescriptor] = _void{} - } - - assert.DeepEqual(t, lockfile.packageExtensions, expectedExtensions) -} - -func Test_StringifyMetadata(t *testing.T) { - metadata := BerryLockfileEntry{ - Version: "6", - CacheKey: "8c0", - } - lockfile := map[string]*BerryLockfileEntry{"__metadata": &metadata} - - var b bytes.Buffer - err := _writeBerryLockfile(&b, lockfile) - assert.Assert(t, err == nil) - assert.Equal(t, b.String(), ` -__metadata: - version: 6 - cacheKey: 8c0 -`) -} - -func Test_BerryRoundtrip(t *testing.T) { - content, err := getFixture(t, "berry.lock") - if err != nil { - t.Error(err) - } - lockfile, err := DecodeBerryLockfile(content) - if err != nil { - t.Error(err) - } - - var b bytes.Buffer - if err := lockfile.Encode(&b); err != nil { - t.Error(err) - } - - assert.Equal(t, b.String(), string(content)) -} - -func Test_PatchPathExtraction(t *testing.T) { - type Case struct { - locator string - patchPath string - isPatch bool - } - cases := []Case{ - { - locator: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::version=4.17.21&hash=2c6e9e&locator=berry-patch%40workspace%3A.", - patchPath: ".yarn/patches/lodash-npm-4.17.21-6382451519.patch", - isPatch: true, - }, - { - locator: "lodash@npm:4.17.21", - isPatch: false, - }, - { - locator: "resolve@patch:resolve@npm%3A2.0.0-next.4#~builtin::version=2.0.0-next.4&hash=07638b", - patchPath: "~builtin", - isPatch: true, - }, - } - - for _, testCase := range cases { - var locator _Locator - err := locator.parseLocator(testCase.locator) - if err != nil { - t.Error(err) - } - patchPath, isPatch := locator.patchPath() - assert.Equal(t, isPatch, testCase.isPatch, locator) - assert.Equal(t, patchPath, testCase.patchPath, locator) - } + patches := lf.Patches() + assert.DeepEqual(t, patches, []turbopath.AnchoredUnixPath{".yarn/patches/lodash-npm-4.17.21-6382451519.patch"}) } -func Test_PatchPrimaryVersion(t *testing.T) { - // todo write tests to make sure extraction actually works - type TestCase struct { - descriptor string - version string - isPatch bool - } - testCases := []TestCase{ - { - descriptor: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch::locator=berry-patch%40workspace%3A.", - version: "npm:4.17.21", - isPatch: true, - }, - { - descriptor: "typescript@patch:typescript@^4.5.2#~builtin", - version: "npm:^4.5.2", - isPatch: true, - }, - { - descriptor: "react@npm:18.2.0", - isPatch: false, - }, - } - - for _, testCase := range testCases { - var d _Descriptor - err := d.parseDescriptor(testCase.descriptor) - assert.NilError(t, err, testCase.descriptor) - actual, isPatch := d.primaryVersion() - assert.Equal(t, isPatch, testCase.isPatch, testCase) - if testCase.isPatch { - assert.Equal(t, actual, testCase.version, testCase.descriptor) - } - } +func Test_EmptyBerryPatches(t *testing.T) { + contents := getRustFixture(t, "minimal-berry.lock") + lf, err := DecodeBerryLockfile(contents, nil) + assert.NilError(t, err) + patches := lf.Patches() + assert.Assert(t, patches == nil) } -func Test_BerryPruneDescriptors(t *testing.T) { - lockfile := getBerryLockfile(t, "minimal-berry.lock") - prunedLockfile, err := lockfile.Subgraph( - []turbopath.AnchoredSystemPath{ - turbopath.AnchoredUnixPath("packages/a").ToSystemPath(), - turbopath.AnchoredUnixPath("packages/c").ToSystemPath(), +func Test_BerryTransitiveClosure(t *testing.T) { + contents := getRustFixture(t, "berry.lock") + lf, err := DecodeBerryLockfile(contents, map[string]string{"lodash@^4.17.21": "patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch"}) + assert.NilError(t, err) + closures, err := AllTransitiveClosures(map[turbopath.AnchoredUnixPath]map[string]string{ + turbopath.AnchoredUnixPath(""): {}, + turbopath.AnchoredUnixPath("apps/web"): {}, + turbopath.AnchoredUnixPath("apps/docs"): { + "lodash": "^4.17.21", }, - []string{"lodash@npm:4.17.21"}, - ) - if err != nil { - t.Error(err) - } - lockfileA := prunedLockfile.(*BerryLockfile) + }, lf) + assert.NilError(t, err) + assert.Equal(t, len(closures), 3) - prunedLockfile, err = lockfile.Subgraph( - []turbopath.AnchoredSystemPath{ - turbopath.AnchoredUnixPath("packages/b").ToSystemPath(), - turbopath.AnchoredUnixPath("packages/c").ToSystemPath(), - }, - []string{"lodash@npm:4.17.21"}, - ) - if err != nil { - t.Error(err) + lodash := Package{ + Key: "lodash@npm:4.17.21", + Version: "4.17.21", + Found: true, } - lockfileB := prunedLockfile.(*BerryLockfile) - - lodashIdent := _Ident{name: "lodash"} - lodashA := _Descriptor{lodashIdent, "npm:^4.17.0"} - lodashB := _Descriptor{lodashIdent, "npm:^3.0.0 || ^4.0.0"} - - lodashEntryA, hasLodashA := lockfileA.descriptors[lodashA] - lodashEntryB, hasLodashB := lockfileB.descriptors[lodashB] - - assert.Assert(t, hasLodashA, "Expected lockfile a to have descriptor used by a") - assert.Assert(t, hasLodashB, "Expected lockfile b to have descriptor used by b") - assert.DeepEqual(t, lodashEntryA.reference, lodashEntryB.reference) - - _, lockfileAHasB := lockfileA.descriptors[lodashB] - _, lockfileBHasA := lockfileB.descriptors[lodashA] - assert.Assert(t, !lockfileAHasB, "Expected lockfile a not to have descriptor used by b") - assert.Assert(t, !lockfileBHasA, "Expected lockfile b not to have descriptor used by a") + assert.Assert(t, !closures[turbopath.AnchoredUnixPath("apps/web")].Contains(lodash)) + assert.Assert(t, closures[turbopath.AnchoredUnixPath("apps/docs")].Contains(lodash)) } diff --git a/cli/internal/lockfile/lockfile.go b/cli/internal/lockfile/lockfile.go index b24deee88f818..81667fde7abdc 100644 --- a/cli/internal/lockfile/lockfile.go +++ b/cli/internal/lockfile/lockfile.go @@ -72,9 +72,12 @@ func AllTransitiveClosures( workspaces map[turbopath.AnchoredUnixPath]map[string]string, lockFile Lockfile, ) (map[turbopath.AnchoredUnixPath]mapset.Set, error) { + // We special case as Rust implementations have their own dep crawl if lf, ok := lockFile.(*NpmLockfile); ok { - // We special case as Rust implementations have their own dep crawl - return rustTransitiveDeps(lf.contents, "npm", workspaces) + return rustTransitiveDeps(lf.contents, "npm", workspaces, nil) + } + if lf, ok := lockFile.(*BerryLockfile); ok { + return rustTransitiveDeps(lf.contents, "berry", workspaces, lf.resolutions) } g := new(errgroup.Group) @@ -163,12 +166,12 @@ func transitiveClosureHelper( } } -func rustTransitiveDeps(content []byte, packageManager string, workspaces map[turbopath.AnchoredUnixPath]map[string]string) (map[turbopath.AnchoredUnixPath]mapset.Set, error) { +func rustTransitiveDeps(content []byte, packageManager string, workspaces map[turbopath.AnchoredUnixPath]map[string]string, resolutions map[string]string) (map[turbopath.AnchoredUnixPath]mapset.Set, error) { processedWorkspaces := make(map[string]map[string]string, len(workspaces)) for workspacePath, workspace := range workspaces { processedWorkspaces[workspacePath.ToString()] = workspace } - workspaceDeps, err := ffi.TransitiveDeps(content, packageManager, processedWorkspaces) + workspaceDeps, err := ffi.TransitiveDeps(content, packageManager, processedWorkspaces, resolutions) if err != nil { return nil, err } diff --git a/cli/internal/lockfile/npm_lockfile.go b/cli/internal/lockfile/npm_lockfile.go index dceb560f4c782..f2282e979c81e 100644 --- a/cli/internal/lockfile/npm_lockfile.go +++ b/cli/internal/lockfile/npm_lockfile.go @@ -1,7 +1,6 @@ package lockfile import ( - "encoding/json" "io" "github.com/vercel/turbo/cli/internal/ffi" @@ -34,7 +33,7 @@ func (l *NpmLockfile) Subgraph(workspacePackages []turbopath.AnchoredSystemPath, for i, workspace := range workspacePackages { workspaces[i] = workspace.ToUnixPath().ToString() } - contents, err := ffi.NpmSubgraph(l.contents, workspaces, packages) + contents, err := ffi.Subgraph("npm", l.contents, workspaces, packages, nil) if err != nil { return nil, err } @@ -60,22 +59,7 @@ func (l *NpmLockfile) GlobalChange(other Lockfile) bool { return true } - // We just grab the few global fields and check if they've changed - type minimalJSON struct { - LockfileVersion string `json:"version"` - Requires bool `json:"requires"` - } - var self minimalJSON - var otherJSON minimalJSON - if err := json.Unmarshal(o.contents, &otherJSON); err != nil { - return true - } - if err := json.Unmarshal(l.contents, &self); err != nil { - return true - } - - return self.LockfileVersion != otherJSON.LockfileVersion || - self.Requires != otherJSON.Requires + return ffi.GlobalChange("npm", o.contents, l.contents) } var _ (Lockfile) = (*NpmLockfile)(nil) diff --git a/cli/internal/packagemanager/berry.go b/cli/internal/packagemanager/berry.go index d6264b1c6c2e0..080f9a328fd77 100644 --- a/cli/internal/packagemanager/berry.go +++ b/cli/internal/packagemanager/berry.go @@ -113,8 +113,20 @@ var nodejsBerry = PackageManager{ return true, nil }, - UnmarshalLockfile: func(_rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) { - return lockfile.DecodeBerryLockfile(contents) + UnmarshalLockfile: func(rootPackageJSON *fs.PackageJSON, contents []byte) (lockfile.Lockfile, error) { + var resolutions map[string]string + if untypedResolutions, ok := rootPackageJSON.RawJSON["resolutions"]; ok { + if untypedResolutions, ok := untypedResolutions.(map[string]interface{}); ok { + resolutions = make(map[string]string, len(untypedResolutions)) + for resolution, reference := range untypedResolutions { + if reference, ok := reference.(string); ok { + resolutions[resolution] = reference + } + } + } + } + + return lockfile.DecodeBerryLockfile(contents, resolutions) }, prunePatches: func(pkgJSON *fs.PackageJSON, patches []turbopath.AnchoredUnixPath) error { diff --git a/crates/turborepo-ffi/messages.proto b/crates/turborepo-ffi/messages.proto index 31bd10d514d1b..b609cab5ac1c1 100644 --- a/crates/turborepo-ffi/messages.proto +++ b/crates/turborepo-ffi/messages.proto @@ -56,6 +56,7 @@ message PreviousContentResp { enum PackageManager { NPM = 0; + BERRY = 1; } message PackageDependency { @@ -75,6 +76,7 @@ message TransitiveDepsRequest { bytes contents = 1; PackageManager package_manager = 2; map workspaces = 3; + optional AdditionalBerryData resolutions = 4; } message TransitiveDepsResponse { @@ -84,6 +86,10 @@ message TransitiveDepsResponse { } } +message AdditionalBerryData { + map resolutions = 1; +} + message LockfilePackage { string key = 1; string version = 2; @@ -96,9 +102,10 @@ message LockfilePackageList { message SubgraphRequest { bytes contents = 1; - string package_manager = 2; + PackageManager package_manager = 2; repeated string workspaces = 3; repeated string packages = 4; + optional AdditionalBerryData resolutions = 5; } message SubgraphResponse { @@ -107,3 +114,29 @@ message SubgraphResponse { string error = 2; } } + +message PatchesRequest { + bytes contents = 1; + PackageManager package_manager = 2; +} + +message PatchesResponse { + oneof response { + Patches patches = 1; + string error = 2; + } +} + +message Patches { + repeated string patches = 1; +} + +message GlobalChangeRequest { + PackageManager package_manager = 1; + bytes prev_contents = 2; + bytes curr_contents = 3; +} + +message GlobalChangeResponse { + bool global_change = 1; +} diff --git a/crates/turborepo-ffi/src/lib.rs b/crates/turborepo-ffi/src/lib.rs index 720853594463b..52f97c64c0522 100644 --- a/crates/turborepo-ffi/src/lib.rs +++ b/crates/turborepo-ffi/src/lib.rs @@ -6,7 +6,7 @@ mod lockfile; use std::{mem::ManuallyDrop, path::PathBuf}; -pub use lockfile::{npm_subgraph, transitive_closure}; +pub use lockfile::{patches, subgraph, transitive_closure}; mod proto { include!(concat!(env!("OUT_DIR"), "/_.rs")); diff --git a/crates/turborepo-ffi/src/lockfile.rs b/crates/turborepo-ffi/src/lockfile.rs index 326b6cd11d399..7864610749e08 100644 --- a/crates/turborepo-ffi/src/lockfile.rs +++ b/crates/turborepo-ffi/src/lockfile.rs @@ -4,7 +4,7 @@ use std::{ }; use thiserror::Error; -use turborepo_lockfiles::{self, npm_subgraph as real_npm_subgraph, NpmLockfile, Package}; +use turborepo_lockfiles::{self, BerryLockfile, LockfileData, NpmLockfile, Package}; use super::{proto, Buffer}; @@ -21,10 +21,14 @@ impl From for proto::LockfilePackage { #[derive(Debug, Error)] enum Error { - #[error("error performing lockfile operation")] + #[error("error performing lockfile operation: {0}")] Lockfile(#[from] turborepo_lockfiles::Error), #[error("error decoding protobuf")] Protobuf(#[from] prost::DecodeError), + #[error(transparent)] + BerryParse(#[from] turborepo_lockfiles::BerryError), + #[error("unsupported package manager {0}")] + UnsupportedPackageManager(proto::PackageManager), } #[no_mangle] @@ -42,8 +46,10 @@ pub extern "C" fn transitive_closure(buf: Buffer) -> Buffer { fn transitive_closure_inner(buf: Buffer) -> Result { let request: proto::TransitiveDepsRequest = buf.into_proto()?; + match request.package_manager() { proto::PackageManager::Npm => npm_transitive_closure_inner(request), + proto::PackageManager::Berry => berry_transitive_closure_inner(request), } } @@ -56,25 +62,38 @@ fn npm_transitive_closure_inner( .. } = request; let lockfile = NpmLockfile::load(contents.as_slice())?; - let dependencies = workspaces - .into_iter() - .map(|(workspace_dir, dependencies)| { - let closure = turborepo_lockfiles::transitive_closure( - &lockfile, - &workspace_dir, - dependencies.into(), - )?; - Ok((workspace_dir, proto::LockfilePackageList::from(closure))) - }) - .collect::, Error>>()?; - Ok(proto::WorkspaceDependencies { dependencies }) + let dependencies = turborepo_lockfiles::all_transitive_closures( + &lockfile, + workspaces.into_iter().map(|(k, v)| (k, v.into())).collect(), + )?; + Ok(dependencies.into()) +} + +fn berry_transitive_closure_inner( + request: proto::TransitiveDepsRequest, +) -> Result { + let proto::TransitiveDepsRequest { + contents, + workspaces, + resolutions, + .. + } = request; + let resolutions = + resolutions.map(|r| turborepo_lockfiles::BerryManifest::with_resolutions(r.resolutions)); + let data = LockfileData::from_bytes(contents.as_slice())?; + let lockfile = BerryLockfile::new(&data, resolutions.as_ref())?; + let dependencies = turborepo_lockfiles::all_transitive_closures( + &lockfile, + workspaces.into_iter().map(|(k, v)| (k, v.into())).collect(), + )?; + Ok(dependencies.into()) } #[no_mangle] -pub extern "C" fn npm_subgraph(buf: Buffer) -> Buffer { +pub extern "C" fn subgraph(buf: Buffer) -> Buffer { use proto::subgraph_response::Response; proto::SubgraphResponse { - response: Some(match npm_subgraph_inner(buf) { + response: Some(match subgraph_inner(buf) { Ok(contents) => Response::Contents(contents), Err(err) => Response::Error(err.to_string()), }), @@ -82,12 +101,85 @@ pub extern "C" fn npm_subgraph(buf: Buffer) -> Buffer { .into() } -fn npm_subgraph_inner(buf: Buffer) -> Result, Error> { +fn subgraph_inner(buf: Buffer) -> Result, Error> { let request: proto::SubgraphRequest = buf.into_proto()?; - let contents = real_npm_subgraph(&request.contents, &request.workspaces, &request.packages)?; + let package_manager = request.package_manager(); + let proto::SubgraphRequest { + contents, + workspaces, + packages, + resolutions, + .. + } = request; + let contents = match package_manager { + proto::PackageManager::Npm => { + turborepo_lockfiles::npm_subgraph(&contents, &workspaces, &packages)? + } + proto::PackageManager::Berry => turborepo_lockfiles::berry_subgraph( + &contents, + &workspaces, + &packages, + resolutions.map(|res| res.resolutions), + )?, + }; Ok(contents) } +#[no_mangle] +pub extern "C" fn patches(buf: Buffer) -> Buffer { + use proto::patches_response::Response; + proto::PatchesResponse { + response: Some(match patches_internal(buf) { + Ok(patches) => Response::Patches(patches), + Err(err) => Response::Error(err.to_string()), + }), + } + .into() +} + +fn patches_internal(buf: Buffer) -> Result { + let request: proto::PatchesRequest = buf.into_proto()?; + let patches = match request.package_manager() { + proto::PackageManager::Berry => { + let data = LockfileData::from_bytes(&request.contents)?; + let lockfile = BerryLockfile::new(&data, None)?; + Ok(lockfile + .patches() + .into_iter() + .map(|p| { + p.to_str() + .expect("patch coming from yarn.lock isn't valid utf8") + .to_string() + }) + .collect::>()) + } + pm => Err(Error::UnsupportedPackageManager(pm)), + }?; + Ok(proto::Patches { patches }) +} + +#[no_mangle] +pub extern "C" fn global_change(buf: Buffer) -> Buffer { + // If there's any issue checking if there's been a global lockfile change + // we assume one has changed. + let global_change = global_change_inner(buf).unwrap_or(true); + proto::GlobalChangeResponse { global_change }.into() +} + +fn global_change_inner(buf: Buffer) -> Result { + let request: proto::GlobalChangeRequest = buf.into_proto()?; + match request.package_manager() { + proto::PackageManager::Npm => Ok(turborepo_lockfiles::npm_global_change( + &request.prev_contents, + &request.curr_contents, + )?), + proto::PackageManager::Berry => Ok(turborepo_lockfiles::berry_global_change( + &request.prev_contents, + &request.curr_contents, + )?), + } +} + impl From for HashMap { fn from(other: proto::PackageDependencyList) -> Self { other @@ -109,10 +201,24 @@ impl From> for proto::LockfilePackageList { } } +impl From>> for proto::WorkspaceDependencies { + fn from(value: HashMap>) -> Self { + proto::WorkspaceDependencies { + dependencies: value + .into_iter() + .map(|(workspace, dependencies)| { + (workspace, proto::LockfilePackageList::from(dependencies)) + }) + .collect(), + } + } +} + impl fmt::Display for proto::PackageManager { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { proto::PackageManager::Npm => "npm", + proto::PackageManager::Berry => "berry", }) } } diff --git a/crates/turborepo-lockfiles/src/berry/identifiers.rs b/crates/turborepo-lockfiles/src/berry/identifiers.rs index bb0e147268848..ea3b07ed9ae05 100644 --- a/crates/turborepo-lockfiles/src/berry/identifiers.rs +++ b/crates/turborepo-lockfiles/src/berry/identifiers.rs @@ -200,7 +200,7 @@ impl<'a> Locator<'a> { }) } - fn from_patch_reference(patch_reference: &'a str) -> Option { + pub fn from_patch_reference(patch_reference: &'a str) -> Option { let caps = patch_ref().captures(patch_reference)?; let capture_group = caps.get(1)?; let Locator { ident, reference } = Locator::try_from(capture_group.as_str()).ok()?; @@ -238,14 +238,28 @@ impl<'a> Locator<'a> { patch_ref() .captures(&self.reference) .and_then(|caps| caps.get(2)) - .map(|m| m.as_str()) + .map(|m| { + let s = m.as_str(); + s.strip_prefix("./").unwrap_or(s) + }) } pub fn patched_locator(&self) -> Option { + // THis has an issue of cutting off the last char Locator::from_patch_reference(&self.reference) } } +impl<'a> From> for Descriptor<'a> { + fn from(value: Locator<'a>) -> Self { + let Locator { ident, reference } = value; + Descriptor { + ident, + range: reference, + } + } +} + #[cfg(test)] mod test { use pretty_assertions::assert_eq; @@ -295,6 +309,26 @@ mod test { ) } + #[test] + fn test_locator_buildin_patch() { + assert_eq!( + Locator::try_from( + "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&\ + hash=07638b" + ) + .unwrap(), + Locator { + ident: Ident { + scope: None, + name: "resolve".into() + }, + reference: "patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&\ + hash=07638b" + .into() + }, + ); + } + #[test] fn test_descriptor_roundtrip() { for descriptor in [ @@ -353,32 +387,33 @@ mod test { fn test_patch_primary_version() { struct TestCase { locator: &'static str, - version: Option<&'static str>, + original: Option<&'static str>, } let test_cases = [ TestCase { locator: "lodash@patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.\ 21-6382451519.patch::locator=berry-patch%40workspace%3A.", - version: Some("npm:4.17.21"), + original: Some("lodash@npm:4.17.21"), }, TestCase { locator: "typescript@patch:typescript@^4.5.2#~builtin", - version: Some("npm:^4.5.2"), + original: Some("typescript@npm:^4.5.2"), }, TestCase { locator: "react@npm:18.2.0", - version: None, + original: None, + }, + TestCase { + locator: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.\ + 22.1&hash=07638b", + original: Some("resolve@npm:1.22.1"), }, ]; for tc in test_cases { let locator = Locator::try_from(tc.locator).unwrap(); + let expected = tc.original.map(Locator::try_from).transpose().unwrap(); let patch_locator = locator.patched_locator(); - assert_eq!( - tc.version, - patch_locator.as_ref().map(|l| l.reference.as_ref()), - "{}", - tc.locator - ); + assert_eq!(patch_locator, expected, "{}", tc.locator); } } } diff --git a/crates/turborepo-lockfiles/src/berry/mod.rs b/crates/turborepo-lockfiles/src/berry/mod.rs index c778f0a5d02a3..7e1172383a1dc 100644 --- a/crates/turborepo-lockfiles/src/berry/mod.rs +++ b/crates/turborepo-lockfiles/src/berry/mod.rs @@ -364,6 +364,7 @@ impl<'a> BerryLockfile<'a> { resolution.reduce_dependency(reference, &dependency, locator) { dependency = override_dependency; + break; } } @@ -391,29 +392,13 @@ impl<'a> Lockfile for BerryLockfile<'a> { }) .ok_or_else(|| crate::Error::MissingWorkspace(workspace_path.to_string()))?; - let mut dependency = Descriptor::new(name, version) + let dependency = self + .resolve_dependency(workspace_locator, name, version) .unwrap_or_else(|_| panic!("{name} is an invalid lockfile identifier")); - for (resolution, reference) in &self.overrides { - if let Some(override_dependency) = - resolution.reduce_dependency(reference, &dependency, workspace_locator) - { - dependency = override_dependency; - } - } - - if dependency.protocol().is_none() { - if let Some(range) = self.resolver.get(&dependency) { - dependency.range = range.into(); - } - } - let locator = self.resolutions.get(&dependency); - - if locator.is_none() { + let Some(locator) = self.resolutions.get(&dependency) else { return Ok(None); - } - - let locator = locator.unwrap(); + }; let package = self .locator_package @@ -432,9 +417,8 @@ impl<'a> Lockfile for BerryLockfile<'a> { ) -> Result>, crate::Error> { let locator = Locator::try_from(key).unwrap_or_else(|_| panic!("Was passed invalid locator: {key}")); - let package = self.locator_package.get(&locator); - let Some(package) = package else { + let Some(package) = self.locator_package.get(&locator) else { return Ok(None); }; @@ -620,6 +604,16 @@ mod test { assert_eq!(package.version.as_ref(), "2.0.0-next.4"); } + #[test] + fn test_empty_patch_list() { + let data = + LockfileData::from_bytes(include_bytes!("../../fixtures/minimal-berry.lock")).unwrap(); + let lockfile = BerryLockfile::new(&data, None).unwrap(); + + let empty_vec: Vec<&Path> = Vec::new(); + assert_eq!(lockfile.patches(), empty_vec); + } + #[test] fn test_basic_descriptor_prune() { let data: LockfileData = @@ -653,6 +647,27 @@ mod test { assert_eq!(lodash_desc.unwrap().reference, "npm:4.17.21"); } + #[test] + fn test_closure_with_patch() { + let data = LockfileData::from_bytes(include_bytes!("../../fixtures/berry.lock")).unwrap(); + let resolutions = BerryManifest::with_resolutions(vec![( + "lodash@^4.17.21".into(), + "patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch".into(), + )]); + let lockfile = BerryLockfile::new(&data, Some(&resolutions)).unwrap(); + let closure = crate::transitive_closure( + &lockfile, + "apps/docs", + HashMap::from_iter(vec![("lodash".into(), "^4.17.21".into())]), + ) + .unwrap(); + + assert!(closure.contains(&Package { + key: "lodash@npm:4.17.21".into(), + version: "4.17.21".into() + })); + } + #[test] fn test_basic_resolutions_dependencies() { let data: LockfileData = serde_yaml::from_str(include_str!( diff --git a/crates/turborepo-lockfiles/src/berry/resolution.rs b/crates/turborepo-lockfiles/src/berry/resolution.rs index d88ffce63e712..8f6bc6638cc27 100644 --- a/crates/turborepo-lockfiles/src/berry/resolution.rs +++ b/crates/turborepo-lockfiles/src/berry/resolution.rs @@ -103,6 +103,8 @@ impl<'a> Resolution<'a> { dependency: &Descriptor<'b>, locator: &Locator, ) -> Option> { + // if the ref is patch locator then it will have a suffix of + // ::locator={ROOT_WORKSPACE}@workspace:. ( with @ and : escaped) if let Some(from) = &self.from { let from_ident = from.ident(); // If the from doesn't match the locator we skip @@ -159,6 +161,20 @@ impl<'a> Resolution<'a> { dependency_override.range.to_mut().insert_str(0, "npm:") } + // Patch references aren't complete in the resolutions field so we + // instead resolve to the package getting patched. + // The patch still gets picked up as we include patches for any + // packages in the pruned lockfile if the package is a member. + if matches!(dependency_override.protocol(), Some("patch")) { + return Some( + Descriptor::from( + Locator::from_patch_reference(reference) + .expect("expected patch reference to contain locator"), + ) + .into_owned(), + ); + } + Some(dependency_override) } } @@ -175,7 +191,7 @@ impl fmt::Display for Resolution<'_> { f.write_fmt(format_args!("{from}/"))?; } f.write_fmt(format_args!("{}", self.descriptor))?; - todo!() + Ok(()) } } @@ -267,7 +283,21 @@ mod test { description: None } } - ) + ); + + assert_eq!( + parse_resolution("is-even/is-odd").unwrap(), + Resolution { + from: Some(Specifier { + full_name: "is-even", + description: None + }), + descriptor: Specifier { + full_name: "is-odd", + description: None + } + } + ); } #[test] @@ -286,4 +316,18 @@ mod test { } ) } + + #[test] + fn test_patch_resolution() { + let resolution = parse_resolution("lodash@^4.17.21").unwrap(); + let dependency = resolution.reduce_dependency( + "patch:lodash@npm%3A4.17.21#./.yarn/patches/lodash-npm-4.17.21-6382451519.patch", + &Descriptor::try_from("lodash@^4.17.21").unwrap(), + &Locator::try_from("test@workspace:.").unwrap(), + ); + assert_eq!( + dependency, + Some(Descriptor::try_from("lodash@npm:4.17.21").unwrap()) + ); + } } diff --git a/crates/turborepo-lockfiles/src/lib.rs b/crates/turborepo-lockfiles/src/lib.rs index 74ccc86f5f939..c18d272ec1252 100644 --- a/crates/turborepo-lockfiles/src/lib.rs +++ b/crates/turborepo-lockfiles/src/lib.rs @@ -6,11 +6,12 @@ mod npm; use std::collections::{HashMap, HashSet}; -pub use berry::*; +pub use berry::{Error as BerryError, *}; pub use error::Error; pub use npm::*; +use serde::Serialize; -#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] +#[derive(Debug, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Serialize)] pub struct Package { pub key: String, pub version: String, @@ -33,6 +34,19 @@ pub trait Lockfile { fn all_dependencies(&self, key: &str) -> Result>, Error>; } +pub fn all_transitive_closures( + lockfile: &L, + workspaces: HashMap>, +) -> Result>, Error> { + workspaces + .into_iter() + .map(|(workspace, unresolved_deps)| { + let closure = transitive_closure(lockfile, &workspace, unresolved_deps)?; + Ok((workspace, closure)) + }) + .collect() +} + // this should get replaced by petgraph in the future :) pub fn transitive_closure( lockfile: &L, diff --git a/crates/turborepo-lockfiles/src/npm.rs b/crates/turborepo-lockfiles/src/npm.rs index a551652df93f5..37c4ec5398a2c 100644 --- a/crates/turborepo-lockfiles/src/npm.rs +++ b/crates/turborepo-lockfiles/src/npm.rs @@ -205,6 +205,15 @@ pub fn npm_subgraph( Ok(new_contents) } +pub fn npm_global_change(prev_contents: &[u8], curr_contents: &[u8]) -> Result { + let prev_lockfile = NpmLockfile::load(prev_contents)?; + let curr_lockfile = NpmLockfile::load(curr_contents)?; + + Ok( + prev_lockfile.lockfile_version != curr_lockfile.lockfile_version + || prev_lockfile.other.get("requires") != curr_lockfile.other.get("requires"), + ) +} #[cfg(test)] mod test { use super::*; diff --git a/turborepo-tests/integration/tests/_fixtures/berry_resolutions/.yarnrc.yml b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/.yarnrc.yml new file mode 100644 index 0000000000000..7f3d03fd8b0a9 --- /dev/null +++ b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: "node-modules" diff --git a/turborepo-tests/integration/tests/_fixtures/berry_resolutions/package.json b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/package.json new file mode 100644 index 0000000000000..75aa970324989 --- /dev/null +++ b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/package.json @@ -0,0 +1,11 @@ +{ + "name": "prune-resolutions", + "packageManager": "yarn@3.3.0", + "workspaces": [ + "packages/**" + ], + "resolutions": { + "is-even/is-odd": "3.0.0", + "is-number": "6.0.0" + } +} diff --git a/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/a/package.json b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/a/package.json new file mode 100644 index 0000000000000..2b2cc18470e38 --- /dev/null +++ b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/a/package.json @@ -0,0 +1,6 @@ +{ + "name": "a", + "dependencies": { + "is-even": "^1.0.0" + } +} diff --git a/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/b/package.json b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/b/package.json new file mode 100644 index 0000000000000..4b60f34fa3bcc --- /dev/null +++ b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/packages/b/package.json @@ -0,0 +1,6 @@ +{ + "name": "b", + "dependencies": { + "is-odd": "^3.0.1" + } +} diff --git a/turborepo-tests/integration/tests/_fixtures/berry_resolutions/yarn.lock b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/yarn.lock new file mode 100644 index 0000000000000..a3ee46f126fb4 --- /dev/null +++ b/turborepo-tests/integration/tests/_fixtures/berry_resolutions/yarn.lock @@ -0,0 +1,62 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"a@workspace:packages/a": + version: 0.0.0-use.local + resolution: "a@workspace:packages/a" + dependencies: + is-even: ^1.0.0 + languageName: unknown + linkType: soft + +"b@workspace:packages/b": + version: 0.0.0-use.local + resolution: "b@workspace:packages/b" + dependencies: + is-odd: ^3.0.1 + languageName: unknown + linkType: soft + +"is-even@npm:^1.0.0": + version: 1.0.0 + resolution: "is-even@npm:1.0.0" + dependencies: + is-odd: ^0.1.2 + checksum: 0267545d7cb6724aee249e88942cf22f6263aa006cd9bf83c2ddbb2a1d47280e8c4d72b2d50e38bd3575df717c993904b44153cc1772a55dabca250ca40cc4f7 + languageName: node + linkType: hard + +"is-number@npm:6.0.0": + version: 6.0.0 + resolution: "is-number@npm:6.0.0" + checksum: f73bfced022128b5684bf77e0266a74e5222522bbc40f81cc1e949170c774a3c14b59a208be025d2d97a9c6b79c7c45fe351ab1c2c780872464fdedde0ae067a + languageName: node + linkType: hard + +"is-odd@npm:3.0.0": + version: 3.0.0 + resolution: "is-odd@npm:3.0.0" + dependencies: + is-number: ^6.0.0 + checksum: 1b0614ce1d6af841a5c04980cb8f9a44594444e448b35b5afd05c0aed5ce297e131f898412c42cdbe2e9b24551488e3f5d12a5917395ca42e2a0bc5518893642 + languageName: node + linkType: hard + +"is-odd@npm:^3.0.1": + version: 3.0.1 + resolution: "is-odd@npm:3.0.1" + dependencies: + is-number: ^6.0.0 + checksum: 4e2b20764dd2296bafe44823d127f281c7039b37d2feaf5caffc1bf162502ef2920bcd4ad171490f371d3f15f52232c763a8ffc0b3633d4c83385fe20f3493af + languageName: node + linkType: hard + +"prune-resolutions@workspace:.": + version: 0.0.0-use.local + resolution: "prune-resolutions@workspace:." + languageName: unknown + linkType: soft diff --git a/turborepo-tests/integration/tests/_helpers/copy_fixture.sh b/turborepo-tests/integration/tests/_helpers/copy_fixture.sh new file mode 100755 index 0000000000000..cf0f1dde3b4c6 --- /dev/null +++ b/turborepo-tests/integration/tests/_helpers/copy_fixture.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -e + +SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]}) +TARGET_DIR=$1 +FIXTURE="_fixtures/${2-basic_monorepo}" +cp -a ${SCRIPT_DIR}/../$FIXTURE/. ${TARGET_DIR}/ diff --git a/turborepo-tests/integration/tests/prune/resolutions.t b/turborepo-tests/integration/tests/prune/resolutions.t new file mode 100644 index 0000000000000..d138bf97f29c8 --- /dev/null +++ b/turborepo-tests/integration/tests/prune/resolutions.t @@ -0,0 +1,25 @@ +Setup + $ . ${TESTDIR}/../../../helpers/setup.sh + $ . ${TESTDIR}/../_helpers/copy_fixture.sh $(pwd) berry_resolutions + +Prune a +We expect to no longer have the non-resolved is-odd descriptor and +only have the override that has been set + $ ${TURBO} prune --scope=a + Generating pruned monorepo for a in .*out (re) + - Added a + $ grep -F '"is-odd@npm:' out/yarn.lock + "is-odd@npm:3.0.0": + resolution: "is-odd@npm:3.0.0" + + +Prune b +We should no longer have the override for is-odd + $ ${TURBO} prune --scope=b + Generating pruned monorepo for b in .*out (re) + - Added b + + + $ grep -F '"is-odd@npm:' out/yarn.lock + "is-odd@npm:^3.0.1": + resolution: "is-odd@npm:3.0.1"