Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 28 additions & 13 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@ The `configureInstaller` pre-run hook:
| --- | --- |
| `list` (default) | Lists all installed packs |
| `list --cached` | Lists packs in `.Download/` |
| `list --public` | Lists all packs from the public index |
| `list --public` | Lists all non-deprecated packs from the public index |
| `list --public --deprecated` | Lists deprecated packs from the public index |
| `list --deprecated` | Lists deprecated packs from the public index |
| `list --updates` | Lists packs with newer versions available |
| `list --filter` | Filters results (case-sensitive, accepts multiple expressions) |
| `list-required` | Lists dependencies of installed packs |
Expand Down Expand Up @@ -239,11 +241,15 @@ type PacksInstallationType struct {
- `UpdatePack()` — Updates one or all packs to latest versions
- `InitializeCache()` — Builds `cache.pidx` from existing PDSC files in `.Web/`
- `CheckConcurrency()` — Validates and adjusts the concurrent-downloads setting
- `DownloadPDSCFiles()` — Downloads all PDSC files from the public index in parallel
- `DownloadPDSCFiles()` — Downloads all PDSC files from the public
index in parallel, optionally skipping deprecated packs
- `UpdateInstalledPDSCFiles()` — Refreshes already-cached PDSC files from the index
- `UpdatePublicIndexIfOnline()` — Updates the public index only when connectivity is available
- `UpdatePublicIndex()` — Downloads and updates the public index and PDSC files
- `ListInstalledPacks()` — Lists packs with various filter modes
- `UpdatePublicIndex()` — Downloads and updates the public index and
PDSC files, with option to skip deprecated PDSC files
- `ListInstalledPacks()` — Lists packs with various filter modes;
supports `--deprecated` flag to show only deprecated packs
(hidden by default in `--public` listing)
- `FindPackURL()` — Resolves a pack ID to a download URL from the index
- `SetPackRoot()` — Initializes the `Installation` singleton and directory paths
- `ReadIndexFiles()` — Loads `index.pidx`, `local_repository.pidx`, and `cache.pidx`
Expand Down Expand Up @@ -329,17 +335,19 @@ type PidxXML struct {
Pdscs []PdscTag // List of all pack references
}
// Internal lookup maps for O(1) access
pdscList map[string][]int // key → indices
pdscListName map[string][]int // vendor.name → indices
pdscList map[string][]PdscTag // key → PdscTags
pdscListName map[string]string // vendor.name → key
deprecatedDate time.Time // today UTC, set once per Read()
}

type PdscTag struct {
URL string `xml:"url,attr"`
Vendor string `xml:"vendor,attr"`
Name string `xml:"name,attr"`
Version string `xml:"version,attr"`
Deprecated string `xml:"deprecated,attr,omitempty"`
Replacement string `xml:"replacement,attr,omitempty"`
URL string `xml:"url,attr"`
Vendor string `xml:"vendor,attr"`
Name string `xml:"name,attr"`
Version string `xml:"version,attr"`
Deprecated string `xml:"deprecated,attr,omitempty"`
Replacement string `xml:"replacement,attr,omitempty"`
isDeprecated bool // cached flag, computed on insert
}
```

Expand All @@ -359,6 +367,11 @@ type PdscTag struct {
- `YamlPackID()` — Returns `Vendor::Name@Version` format
- `PackURL()` — Constructs the full `.pack` download URL (PdscTag method)
- `PdscFileName()` — Returns the `.pdsc` filename (PdscTag method)
- `IsDeprecated()` — Returns the cached deprecated flag.
Computed via `computeIsDeprecated()` when a PdscTag is
inserted (`Read`, `AddPdsc`, `AddReplacePdsc`).
Uses `PidxXML.deprecatedDate` (today UTC, set once per
`NewPidxXML`/`Read`) as reference (PdscTag method)

### 7.2 PDSC — Pack Description (`pdsc.go`)

Expand Down Expand Up @@ -666,7 +679,8 @@ All errors are predefined constants in `errors.go`, allowing consistent error ch
Helper functions:

- `Is()` — Wraps `errors.Is()` for convenience
- `AlreadyLogged()` — Wraps errors to prevent the same message from being logged twice as the error travels up the call stack
- `AlreadyLogged()` — Wraps errors to prevent the same message from
being logged twice as the error travels up the call stack

---

Expand Down Expand Up @@ -706,6 +720,7 @@ installer.UpdatePublicIndex()
├── Download new index.pidx from upstream URL
├── Compare old vs. new entries
├── Download updated/new PDSC files (concurrent, via semaphore)
│ └── Skip PDSC files where Deprecated date ≤ today
├── Update cache.pidx to reflect changes
└── Remove deprecated entries
```
Expand Down
2 changes: 1 addition & 1 deletion cmd/commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ The index-url is mandatory. Ex "cpackget init --pack-root path/to/mypackroot htt
return err
}

