in cmd/acr/purge.go [83:176]
func newPurgeCmd(rootParams *rootParameters) *cobra.Command {
purgeParams := purgeParameters{rootParameters: rootParams}
cmd := &cobra.Command{
Use: "purge",
Short: "Delete images from a registry.",
Long: newPurgeCmdLongMessage,
Example: purgeExampleMessage,
RunE: func(_ *cobra.Command, _ []string) error {
// This context is used for all the http requests.
ctx := context.Background()
registryName, err := purgeParams.GetRegistryName()
if err != nil {
return err
}
loginURL := api.LoginURL(registryName)
// An acrClient with authentication is generated, if the authentication cannot be resolved an error is returned.
acrClient, err := api.GetAcrCLIClientWithAuth(loginURL, purgeParams.username, purgeParams.password, purgeParams.configs)
if err != nil {
return err
}
// A map is used to collect the regex tags for every repository.
tagFilters, err := common.CollectTagFilters(ctx, purgeParams.filters, acrClient.AutorestClient, purgeParams.filterTimeout, purgeParams.repoPageSize)
if err != nil {
return err
}
// A clarification message for --dry-run.
if purgeParams.dryRun {
fmt.Println("DRY RUN: The following output shows what WOULD be deleted if the purge command was executed. Nothing is deleted.")
}
// In order to print a summary of the deleted tags/manifests the counters get updated everytime a repo is purged.
deletedTagsCount := 0
deletedManifestsCount := 0
for repoName, tagRegex := range tagFilters {
if !purgeParams.dryRun {
poolSize := purgeParams.concurrency
if poolSize <= 0 {
poolSize = defaultPoolSize
fmt.Printf("Specified concurrency value invalid. Set to default value: %d \n", defaultPoolSize)
} else if poolSize > maxPoolSize {
poolSize = maxPoolSize
fmt.Printf("Specified concurrency value too large. Set to maximum value: %d \n", maxPoolSize)
}
singleDeletedTagsCount, err := purgeTags(ctx, acrClient, poolSize, loginURL, repoName, purgeParams.ago, tagRegex, purgeParams.keep, purgeParams.filterTimeout)
if err != nil {
return errors.Wrap(err, "failed to purge tags")
}
singleDeletedManifestsCount := 0
// If the untagged flag is set then also manifests are deleted.
if purgeParams.untagged {
singleDeletedManifestsCount, err = purgeDanglingManifests(ctx, acrClient, poolSize, loginURL, repoName)
if err != nil {
return errors.Wrap(err, "failed to purge manifests")
}
}
// After every repository is purged the counters are updated.
deletedTagsCount += singleDeletedTagsCount
deletedManifestsCount += singleDeletedManifestsCount
} else {
// No tag or manifest will be deleted but the counters still will be updated.
singleDeletedTagsCount, singleDeletedManifestsCount, err := dryRunPurge(ctx, acrClient, loginURL, repoName, purgeParams.ago, tagRegex, purgeParams.untagged, purgeParams.keep, purgeParams.filterTimeout)
if err != nil {
return errors.Wrap(err, "failed to dry-run purge")
}
deletedTagsCount += singleDeletedTagsCount
deletedManifestsCount += singleDeletedManifestsCount
}
}
// After all repos have been purged the summary is printed.
if purgeParams.dryRun {
fmt.Printf("\nNumber of tags to be deleted: %d\n", deletedTagsCount)
fmt.Printf("Number of manifests to be deleted: %d\n", deletedManifestsCount)
} else {
fmt.Printf("\nNumber of deleted tags: %d\n", deletedTagsCount)
fmt.Printf("Number of deleted manifests: %d\n", deletedManifestsCount)
}
return nil
},
}
cmd.Flags().BoolVar(&purgeParams.untagged, "untagged", false, "If the untagged flag is set all the manifests that do not have any tags associated to them will be also purged, except if they belong to a manifest list that contains at least one tag")
cmd.Flags().BoolVar(&purgeParams.dryRun, "dry-run", false, "If the dry-run flag is set no manifest or tag will be deleted, the output would be the same as if they were deleted")
cmd.Flags().StringVar(&purgeParams.ago, "ago", "", "The tags that were last updated before this duration will be deleted, the format is [number]d[string] where the first number represents an amount of days and the string is in a Go duration format (e.g. 2d3h6m selects images older than 2 days, 3 hours and 6 minutes)")
cmd.Flags().IntVar(&purgeParams.keep, "keep", 0, "Number of latest to-be-deleted tags to keep, use this when you want to keep at least x number of latest tags that could be deleted meeting all other filter criteria")
cmd.Flags().StringArrayVarP(&purgeParams.filters, "filter", "f", nil, "Specify the repository and a regular expression filter for the tag name, if a tag matches the filter and is older than the duration specified in ago it will be deleted. Note: If backtracking is used in the regexp it's possible for the expression to run into an infinite loop. The default timeout is set to 1 minute for evaluation of any filter expression. Use the '--filter-timeout-seconds' option to set a different value.")
cmd.Flags().StringArrayVarP(&purgeParams.configs, "config", "c", nil, "Authentication config paths (e.g. C://Users/docker/config.json)")
cmd.Flags().Int64Var(&purgeParams.filterTimeout, "filter-timeout-seconds", defaultRegexpMatchTimeoutSeconds, "This limits the evaluation of the regex filter, and will return a timeout error if this duration is exceeded during a single evaluation. If written incorrectly a regexp filter with backtracking can result in an infinite loop.")
cmd.Flags().IntVar(&purgeParams.concurrency, "concurrency", defaultPoolSize, concurrencyDescription)
cmd.Flags().Int32Var(&purgeParams.repoPageSize, "repository-page-size", defaultRepoPageSize, repoPageSizeDescription)
cmd.Flags().BoolP("help", "h", false, "Print usage")
cmd.MarkFlagRequired("filter")
cmd.MarkFlagRequired("ago")
return cmd
}