/* Copyright © 2021 Drew Short Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // Package parser implements the required components for working with image definitions package parser import ( "errors" "fmt" log "github.com/sirupsen/logrus" ) // ParseResult is the standard representation for am image declaration type ParseResult struct { FilePath string Stages []*Stage } // String implements fmt.Stringer interface func (pr ParseResult) String() string { return fmt.Sprintf( "%s with %d stage(s)", pr.FilePath, len(pr.Stages), ) } // Stage is the representation of a stage in the image declaration type Stage struct { Index int Name string Image *Image Repositories []*Repository Packages []*Package StageLocation ContentLocation CommandLocations []*ContentLocation } // String implements fmt.Stringer interface func (s Stage) String() string { return fmt.Sprintf( "%d %s %s", s.Index, s.Name, s.Image, ) } // ContentLocation information about where a specific set of information exists within the file/manifest type ContentLocation struct { StartLine int StartCharacter int EndLine int EndCharacter int } // String implements fmt.Stringer interface func (cl ContentLocation) String() string { return fmt.Sprintf( "%d.%d:%d.%d", cl.StartLine, cl.StartCharacter, cl.EndLine, cl.EndCharacter, ) } // Image is the representation of the reference to a container image layer type Image struct { Name string Tag string } // String implements fmt.Stringer interface func (i Image) String() string { return fmt.Sprintf( "%s:%s", i.Name, i.Tag, ) } // Package is the representation of an installed pinned package defined in an image stage declaration type Package struct { Name string Version string } // String implements fmt.Stringer interface func (p Package) String() string { return fmt.Sprintf( "%s=%s", p.Name, p.Version, ) } // Repository is the representation of an added repository defined in a stage declaration type Repository struct { Information string } // String implements fmt.Stringer interface func (r Repository) String() string { return fmt.Sprintf( "%s", r.Information, ) } // CommandParserType represents the recognized type of parser usable for a specific image type CommandParserType int const ( CommandParserTypeDebian CommandParserType = iota ) // commandParserTypeIds is a lookup map between CommandParserType and a representation string var commandParserTypeIds = map[CommandParserType][]string{ CommandParserTypeDebian: {"debian"}, } // findCommandParserTypeName lookup the command parser name by type enum func findCommandParserTypeName(parserType CommandParserType) string { if parserTypeName, ok := commandParserTypeIds[parserType]; ok { return parserTypeName[0] } else { return "UNKNOWN" } } var availableCommandParsers = map[CommandParserType]CommandParser{} // CommandParser handles parsing commands from RUN arguments dependent on the base image type type CommandParser interface { GetRepositories(logger *log.Entry, runCommand string) ([]*Repository, error) GetPinnedPackages(logger *log.Entry, runCommand string) ([]*Package, error) } // InitCommandParsers exposes functionality to configure the behavior of mapping images to a CommandParser func InitCommandParsers() error { // Registering known parsers availableCommandParsers[CommandParserTypeDebian] = newDebianCommandParser() // TODO: Add dynamic loading from configuration return nil } func GetCommandParser(image Image) (*CommandParser, error) { parserType, err := determineParserForImage(image) if err != nil { log.WithFields(log.Fields{ "imageName": image.Name, "imageTag": image.Tag, "sourceError": err, }).Fatal("failed to determine a matching CommandParser for image") return nil, err } if requestedCommandParser, ok := availableCommandParsers[parserType]; ok { return &requestedCommandParser, nil } else { message := "unable to identify command parser type" log.WithFields(log.Fields{ "commandParserType": findCommandParserTypeName(parserType), }).Fatal(message) return nil, errors.New(message) } } // determineParserForImage matches image information to the correct CommandParserType func determineParserForImage(_ Image) (CommandParserType, error) { // TODO: Map image information to the list of command parsers supported return CommandParserTypeDebian, nil }