err = installer.UpdatePublicIndex(indexPath, true, initCmdFlags.downloadPdscFiles, false, true, true, initCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
err = installer.UpdatePublicIndex(indexPath, true, initCmdFlags.downloadPdscFiles, false, true, true, true, initCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
return err
},
}
Expand Down
13 changes: 10 additions & 3 deletions cmd/commands/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,24 @@ var listCmdFlags struct {
// listCached tells whether listing all cached packs
listCached bool

// listDeprecated tells whether listing all deprecated packs
listDeprecated bool

// listFilter is a set of words by which to filter listed packs
listFilter string
}

var ListCmd = &cobra.Command{
Use: "list [--cached|--public|--updates]",
Use: "list [--cached|--public|--updates|--deprecated] [--filter <expression>]",
Short: "List installed packs",
Long: "List all installed packs and optionally cached packs or those for which updates are available",
Args: cobra.MaximumNArgs(0),
PersistentPreRunE: configureInstaller,
RunE: func(cmd *cobra.Command, args []string) error {
return installer.ListInstalledPacks(listCmdFlags.listCached, listCmdFlags.listPublic, listCmdFlags.listUpdates, false, false, listCmdFlags.listFilter)
if listCmdFlags.listDeprecated {
listCmdFlags.listPublic = true
}
return installer.ListInstalledPacks(listCmdFlags.listCached, listCmdFlags.listPublic, listCmdFlags.listUpdates, listCmdFlags.listDeprecated, false, false, listCmdFlags.listFilter)
},
}

Expand All @@ -41,14 +47,15 @@ var listRequiredCmd = &cobra.Command{
Args: cobra.MaximumNArgs(0),
PersistentPreRunE: configureInstaller,
RunE: func(cmd *cobra.Command, args []string) error {
return installer.ListInstalledPacks(listCmdFlags.listCached, listCmdFlags.listPublic, listCmdFlags.listUpdates, true, false, listCmdFlags.listFilter)
return installer.ListInstalledPacks(listCmdFlags.listCached, listCmdFlags.listPublic, listCmdFlags.listUpdates, listCmdFlags.listDeprecated, true, false, listCmdFlags.listFilter)
},
}

