github.com/arunkumar7540/cli@v6.45.0+incompatible/api/cloudcontroller/ccv2/buildpack.go (about) 1 package ccv2 2 3 import ( 4 "bytes" 5 "code.cloudfoundry.org/cli/api/cloudcontroller" 6 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 7 "code.cloudfoundry.org/cli/api/cloudcontroller/ccv2/internal" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/uploads" 9 "code.cloudfoundry.org/cli/types" 10 "encoding/json" 11 "io" 12 ) 13 14 // Buildpack represents a Cloud Controller Buildpack. 15 type Buildpack struct { 16 Locked types.NullBool 17 Enabled types.NullBool 18 GUID string 19 Name string 20 Position types.NullInt 21 Stack string 22 } 23 24 func (buildpack Buildpack) MarshalJSON() ([]byte, error) { 25 ccBuildpack := struct { 26 Locked *bool `json:"locked,omitempty"` 27 Enabled *bool `json:"enabled,omitempty"` 28 Name string `json:"name"` 29 Position *int `json:"position,omitempty"` 30 Stack string `json:"stack,omitempty"` 31 }{ 32 Name: buildpack.Name, 33 Stack: buildpack.Stack, 34 } 35 36 if buildpack.Position.IsSet { 37 ccBuildpack.Position = &buildpack.Position.Value 38 } 39 if buildpack.Enabled.IsSet { 40 ccBuildpack.Enabled = &buildpack.Enabled.Value 41 } 42 if buildpack.Locked.IsSet { 43 ccBuildpack.Locked = &buildpack.Locked.Value 44 } 45 46 return json.Marshal(ccBuildpack) 47 } 48 49 func (buildpack *Buildpack) UnmarshalJSON(data []byte) error { 50 var alias struct { 51 Metadata internal.Metadata `json:"metadata"` 52 Entity struct { 53 Locked types.NullBool `json:"locked"` 54 Enabled types.NullBool `json:"enabled"` 55 Name string `json:"name"` 56 Position types.NullInt `json:"position"` 57 Stack string `json:"stack"` 58 } `json:"entity"` 59 } 60 61 err := json.Unmarshal(data, &alias) 62 if err != nil { 63 return err 64 } 65 66 buildpack.Locked = alias.Entity.Locked 67 buildpack.Enabled = alias.Entity.Enabled 68 buildpack.GUID = alias.Metadata.GUID 69 buildpack.Name = alias.Entity.Name 70 buildpack.Position = alias.Entity.Position 71 buildpack.Stack = alias.Entity.Stack 72 return nil 73 } 74 75 // CreateBuildpack creates a new buildpack. 76 func (client *Client) CreateBuildpack(buildpack Buildpack) (Buildpack, Warnings, error) { 77 body, err := json.Marshal(buildpack) 78 if err != nil { 79 return Buildpack{}, nil, err 80 } 81 82 request, err := client.newHTTPRequest(requestOptions{ 83 RequestName: internal.PostBuildpackRequest, 84 Body: bytes.NewReader(body), 85 }) 86 if err != nil { 87 return Buildpack{}, nil, err 88 } 89 90 var createdBuildpack Buildpack 91 response := cloudcontroller.Response{ 92 DecodeJSONResponseInto: &createdBuildpack, 93 } 94 95 err = client.connection.Make(request, &response) 96 return createdBuildpack, response.Warnings, err 97 } 98 99 // GetBuildpacks searches for a buildpack with the given name and returns it if it exists. 100 func (client *Client) GetBuildpacks(filters ...Filter) ([]Buildpack, Warnings, error) { 101 request, err := client.newHTTPRequest(requestOptions{ 102 RequestName: internal.GetBuildpacksRequest, 103 Query: ConvertFilterParameters(filters), 104 }) 105 106 if err != nil { 107 return nil, nil, err 108 } 109 110 var buildpacks []Buildpack 111 warnings, err := client.paginate(request, Buildpack{}, func(item interface{}) error { 112 if buildpack, ok := item.(Buildpack); ok { 113 buildpacks = append(buildpacks, buildpack) 114 } else { 115 return ccerror.UnknownObjectInListError{ 116 Expected: Buildpack{}, 117 Unexpected: item, 118 } 119 } 120 return nil 121 }) 122 123 return buildpacks, warnings, err 124 } 125 126 // UpdateBuildpack updates the buildpack with the provided GUID and returns the 127 // updated buildpack. Note: Stack cannot be updated without uploading a new 128 // buildpack. 129 func (client *Client) UpdateBuildpack(buildpack Buildpack) (Buildpack, Warnings, error) { 130 body, err := json.Marshal(buildpack) 131 if err != nil { 132 return Buildpack{}, nil, err 133 } 134 135 request, err := client.newHTTPRequest(requestOptions{ 136 RequestName: internal.PutBuildpackRequest, 137 URIParams: Params{"buildpack_guid": buildpack.GUID}, 138 Body: bytes.NewReader(body), 139 }) 140 if err != nil { 141 return Buildpack{}, nil, err 142 } 143 144 var updatedBuildpack Buildpack 145 response := cloudcontroller.Response{ 146 DecodeJSONResponseInto: &updatedBuildpack, 147 } 148 149 err = client.connection.Make(request, &response) 150 if err != nil { 151 return Buildpack{}, response.Warnings, err 152 } 153 154 return updatedBuildpack, response.Warnings, nil 155 } 156 157 // UploadBuildpack uploads the contents of a buildpack zip to the server. 158 func (client *Client) UploadBuildpack(buildpackGUID string, buildpackPath string, buildpack io.Reader, buildpackLength int64) (Warnings, error) { 159 160 contentLength, err := uploads.CalculateRequestSize(buildpackLength, buildpackPath, "buildpack") 161 if err != nil { 162 return nil, err 163 } 164 165 contentType, body, writeErrors := uploads.CreateMultipartBodyAndHeader(buildpack, buildpackPath, "buildpack") 166 167 request, err := client.newHTTPRequest(requestOptions{ 168 RequestName: internal.PutBuildpackBitsRequest, 169 URIParams: Params{"buildpack_guid": buildpackGUID}, 170 Body: body, 171 }) 172 173 if err != nil { 174 return nil, err 175 } 176 177 request.Header.Set("Content-Type", contentType) 178 request.ContentLength = contentLength 179 180 _, warnings, err := client.uploadBuildpackAsynchronously(request, writeErrors) 181 if err != nil { 182 return warnings, err 183 } 184 return warnings, nil 185 } 186 187 func (client *Client) uploadBuildpackAsynchronously(request *cloudcontroller.Request, writeErrors <-chan error) (Buildpack, Warnings, error) { 188 189 var buildpack Buildpack 190 response := cloudcontroller.Response{ 191 DecodeJSONResponseInto: &buildpack, 192 } 193 194 httpErrors := make(chan error) 195 196 go func() { 197 defer close(httpErrors) 198 199 err := client.connection.Make(request, &response) 200 if err != nil { 201 httpErrors <- err 202 } 203 }() 204 205 // The following section makes the following assumptions: 206 // 1) If an error occurs during file reading, an EOF is sent to the request 207 // object. Thus ending the request transfer. 208 // 2) If an error occurs during request transfer, an EOF is sent to the pipe. 209 // Thus ending the writing routine. 210 var firstError error 211 var writeClosed, httpClosed bool 212 213 for { 214 select { 215 case writeErr, ok := <-writeErrors: 216 if !ok { 217 writeClosed = true 218 break // for select 219 } 220 if firstError == nil { 221 firstError = writeErr 222 } 223 case httpErr, ok := <-httpErrors: 224 if !ok { 225 httpClosed = true 226 break // for select 227 } 228 if firstError == nil { 229 firstError = httpErr 230 } 231 } 232 233 if writeClosed && httpClosed { 234 break // for for 235 } 236 } 237 return buildpack, response.Warnings, firstError 238 }