github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/build/buildinstruction/copy.go (about) 1 // Copyright © 2021 Alibaba Group Holding Ltd. 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 buildinstruction 16 17 import ( 18 "fmt" 19 "path/filepath" 20 "strings" 21 22 "github.com/alibaba/sealer/common" 23 "github.com/alibaba/sealer/logger" 24 "github.com/alibaba/sealer/pkg/image/cache" 25 "github.com/alibaba/sealer/pkg/image/store" 26 v1 "github.com/alibaba/sealer/types/api/v1" 27 "github.com/alibaba/sealer/utils" 28 "github.com/alibaba/sealer/utils/collector" 29 "github.com/opencontainers/go-digest" 30 ) 31 32 const ArchReg = "${ARCH}" 33 34 type CopyInstruction struct { 35 src string 36 dest string 37 platform v1.Platform 38 rawLayer v1.Layer 39 fs store.Backend 40 collector collector.Collector 41 } 42 43 func (c CopyInstruction) Exec(execContext ExecContext) (out Out, err error) { 44 var ( 45 hitCache bool 46 chainID cache.ChainID 47 cacheID digest.Digest 48 layerID digest.Digest 49 src = c.src 50 ) 51 defer func() { 52 out.ContinueCache = hitCache 53 out.ParentID = chainID 54 }() 55 56 src = strings.Replace(src, ArchReg, c.platform.Architecture, -1) 57 if !isRemoteSource(src) { 58 cacheID, err = GenerateSourceFilesDigest(execContext.BuildContext, src) 59 if err != nil { 60 logger.Warn("failed to generate src digest,discard cache,%s", err) 61 } 62 63 if execContext.ContinueCache { 64 hitCache, layerID, chainID = tryCache(execContext.ParentID, c.rawLayer, execContext.CacheSvc, execContext.Prober, cacheID) 65 // we hit the cache, so we will reuse the layerID layer. 66 if hitCache { 67 // update chanid as parentid via defer 68 out.LayerID = layerID 69 return out, nil 70 } 71 } 72 } 73 74 tmp, err := utils.MkTmpdir() 75 if err != nil { 76 return out, fmt.Errorf("failed to create tmp dir %s:%v", tmp, err) 77 } 78 79 err = c.collector.Collect(execContext.BuildContext, src, filepath.Join(tmp, c.dest)) 80 if err != nil { 81 return out, fmt.Errorf("failed to collect files to temp dir %s, err: %v", tmp, err) 82 } 83 // if we come here, its new layer need set cache id . 84 layerID, err = execContext.LayerStore.RegisterLayerForBuilder(tmp) 85 if err != nil { 86 return out, fmt.Errorf("failed to register copy layer, err: %v", err) 87 } 88 89 if setErr := c.setCacheID(layerID, cacheID.String()); setErr != nil { 90 logger.Warn("failed to set cache for copy layer err: %v", err) 91 } 92 93 out.LayerID = layerID 94 return out, nil 95 } 96 97 // SetCacheID This function only has meaning for copy layers 98 func (c CopyInstruction) setCacheID(layerID digest.Digest, cID string) error { 99 return c.fs.SetMetadata(layerID, common.CacheID, []byte(cID)) 100 } 101 102 func NewCopyInstruction(ctx InstructionContext) (*CopyInstruction, error) { 103 fs, err := store.NewFSStoreBackend() 104 if err != nil { 105 return nil, fmt.Errorf("failed to init store backend, err: %s", err) 106 } 107 src, dest := ParseCopyLayerContent(ctx.CurrentLayer.Value) 108 c, err := collector.NewCollector(src) 109 if err != nil { 110 return nil, fmt.Errorf("failed to init copy Collector, err: %s", err) 111 } 112 113 return &CopyInstruction{ 114 platform: ctx.Platform, 115 fs: fs, 116 rawLayer: *ctx.CurrentLayer, 117 src: src, 118 dest: dest, 119 collector: c, 120 }, nil 121 }