func init() {
ListCmd.Flags().BoolVarP(&listCmdFlags.listCached, "cached", "c", false, "list only cached packs")
ListCmd.Flags().BoolVarP(&listCmdFlags.listPublic, "public", "p", false, "list packs in the public index")
ListCmd.Flags().BoolVarP(&listCmdFlags.listUpdates, "updates", "u", false, "list packs which have newer versions")
ListCmd.Flags().BoolVarP(&listCmdFlags.listDeprecated, "deprecated", "d", false, "list only deprecated packs")
ListCmd.Flags().StringVarP(&listCmdFlags.listFilter, "filter", "f", "", "filter results (case sensitive, accepts several expressions)")
ListCmd.AddCommand(listRequiredCmd)

Expand Down
2 changes: 1 addition & 1 deletion cmd/commands/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func configureInstaller(cmd *cobra.Command, args []string) error {
// Exclude index updating commands to not double update
if cmd.Name() != "init" && cmd.Name() != "index" && cmd.Name() != "update-index" && cmd.Name() != "list" {
installer.UnlockPackRoot()
err = installer.UpdatePublicIndex(installer.ActualPublicIndex, true, false, false, false, true, false, 0, 0)
err = installer.UpdatePublicIndex(installer.ActualPublicIndex, true, false, false, true, false, true, false, 0, 0)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/commands/update_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ var UpdateIndexCmd = &cobra.Command{
return err
}

err = installer.UpdatePublicIndex("", updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, true, true, updateIndexCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
err = installer.UpdatePublicIndex("", updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, updateIndexCmdFlags.downloadUpdatePdscFiles, true, true, updateIndexCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
return err
},
}
Expand Down
47 changes: 39 additions & 8 deletions cmd/installer/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -674,19 +674,34 @@ func CheckConcurrency(concurrency int) int {
//
// Parameters:
// - skipInstalledPdscFiles: If true, skips downloading PDSC files that are already installed.
// - skipDeprecatedPdscFiles: If true, skips downloading PDSC files that are marked as deprecated.
// - insecureSkipVerify: If true, skips TLS certificate verification for HTTPS downloads.
// - concurrency: The number of concurrent downloads to allow. If 0, downloads are sequential.
// - timeout: The timeout for each download operation.
//
// Returns:
// - An error if there is an issue reading the public index XML or acquiring the semaphore.
func DownloadPDSCFiles(skipInstalledPdscFiles, insecureSkipVerify bool, concurrency int, timeout int) error {
func DownloadPDSCFiles(skipInstalledPdscFiles, skipDeprecatedPdscFiles, insecureSkipVerify bool, concurrency int, timeout int) error {
log.Info("Downloading all PDSC files available on the public index")
// if err := Installation.PublicIndexXML.Read(); err != nil {
// return err
// }

pdscTags := Installation.PublicIndexXML.ListPdscTags()
allPdscTags := Installation.PublicIndexXML.ListPdscTags()

// Filter out deprecated tags upfront if requested, so the job count
// used for progress reporting matches the actual number of downloads.
var pdscTags []xml.PdscTag
if skipDeprecatedPdscFiles {
for _, t := range allPdscTags {
if !t.IsDeprecated() {
pdscTags = append(pdscTags, t)
}
}
} else {
pdscTags = allPdscTags
}

numPdsc := len(pdscTags)
if numPdsc == 0 {
log.Info("(no packs in public index)")
Expand Down Expand Up @@ -940,7 +955,7 @@ func UpdatePublicIndexIfOnline() error {
err = Installation.checkUpdateCfg(&updateConf, true)
if err != nil {
UnlockPackRoot()
err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, false, false, false, 0, 0)
err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, true, false, false, false, 0, 0)
if err1 != nil {
log.Warnf("Cannot update public index: %v", err1)
return nil
Expand All @@ -954,7 +969,7 @@ func UpdatePublicIndexIfOnline() error {
// if public index does not or not yet exist then download without check
if !utils.FileExists(Installation.PublicIndex) {
UnlockPackRoot()
err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, false, false, false, 0, 0)
err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, true, false, false, false, 0, 0)
if err1 != nil {
log.Warnf("Cannot update public index: %v", err1)
return nil
Expand All @@ -974,6 +989,7 @@ func UpdatePublicIndexIfOnline() error {
// - sparse: A boolean flag to indicate whether to perform a sparse update.
// - downloadPdsc: A boolean flag to indicate whether to download PDSC files.
// - downloadRemainingPdscFiles: A boolean flag to indicate whether to download all remaining PDSC files.
// - skipDeprecatedPdscFiles: If true, skips downloading deprecated PDSC files.
// - updatePrivatePdsc: If true, updates private PDSC files during the update process.
// - showInfo: If true, logs informational messages about the download.
// - insecureSkipVerify: A boolean flag to indicate whether to skip TLS certificate verification for HTTPS downloads.
Expand All @@ -982,7 +998,7 @@ func UpdatePublicIndexIfOnline() error {
//
// Returns:
// - error: An error if the update fails, otherwise nil.
func UpdatePublicIndex(indexPath string, sparse, downloadPdsc, downloadRemainingPdscFiles, updatePrivatePdsc, showInfo, insecureSkipVerify bool, concurrency int, timeout int) error {
func UpdatePublicIndex(indexPath string, sparse, downloadPdsc, downloadRemainingPdscFiles, skipDeprecatedPdscFiles, updatePrivatePdsc, showInfo, insecureSkipVerify bool, concurrency int, timeout int) error {
// For backwards compatibility, allow indexPath to be a file, but ideally it should be empty
if indexPath == "" {
indexPath = strings.TrimSuffix(Installation.PublicIndexXML.URL, "/") + "/" + PublicIndexName
Expand Down Expand Up @@ -1043,7 +1059,7 @@ func UpdatePublicIndex(indexPath string, sparse, downloadPdsc, downloadRemaining
utils.SetReadOnly(Installation.PublicIndex)

if downloadPdsc {
err = DownloadPDSCFiles(false, insecureSkipVerify, concurrency, timeout)
err = DownloadPDSCFiles(false, skipDeprecatedPdscFiles, insecureSkipVerify, concurrency, timeout)
if err != nil {
return err
}
Expand All @@ -1066,7 +1082,7 @@ func UpdatePublicIndex(indexPath string, sparse, downloadPdsc, downloadRemaining
Installation.PublicIndexXML.SetFileName(savedIndexPath)

if downloadRemainingPdscFiles {
err = DownloadPDSCFiles(true, insecureSkipVerify, concurrency, timeout)
err = DownloadPDSCFiles(true, skipDeprecatedPdscFiles, insecureSkipVerify, concurrency, timeout)
if err != nil {
return err
}
Expand Down Expand Up @@ -1190,12 +1206,14 @@ func findInstalledPacks(addLocalPacks, removeDuplicates bool) ([]installedPack,
// - listCached: If true, lists the cached packs.
// - listPublic: If true, lists the packs from the public index.
// - listUpdates: If true, lists the installed packs with available updates.
// - listDeprecated: If true, lists the deprecated packs.
// - listRequirements: If true, lists the installed packs with dependencies.
// - testing: If true, skips reading index files (used for testing).
// - listFilter: A string to filter the packs by.
//
// Returns:
// - error: An error if any occurs during the listing process.
func ListInstalledPacks(listCached, listPublic, listUpdates, listRequirements, testing bool, listFilter string) error {
func ListInstalledPacks(listCached, listPublic, listUpdates, listDeprecated, listRequirements, testing bool, listFilter string) error {
log.Debugf("Listing packs")

if !testing {
Expand All @@ -1222,7 +1240,20 @@ func ListInstalledPacks(listCached, listPublic, listUpdates, listRequirements, t
})
// List all available packs from the index
for _, pdscTag := range pdscTags {
isDeprecated := pdscTag.IsDeprecated()
// Filter by deprecated status:
// --deprecated: show only deprecated packs
// without --deprecated: hide deprecated packs
if listDeprecated && !isDeprecated {
continue
}
if !listDeprecated && isDeprecated {
continue
}
logMessage := pdscTag.YamlPackID()
if isDeprecated {
logMessage += " (deprecated)"
}
packFilePath := filepath.Join(Installation.DownloadDir, pdscTag.Key()) + utils.PackExtension

if ok, _ := Installation.PackIsInstalled(&PackType{PdscTag: pdscTag}, false); ok {
Expand Down
Loading
Loading