github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/buildtools/cocoapods/lockfile.go (about)

     1  package cocoapods
     2  
     3  import (
     4  	"path/filepath"
     5  	"regexp"
     6  	"strings"
     7  
     8  	"github.com/fossas/fossa-cli/files"
     9  )
    10  
    11  type RawLockfile struct {
    12  	Pods            []interface{}                `yaml:"PODS"`         // Transitive dependencies (this is actually `[](map[string][]string | string)`)
    13  	Dependencies    []string                     `yaml:"DEPENDENCIES"` // Direct dependencies
    14  	CheckoutOptions map[string]map[string]string `yaml:"CHECKOUT OPTIONS"`
    15  	ExternalSources map[string]map[string]string `yaml:"EXTERNAL SOURCES"`
    16  	SpecRepos       map[string][]string          `yaml:"SPEC REPOS"`
    17  }
    18  
    19  type Lockfile struct {
    20  	Pods            []Spec
    21  	Dependencies    []Requirement
    22  	CheckoutOptions map[string]CheckoutOptions
    23  	ExternalSources map[string]ExternalSource
    24  	SpecRepos       map[string][]string
    25  }
    26  
    27  type Spec struct {
    28  	Name         string
    29  	Version      string
    30  	Dependencies []Requirement
    31  }
    32  
    33  type Requirement struct {
    34  	Name       string
    35  	Version    string
    36  	Repository string
    37  	Branch     string
    38  	Tag        string
    39  
    40  	Original string
    41  }
    42  
    43  func (r *Requirement) String() string {
    44  	return r.Original
    45  }
    46  
    47  type CheckoutOptions struct {
    48  	Git    string
    49  	Commit string
    50  	Tag    string
    51  }
    52  
    53  type ExternalSource struct {
    54  	Git    string
    55  	Branch string
    56  	Tag    string
    57  
    58  	Path string
    59  }
    60  
    61  func FromLockfile(filename ...string) (Lockfile, error) {
    62  	var raw RawLockfile
    63  	err := files.ReadYAML(&raw, filepath.Join(filename...))
    64  
    65  	var lockfile Lockfile
    66  	// Parse pods.
    67  	for _, rawPod := range raw.Pods {
    68  		switch r := rawPod.(type) {
    69  		case map[interface{}]interface{}:
    70  			for pod, deps := range r {
    71  				var reqs []Requirement
    72  				dep := ParseRequirement(pod.(string))
    73  				for _, req := range deps.([]interface{}) {
    74  					reqs = append(reqs, ParseRequirement(req.(string)))
    75  				}
    76  				lockfile.Pods = append(lockfile.Pods, Spec{
    77  					Name:         dep.Name,
    78  					Version:      dep.Version,
    79  					Dependencies: reqs,
    80  				})
    81  			}
    82  		case string:
    83  			dep := ParseRequirement(r)
    84  			lockfile.Pods = append(lockfile.Pods, Spec{
    85  				Name:    dep.Name,
    86  				Version: dep.Version,
    87  			})
    88  		default:
    89  			panic(rawPod)
    90  		}
    91  	}
    92  
    93  	// Parse dependencies.
    94  	for _, dep := range raw.Dependencies {
    95  		lockfile.Dependencies = append(lockfile.Dependencies, ParseRequirement(dep))
    96  	}
    97  
    98  	// Parse checkout options.
    99  	lockfile.CheckoutOptions = make(map[string]CheckoutOptions)
   100  	for dep, options := range raw.CheckoutOptions {
   101  		lockfile.CheckoutOptions[dep] = CheckoutOptions{
   102  			Git:    options[":git"],
   103  			Commit: options[":commit"],
   104  			Tag:    options[":tag"],
   105  		}
   106  	}
   107  
   108  	// Parse external sources.
   109  	lockfile.ExternalSources = make(map[string]ExternalSource)
   110  	for dep, options := range raw.ExternalSources {
   111  		lockfile.ExternalSources[dep] = ExternalSource{
   112  			Git:    options[":git"],
   113  			Branch: options[":branch"],
   114  			Tag:    options[":tag"],
   115  			Path:   options[":path"],
   116  		}
   117  	}
   118  
   119  	// Parse spec repos.
   120  	lockfile.SpecRepos = raw.SpecRepos
   121  
   122  	return lockfile, err
   123  }
   124  
   125  func ParseRequirement(req string) Requirement {
   126  	splits := strings.Split(req, " ")
   127  	name := splits[0]
   128  	versionSpecifier := strings.TrimPrefix(strings.TrimSuffix(strings.Join(splits[1:], " "), ")"), "(")
   129  
   130  	if strings.HasPrefix(versionSpecifier, "from ") {
   131  		repoRegexp := regexp.MustCompile("from `(.*?)`")
   132  		branchRegexp := regexp.MustCompile("branch `(.*?)`")
   133  		tagRegexp := regexp.MustCompile("tag `(.*?)`")
   134  
   135  		repoMatches := repoRegexp.FindStringSubmatch(versionSpecifier)
   136  		repo := ""
   137  		if len(repoMatches) == 2 {
   138  			repo = repoMatches[1]
   139  		}
   140  		branchMatches := branchRegexp.FindStringSubmatch(versionSpecifier)
   141  		branch := ""
   142  		if len(branchMatches) == 2 {
   143  			branch = branchMatches[1]
   144  		}
   145  		tagMatches := tagRegexp.FindStringSubmatch(versionSpecifier)
   146  		tag := ""
   147  		if len(tagMatches) == 2 {
   148  			tag = tagMatches[1]
   149  		}
   150  
   151  		return Requirement{
   152  			Name:       name,
   153  			Repository: repo,
   154  			Branch:     branch,
   155  			Tag:        tag,
   156  
   157  			Original: req,
   158  		}
   159  	}
   160  	return Requirement{
   161  		Name:    name,
   162  		Version: versionSpecifier,
   163  
   164  		Original: req,
   165  	}
   166  }