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  }