github.com/jfrog/jfrog-cli-core@v1.12.1/artifactory/commands/repository/template.go (about)

     1  package repository
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"strings"
     9  
    10  	"github.com/c-bata/go-prompt"
    11  	"github.com/jfrog/jfrog-cli-core/artifactory/commands/utils"
    12  	"github.com/jfrog/jfrog-cli-core/utils/config"
    13  	"github.com/jfrog/jfrog-client-go/utils/errorutils"
    14  	"github.com/jfrog/jfrog-client-go/utils/log"
    15  )
    16  
    17  type RepoTemplateCommand struct {
    18  	path string
    19  }
    20  
    21  const (
    22  	PathErrorSuffixMsg = " please enter a path, in which the new template file will be created"
    23  
    24  	// Strings for prompt questions
    25  	SelectConfigKeyMsg   = "Select the next configuration key" + utils.PressTabMsg
    26  	InsertValuePromptMsg = "Insert the value for "
    27  
    28  	TemplateType = "templateType"
    29  	Create       = "create"
    30  	Update       = "update"
    31  
    32  	MandatoryUrl = "mandatoryUrl"
    33  
    34  	// Common repository configuration JSON keys
    35  	Key             = "key"
    36  	Rclass          = "rclass"
    37  	PackageType     = "packageType"
    38  	Description     = "description"
    39  	Notes           = "notes"
    40  	IncludePatterns = "includesPattern"
    41  	ExcludePatterns = "excludesPattern"
    42  	RepoLayoutRef   = "repoLayoutRef"
    43  
    44  	// Mutual local and remote repository configuration JSON keys
    45  	HandleReleases               = "handleReleases"
    46  	HandleSnapshots              = "handleSnapshots"
    47  	MaxUniqueSnapshots           = "maxUniqueSnapshots"
    48  	SuppressPomConsistencyChecks = "suppressPomConsistencyChecks"
    49  	BlackedOut                   = "blackedOut"
    50  	XrayIndex                    = "xrayIndex"
    51  	PropertySets                 = "propertySets"
    52  	DownloadRedirect             = "downloadRedirect"
    53  	BlockPushingSchema1          = "blockPushingSchema1"
    54  
    55  	// Mutual local and virtual repository configuration JSON keys
    56  	DebianTrivialLayout = "debianTrivialLayout"
    57  
    58  	// Mutual remote and virtual repository configuration JSON keys
    59  	ExternalDependenciesEnabled  = "externalDependenciesEnabled"
    60  	ExternalDependenciesPatterns = "externalDependenciesPatterns"
    61  
    62  	// Unique local repository configuration JSON keys
    63  	ChecksumPolicyType              = "checksumPolicyType"
    64  	MaxUniqueTags                   = "maxUniqueTags"
    65  	SnapshotVersionBehavior         = "snapshotVersionBehavior"
    66  	ArchiveBrowsingEnabled          = "archiveBrowsingEnabled"
    67  	CalculateYumMetadata            = "calculateYumMetadata"
    68  	YumRootDepth                    = "yumRootDepth"
    69  	DockerApiVersion                = "dockerApiVersion"
    70  	EnableFileListsIndexing         = "enableFileListsIndexing"
    71  	OptionalIndexCompressionFormats = "optionalIndexCompressionFormats"
    72  	ForceNugetAuthentication        = "forceNugetAuthentication"
    73  
    74  	// Unique remote repository configuration JSON keys
    75  	Url                               = "url"
    76  	Username                          = "username"
    77  	Password                          = "password"
    78  	Proxy                             = "proxy"
    79  	RemoteRepoChecksumPolicyType      = "remoteRepoChecksumPolicyType"
    80  	HardFail                          = "hardFail"
    81  	Offline                           = "offline"
    82  	StoreArtifactsLocally             = "storeArtifactsLocally"
    83  	SocketTimeoutMillis               = "socketTimeoutMillis"
    84  	LocalAddress                      = "localAddress"
    85  	RetrievalCachePeriodSecs          = "retrievalCachePeriodSecs"
    86  	FailedRetrievalCachePeriodSecs    = "failedRetrievalCachePeriodSecs"
    87  	MissedRetrievalCachePeriodSecs    = "missedRetrievalCachePeriodSecs"
    88  	UnusedArtifactsCleanupEnabled     = "unusedArtifactsCleanupEnabled"
    89  	UnusedArtifactsCleanupPeriodHours = "unusedArtifactsCleanupPeriodHours"
    90  	AssumedOfflinePeriodSecs          = "assumedOfflinePeriodSecs"
    91  	FetchJarsEagerly                  = "fetchJarsEagerly"
    92  	FetchSourcesEagerly               = "fetchSourcesEagerly"
    93  	RejectInvalidJars                 = "rejectInvalidJars"
    94  	ShareConfiguration                = "shareConfiguration"
    95  	SynchronizeProperties             = "synchronizeProperties"
    96  	BlockMismatchingMimeTypes         = "blockMismatchingMimeTypes"
    97  	AllowAnyHostAuth                  = "allowAnyHostAuth"
    98  	EnableCookieManagement            = "enableCookieManagement"
    99  	BowerRegistryUrl                  = "bowerRegistryUrl"
   100  	ComposerRegistryUrl               = "composerRegistryUrl"
   101  	PyPIRegistryUrl                   = "pyPIRegistryUrl"
   102  	VcsType                           = "vcsType"
   103  	VcsGitProvider                    = "vcsGitProvider"
   104  	VcsGitDownloadUrl                 = "vcsGitDownloadUrl"
   105  	BypassHeadRequests                = "bypassHeadRequests"
   106  	ClientTlsCertificate              = "clientTlsCertificate"
   107  	FeedContextPath                   = "feedContextPath"
   108  	DownloadContextPath               = "downloadContextPath"
   109  	V3FeedUrl                         = "v3FeedUrl"
   110  	ContentSynchronisation            = "contentSynchronisation"
   111  	ListRemoteFolderItems             = "listRemoteFolderItems"
   112  	EnableTokenAuthentication         = "enableTokenAuthentication"
   113  	PodsSpecsRepoUrl                  = "podsSpecsRepoUrl"
   114  
   115  	// Unique virtual repository configuration JSON keys
   116  	Repositories                                  = "repositories"
   117  	ArtifactoryRequestsCanRetrieveRemoteArtifacts = "artifactoryRequestsCanRetrieveRemoteArtifacts"
   118  	KeyPair                                       = "keyPair"
   119  	PomRepositoryReferencesCleanupPolicy          = "pomRepositoryReferencesCleanupPolicy"
   120  	DefaultDeploymentRepo                         = "defaultDeploymentRepo"
   121  	ForceMavenAuthentication                      = "forceMavenAuthentication"
   122  	ExternalDependenciesRemoteRepo                = "externalDependenciesRemoteRepo"
   123  
   124  	// rclasses
   125  	Local   = "local"
   126  	Remote  = "remote"
   127  	Virtual = "virtual"
   128  
   129  	// PackageTypes
   130  	Generic   = "generic"
   131  	Maven     = "maven"
   132  	Gradle    = "gradle"
   133  	Ivy       = "ivy"
   134  	Sbt       = "sbt"
   135  	Helm      = "helm"
   136  	Cocoapods = "cocoapods"
   137  	Opkg      = "opkg"
   138  	Rpm       = "rpm"
   139  	Nuget     = "nuget"
   140  	Cran      = "cran"
   141  	Gems      = "gems"
   142  	Npm       = "npm"
   143  	Bower     = "bower"
   144  	Debian    = "debian"
   145  	Composer  = "composer"
   146  	Pypi      = "pypi"
   147  	Docker    = "docker"
   148  	Vagrant   = "vagrant"
   149  	Gitlfs    = "gitlfs"
   150  	Go        = "go"
   151  	Yum       = "yum"
   152  	Conan     = "conan"
   153  	Chef      = "chef"
   154  	Puppet    = "puppet"
   155  	Vcs       = "vcs"
   156  	Conda     = "conda"
   157  	P2        = "p2"
   158  
   159  	// Repo layout Refs
   160  	BowerDefaultRepoLayout    = "bower-default"
   161  	buildDefaultRepoLayout    = "build-default"
   162  	ComposerDefaultRepoLayout = "composer-default"
   163  	ConanDefaultRepoLayout    = "conan-default"
   164  	GoDefaultRepoLayout       = "go-default"
   165  	GradleDefaultRepoLayout   = "maven-2-default"
   166  	IvyDefaultRepoLayout      = "ivy-default"
   167  	Maven1DefaultRepoLayout   = "maven-1-default"
   168  	Maven2DefaultRepoLayout   = "maven-2-default"
   169  	NpmDefaultRepoLayout      = "npm-default"
   170  	NugetDefaultRepoLayout    = "nuget-default"
   171  	puppetDefaultRepoLayout   = "puppet-default"
   172  	SbtDefaultRepoLayout      = "sbt-default"
   173  	SimpleDefaultRepoLayout   = "simple-default"
   174  	VcsDefaultRepoLayout      = "vcs-default"
   175  
   176  	// Checksum Policies
   177  	ClientChecksumPolicy           = "client-checksums"
   178  	ServerGeneratedChecksumsPolicy = "server-generated-checksums"
   179  
   180  	// Snapshot version behaviors
   181  	UniqueBehavior    = "unique"
   182  	NonUniqueBehavior = "non-unique"
   183  	DeployerBehavior  = "deployer"
   184  
   185  	// Optional index compression formats
   186  	Bz2Compression  = "bz2"
   187  	LzmaCompression = "lzma"
   188  	XzCompression   = "xz"
   189  
   190  	// Docker api versions
   191  	DockerApiV1 = "V1"
   192  	DockerApiV2 = "V2"
   193  
   194  	// Remote repo checksum policies
   195  	GenerateIfAbsentPolicy  = "generate-if-absent"
   196  	FailPolicy              = "fail"
   197  	IgnoreAndGeneratePolicy = "ignore-and-generate"
   198  	PassThruPolicy          = "pass-thru"
   199  
   200  	// Vcs Types
   201  	Git = "GIT"
   202  
   203  	// Vcs git provider
   204  	GithubVcsProvider      = "GITHUB"
   205  	BitbucketVcsProvider   = "BITBUCKET"
   206  	OldstashVcsProvider    = "OLDSTASH"
   207  	StashVcsProvider       = "STASH"
   208  	ArtifactoryVcsProvider = "ARTIFACTORY"
   209  	CustomVcsProvider      = "CUSTOM"
   210  
   211  	// POM repository references cleanup policies
   212  	DiscardActiveRefrencePolicy = "discard_active_reference"
   213  	DiscardAnyReferencePolicy   = "discard_any_reference"
   214  	NothingPolicy               = "nothing"
   215  )
   216  
   217  var optionalSuggestsMap = map[string]prompt.Suggest{
   218  	utils.SaveAndExit:                 {Text: utils.SaveAndExit},
   219  	Description:                       {Text: Description},
   220  	Notes:                             {Text: Notes},
   221  	IncludePatterns:                   {Text: IncludePatterns},
   222  	ExcludePatterns:                   {Text: ExcludePatterns},
   223  	RepoLayoutRef:                     {Text: RepoLayoutRef},
   224  	HandleReleases:                    {Text: HandleReleases},
   225  	HandleSnapshots:                   {Text: HandleSnapshots},
   226  	MaxUniqueSnapshots:                {Text: MaxUniqueSnapshots},
   227  	SuppressPomConsistencyChecks:      {Text: SuppressPomConsistencyChecks},
   228  	BlackedOut:                        {Text: BlackedOut},
   229  	DownloadRedirect:                  {Text: DownloadRedirect},
   230  	BlockPushingSchema1:               {Text: BlockPushingSchema1},
   231  	DebianTrivialLayout:               {Text: DebianTrivialLayout},
   232  	ExternalDependenciesEnabled:       {Text: ExternalDependenciesEnabled},
   233  	ExternalDependenciesPatterns:      {Text: ExternalDependenciesPatterns},
   234  	ChecksumPolicyType:                {Text: ChecksumPolicyType},
   235  	MaxUniqueTags:                     {Text: MaxUniqueTags},
   236  	SnapshotVersionBehavior:           {Text: SnapshotVersionBehavior},
   237  	XrayIndex:                         {Text: XrayIndex},
   238  	PropertySets:                      {Text: PropertySets},
   239  	ArchiveBrowsingEnabled:            {Text: ArchiveBrowsingEnabled},
   240  	CalculateYumMetadata:              {Text: CalculateYumMetadata},
   241  	YumRootDepth:                      {Text: YumRootDepth},
   242  	DockerApiVersion:                  {Text: DockerApiVersion},
   243  	EnableFileListsIndexing:           {Text: EnableFileListsIndexing},
   244  	OptionalIndexCompressionFormats:   {Text: OptionalIndexCompressionFormats},
   245  	Url:                               {Text: Url},
   246  	Username:                          {Text: Username},
   247  	Password:                          {Text: Password},
   248  	Proxy:                             {Text: Proxy},
   249  	RemoteRepoChecksumPolicyType:      {Text: RemoteRepoChecksumPolicyType},
   250  	HardFail:                          {Text: HardFail},
   251  	Offline:                           {Text: Offline},
   252  	StoreArtifactsLocally:             {Text: StoreArtifactsLocally},
   253  	SocketTimeoutMillis:               {Text: SocketTimeoutMillis},
   254  	LocalAddress:                      {Text: LocalAddress},
   255  	RetrievalCachePeriodSecs:          {Text: RetrievalCachePeriodSecs},
   256  	FailedRetrievalCachePeriodSecs:    {Text: FailedRetrievalCachePeriodSecs},
   257  	MissedRetrievalCachePeriodSecs:    {Text: MissedRetrievalCachePeriodSecs},
   258  	UnusedArtifactsCleanupEnabled:     {Text: UnusedArtifactsCleanupEnabled},
   259  	UnusedArtifactsCleanupPeriodHours: {Text: UnusedArtifactsCleanupPeriodHours},
   260  	AssumedOfflinePeriodSecs:          {Text: AssumedOfflinePeriodSecs},
   261  	FetchJarsEagerly:                  {Text: FetchJarsEagerly},
   262  	FetchSourcesEagerly:               {Text: FetchSourcesEagerly},
   263  	RejectInvalidJars:                 {Text: RejectInvalidJars},
   264  	ShareConfiguration:                {Text: ShareConfiguration},
   265  	SynchronizeProperties:             {Text: SynchronizeProperties},
   266  	BlockMismatchingMimeTypes:         {Text: BlockMismatchingMimeTypes},
   267  	AllowAnyHostAuth:                  {Text: AllowAnyHostAuth},
   268  	EnableCookieManagement:            {Text: EnableCookieManagement},
   269  	BowerRegistryUrl:                  {Text: BowerRegistryUrl},
   270  	ComposerRegistryUrl:               {Text: ComposerRegistryUrl},
   271  	PyPIRegistryUrl:                   {Text: PyPIRegistryUrl},
   272  	VcsType:                           {Text: VcsType},
   273  	VcsGitProvider:                    {Text: VcsGitProvider},
   274  	VcsGitDownloadUrl:                 {Text: VcsGitDownloadUrl},
   275  	BypassHeadRequests:                {Text: BypassHeadRequests},
   276  	ClientTlsCertificate:              {Text: ClientTlsCertificate},
   277  	FeedContextPath:                   {Text: FeedContextPath},
   278  	DownloadContextPath:               {Text: DownloadContextPath},
   279  	V3FeedUrl:                         {Text: V3FeedUrl},
   280  	ContentSynchronisation:            {Text: ContentSynchronisation},
   281  	ListRemoteFolderItems:             {Text: ListRemoteFolderItems},
   282  	PodsSpecsRepoUrl:                  {Text: PodsSpecsRepoUrl},
   283  	EnableTokenAuthentication:         {Text: EnableTokenAuthentication},
   284  	Repositories:                      {Text: Repositories},
   285  	ArtifactoryRequestsCanRetrieveRemoteArtifacts: {Text: ArtifactoryRequestsCanRetrieveRemoteArtifacts},
   286  	KeyPair:                              {Text: KeyPair},
   287  	PomRepositoryReferencesCleanupPolicy: {Text: PomRepositoryReferencesCleanupPolicy},
   288  	DefaultDeploymentRepo:                {Text: DefaultDeploymentRepo},
   289  	ForceMavenAuthentication:             {Text: ForceMavenAuthentication},
   290  	ExternalDependenciesRemoteRepo:       {Text: ExternalDependenciesRemoteRepo},
   291  }
   292  
   293  var baseLocalRepoConfKeys = []string{
   294  	Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, BlackedOut, XrayIndex,
   295  	PropertySets, ArchiveBrowsingEnabled, OptionalIndexCompressionFormats, DownloadRedirect, BlockPushingSchema1,
   296  }
   297  
   298  var mavenGradleLocalRepoConfKeys = []string{
   299  	MaxUniqueSnapshots, HandleReleases, HandleSnapshots, SuppressPomConsistencyChecks, SnapshotVersionBehavior, ChecksumPolicyType,
   300  }
   301  
   302  var rpmLocalRepoConfKeys = []string{
   303  	YumRootDepth, CalculateYumMetadata, EnableFileListsIndexing,
   304  }
   305  
   306  var nugetLocalRepoConfKeys = []string{
   307  	MaxUniqueSnapshots, ForceNugetAuthentication,
   308  }
   309  
   310  var debianLocalRepoConfKeys = []string{
   311  	DebianTrivialLayout,
   312  }
   313  
   314  var dockerLocalRepoConfKeys = []string{
   315  	DockerApiVersion, MaxUniqueTags,
   316  }
   317  
   318  var baseRemoteRepoConfKeys = []string{
   319  	Username, Password, Proxy, Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, HardFail, Offline,
   320  	BlackedOut, XrayIndex, StoreArtifactsLocally, SocketTimeoutMillis, LocalAddress, RetrievalCachePeriodSecs, FailedRetrievalCachePeriodSecs,
   321  	MissedRetrievalCachePeriodSecs, UnusedArtifactsCleanupEnabled, UnusedArtifactsCleanupPeriodHours, AssumedOfflinePeriodSecs,
   322  	ShareConfiguration, SynchronizeProperties, BlockMismatchingMimeTypes, PropertySets, AllowAnyHostAuth, EnableCookieManagement,
   323  	BypassHeadRequests, ClientTlsCertificate, DownloadRedirect, BlockPushingSchema1, ContentSynchronisation,
   324  }
   325  
   326  var mavenGradleRemoteRepoConfKeys = []string{
   327  	FetchJarsEagerly, FetchSourcesEagerly, RemoteRepoChecksumPolicyType, HandleReleases, HandleSnapshots,
   328  	SuppressPomConsistencyChecks, RejectInvalidJars,
   329  }
   330  
   331  var cocoapodsRemoteRepoConfKeys = []string{
   332  	PodsSpecsRepoUrl,
   333  }
   334  
   335  var opkgRemoteRepoConfKeys = []string{
   336  	ListRemoteFolderItems,
   337  }
   338  
   339  var rpmRemoteRepoConfKeys = []string{
   340  	ListRemoteFolderItems,
   341  }
   342  
   343  var nugetRemoteRepoConfKeys = []string{
   344  	FeedContextPath, DownloadContextPath, V3FeedUrl, ForceNugetAuthentication,
   345  }
   346  
   347  var gemsRemoteRepoConfKeys = []string{
   348  	ListRemoteFolderItems,
   349  }
   350  
   351  var npmRemoteRepoConfKeys = []string{
   352  	ListRemoteFolderItems,
   353  }
   354  
   355  var bowerRemoteRepoConfKeys = []string{
   356  	BowerRegistryUrl,
   357  }
   358  
   359  var debianRemoteRepoConfKeys = []string{
   360  	ListRemoteFolderItems,
   361  }
   362  
   363  var composerRemoteRepoConfKeys = []string{
   364  	ComposerRegistryUrl,
   365  }
   366  
   367  var pypiRemoteRepoConfKeys = []string{
   368  	PyPIRegistryUrl, ListRemoteFolderItems,
   369  }
   370  
   371  var dockerRemoteRepoConfKeys = []string{
   372  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, EnableTokenAuthentication,
   373  }
   374  
   375  var gitlfsRemoteRepoConfKeys = []string{
   376  	ListRemoteFolderItems,
   377  }
   378  
   379  var vcsRemoteRepoConfKeys = []string{
   380  	VcsGitProvider, VcsType, MaxUniqueSnapshots, VcsGitDownloadUrl, ListRemoteFolderItems,
   381  }
   382  
   383  var genericRemoteRepoConfKeys = []string{
   384  	ListRemoteFolderItems,
   385  }
   386  
   387  var baseVirtualRepoConfKeys = []string{
   388  	Repositories, Description, Notes, IncludePatterns, ExcludePatterns, RepoLayoutRef, ArtifactoryRequestsCanRetrieveRemoteArtifacts,
   389  	DefaultDeploymentRepo,
   390  }
   391  
   392  var mavenGradleVirtualRepoConfKeys = []string{
   393  	ForceMavenAuthentication, PomRepositoryReferencesCleanupPolicy, KeyPair,
   394  }
   395  
   396  var nugetVirtualRepoConfKeys = []string{
   397  	ForceNugetAuthentication,
   398  }
   399  
   400  var npmVirtualRepoConfKeys = []string{
   401  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, ExternalDependenciesRemoteRepo,
   402  }
   403  
   404  var bowerVirtualRepoConfKeys = []string{
   405  	ExternalDependenciesEnabled, ExternalDependenciesPatterns, ExternalDependenciesRemoteRepo,
   406  }
   407  
   408  var debianVirtualRepoConfKeys = []string{
   409  	DebianTrivialLayout,
   410  }
   411  
   412  var goVirtualRepoConfKeys = []string{
   413  	ExternalDependenciesEnabled, ExternalDependenciesPatterns,
   414  }
   415  
   416  var commonPkgTypes = []string{
   417  	Maven, Gradle, Ivy, Sbt, Helm, Rpm, Nuget, Cran, Gems, Npm, Bower, Debian, Pypi, Docker, Gitlfs, Go, Yum, Conan,
   418  	Chef, Puppet, Generic,
   419  }
   420  
   421  var localRepoAdditionalPkgTypes = []string{
   422  	Cocoapods, Opkg, Composer, Vagrant,
   423  }
   424  
   425  var remoteRepoAdditionalPkgTypes = []string{
   426  	Cocoapods, Opkg, Composer, Conda, P2, Vcs,
   427  }
   428  
   429  var virtualRepoAdditionalPkgTypes = []string{
   430  	Conda, P2,
   431  }
   432  
   433  var pkgTypeSuggestsMap = map[string]prompt.Suggest{
   434  	Generic:   {Text: Generic},
   435  	Maven:     {Text: Maven},
   436  	Gradle:    {Text: Gradle},
   437  	Ivy:       {Text: Ivy},
   438  	Sbt:       {Text: Sbt},
   439  	Helm:      {Text: Helm},
   440  	Cocoapods: {Text: Cocoapods},
   441  	Opkg:      {Text: Opkg},
   442  	Rpm:       {Text: Rpm},
   443  	Nuget:     {Text: Nuget},
   444  	Cran:      {Text: Cran},
   445  	Gems:      {Text: Gems},
   446  	Npm:       {Text: Npm},
   447  	Bower:     {Text: Bower},
   448  	Debian:    {Text: Debian},
   449  	Composer:  {Text: Composer},
   450  	Pypi:      {Text: Pypi},
   451  	Docker:    {Text: Docker},
   452  	Vagrant:   {Text: Vagrant},
   453  	Gitlfs:    {Text: Gitlfs},
   454  	Go:        {Text: Go},
   455  	Yum:       {Text: Yum},
   456  	Conan:     {Text: Conan},
   457  	Chef:      {Text: Chef},
   458  	Puppet:    {Text: Puppet},
   459  	Vcs:       {Text: Vcs},
   460  	Conda:     {Text: Conda},
   461  	P2:        {Text: P2},
   462  }
   463  
   464  func NewRepoTemplateCommand() *RepoTemplateCommand {
   465  	return &RepoTemplateCommand{}
   466  }
   467  
   468  func (rtc *RepoTemplateCommand) SetTemplatePath(path string) *RepoTemplateCommand {
   469  	rtc.path = path
   470  	return rtc
   471  }
   472  
   473  func (rtc *RepoTemplateCommand) ServerDetails() (*config.ServerDetails, error) {
   474  	// Since it's a local command, usage won't be reported.
   475  	return nil, nil
   476  }
   477  
   478  func (rtc *RepoTemplateCommand) Run() (err error) {
   479  	err = utils.ValidateTemplatePath(rtc.path)
   480  	if err != nil {
   481  		return
   482  	}
   483  	repoTemplateQuestionnaire := &utils.InteractiveQuestionnaire{
   484  		MandatoryQuestionsKeys: []string{TemplateType, Key, Rclass},
   485  		QuestionsMap:           questionMap,
   486  	}
   487  	err = repoTemplateQuestionnaire.Perform()
   488  	if err != nil {
   489  		return err
   490  	}
   491  	resBytes, err := json.Marshal(repoTemplateQuestionnaire.AnswersMap)
   492  	if err != nil {
   493  		return errorutils.CheckError(err)
   494  	}
   495  	if err = os.WriteFile(rtc.path, resBytes, 0644); err != nil {
   496  		return errorutils.CheckError(err)
   497  	}
   498  	log.Info(fmt.Sprintf("Repository configuration template successfully created at %s.", rtc.path))
   499  
   500  	return nil
   501  }
   502  
   503  func (rtc *RepoTemplateCommand) CommandName() string {
   504  	return "rt_repo_template"
   505  }
   506  
   507  func rclassCallback(iq *utils.InteractiveQuestionnaire, rclass string) (string, error) {
   508  	var pkgTypes []string
   509  	switch rclass {
   510  	case Remote:
   511  		// For create template url is mandatory, for update we will allow url as an optional key
   512  		if _, ok := iq.AnswersMap[TemplateType]; !ok {
   513  			return "", errors.New("package type is missing in configuration map")
   514  		}
   515  		if iq.AnswersMap[TemplateType] == Create {
   516  			iq.AskQuestion(iq.QuestionsMap[MandatoryUrl])
   517  		}
   518  		pkgTypes = append(commonPkgTypes, remoteRepoAdditionalPkgTypes...)
   519  	case Local:
   520  		pkgTypes = append(commonPkgTypes, localRepoAdditionalPkgTypes...)
   521  	case Virtual:
   522  		pkgTypes = append(commonPkgTypes, virtualRepoAdditionalPkgTypes...)
   523  	default:
   524  		return "", errors.New("unsupported rclass")
   525  	}
   526  	// PackageType is also mandatory. Since the possible types depend on which rcalss was chosen, we ask the question here.
   527  	var pkgTypeQuestion = utils.QuestionInfo{
   528  		Options:      utils.GetSuggestsFromKeys(pkgTypes, pkgTypeSuggestsMap),
   529  		Msg:          "",
   530  		PromptPrefix: "Select the repository's package type" + utils.PressTabMsg,
   531  		AllowVars:    false,
   532  		Writer:       utils.WriteStringAnswer,
   533  		MapKey:       PackageType,
   534  		Callback:     pkgTypeCallback,
   535  	}
   536  	return iq.AskQuestion(pkgTypeQuestion)
   537  }
   538  
   539  func pkgTypeCallback(iq *utils.InteractiveQuestionnaire, pkgType string) (string, error) {
   540  	// Each combination of (rclass,packageType) has its own optional configuration keys.
   541  	// We set the questionnaire's optionalKeys suggests according to the selected combination.
   542  	if _, ok := iq.AnswersMap[Rclass]; !ok {
   543  		return "", errors.New("rclass is missing in configuration map")
   544  	}
   545  	switch iq.AnswersMap[Rclass] {
   546  	case Local:
   547  		iq.OptionalKeysSuggests = getLocalRepoConfKeys(pkgType)
   548  	case Remote:
   549  		// For update template we need to allow url as an optional key
   550  		if _, ok := iq.AnswersMap[TemplateType]; !ok {
   551  			return "", errors.New("package type is missing in configuration map")
   552  		}
   553  		iq.OptionalKeysSuggests = getRemoteRepoConfKeys(pkgType, iq.AnswersMap[TemplateType].(string))
   554  	case Virtual:
   555  		iq.OptionalKeysSuggests = getVirtualRepoConfKeys(pkgType)
   556  	default:
   557  		return "", errors.New("unsupported rclass was configured")
   558  	}
   559  	// We don't need the templateType value in the final configuration
   560  	delete(iq.AnswersMap, TemplateType)
   561  	return "", nil
   562  }
   563  
   564  func getLocalRepoConfKeys(pkgType string) []prompt.Suggest {
   565  	optionalKeys := []string{utils.SaveAndExit}
   566  	optionalKeys = append(optionalKeys, baseLocalRepoConfKeys...)
   567  	switch pkgType {
   568  	case Gradle:
   569  	case Maven:
   570  		optionalKeys = append(optionalKeys, mavenGradleLocalRepoConfKeys...)
   571  	case Rpm:
   572  		optionalKeys = append(optionalKeys, rpmLocalRepoConfKeys...)
   573  	case Nuget:
   574  		optionalKeys = append(optionalKeys, nugetLocalRepoConfKeys...)
   575  	case Debian:
   576  		optionalKeys = append(optionalKeys, debianLocalRepoConfKeys...)
   577  	case Docker:
   578  		optionalKeys = append(optionalKeys, dockerLocalRepoConfKeys...)
   579  	}
   580  	return utils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   581  }
   582  
   583  func getRemoteRepoConfKeys(pkgType, templateType string) []prompt.Suggest {
   584  	optionalKeys := []string{utils.SaveAndExit}
   585  	if templateType == Update {
   586  		optionalKeys = append(optionalKeys, Url)
   587  	}
   588  	optionalKeys = append(optionalKeys, baseRemoteRepoConfKeys...)
   589  	switch pkgType {
   590  	case Gradle:
   591  	case Maven:
   592  		optionalKeys = append(optionalKeys, mavenGradleRemoteRepoConfKeys...)
   593  	case Cocoapods:
   594  		optionalKeys = append(optionalKeys, cocoapodsRemoteRepoConfKeys...)
   595  	case Opkg:
   596  		optionalKeys = append(optionalKeys, opkgRemoteRepoConfKeys...)
   597  	case Rpm:
   598  		optionalKeys = append(optionalKeys, rpmRemoteRepoConfKeys...)
   599  	case Nuget:
   600  		optionalKeys = append(optionalKeys, nugetRemoteRepoConfKeys...)
   601  	case Gems:
   602  		optionalKeys = append(optionalKeys, gemsRemoteRepoConfKeys...)
   603  	case Npm:
   604  		optionalKeys = append(optionalKeys, npmRemoteRepoConfKeys...)
   605  	case Bower:
   606  		optionalKeys = append(optionalKeys, bowerRemoteRepoConfKeys...)
   607  	case Debian:
   608  		optionalKeys = append(optionalKeys, debianRemoteRepoConfKeys...)
   609  	case Composer:
   610  		optionalKeys = append(optionalKeys, composerRemoteRepoConfKeys...)
   611  	case Pypi:
   612  		optionalKeys = append(optionalKeys, pypiRemoteRepoConfKeys...)
   613  	case Docker:
   614  		optionalKeys = append(optionalKeys, dockerRemoteRepoConfKeys...)
   615  	case Gitlfs:
   616  		optionalKeys = append(optionalKeys, gitlfsRemoteRepoConfKeys...)
   617  	case Vcs:
   618  		optionalKeys = append(optionalKeys, vcsRemoteRepoConfKeys...)
   619  	}
   620  	return utils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   621  }
   622  
   623  func getVirtualRepoConfKeys(pkgType string) []prompt.Suggest {
   624  	optionalKeys := []string{utils.SaveAndExit}
   625  	optionalKeys = append(optionalKeys, baseVirtualRepoConfKeys...)
   626  	switch pkgType {
   627  	case Gradle:
   628  	case Maven:
   629  		optionalKeys = append(optionalKeys, mavenGradleVirtualRepoConfKeys...)
   630  	case Nuget:
   631  		optionalKeys = append(optionalKeys, nugetVirtualRepoConfKeys...)
   632  	case Npm:
   633  		optionalKeys = append(optionalKeys, npmVirtualRepoConfKeys...)
   634  	case Bower:
   635  		optionalKeys = append(optionalKeys, bowerVirtualRepoConfKeys...)
   636  	case Debian:
   637  		optionalKeys = append(optionalKeys, debianVirtualRepoConfKeys...)
   638  	case Go:
   639  		optionalKeys = append(optionalKeys, goVirtualRepoConfKeys...)
   640  	}
   641  	return utils.GetSuggestsFromKeys(optionalKeys, optionalSuggestsMap)
   642  }
   643  
   644  func contentSynchronisationCallBack(iq *utils.InteractiveQuestionnaire, answer string) (value string, err error) {
   645  	// contentSynchronisation has an object value with 4 bool fields.
   646  	// We ask for the rest of the values and writes the values in comma separated list.
   647  	if err != nil {
   648  		return "", nil
   649  	}
   650  	answer += "," + utils.AskFromList("", "Insert the value for statistic.enable >", false, utils.GetBoolSuggests(), "")
   651  	//cs.Statistics.Enabled, err = strconv.ParseBool(enabled)
   652  	if err != nil {
   653  		return "", nil
   654  	}
   655  	answer += "," + utils.AskFromList("", "Insert the value for properties.enable >", false, utils.GetBoolSuggests(), "")
   656  	//cs.Properties.Enabled, err = strconv.ParseBool(enabled)
   657  	if err != nil {
   658  		return "", nil
   659  	}
   660  	answer += "," + utils.AskFromList("", "Insert the value for source.originAbsenceDetection >", false, utils.GetBoolSuggests(), "")
   661  	//cs.Source.OriginAbsenceDetection, err = strconv.ParseBool(enabled)
   662  	if err != nil {
   663  		return "", nil
   664  	}
   665  	iq.AnswersMap[ContentSynchronisation] = answer
   666  	return "", nil
   667  }
   668  
   669  // Specific writers for repo templates, since all the values in the templates should be written as string
   670  var BoolToStringQuestionInfo = utils.QuestionInfo{
   671  	Options:   utils.GetBoolSuggests(),
   672  	AllowVars: true,
   673  	Writer:    utils.WriteStringAnswer,
   674  }
   675  
   676  var IntToStringQuestionInfo = utils.QuestionInfo{
   677  	Options:   nil,
   678  	AllowVars: true,
   679  	Writer:    utils.WriteStringAnswer,
   680  }
   681  
   682  var StringListToStringQuestionInfo = utils.QuestionInfo{
   683  	Msg:       utils.CommaSeparatedListMsg,
   684  	Options:   nil,
   685  	AllowVars: true,
   686  	Writer:    utils.WriteStringAnswer,
   687  }
   688  
   689  var questionMap = map[string]utils.QuestionInfo{
   690  	TemplateType: {
   691  		Options: []prompt.Suggest{
   692  			{Text: Create, Description: "Template for creating a new repository"},
   693  			{Text: Update, Description: "Template for updating an existing repository"},
   694  		},
   695  		Msg:          "",
   696  		PromptPrefix: "Select the template type" + utils.PressTabMsg,
   697  		AllowVars:    false,
   698  		Writer:       utils.WriteStringAnswer,
   699  		MapKey:       TemplateType,
   700  		Callback:     nil,
   701  	},
   702  	utils.OptionalKey: {
   703  		Msg:          "",
   704  		PromptPrefix: SelectConfigKeyMsg,
   705  		AllowVars:    false,
   706  		Writer:       nil,
   707  		MapKey:       "",
   708  		Callback:     utils.OptionalKeyCallback,
   709  	},
   710  	Key: {
   711  		Msg:          "",
   712  		PromptPrefix: "Insert the repository key >",
   713  		AllowVars:    true,
   714  		Writer:       utils.WriteStringAnswer,
   715  		MapKey:       Key,
   716  		Callback:     nil,
   717  	},
   718  	Rclass: {
   719  		Options: []prompt.Suggest{
   720  			{Text: Local, Description: "A physical, locally-managed repository into which you can deploy artifacts"},
   721  			{Text: Remote, Description: "A caching proxy for a repository managed at a remote URL"},
   722  			{Text: Virtual, Description: "An Aggregation of several repositories with the same package type under a common URL."},
   723  		},
   724  		Msg:          "",
   725  		PromptPrefix: "Select the repository class" + utils.PressTabMsg,
   726  		AllowVars:    false,
   727  		Writer:       utils.WriteStringAnswer,
   728  		MapKey:       Rclass,
   729  		Callback:     rclassCallback,
   730  	},
   731  	MandatoryUrl: {
   732  		Msg:          "",
   733  		PromptPrefix: "Insert the remote repository URL >",
   734  		AllowVars:    true,
   735  		Writer:       utils.WriteStringAnswer,
   736  		MapKey:       Url,
   737  		Callback:     nil,
   738  	},
   739  	Url:             utils.FreeStringQuestionInfo,
   740  	Description:     utils.FreeStringQuestionInfo,
   741  	Notes:           utils.FreeStringQuestionInfo,
   742  	IncludePatterns: StringListToStringQuestionInfo,
   743  	ExcludePatterns: StringListToStringQuestionInfo,
   744  	RepoLayoutRef: {
   745  		Options: []prompt.Suggest{
   746  			{Text: BowerDefaultRepoLayout},
   747  			{Text: buildDefaultRepoLayout},
   748  			{Text: ComposerDefaultRepoLayout},
   749  			{Text: ConanDefaultRepoLayout},
   750  			{Text: GoDefaultRepoLayout},
   751  			{Text: GradleDefaultRepoLayout},
   752  			{Text: IvyDefaultRepoLayout},
   753  			{Text: Maven1DefaultRepoLayout},
   754  			{Text: Maven2DefaultRepoLayout},
   755  			{Text: NpmDefaultRepoLayout},
   756  			{Text: NugetDefaultRepoLayout},
   757  			{Text: puppetDefaultRepoLayout},
   758  			{Text: SbtDefaultRepoLayout},
   759  			{Text: SimpleDefaultRepoLayout},
   760  			{Text: VcsDefaultRepoLayout},
   761  		},
   762  		AllowVars: true,
   763  		Writer:    utils.WriteStringAnswer,
   764  	},
   765  	HandleReleases:               BoolToStringQuestionInfo,
   766  	HandleSnapshots:              BoolToStringQuestionInfo,
   767  	MaxUniqueSnapshots:           IntToStringQuestionInfo,
   768  	SuppressPomConsistencyChecks: BoolToStringQuestionInfo,
   769  	BlackedOut:                   BoolToStringQuestionInfo,
   770  	DownloadRedirect:             BoolToStringQuestionInfo,
   771  	BlockPushingSchema1:          BoolToStringQuestionInfo,
   772  	DebianTrivialLayout:          BoolToStringQuestionInfo,
   773  	ExternalDependenciesEnabled:  BoolToStringQuestionInfo,
   774  	ExternalDependenciesPatterns: StringListToStringQuestionInfo,
   775  	ChecksumPolicyType: {
   776  		Options: []prompt.Suggest{
   777  			{Text: ClientChecksumPolicy},
   778  			{Text: ServerGeneratedChecksumsPolicy},
   779  		},
   780  		AllowVars: true,
   781  		Writer:    utils.WriteStringAnswer,
   782  	},
   783  	MaxUniqueTags: IntToStringQuestionInfo,
   784  	SnapshotVersionBehavior: {
   785  		Options: []prompt.Suggest{
   786  			{Text: UniqueBehavior},
   787  			{Text: NonUniqueBehavior},
   788  			{Text: DeployerBehavior},
   789  		},
   790  		AllowVars: true,
   791  		Writer:    utils.WriteStringAnswer,
   792  	},
   793  	XrayIndex:              BoolToStringQuestionInfo,
   794  	PropertySets:           StringListToStringQuestionInfo,
   795  	ArchiveBrowsingEnabled: BoolToStringQuestionInfo,
   796  	CalculateYumMetadata:   BoolToStringQuestionInfo,
   797  	YumRootDepth:           IntToStringQuestionInfo,
   798  	DockerApiVersion: {
   799  		Options: []prompt.Suggest{
   800  			{Text: DockerApiV1},
   801  			{Text: DockerApiV2},
   802  		},
   803  		AllowVars: true,
   804  		Writer:    utils.WriteStringAnswer,
   805  	},
   806  	EnableFileListsIndexing: BoolToStringQuestionInfo,
   807  	OptionalIndexCompressionFormats: {
   808  		Msg:       "Enter a comma separated list of values from " + strings.Join([]string{Bz2Compression, LzmaCompression, XzCompression}, ","),
   809  		Options:   nil,
   810  		AllowVars: true,
   811  		Writer:    utils.WriteStringArrayAnswer,
   812  	},
   813  	Username: utils.FreeStringQuestionInfo,
   814  	Password: utils.FreeStringQuestionInfo,
   815  	Proxy:    utils.FreeStringQuestionInfo,
   816  	RemoteRepoChecksumPolicyType: {
   817  		Options: []prompt.Suggest{
   818  			{Text: GenerateIfAbsentPolicy},
   819  			{Text: FailPolicy},
   820  			{Text: IgnoreAndGeneratePolicy},
   821  			{Text: PassThruPolicy},
   822  		},
   823  		AllowVars: true,
   824  		Writer:    utils.WriteStringAnswer,
   825  	},
   826  	HardFail:                          BoolToStringQuestionInfo,
   827  	Offline:                           BoolToStringQuestionInfo,
   828  	StoreArtifactsLocally:             BoolToStringQuestionInfo,
   829  	SocketTimeoutMillis:               IntToStringQuestionInfo,
   830  	LocalAddress:                      utils.FreeStringQuestionInfo,
   831  	RetrievalCachePeriodSecs:          IntToStringQuestionInfo,
   832  	FailedRetrievalCachePeriodSecs:    IntToStringQuestionInfo,
   833  	MissedRetrievalCachePeriodSecs:    IntToStringQuestionInfo,
   834  	UnusedArtifactsCleanupEnabled:     BoolToStringQuestionInfo,
   835  	UnusedArtifactsCleanupPeriodHours: IntToStringQuestionInfo,
   836  	AssumedOfflinePeriodSecs:          IntToStringQuestionInfo,
   837  	FetchJarsEagerly:                  BoolToStringQuestionInfo,
   838  	FetchSourcesEagerly:               BoolToStringQuestionInfo,
   839  	RejectInvalidJars:                 BoolToStringQuestionInfo,
   840  	ShareConfiguration:                BoolToStringQuestionInfo,
   841  	SynchronizeProperties:             BoolToStringQuestionInfo,
   842  	BlockMismatchingMimeTypes:         BoolToStringQuestionInfo,
   843  	AllowAnyHostAuth:                  BoolToStringQuestionInfo,
   844  	EnableCookieManagement:            BoolToStringQuestionInfo,
   845  	BowerRegistryUrl:                  utils.FreeStringQuestionInfo,
   846  	ComposerRegistryUrl:               utils.FreeStringQuestionInfo,
   847  	PyPIRegistryUrl:                   utils.FreeStringQuestionInfo,
   848  	VcsType: {
   849  		Options: []prompt.Suggest{
   850  			{Text: Git},
   851  		},
   852  		AllowVars: true,
   853  		Writer:    utils.WriteStringAnswer,
   854  	},
   855  	VcsGitProvider: {
   856  		Options: []prompt.Suggest{
   857  			{Text: GithubVcsProvider},
   858  			{Text: BitbucketVcsProvider},
   859  			{Text: OldstashVcsProvider},
   860  			{Text: StashVcsProvider},
   861  			{Text: ArtifactoryVcsProvider},
   862  			{Text: CustomVcsProvider},
   863  		},
   864  		AllowVars: true,
   865  		Writer:    utils.WriteStringAnswer,
   866  	},
   867  	VcsGitDownloadUrl:         utils.FreeStringQuestionInfo,
   868  	BypassHeadRequests:        BoolToStringQuestionInfo,
   869  	ClientTlsCertificate:      utils.FreeStringQuestionInfo,
   870  	FeedContextPath:           utils.FreeStringQuestionInfo,
   871  	DownloadContextPath:       utils.FreeStringQuestionInfo,
   872  	V3FeedUrl:                 utils.FreeStringQuestionInfo,
   873  	ListRemoteFolderItems:     BoolToStringQuestionInfo,
   874  	EnableTokenAuthentication: BoolToStringQuestionInfo,
   875  	PodsSpecsRepoUrl:          utils.FreeStringQuestionInfo,
   876  	ContentSynchronisation: {
   877  		Options:   utils.GetBoolSuggests(),
   878  		AllowVars: true,
   879  		Writer:    nil,
   880  		Callback:  contentSynchronisationCallBack,
   881  	},
   882  	Repositories: StringListToStringQuestionInfo,
   883  	ArtifactoryRequestsCanRetrieveRemoteArtifacts: BoolToStringQuestionInfo,
   884  	KeyPair: utils.FreeStringQuestionInfo,
   885  	PomRepositoryReferencesCleanupPolicy: {
   886  		Options: []prompt.Suggest{
   887  			{Text: DiscardActiveRefrencePolicy},
   888  			{Text: DiscardAnyReferencePolicy},
   889  			{Text: NothingPolicy},
   890  		},
   891  		AllowVars: true,
   892  		Writer:    utils.WriteStringAnswer,
   893  	},
   894  	DefaultDeploymentRepo:          utils.FreeStringQuestionInfo,
   895  	ForceMavenAuthentication:       BoolToStringQuestionInfo,
   896  	ExternalDependenciesRemoteRepo: utils.FreeStringQuestionInfo,
   897  }