Skip to content

Commit cb02b12

Browse files
authored
Issue 575 (#592)
## Fixes - #575 ## Changes - added verbosity flags in different levels - show progress bar with automatic PDSC update ## Checklist <!-- Put an `x` in the boxes. All tasks must be completed and boxes checked before merging. --> - [x] 🤖 This change is covered by unit tests (if applicable). - [ ] 🤹 Manual testing has been performed (if necessary). - [x] 🛡️ Security impacts have been considered (if relevant). - [x] 📖 Documentation updates are complete (if required). - [x] 🧠 Third-party dependencies and TPIP updated (if required).
1 parent b46274d commit cb02b12

File tree

9 files changed

+141
-74
lines changed

9 files changed

+141
-74
lines changed

cmd/commands/init.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ The index-url is mandatory. Ex "cpackget init --pack-root path/to/mypackroot htt
5353
return err
5454
}
5555

56-
err = installer.UpdatePublicIndex(indexPath, true, true, initCmdFlags.downloadPdscFiles, false, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
56+
err = installer.UpdatePublicIndex(indexPath, true, true, initCmdFlags.downloadPdscFiles, false, true, true, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
5757
return err
5858
},
5959
}

cmd/commands/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func configureInstaller(cmd *cobra.Command, args []string) error {
7979
// Exclude index updating commands to not double update
8080
if cmd.Name() != "init" && cmd.Name() != "index" && cmd.Name() != "update-index" && cmd.Name() != "list" {
8181
installer.UnlockPackRoot()
82-
err = installer.UpdatePublicIndex(installer.ActualPublicIndex, true, true, false, false, 0, 0)
82+
err = installer.UpdatePublicIndex(installer.ActualPublicIndex, true, true, false, false, false, true, 0, 0)
8383
if err != nil {
8484
return err
8585
}

cmd/commands/update_index.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ var UpdateIndexCmd = &cobra.Command{
4444
return err
4545
}
4646

47-
err = installer.UpdatePublicIndex("", true, updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
47+
err = installer.UpdatePublicIndex("", true, updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, true, true, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout"))
4848
return err
4949
},
5050
}

cmd/installer/pack.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ func (p *PackType) fetch(timeout int) error {
191191
log.Debugf("Fetching pack file %q (or just making sure it exists locally)", p.path)
192192
var err error
193193
if strings.HasPrefix(p.path, "http") {
194-
p.path, err = utils.DownloadFile(p.path, true, false, timeout)
194+
p.path, err = utils.DownloadFile(p.path, true, true, true, timeout)
195195
if err == errs.ErrTerminatedByUser {
196196
log.Infof("Aborting pack download. Removing %q", p.path)
197197
}

cmd/installer/root.go

Lines changed: 100 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/open-cmsis-pack/cpackget/cmd/ui"
2424
"github.com/open-cmsis-pack/cpackget/cmd/utils"
2525
"github.com/open-cmsis-pack/cpackget/cmd/xml"
26+
"github.com/schollz/progressbar/v3"
2627
log "github.com/sirupsen/logrus"
2728
"github.com/spf13/viper"
2829
"golang.org/x/mod/semver"
@@ -400,13 +401,14 @@ func RemovePdsc(pdscPath string) error {
400401
// Parameters:
401402
// - pdscTag: The PDSC tag containing information about the files to be downloaded.
402403
// - skipInstalledPdscFiles: A boolean flag indicating whether to skip already installed PDSC files.
404+
// - showInfo: If true, logs informational messages about the download.
403405
// - timeout: An integer specifying the timeout duration in seconds.
404406
//
405407
// Example:
406408
//
407409
// massDownloadPdscFiles(pdscTag, true, 30)
408-
func massDownloadPdscFiles(pdscTag xml.PdscTag, skipInstalledPdscFiles bool, timeout int, errTags *lockedSlice) {
409-
if err := Installation.downloadPdscFile(pdscTag, skipInstalledPdscFiles, true, timeout); err != nil {
410+
func massDownloadPdscFiles(pdscTag xml.PdscTag, skipInstalledPdscFiles, showInfo bool, timeout int, errTags *lockedSlice) {
411+
if err := Installation.downloadPdscFile(pdscTag, skipInstalledPdscFiles, showInfo, false, timeout); err != nil {
410412
errTags.lock.Lock()
411413
errTags.slice = append(errTags.slice, pdscTag)
412414
errTags.lock.Unlock()
@@ -613,7 +615,7 @@ func DownloadPDSCFiles(skipInstalledPdscFiles bool, concurrency int, timeout int
613615

614616
for _, pdscTag := range pdscTags {
615617
if concurrency == 0 {
616-
massDownloadPdscFiles(pdscTag, skipInstalledPdscFiles, timeout, &errTags)
618+
massDownloadPdscFiles(pdscTag, skipInstalledPdscFiles, true, timeout, &errTags)
617619
} else {
618620
if err := sem.Acquire(ctx, 1); err != nil {
619621
log.Errorf("Failed to acquire semaphore: %v", err)
@@ -622,7 +624,7 @@ func DownloadPDSCFiles(skipInstalledPdscFiles bool, concurrency int, timeout int
622624

623625
go func(pdscTag xml.PdscTag, errTags *lockedSlice) {
624626
defer sem.Release(1)
625-
massDownloadPdscFiles(pdscTag, skipInstalledPdscFiles, timeout, errTags)
627+
massDownloadPdscFiles(pdscTag, skipInstalledPdscFiles, true, timeout, errTags)
626628
}(pdscTag, &errTags)
627629
}
628630
}
@@ -635,54 +637,96 @@ func DownloadPDSCFiles(skipInstalledPdscFiles bool, concurrency int, timeout int
635637
return nil
636638
}
637639

638-
// UpdateInstalledPDSCFiles updates the PDSC files of installed packs referenced in the public index.
639-
// It checks if the PDSC files need updating and downloads the latest versions if necessary.
640+
// UpdateInstalledPDSCFiles updates the installed PDSC files for both public and private packs.
641+
// It compares the provided pidxXML (current index) and oldPidxXML (previous index) to determine
642+
// which PDSC files need to be updated. For public packs, it downloads new versions of PDSC files
643+
// if available, using concurrency control. If any errors occur during download, it attempts to
644+
// revert to previous versions. After updating, it writes the updated index and moves it to the
645+
// installation directory, handling file permissions appropriately.
646+
//
647+
// For private packs, it scans the local directory for PDSC files and checks if they need updating
648+
// by loading the latest version from the source. If an update is available, it logs the upgrade
649+
// information. The function supports configurable concurrency and timeout for downloads.
640650
//
641651
// Parameters:
642-
// - pidxXML: A pointer to the PidxXML structure containing the public index data.
643-
// - concurrency: The number of concurrent downloads allowed. If set to 0, downloads are performed sequentially.
644-
// - timeout: The timeout duration for downloading PDSC files.
652+
// - pidxXML: The current public index XML structure.
653+
// - oldPidxXML: The previous public index XML structure (can be nil).
654+
// - updatePrivatePdsc: Whether to update private PDSC files.
655+
// - showInfo: If true, logs informational messages about the download.
656+
// - concurrency: Number of concurrent downloads allowed.
657+
// - timeout: Timeout in seconds for downloading PDSC files.
645658
//
646659
// Returns:
647-
// - error: An error if any issue occurs during the update process.
648-
//
649-
// The function performs the following steps:
650-
// 1. Lists all PDSC files in the installation web directory.
651-
// 2. For each PDSC file, it reads the file and checks if the pack is still present in the public index.
652-
// 3. If the pack is no longer present, it deletes the PDSC file.
653-
// 4. If the pack is present but has a newer version in the public index, it downloads the latest version.
654-
// 5. Lists all PDSC files in the local directory and repeats the update process for these files.
655-
func UpdateInstalledPDSCFiles(pidxXML, oldPidxXML *xml.PidxXML, concurrency int, timeout int) error {
656-
log.Info("Updating PDSC files of public packs")
657-
660+
// - error: An error if any operation fails, otherwise nil.
661+
func UpdateInstalledPDSCFiles(pidxXML, oldPidxXML *xml.PidxXML, updatePrivatePdsc, showInfo bool, concurrency int, timeout int) error {
658662
ctx := context.TODO()
659663
concurrency = CheckConcurrency(concurrency)
660664
sem := semaphore.NewWeighted(int64(concurrency))
661665

662666
var errTags lockedSlice
663667

664668
if oldPidxXML != nil && !oldPidxXML.Empty() {
669+
var pdscToUpdate []xml.PdscTag
670+
updatingMessageShown := false
671+
// Find all pdsc tags that are in the new pidxXML but not in the oldPidxXML
672+
// or have a different URL (indicating a new version)
673+
// and add them to the pdscToUpdate slice
665674
for _, pdscTag := range pidxXML.ListPdscTags() {
666675
if oldPidxXML.HasPdsc(pdscTag) != xml.PdscIndexNotFound {
667676
continue // found in old pidx and same URL
668677
}
669678
oldTags := oldPidxXML.FindPdscNameTags(pdscTag)
670679
if len(oldTags) != 0 {
671-
log.Infof("%s::%s has a new version %q, previous was %q", pdscTag.Vendor, pdscTag.Name, pdscTag.Version, oldTags[0].Version)
680+
if !updatingMessageShown {
681+
log.Info("Updating cached public PDSC files with new version")
682+
updatingMessageShown = true
683+
}
684+
if showInfo {
685+
log.Infof("%s::%s has a new version %q, previous was %q", pdscTag.Vendor, pdscTag.Name, pdscTag.Version, oldTags[0].Version)
686+
}
687+
pdscToUpdate = append(pdscToUpdate, pdscTag)
688+
}
689+
}
690+
// Avoid repeated calls to IsTerminalInteractive
691+
// as it cleans the stdout buffer
692+
interactiveTerminal := utils.IsTerminalInteractive()
693+
var progress *progressbar.ProgressBar
694+
var encodedProgress *utils.EncodedProgress
672695

673-
if concurrency == 0 {
674-
massDownloadPdscFiles(pdscTag, false, timeout, &errTags)
675-
} else {
676-
if err := sem.Acquire(ctx, 1); err != nil {
677-
log.Errorf("Failed to acquire semaphore: %v", err)
678-
break
696+
if !showInfo && len(pdscToUpdate) > 0 {
697+
if utils.GetEncodedProgress() {
698+
encodedProgress = utils.NewEncodedProgress(int64(len(pdscToUpdate)), 0, "PDSC files updated:")
699+
} else if interactiveTerminal && log.GetLevel() != log.ErrorLevel {
700+
progress = progressbar.Default(int64(len(pdscToUpdate)), "I:")
701+
}
702+
}
703+
for _, pdscTag := range pdscToUpdate {
704+
if concurrency == 0 {
705+
if !showInfo {
706+
if utils.GetEncodedProgress() {
707+
_ = encodedProgress.Add(1)
708+
} else if interactiveTerminal && log.GetLevel() != log.ErrorLevel {
709+
_ = progress.Add64(1)
679710
}
680-
681-
go func(pdscTag xml.PdscTag, errTags *lockedSlice) {
682-
defer sem.Release(1)
683-
massDownloadPdscFiles(pdscTag, false, timeout, errTags)
684-
}(pdscTag, &errTags)
685711
}
712+
massDownloadPdscFiles(pdscTag, false, showInfo, timeout, &errTags)
713+
} else {
714+
if err := sem.Acquire(ctx, 1); err != nil {
715+
log.Errorf("Failed to acquire semaphore: %v", err)
716+
break
717+
}
718+
719+
go func(pdscTag xml.PdscTag, errTags *lockedSlice) {
720+
defer sem.Release(1)
721+
if !showInfo {
722+
if utils.GetEncodedProgress() {
723+
_ = encodedProgress.Add(1)
724+
} else if interactiveTerminal && log.GetLevel() != log.ErrorLevel {
725+
_ = progress.Add64(1)
726+
}
727+
}
728+
massDownloadPdscFiles(pdscTag, false, showInfo, timeout, errTags)
729+
}(pdscTag, &errTags)
686730
}
687731
}
688732
if len(errTags.slice) > 0 {
@@ -712,6 +756,10 @@ func UpdateInstalledPDSCFiles(pidxXML, oldPidxXML *xml.PidxXML, concurrency int,
712756
utils.SetReadOnly(Installation.PublicIndex)
713757
}
714758

759+
if !updatePrivatePdsc {
760+
return nil
761+
}
762+
715763
pdscFiles, err := utils.ListDir(Installation.LocalDir, ".pdsc$")
716764
if err != nil {
717765
return err
@@ -721,6 +769,11 @@ func UpdateInstalledPDSCFiles(pidxXML, oldPidxXML *xml.PidxXML, concurrency int,
721769
if utils.GetEncodedProgress() {
722770
log.Infof("[J%d:F%q]", numPdsc, Installation.LocalDir)
723771
}
772+
if numPdsc == 0 {
773+
return nil
774+
}
775+
776+
log.Info("Updating PDSC files of private packs")
724777

725778
for _, pdscFile := range pdscFiles {
726779
log.Debugf("Checking if %q needs updating", pdscFile)
@@ -816,7 +869,7 @@ func UpdatePublicIndexIfOnline() error {
816869
err = Installation.checkUpdateCfg(&updateConf)
817870
if err != nil {
818871
UnlockPackRoot()
819-
err1 := UpdatePublicIndex(ActualPublicIndex, true, false, false, false, 0, 0)
872+
err1 := UpdatePublicIndex(ActualPublicIndex, true, false, false, false, false, false, 0, 0)
820873
if err1 != nil {
821874
return err1
822875
}
@@ -829,7 +882,7 @@ func UpdatePublicIndexIfOnline() error {
829882
// if public index does not or not yet exist then download without check
830883
if !utils.FileExists(Installation.PublicIndex) {
831884
UnlockPackRoot()
832-
err1 := UpdatePublicIndex(ActualPublicIndex, true, false, false, false, 0, 0)
885+
err1 := UpdatePublicIndex(ActualPublicIndex, true, false, false, false, false, false, 0, 0)
833886
if err1 != nil {
834887
return err1
835888
}
@@ -848,12 +901,14 @@ func UpdatePublicIndexIfOnline() error {
848901
// - sparse: A boolean flag to indicate whether to perform a sparse update.
849902
// - downloadPdsc: A boolean flag to indicate whether to download PDSC files.
850903
// - downloadRemainingPdscFiles: A boolean flag to indicate whether to download all remaining PDSC files.
904+
// - updatePrivatePdsc: If true, updates private PDSC files during the update process.
905+
// - showInfo: If true, logs informational messages about the download.
851906
// - concurrency: The number of concurrent operations allowed.
852907
// - timeout: The timeout duration for network operations.
853908
//
854909
// Returns:
855910
// - error: An error if the update fails, otherwise nil.
856-
func UpdatePublicIndex(indexPath string, overwrite bool, sparse bool, downloadPdsc bool, downloadRemainingPdscFiles bool, concurrency int, timeout int) error {
911+
func UpdatePublicIndex(indexPath string, overwrite, sparse, downloadPdsc, downloadRemainingPdscFiles, updatePrivatePdsc, showInfo bool, concurrency int, timeout int) error {
857912
// TODO: Remove overwrite when cpackget v1 gets released
858913
if !overwrite {
859914
return errs.ErrCannotOverwritePublicIndex
@@ -886,7 +941,7 @@ func UpdatePublicIndex(indexPath string, overwrite bool, sparse bool, downloadPd
886941
log.Warnf("Non-HTTPS url: %q", indexPath)
887942
}
888943

889-
indexPath, err = utils.DownloadFile(indexPath, false, false, timeout)
944+
indexPath, err = utils.DownloadFile(indexPath, false, true, true, timeout)
890945
if err != nil {
891946
return err
892947
}
@@ -933,7 +988,7 @@ func UpdatePublicIndex(indexPath string, overwrite bool, sparse bool, downloadPd
933988
}
934989

935990
if !sparse {
936-
err = UpdateInstalledPDSCFiles(Installation.PublicIndexXML, oldPidxXML, concurrency, timeout)
991+
err = UpdateInstalledPDSCFiles(Installation.PublicIndexXML, oldPidxXML, updatePrivatePdsc, showInfo, concurrency, timeout)
937992
if err != nil {
938993
return err
939994
}
@@ -1320,7 +1375,7 @@ func FindPackURL(pack *PackType, testing bool) (string, error) {
13201375
Name: pack.Name,
13211376
})
13221377
if len(tags) != 0 {
1323-
if err := Installation.downloadPdscFile(tags[0], true, false, 0); err != nil {
1378+
if err := Installation.downloadPdscFile(tags[0], true, true, true, 0); err != nil {
13241379
return "", err
13251380
}
13261381
} else {
@@ -1331,7 +1386,7 @@ func FindPackURL(pack *PackType, testing bool) (string, error) {
13311386
URL: pack.URL,
13321387
Vendor: pack.Vendor,
13331388
Name: pack.Name,
1334-
}, true, false, 0); err != nil {
1389+
}, true, true, true, 0); err != nil {
13351390
return "", err
13361391
}
13371392
}
@@ -1358,7 +1413,7 @@ func FindPackURL(pack *PackType, testing bool) (string, error) {
13581413
URL: pack.URL,
13591414
Vendor: pack.Vendor,
13601415
Name: pack.Name,
1361-
}, false, false, 0); err != nil {
1416+
}, false, true, true, 0); err != nil {
13621417
log.Warnf("Latest pdsc %q does not exist in public index", xmlTag.Key())
13631418
return "", err
13641419
}
@@ -1962,7 +2017,8 @@ func (p *PacksInstallationType) packIsPublic(pack *PackType, pdscTag *xml.PdscTa
19622017
// Parameters:
19632018
// - pdscTag: An xml.PdscTag object containing metadata about the PDSC file to be downloaded.
19642019
// - skipInstalledPdscFiles: A boolean flag indicating whether to skip downloading if the PDSC file already exists locally.
1965-
// - noProgressBar: A boolean flag indicating whether to suppress the progress bar during the download.
2020+
// - showInfo: If true, logs informational messages about the download.
2021+
// - showProgressBar: A boolean flag indicating whether to show the progress bar during the download.
19662022
// - timeout: An integer specifying the timeout duration (in seconds) for the download operation.
19672023
//
19682024
// Returns:
@@ -1974,7 +2030,7 @@ func (p *PacksInstallationType) packIsPublic(pack *PackType, pdscTag *xml.PdscTa
19742030
// the function switches to the cache URL for downloading.
19752031
// - The function downloads the PDSC file, temporarily saves it, and then moves it to the target location,
19762032
// ensuring proper file permissions are set before and after the operation.
1977-
func (p *PacksInstallationType) downloadPdscFile(pdscTag xml.PdscTag, skipInstalledPdscFiles, noProgressBar bool, timeout int) error {
2033+
func (p *PacksInstallationType) downloadPdscFile(pdscTag xml.PdscTag, skipInstalledPdscFiles, showInfo, showProgressBar bool, timeout int) error {
19782034
basePdscFile := fmt.Sprintf("%s.pdsc", pdscTag.VName())
19792035
pdscFilePath := filepath.Join(p.WebDir, basePdscFile)
19802036

@@ -2004,7 +2060,7 @@ func (p *PacksInstallationType) downloadPdscFile(pdscTag xml.PdscTag, skipInstal
20042060

20052061
pdscFileURL.Path = path.Join(pdscFileURL.Path, basePdscFile)
20062062

2007-
localFileName, err := utils.DownloadFile(pdscFileURL.String(), true, noProgressBar, timeout)
2063+
localFileName, err := utils.DownloadFile(pdscFileURL.String(), true, showInfo, showProgressBar, timeout)
20082064
defer os.Remove(localFileName)
20092065

20102066
if err != nil {
@@ -2066,7 +2122,7 @@ func (p *PacksInstallationType) loadPdscFile(pdscTag xml.PdscTag, timeout int) e
20662122
return nil
20672123
}
20682124

2069-
localFileName, err := utils.DownloadFile(pdscFileURL.String(), true, false, timeout)
2125+
localFileName, err := utils.DownloadFile(pdscFileURL.String(), true, true, true, timeout)
20702126
defer os.Remove(localFileName)
20712127

20722128
if err != nil {

0 commit comments

Comments
 (0)