github.com/c3pm-labs/c3pm@v0.3.0/ctpm/add.go (about) 1 package ctpm 2 3 import ( 4 "fmt" 5 "github.com/Masterminds/semver/v3" 6 "github.com/c3pm-labs/c3pm/config" 7 "github.com/c3pm-labs/c3pm/config/manifest" 8 "github.com/c3pm-labs/c3pm/dependencies" 9 "github.com/c3pm-labs/c3pm/env" 10 "github.com/c3pm-labs/c3pm/registry" 11 "regexp" 12 "strings" 13 ) 14 15 func Add(pc *config.ProjectConfig, opts AddOptions) error { 16 options := buildOptions(opts) 17 for _, dep := range opts.Dependencies { 18 name, version, err := getRequiredVersion(dep, options) 19 if err != nil { 20 return fmt.Errorf("error getting dependencies: %w", err) 21 } 22 _, err = dependencies.Install(dependencies.PackageRequest{Name: name, Version: version.String()}, InstallHandler{}) 23 if err != nil { 24 return fmt.Errorf("error adding %s: %w", dep, err) 25 } 26 libPath := config.LibCachePath(name, version.String()) 27 libPc, err := config.Load(libPath) 28 if err != nil { 29 return fmt.Errorf("failed to read c3pm.yml: %w", err) 30 } 31 err = Build(libPc) 32 if err != nil { 33 return err 34 } 35 if pc.Manifest.Dependencies == nil { 36 pc.Manifest.Dependencies = make(manifest.Dependencies) 37 } 38 pc.Manifest.Dependencies[name] = version.String() 39 } 40 if err := pc.Save(); err != nil { 41 return fmt.Errorf("error saving project config: %w", err) 42 } 43 return nil 44 } 45 46 type AddOptions struct { 47 Force bool 48 RegistryURL string 49 50 Dependencies []string 51 } 52 53 func buildOptions(opts AddOptions) AddOptions { 54 if opts.RegistryURL == "" { 55 opts.RegistryURL = env.REGISTRY_ENDPOINT 56 } 57 return opts 58 } 59 60 const depRegexString = `^[\-a-zA-Z0-9_\/]*(@.*)?$` 61 62 var depRegex *regexp.Regexp 63 64 func getDepRegexp() (regex *regexp.Regexp, err error) { 65 if depRegex == nil { 66 depRegex, err = regexp.Compile(depRegexString) 67 } 68 regex = depRegex 69 return 70 } 71 72 func validateDependency(dep string) error { 73 regex, err := getDepRegexp() 74 if err != nil { 75 return fmt.Errorf("error compiling validation regexp: %w", err) 76 } 77 if regex.MatchString(dep) { 78 return nil 79 } 80 return fmt.Errorf("%s is not a valid dependency string", dep) 81 } 82 83 func getRequiredVersion(dep string, options AddOptions) (name string, version *semver.Version, err error) { 84 if err := validateDependency(dep); err != nil { 85 return "", nil, err 86 } 87 dependency := strings.Split(dep, "@") 88 if len(dependency) == 1 { 89 version, err = registry.GetLastVersion(dep, registry.Options{ 90 RegistryURL: options.RegistryURL, 91 }) 92 name = dep 93 return 94 } 95 name = dependency[0] 96 version, err = semver.NewVersion(dependency[1]) 97 if err != nil { 98 return "", nil, fmt.Errorf("invalid semver string: %w", err) 99 } 100 return 101 }