func Build()

in pkg/crate/build.go [43:143]


func Build(rootFs fs.FS, spec *cratefile.Config) (*Image, error) {
	// Check arguments
	if spec == nil {
		return nil, errors.New("unable to build a crate with nil specification")
	}

	log.Bg().Info("Extract container ...", zap.String("container", spec.Container.Path))

	// Open container file
	cf, err := fs.ReadFile(rootFs, spec.Container.Path)
	if err != nil {
		return nil, fmt.Errorf("unable to open container '%s': %w", spec.Container.Path, err)
	}

	// Try to load container
	c, err := container.Load(io.LimitReader(bytes.NewBuffer(cf), maxContainerSize))
	if err != nil {
		return nil, fmt.Errorf("unable to load input container '%s': %w", spec.Container.Path, err)
	}

	// Check container sealing status
	if !container.IsSealed(c) {
		log.Bg().Info("Sealing container ...", zap.String("container", spec.Container.Path))

		// Seal with appropriate algorithm
		sc, err := container.Seal(rand.Reader, c, spec.Container.Identities...)
		if err != nil {
			return nil, fmt.Errorf("unable to seal container '%s': %w", spec.Container.Path, err)
		}

		log.Bg().Info("Container sealed ...", zap.String("container", spec.Container.Path))

		// Replace container instance by the sealed one
		c = sc
	}

	// Prepare config manifest
	cfg := schemav1.NewConfig()
	cfg.SetContainers([]string{spec.Container.Name})

	// Preapre archives
	templateArchives := []*TemplateArchive{}

	// Create archives
	archiveNames := []string{}
	for _, arch := range spec.Archives {
		// Clean root path
		rootPath := strings.TrimPrefix(arch.RootPath, ".")
		rootPath = strings.TrimPrefix(rootPath, "/")

		// Restrict sub filesystem
		subFs, errFs := fs.Sub(rootFs, rootPath)
		if errFs != nil {
			return nil, fmt.Errorf("unable to restrict to sub-filesystem: %w", errFs)
		}

		log.Bg().Info("Creating archive ...", zap.String("archive", arch.Name), zap.String("path", arch.RootPath))

		// Create tar.gz archive
		var buf bytes.Buffer
		if err := archive.Create(subFs, &buf,
			archive.ExcludeFiles(arch.ExcludeGlob...),
			archive.IncludeFiles(arch.IncludeGlob...),
		); err != nil {
			return nil, fmt.Errorf("unable to create archive '%s': %w", arch.Name, err)
		}

		// Add archive format suffix
		name := arch.Name
		if !strings.HasSuffix(name, ".tar.gz") {
			name = fmt.Sprintf("%s.tar.gz", arch.Name)
		}

		// Add to config manifest
		archiveNames = append(archiveNames, name)

		// Add layer.
		templateArchives = append(templateArchives, &TemplateArchive{
			Name:    name,
			Archive: buf.Bytes(),
		})
	}

	// Update config manifest
	cfg.SetTemplates(archiveNames)

	// Create
	res := &Image{
		Config: cfg,
		Containers: []*SealedContainer{
			{
				Name:      spec.Container.Name,
				Container: c,
			},
		},
		TemplateArchives: templateArchives,
	}

	// No error
	return res, nil
}