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  }