You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
4.9 KiB

  1. /*
  2. Copyright © 2021 Drew Short <warrick@sothr.com>
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // Package parser implements the required components for working with image definitions
  14. package parser
  15. import (
  16. "errors"
  17. "fmt"
  18. log "github.com/sirupsen/logrus"
  19. )
  20. // ParseResult is the standard representation for am image declaration
  21. type ParseResult struct {
  22. FilePath string
  23. Stages []*Stage
  24. }
  25. // String implements fmt.Stringer interface
  26. func (pr ParseResult) String() string {
  27. return fmt.Sprintf(
  28. "%s with %d stage(s)",
  29. pr.FilePath,
  30. len(pr.Stages),
  31. )
  32. }
  33. // Stage is the representation of a stage in the image declaration
  34. type Stage struct {
  35. Index int
  36. Name string
  37. Image *Image
  38. Repositories []*Repository
  39. Packages []*Package
  40. StageLocation ContentLocation
  41. CommandLocations []*ContentLocation
  42. }
  43. // String implements fmt.Stringer interface
  44. func (s Stage) String() string {
  45. return fmt.Sprintf(
  46. "%d %s %s",
  47. s.Index,
  48. s.Name,
  49. s.Image,
  50. )
  51. }
  52. // ContentLocation information about where a specific set of information exists within the file/manifest
  53. type ContentLocation struct {
  54. StartLine int
  55. StartCharacter int
  56. EndLine int
  57. EndCharacter int
  58. }
  59. // String implements fmt.Stringer interface
  60. func (cl ContentLocation) String() string {
  61. return fmt.Sprintf(
  62. "%d.%d:%d.%d",
  63. cl.StartLine,
  64. cl.StartCharacter,
  65. cl.EndLine,
  66. cl.EndCharacter,
  67. )
  68. }
  69. // Image is the representation of the reference to a container image layer
  70. type Image struct {
  71. Name string
  72. Tag string
  73. }
  74. // String implements fmt.Stringer interface
  75. func (i Image) String() string {
  76. return fmt.Sprintf(
  77. "%s:%s",
  78. i.Name,
  79. i.Tag,
  80. )
  81. }
  82. // Package is the representation of an installed pinned package defined in an image stage declaration
  83. type Package struct {
  84. Name string
  85. Version string
  86. }
  87. // String implements fmt.Stringer interface
  88. func (p Package) String() string {
  89. return fmt.Sprintf(
  90. "%s=%s",
  91. p.Name,
  92. p.Version,
  93. )
  94. }
  95. // Repository is the representation of an added repository defined in a stage declaration
  96. type Repository struct {
  97. Information string
  98. }
  99. // String implements fmt.Stringer interface
  100. func (r Repository) String() string {
  101. return fmt.Sprintf(
  102. "%s",
  103. r.Information,
  104. )
  105. }
  106. // CommandParserType represents the recognized type of parser usable for a specific image
  107. type CommandParserType int
  108. const (
  109. CommandParserTypeDebian CommandParserType = iota
  110. )
  111. // commandParserTypeIds is a lookup map between CommandParserType and a representation string
  112. var commandParserTypeIds = map[CommandParserType][]string{
  113. CommandParserTypeDebian: {"debian"},
  114. }
  115. // findCommandParserTypeName lookup the command parser name by type enum
  116. func findCommandParserTypeName(parserType CommandParserType) string {
  117. if parserTypeName, ok := commandParserTypeIds[parserType]; ok {
  118. return parserTypeName[0]
  119. } else {
  120. return "UNKNOWN"
  121. }
  122. }
  123. var availableCommandParsers = map[CommandParserType]CommandParser{}
  124. // CommandParser handles parsing commands from RUN arguments dependent on the base image type
  125. type CommandParser interface {
  126. GetRepositories(logger *log.Entry, runCommand string) ([]*Repository, error)
  127. GetPinnedPackages(logger *log.Entry, runCommand string) ([]*Package, error)
  128. }
  129. // InitCommandParsers exposes functionality to configure the behavior of mapping images to a CommandParser
  130. func InitCommandParsers() error {
  131. // Registering known parsers
  132. availableCommandParsers[CommandParserTypeDebian] = newDebianCommandParser()
  133. // TODO: Add dynamic loading from configuration
  134. return nil
  135. }
  136. func GetCommandParser(image Image) (*CommandParser, error) {
  137. parserType, err := determineParserForImage(image)
  138. if err != nil {
  139. log.WithFields(log.Fields{
  140. "imageName": image.Name,
  141. "imageTag": image.Tag,
  142. "sourceError": err,
  143. }).Fatal("failed to determine a matching CommandParser for image")
  144. return nil, err
  145. }
  146. if requestedCommandParser, ok := availableCommandParsers[parserType]; ok {
  147. return &requestedCommandParser, nil
  148. } else {
  149. message := "unable to identify command parser type"
  150. log.WithFields(log.Fields{
  151. "commandParserType": findCommandParserTypeName(parserType),
  152. }).Fatal(message)
  153. return nil, errors.New(message)
  154. }
  155. }
  156. // determineParserForImage matches image information to the correct CommandParserType
  157. func determineParserForImage(_ Image) (CommandParserType, error) {
  158. // TODO: Map image information to the list of command parsers supported
  159. return CommandParserTypeDebian, nil
  160. }