go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cipkg/base/generators/cipd.go (about)

     1  // Copyright 2023 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //	http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package generators
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"reflect"
    21  	"strings"
    22  
    23  	"go.chromium.org/luci/cipd/client/cipd"
    24  	"go.chromium.org/luci/cipd/client/cipd/ensure"
    25  	"go.chromium.org/luci/cipd/client/cipd/template"
    26  	"go.chromium.org/luci/cipkg/core"
    27  	"go.chromium.org/luci/common/errors"
    28  	"go.chromium.org/luci/common/system/environ"
    29  )
    30  
    31  // CIPDExport is used for downloading CIPD packages. It behaves similar to
    32  // `cipd export` for the provided ensure file and use ${out} as the cipd
    33  // root path.
    34  // TODO(crbug/1323147): Replace direct call cipd binary with cipd sdk when it's
    35  // available.
    36  type CIPDExport struct {
    37  	Name     string
    38  	Metadata *core.Action_Metadata
    39  
    40  	Ensure   ensure.File
    41  	Expander template.Expander
    42  
    43  	ConfigFile          string
    44  	CacheDir            string
    45  	HTTPUserAgentPrefix string
    46  	MaxThreads          int
    47  	ParallelDownloads   int
    48  	ServiceURL          string
    49  }
    50  
    51  func (c *CIPDExport) Generate(ctx context.Context, plats Platforms) (*core.Action, error) {
    52  	// Expand template based on ctx.Platform.Host before pass it to cipd client
    53  	// for cross-compile
    54  	expander := c.Expander
    55  	if expander == nil {
    56  		expander = template.Platform{
    57  			OS:   cipdOS(plats.Host.OS()),
    58  			Arch: cipdArch(plats.Host.Arch()),
    59  		}.Expander()
    60  	}
    61  
    62  	ef, err := expandEnsureFile(&c.Ensure, expander)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("failed to expand ensure file: %v: %w", c.Ensure, err)
    65  	}
    66  
    67  	var w strings.Builder
    68  	if err := ef.Serialize(&w); err != nil {
    69  		return nil, fmt.Errorf("failed to encode ensure file: %v: %w", ef, err)
    70  	}
    71  
    72  	env := environ.New(nil)
    73  	addEnv := func(k string, v any) {
    74  		if vv := reflect.ValueOf(v); !vv.IsValid() || vv.IsZero() {
    75  			return
    76  		}
    77  		env.Set(k, fmt.Sprintf("%v", v))
    78  	}
    79  
    80  	addEnv(cipd.EnvConfigFile, c.ConfigFile)
    81  	addEnv(cipd.EnvCacheDir, c.CacheDir)
    82  	addEnv(cipd.EnvHTTPUserAgentPrefix, c.HTTPUserAgentPrefix)
    83  	addEnv(cipd.EnvMaxThreads, c.MaxThreads)
    84  	addEnv(cipd.EnvParallelDownloads, c.ParallelDownloads)
    85  	addEnv(cipd.EnvCIPDServiceURL, c.ServiceURL)
    86  
    87  	return &core.Action{
    88  		Name:     c.Name,
    89  		Metadata: c.Metadata,
    90  		Spec: &core.Action_Cipd{
    91  			Cipd: &core.ActionCIPDExport{
    92  				EnsureFile: w.String(),
    93  				Env:        env.Sorted(),
    94  			},
    95  		},
    96  	}, nil
    97  }
    98  
    99  func expandEnsureFile(ef *ensure.File, expander template.Expander) (*ensure.File, error) {
   100  	ef = ef.Clone()
   101  
   102  	for dir, slice := range ef.PackagesBySubdir {
   103  		var s ensure.PackageSlice
   104  		for _, p := range slice {
   105  			pkg, err := p.Expand(expander)
   106  			switch err {
   107  			case template.ErrSkipTemplate:
   108  				continue
   109  			case nil:
   110  			default:
   111  				return nil, errors.Annotate(err, "expanding %#v", pkg).Err()
   112  			}
   113  			p.PackageTemplate = pkg
   114  			s = append(s, p)
   115  		}
   116  		ef.PackagesBySubdir[dir] = s
   117  	}
   118  	return ef, nil
   119  }
   120  
   121  // TODO(fancl): move these to go.chromium.org/luci/cipd as utilities.
   122  func cipdOS(os string) string {
   123  	if os == "darwin" {
   124  		return "mac"
   125  	}
   126  	return os
   127  }
   128  
   129  func cipdArch(arch string) string {
   130  	if arch == "arm" {
   131  		return "armv6l"
   132  	}
   133  	return arch
   134  }