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 }