From 20e66fc7ce7febe56a1e1cadb140a5d48e871a5a Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 09:48:44 +0200 Subject: [PATCH 1/6] Honor update.cfg settings for public index updates Record successful explicit updates while preserving the Auto setting, and skip stale automatic updates when Auto is disabled. Default malformed Auto values to enabled for backward compatibility and leave config unchanged on failed updates. Ignore local AI tooling files. --- .gitignore | 4 ++ cmd/commands/update_index.go | 6 ++- cmd/commands/update_index_test.go | 61 ++++++++++++++++++++++++++++ cmd/installer/root.go | 18 ++++++++- cmd/installer/root_test.go | 66 +++++++++++++++++++++++++++++-- 5 files changed, 148 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index d7da4ace..2c2945c0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ tmp/ .vagrant/ # IDEs .vscode/ +# AI files and directories +.cmsis-dev +.plans +.codex \ No newline at end of file diff --git a/cmd/commands/update_index.go b/cmd/commands/update_index.go index fcaca6b5..025e43ab 100644 --- a/cmd/commands/update_index.go +++ b/cmd/commands/update_index.go @@ -50,8 +50,10 @@ var UpdateIndexCmd = &cobra.Command{ return err } - err = installer.UpdatePublicIndex("", updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, !updateIndexCmdFlags.includeDeprecated, true, true, updateIndexCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout")) - return err + if err := installer.UpdatePublicIndex("", updateIndexCmdFlags.sparse, false, updateIndexCmdFlags.downloadUpdatePdscFiles, !updateIndexCmdFlags.includeDeprecated, true, true, updateIndexCmdFlags.insecureSkipVerify, viper.GetInt("concurrent-downloads"), viper.GetInt("timeout")); err != nil { + return err + } + return installer.RecordPublicIndexUpdate() }, } diff --git a/cmd/commands/update_index_test.go b/cmd/commands/update_index_test.go index 267abf90..d24c86da 100644 --- a/cmd/commands/update_index_test.go +++ b/cmd/commands/update_index_test.go @@ -7,8 +7,11 @@ import ( "errors" "fmt" "os" + "path/filepath" "testing" + "time" + errs "github.com/open-cmsis-pack/cpackget/cmd/errors" "github.com/open-cmsis-pack/cpackget/cmd/installer" ) @@ -42,9 +45,23 @@ var updateIndexCmdTests = []TestCase{ ` indexContent = fmt.Sprintf(indexContent, updateIndexServer.URL()) _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0600) + oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + _ = os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=false\n"), 0600) updateIndexServer.AddRoute(installer.PublicIndexName, []byte(indexContent)) }, + validationFunc: func(t *testing.T) { + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + content, err := os.ReadFile(updateCfgPath) + if err != nil { + t.Fatal(err) + } + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=false\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } + }, }, { name: "test updating index", @@ -66,6 +83,17 @@ var updateIndexCmdTests = []TestCase{ updateIndexServer.AddRoute(installer.PublicIndexName, []byte(indexContent)) }, + validationFunc: func(t *testing.T) { + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + content, err := os.ReadFile(updateCfgPath) + if err != nil { + t.Fatal(err) + } + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=true\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } + }, }, { name: "test updating index with insecure-skip-verify flag", @@ -88,6 +116,39 @@ var updateIndexCmdTests = []TestCase{ updateIndexServer.AddRoute(installer.PublicIndexName, []byte(indexContent)) }, }, + { + name: "test failed update preserves update config", + args: []string{"update-index"}, + createPackRoot: true, + expectedErr: errs.ErrBadRequest, + expErrUnwrap: true, + setUpFunc: func(t *TestCase) { + indexContent := ` + +TheVendor +%s +2021-10-17T12:21:59.1747971+00:00 + + + +` + indexContent = fmt.Sprintf(indexContent, updateIndexServer.URL()) + _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0600) + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=false\n"), 0600) + updateIndexServer.AddRoute(installer.PublicIndexName, nil) + }, + validationFunc: func(t *testing.T) { + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + content, err := os.ReadFile(updateCfgPath) + if err != nil { + t.Fatal(err) + } + if string(content) != "Date=1-1-2000\nAuto=false\n" { + t.Fatalf("failed update modified update.cfg: %q", content) + } + }, + }, } func TestUpdateIndexCmd(t *testing.T) { diff --git a/cmd/installer/root.go b/cmd/installer/root.go index cd5e1cbe..e9e1d965 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -14,6 +14,7 @@ import ( "path/filepath" "runtime" "sort" + "strconv" "strings" "sync" "syscall" @@ -962,7 +963,7 @@ func UpdatePublicIndexIfOnline() error { if errors.Unwrap(err) != errs.ErrOffline { var updateConf updateCfg err = Installation.checkUpdateCfg(&updateConf, true) - if err != nil { + if err != nil && updateConf.Auto { UnlockPackRoot() err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, true, false, false, false, 0, 0) if err1 != nil { @@ -1833,6 +1834,7 @@ type updateCfg struct { // "Date" field cannot be parsed, or if the timestamp in the "Date" field is older // than 24 hours. If no errors occur, nil is returned. func (p *PacksInstallationType) checkUpdateCfg(conf *updateCfg, WarningInsteadOfErrors bool) error { + conf.Auto = true f, err := os.Open(filepath.Join(p.WebDir, "update.cfg")) if err != nil { if WarningInsteadOfErrors { @@ -1850,9 +1852,14 @@ func (p *PacksInstallationType) checkUpdateCfg(conf *updateCfg, WarningInsteadOf if strings.HasPrefix(line, "Date=") { conf.Date = strings.TrimPrefix(line, "Date=") } else if strings.HasPrefix(line, "Auto=") { - conf.Auto = strings.TrimPrefix(line, "Auto=") == "true" + if auto, err := strconv.ParseBool(strings.TrimPrefix(line, "Auto=")); err == nil { + conf.Auto = auto + } } } + if err := scanner.Err(); err != nil { + return err + } if t, err := time.Parse("2-1-2006", conf.Date); err != nil { return err } else { @@ -1899,6 +1906,13 @@ func (p *PacksInstallationType) updateUpdateCfg(conf *updateCfg) error { return f.Sync() } +// RecordPublicIndexUpdate records a successful explicit public index update. +func RecordPublicIndexUpdate() error { + var updateConf updateCfg + _ = Installation.checkUpdateCfg(&updateConf, false) + return Installation.updateUpdateCfg(&updateConf) +} + // touchPackIdx updates the timestamp of the PackIdx file to the current time. // If the skip touch flag is set, the function returns immediately without making any changes. // The function temporarily removes the read-only attribute from the PackIdx file, diff --git a/cmd/installer/root_test.go b/cmd/installer/root_test.go index 556fd0eb..d5222da3 100644 --- a/cmd/installer/root_test.go +++ b/cmd/installer/root_test.go @@ -501,7 +501,7 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { // Create a recent update.cfg file (less than one day old) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") recentDate := time.Now().Format("2-1-2006") - updateCfgContent := "Date: " + recentDate + "\nAuto: true\n" + updateCfgContent := "Date=" + recentDate + "\nAuto=true\n" assert.Nil(os.WriteFile(updateCfgPath, []byte(updateCfgContent), 0600)) // Get modification time before @@ -552,7 +552,7 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { // Create an old update.cfg file (more than one day old) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") - updateCfgContent := "Date: " + oldDate + "\nAuto: true\n" + updateCfgContent := "Date=" + oldDate + "\nAuto=true\n" assert.Nil(os.WriteFile(updateCfgPath, []byte(updateCfgContent), 0600)) // Call UpdatePublicIndexIfOnline - may fail depending on connection but should return nil @@ -561,6 +561,66 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { assert.Nil(err) }) + t.Run("test automatic update disabled", func(t *testing.T) { + localTestingDir := "test-update-online-auto-disabled" + assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) + installer.UnlockPackRoot() + defer removePackRoot(localTestingDir) + + server := NewServer() + defer server.httpsServer.Close() + + publicIndexContent, err := os.ReadFile(samplePublicIndex) + assert.Nil(err) + server.AddRoute("index.pidx", publicIndexContent) + installer.Installation.PublicIndexXML.URL = server.URL() + "index.pidx" + installer.ActualPublicIndex = server.URL() + "index.pidx" + + originalIndexContent := []byte("existing index") + assert.Nil(os.WriteFile(installer.Installation.PublicIndex, originalIndexContent, 0600)) + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") + updateCfgContent := []byte("Date=" + oldDate + "\nAuto=false\n") + assert.Nil(os.WriteFile(updateCfgPath, updateCfgContent, 0600)) + + assert.Nil(installer.UpdatePublicIndexIfOnline()) + + actualIndexContent, err := os.ReadFile(installer.Installation.PublicIndex) + assert.Nil(err) + assert.Equal(originalIndexContent, actualIndexContent) + actualUpdateCfgContent, err := os.ReadFile(updateCfgPath) + assert.Nil(err) + assert.Equal(updateCfgContent, actualUpdateCfgContent) + }) + + t.Run("test malformed Auto defaults to enabled", func(t *testing.T) { + localTestingDir := "test-update-online-malformed-auto" + assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) + installer.UnlockPackRoot() + defer removePackRoot(localTestingDir) + + server := NewServer() + defer server.httpsServer.Close() + + publicIndexContent, err := os.ReadFile(samplePublicIndex) + assert.Nil(err) + server.AddRoute("index.pidx", publicIndexContent) + installer.Installation.PublicIndexXML.URL = server.URL() + "index.pidx" + installer.ActualPublicIndex = server.URL() + "index.pidx" + + assert.Nil(utils.TouchFile(installer.Installation.PublicIndex)) + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") + assert.Nil(os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=invalid\n"), 0600)) + + assert.Nil(installer.UpdatePublicIndexIfOnline()) + + actualUpdateCfgContent, err := os.ReadFile(updateCfgPath) + assert.Nil(err) + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=true\n" + assert.Equal(expected, string(actualUpdateCfgContent)) + }) + t.Run("test with missing index file", func(t *testing.T) { localTestingDir := "test-update-missing-index" assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) @@ -654,7 +714,7 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { // Create a corrupted update.cfg file (invalid date format) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - corruptedContent := "Date: invalid-date-format\nAuto: true\n" + corruptedContent := "Date=invalid-date-format\nAuto=true\n" assert.Nil(os.WriteFile(updateCfgPath, []byte(corruptedContent), 0600)) // Call UpdatePublicIndexIfOnline - should handle corrupted file gracefully From 4b34740539bb35be4e155e7ca1f4dbb562c99011 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 11:15:23 +0200 Subject: [PATCH 2/6] Introduce UpdateDaily option and --daily flag --- .gitignore | 2 +- cmd/commands/update_index.go | 12 ++++- cmd/commands/update_index_test.go | 79 ++++++++++++++++--------------- cmd/installer/root.go | 53 +++++++++++++++++++-- cmd/installer/root_test.go | 41 +++++++++++++--- 5 files changed, 136 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index 2c2945c0..b43a2e86 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,4 @@ tmp/ # AI files and directories .cmsis-dev .plans -.codex \ No newline at end of file +.codex diff --git a/cmd/commands/update_index.go b/cmd/commands/update_index.go index 025e43ab..5472c796 100644 --- a/cmd/commands/update_index.go +++ b/cmd/commands/update_index.go @@ -28,6 +28,9 @@ var updateIndexCmdFlags struct { // insecureSkipVerify skips TLS certificate verification for HTTPS downloads insecureSkipVerify bool + + // daily controls automatic daily public index updates + daily bool } var UpdateIndexCmd = &cobra.Command{ @@ -36,6 +39,13 @@ var UpdateIndexCmd = &cobra.Command{ Long: getLongUpdateDescription(), Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { + if cmd.Flags().Changed("daily") { + if err := configureInstallerGlobalCmd(cmd, args); err != nil { + return err + } + return installer.SetUpdateDaily(viper.GetString("pack-root"), updateIndexCmdFlags.daily) + } + utils.SetEncodedProgress(updateIndexCmdFlags.encodedProgress) utils.SetSkipTouch(updateIndexCmdFlags.skipTouch) @@ -43,7 +53,6 @@ var UpdateIndexCmd = &cobra.Command{ if err != nil { return err } - installer.UnlockPackRoot() defer installer.LockPackRoot() if err := installer.ReadIndexFiles(); err != nil { @@ -69,4 +78,5 @@ func init() { UpdateIndexCmd.Flags().BoolVarP(&updateIndexCmdFlags.encodedProgress, "encoded-progress", "E", false, "reports encoded progress for files and download when used by other tools") UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.skipTouch, "skip-touch", false, "do not touch pack.idx") UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.insecureSkipVerify, "insecure-skip-verify", false, "skip verification of server's TLS certificate when downloading packs over HTTPS") + UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.daily, "daily", true, "enable automatic daily public index updates") } diff --git a/cmd/commands/update_index_test.go b/cmd/commands/update_index_test.go index d24c86da..273494b1 100644 --- a/cmd/commands/update_index_test.go +++ b/cmd/commands/update_index_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - errs "github.com/open-cmsis-pack/cpackget/cmd/errors" "github.com/open-cmsis-pack/cpackget/cmd/installer" ) @@ -47,7 +46,7 @@ var updateIndexCmdTests = []TestCase{ _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0600) oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - _ = os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=false\n"), 0600) + _ = os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=false\nUpdateDaily=false\n"), 0600) updateIndexServer.AddRoute(installer.PublicIndexName, []byte(indexContent)) }, @@ -57,7 +56,7 @@ var updateIndexCmdTests = []TestCase{ if err != nil { t.Fatal(err) } - expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=false\n" + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=false\nUpdateDaily=false\n" if string(content) != expected { t.Fatalf("unexpected update.cfg content: %q", content) } @@ -89,63 +88,65 @@ var updateIndexCmdTests = []TestCase{ if err != nil { t.Fatal(err) } - expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=true\n" + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=true\nUpdateDaily=true\n" if string(content) != expected { t.Fatalf("unexpected update.cfg content: %q", content) } }, }, { - name: "test updating index with insecure-skip-verify flag", - args: []string{"update-index", "--insecure-skip-verify"}, + name: "test disabling daily updates only changes update config", + args: []string{"update-index", "--insecure-skip-verify", "--daily=false"}, createPackRoot: true, - expectedStdout: []string{"Updating public index", "Downloading " + installer.PublicIndexName}, setUpFunc: func(t *TestCase) { - indexContent := ` - -TheVendor -%s -2021-10-17T12:21:59.1747971+00:00 - - - -` - indexContent = fmt.Sprintf(indexContent, updateIndexServer.URL()) - _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0600) - - updateIndexServer.AddRoute(installer.PublicIndexName, []byte(indexContent)) + _ = os.WriteFile(installer.Installation.PublicIndex, []byte("existing index"), 0600) + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=true\nUpdateDaily=true\n"), 0600) + }, + validationFunc: func(t *testing.T) { + indexContent, err := os.ReadFile(installer.Installation.PublicIndex) + if err != nil { + t.Fatal(err) + } + if string(indexContent) != "existing index" { + t.Fatalf("daily flag modified public index: %q", indexContent) + } + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + content, err := os.ReadFile(updateCfgPath) + if err != nil { + t.Fatal(err) + } + expected := "Date=1-1-2000\nAuto=true\nUpdateDaily=false\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } }, }, { - name: "test failed update preserves update config", - args: []string{"update-index"}, + name: "test enabling daily updates only changes update config", + args: []string{"update-index", "--daily=true"}, createPackRoot: true, - expectedErr: errs.ErrBadRequest, - expErrUnwrap: true, setUpFunc: func(t *TestCase) { - indexContent := ` - -TheVendor -%s -2021-10-17T12:21:59.1747971+00:00 - - - -` - indexContent = fmt.Sprintf(indexContent, updateIndexServer.URL()) - _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0600) + _ = os.WriteFile(installer.Installation.PublicIndex, []byte("existing index"), 0600) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=false\n"), 0600) - updateIndexServer.AddRoute(installer.PublicIndexName, nil) + _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=false\nUpdateDaily=false\n"), 0600) }, validationFunc: func(t *testing.T) { + indexContent, err := os.ReadFile(installer.Installation.PublicIndex) + if err != nil { + t.Fatal(err) + } + if string(indexContent) != "existing index" { + t.Fatalf("daily flag modified public index: %q", indexContent) + } updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") content, err := os.ReadFile(updateCfgPath) if err != nil { t.Fatal(err) } - if string(content) != "Date=1-1-2000\nAuto=false\n" { - t.Fatalf("failed update modified update.cfg: %q", content) + expected := "Date=1-1-2000\nAuto=false\nUpdateDaily=true\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) } }, }, diff --git a/cmd/installer/root.go b/cmd/installer/root.go index e9e1d965..76118dfb 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -963,7 +963,7 @@ func UpdatePublicIndexIfOnline() error { if errors.Unwrap(err) != errs.ErrOffline { var updateConf updateCfg err = Installation.checkUpdateCfg(&updateConf, true) - if err != nil && updateConf.Auto { + if err != nil && updateConf.UpdateDaily { UnlockPackRoot() err1 := UpdatePublicIndex(ActualPublicIndex, false, false, false, true, false, false, false, 0, 0) if err1 != nil { @@ -986,6 +986,7 @@ func UpdatePublicIndexIfOnline() error { } var updateConf updateCfg updateConf.Auto = true + updateConf.UpdateDaily = true _ = Installation.updateUpdateCfg(&updateConf) // create the update config file } return nil @@ -1811,11 +1812,13 @@ type PacksInstallationType struct { // updateCfg represents the content of "update.cfg" file. // - Date: a string representing the date of the last update. -// - Auto: a boolean indicating whether automatic updates are enabled. +// - Auto: a legacy setting preserved for compatibility. +// - UpdateDaily: a boolean indicating whether automatic daily updates are enabled. type updateCfg struct { // Default struct { - Date string - Auto bool + Date string + Auto bool + UpdateDaily bool // } } @@ -1835,6 +1838,7 @@ type updateCfg struct { // than 24 hours. If no errors occur, nil is returned. func (p *PacksInstallationType) checkUpdateCfg(conf *updateCfg, WarningInsteadOfErrors bool) error { conf.Auto = true + conf.UpdateDaily = true f, err := os.Open(filepath.Join(p.WebDir, "update.cfg")) if err != nil { if WarningInsteadOfErrors { @@ -1855,6 +1859,10 @@ func (p *PacksInstallationType) checkUpdateCfg(conf *updateCfg, WarningInsteadOf if auto, err := strconv.ParseBool(strings.TrimPrefix(line, "Auto=")); err == nil { conf.Auto = auto } + } else if strings.HasPrefix(line, "UpdateDaily=") { + if updateDaily, err := strconv.ParseBool(strings.TrimPrefix(line, "UpdateDaily=")); err == nil { + conf.UpdateDaily = updateDaily + } } } if err := scanner.Err(); err != nil { @@ -1880,6 +1888,10 @@ func (p *PacksInstallationType) checkUpdateCfg(conf *updateCfg, WarningInsteadOf // - An error if there is an issue opening, writing to, or syncing the file; otherwise, nil. func (p *PacksInstallationType) updateUpdateCfg(conf *updateCfg) error { conf.Date = time.Now().Local().Format("2-1-2006") + return p.writeUpdateCfg(conf) +} + +func (p *PacksInstallationType) writeUpdateCfg(conf *updateCfg) error { flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY f, err := os.OpenFile(filepath.Join(p.WebDir, "update.cfg"), flags, os.FileMode(0o644)) if err != nil { @@ -1902,6 +1914,18 @@ func (p *PacksInstallationType) updateUpdateCfg(conf *updateCfg) error { return err } } + if _, err := f.WriteString("UpdateDaily="); err != nil { + return err + } + if conf.UpdateDaily { + if _, err := f.WriteString("true\n"); err != nil { + return err + } + } else { + if _, err := f.WriteString("false\n"); err != nil { + return err + } + } return f.Sync() } @@ -1913,6 +1937,27 @@ func RecordPublicIndexUpdate() error { return Installation.updateUpdateCfg(&updateConf) } +// SetUpdateDaily changes the automatic daily update setting without modifying other pack-root files. +func SetUpdateDaily(packRoot string, updateDaily bool) error { + if len(packRoot) == 0 { + return errs.ErrPackRootNotFound + } + packRoot = filepath.Clean(packRoot) + if !utils.DirExists(packRoot) { + return errs.ErrPackRootDoesNotExist + } + webDir := filepath.Join(packRoot, ".Web") + if !utils.DirExists(webDir) { + return errs.ErrPackRootDoesNotExist + } + + installation := PacksInstallationType{WebDir: webDir} + var updateConf updateCfg + _ = installation.checkUpdateCfg(&updateConf, false) + updateConf.UpdateDaily = updateDaily + return installation.writeUpdateCfg(&updateConf) +} + // touchPackIdx updates the timestamp of the PackIdx file to the current time. // If the skip touch flag is set, the function returns immediately without making any changes. // The function temporarily removes the read-only attribute from the PackIdx file, diff --git a/cmd/installer/root_test.go b/cmd/installer/root_test.go index d5222da3..a34d498e 100644 --- a/cmd/installer/root_test.go +++ b/cmd/installer/root_test.go @@ -561,7 +561,7 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { assert.Nil(err) }) - t.Run("test automatic update disabled", func(t *testing.T) { + t.Run("test legacy Auto false is ignored", func(t *testing.T) { localTestingDir := "test-update-online-auto-disabled" assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) installer.UnlockPackRoot() @@ -576,11 +576,40 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { installer.Installation.PublicIndexXML.URL = server.URL() + "index.pidx" installer.ActualPublicIndex = server.URL() + "index.pidx" + assert.Nil(utils.TouchFile(installer.Installation.PublicIndex)) + updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") + oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") + updateCfgContent := []byte("Date=" + oldDate + "\nAuto=false\n") + assert.Nil(os.WriteFile(updateCfgPath, updateCfgContent, 0600)) + + assert.Nil(installer.UpdatePublicIndexIfOnline()) + + actualUpdateCfgContent, err := os.ReadFile(updateCfgPath) + assert.Nil(err) + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=false\nUpdateDaily=true\n" + assert.Equal(expected, string(actualUpdateCfgContent)) + }) + + t.Run("test daily update disabled", func(t *testing.T) { + localTestingDir := "test-update-online-daily-disabled" + assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) + installer.UnlockPackRoot() + defer removePackRoot(localTestingDir) + + server := NewServer() + defer server.httpsServer.Close() + + publicIndexContent, err := os.ReadFile(samplePublicIndex) + assert.Nil(err) + server.AddRoute("index.pidx", publicIndexContent) + installer.Installation.PublicIndexXML.URL = server.URL() + "index.pidx" + installer.ActualPublicIndex = server.URL() + "index.pidx" + originalIndexContent := []byte("existing index") assert.Nil(os.WriteFile(installer.Installation.PublicIndex, originalIndexContent, 0600)) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") - updateCfgContent := []byte("Date=" + oldDate + "\nAuto=false\n") + updateCfgContent := []byte("Date=" + oldDate + "\nAuto=true\nUpdateDaily=false\n") assert.Nil(os.WriteFile(updateCfgPath, updateCfgContent, 0600)) assert.Nil(installer.UpdatePublicIndexIfOnline()) @@ -593,8 +622,8 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { assert.Equal(updateCfgContent, actualUpdateCfgContent) }) - t.Run("test malformed Auto defaults to enabled", func(t *testing.T) { - localTestingDir := "test-update-online-malformed-auto" + t.Run("test malformed daily setting defaults to enabled", func(t *testing.T) { + localTestingDir := "test-update-online-malformed-daily" assert.Nil(installer.SetPackRoot(localTestingDir, CreatePackRoot)) installer.UnlockPackRoot() defer removePackRoot(localTestingDir) @@ -611,13 +640,13 @@ func TestUpdatePublicIndexIfOnline(t *testing.T) { assert.Nil(utils.TouchFile(installer.Installation.PublicIndex)) updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") oldDate := time.Now().AddDate(0, 0, -2).Format("2-1-2006") - assert.Nil(os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=invalid\n"), 0600)) + assert.Nil(os.WriteFile(updateCfgPath, []byte("Date="+oldDate+"\nAuto=false\nUpdateDaily=invalid\n"), 0600)) assert.Nil(installer.UpdatePublicIndexIfOnline()) actualUpdateCfgContent, err := os.ReadFile(updateCfgPath) assert.Nil(err) - expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=true\n" + expected := "Date=" + time.Now().Format("2-1-2006") + "\nAuto=false\nUpdateDaily=true\n" assert.Equal(expected, string(actualUpdateCfgContent)) }) From 1f21d5c0aefb2319c9dfad251751db1690e09be3 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 11:36:32 +0200 Subject: [PATCH 3/6] coverage --- cmd/commands/update_index_internal_test.go | 60 ++++++++ cmd/commands/update_index_test.go | 32 +++++ cmd/installer/root.go | 40 +----- cmd/installer/update_cfg_internal_test.go | 156 +++++++++++++++++++++ 4 files changed, 252 insertions(+), 36 deletions(-) create mode 100644 cmd/commands/update_index_internal_test.go create mode 100644 cmd/installer/update_cfg_internal_test.go diff --git a/cmd/commands/update_index_internal_test.go b/cmd/commands/update_index_internal_test.go new file mode 100644 index 00000000..156db0e0 --- /dev/null +++ b/cmd/commands/update_index_internal_test.go @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright Contributors to the cpackget project. */ + +package commands + +import ( + "errors" + "path/filepath" + "testing" + + errs "github.com/open-cmsis-pack/cpackget/cmd/errors" + viperType "github.com/spf13/viper" +) + +func TestUpdateIndexDailyRejectsConflictingVerbosity(t *testing.T) { + originalViper := viper + originalDaily := updateIndexCmdFlags.daily + dailyFlag := UpdateIndexCmd.Flags().Lookup("daily") + originalDailyValue := dailyFlag.Value.String() + originalDailyChanged := dailyFlag.Changed + t.Cleanup(func() { + viper = originalViper + updateIndexCmdFlags.daily = originalDaily + _ = dailyFlag.Value.Set(originalDailyValue) + dailyFlag.Changed = originalDailyChanged + }) + + viper = viperType.New() + viper.Set("quiet", true) + viper.Set("verbose", true) + updateIndexCmdFlags.daily = false + dailyFlag.Changed = true + + err := UpdateIndexCmd.RunE(UpdateIndexCmd, nil) + if err == nil || err.Error() != "both \"-q\" and \"-v\" were specified, please pick only one verboseness option" { + t.Fatalf("expected conflicting verbosity error, got %v", err) + } +} + +func TestUpdateIndexRejectsMissingPackRoot(t *testing.T) { + originalViper := viper + originalCreatePackRoot := createPackRoot + dailyFlag := UpdateIndexCmd.Flags().Lookup("daily") + originalDailyChanged := dailyFlag.Changed + t.Cleanup(func() { + viper = originalViper + createPackRoot = originalCreatePackRoot + dailyFlag.Changed = originalDailyChanged + }) + + viper = viperType.New() + viper.Set("pack-root", filepath.Join(t.TempDir(), "missing")) + createPackRoot = false + dailyFlag.Changed = false + + err := UpdateIndexCmd.RunE(UpdateIndexCmd, nil) + if !errors.Is(err, errs.ErrPackRootDoesNotExist) { + t.Fatalf("expected ErrPackRootDoesNotExist, got %v", err) + } +} diff --git a/cmd/commands/update_index_test.go b/cmd/commands/update_index_test.go index 273494b1..84eaf4e3 100644 --- a/cmd/commands/update_index_test.go +++ b/cmd/commands/update_index_test.go @@ -11,6 +11,7 @@ import ( "testing" "time" + errs "github.com/open-cmsis-pack/cpackget/cmd/errors" "github.com/open-cmsis-pack/cpackget/cmd/installer" ) @@ -150,6 +151,37 @@ var updateIndexCmdTests = []TestCase{ } }, }, + { + name: "test malformed index returns read error", + args: []string{"update-index"}, + createPackRoot: true, + setUpFunc: func(test *TestCase) { + if err := os.WriteFile(installer.Installation.PublicIndex, []byte("not xml"), 0o600); err != nil { + test.expectedErr = err + return + } + test.expectedErr = installer.Installation.PublicIndexXML.Read() + }, + }, + { + name: "test failed index update returns download error", + args: []string{"update-index"}, + createPackRoot: true, + expectedErr: errs.ErrBadRequest, + expErrUnwrap: true, + setUpFunc: func(test *TestCase) { + indexContent := ` + +TheVendor +%s +2021-10-17T12:21:59.1747971+00:00 + +` + indexContent = fmt.Sprintf(indexContent, updateIndexServer.URL()) + _ = os.WriteFile(installer.Installation.PublicIndex, []byte(indexContent), 0o600) + updateIndexServer.AddRoute(installer.PublicIndexName, nil) + }, + }, } func TestUpdateIndexCmd(t *testing.T) { diff --git a/cmd/installer/root.go b/cmd/installer/root.go index 76118dfb..f52f56a7 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -1892,42 +1892,10 @@ func (p *PacksInstallationType) updateUpdateCfg(conf *updateCfg) error { } func (p *PacksInstallationType) writeUpdateCfg(conf *updateCfg) error { - flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY - f, err := os.OpenFile(filepath.Join(p.WebDir, "update.cfg"), flags, os.FileMode(0o644)) - if err != nil { - return err - } - defer f.Close() - - if _, err := f.WriteString("Date=" + conf.Date + "\n"); err != nil { - return err - } - if _, err := f.WriteString("Auto="); err != nil { - return err - } - if conf.Auto { - if _, err := f.WriteString("true\n"); err != nil { - return err - } - } else { - if _, err := f.WriteString("false\n"); err != nil { - return err - } - } - if _, err := f.WriteString("UpdateDaily="); err != nil { - return err - } - if conf.UpdateDaily { - if _, err := f.WriteString("true\n"); err != nil { - return err - } - } else { - if _, err := f.WriteString("false\n"); err != nil { - return err - } - } - - return f.Sync() + content := "Date=" + conf.Date + "\n" + + "Auto=" + strconv.FormatBool(conf.Auto) + "\n" + + "UpdateDaily=" + strconv.FormatBool(conf.UpdateDaily) + "\n" + return os.WriteFile(filepath.Join(p.WebDir, "update.cfg"), []byte(content), os.FileMode(0o644)) } // RecordPublicIndexUpdate records a successful explicit public index update. diff --git a/cmd/installer/update_cfg_internal_test.go b/cmd/installer/update_cfg_internal_test.go new file mode 100644 index 00000000..b9e4410e --- /dev/null +++ b/cmd/installer/update_cfg_internal_test.go @@ -0,0 +1,156 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright Contributors to the cpackget project. */ + +package installer + +import ( + "errors" + "os" + "path/filepath" + "strconv" + "testing" + "time" + + errs "github.com/open-cmsis-pack/cpackget/cmd/errors" +) + +func TestWriteUpdateCfg(t *testing.T) { + webDir := t.TempDir() + installation := PacksInstallationType{WebDir: webDir} + + tests := []struct { + name string + conf updateCfg + expected string + }{ + { + name: "enabled", + conf: updateCfg{Date: "1-1-2000", Auto: true, UpdateDaily: true}, + expected: "Date=1-1-2000\nAuto=true\nUpdateDaily=true\n", + }, + { + name: "disabled", + conf: updateCfg{Date: "2-2-2000", Auto: false, UpdateDaily: false}, + expected: "Date=2-2-2000\nAuto=false\nUpdateDaily=false\n", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if err := installation.writeUpdateCfg(&test.conf); err != nil { + t.Fatal(err) + } + content, err := os.ReadFile(filepath.Join(webDir, "update.cfg")) + if err != nil { + t.Fatal(err) + } + if string(content) != test.expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } + }) + } + + t.Run("write error", func(t *testing.T) { + installation := PacksInstallationType{WebDir: filepath.Join(t.TempDir(), "missing")} + if err := installation.writeUpdateCfg(&updateCfg{}); err == nil { + t.Fatal("expected an error for a missing web directory") + } + }) +} + +func TestRecordPublicIndexUpdate(t *testing.T) { + originalInstallation := Installation + t.Cleanup(func() { Installation = originalInstallation }) + + t.Run("preserves settings and records current date", func(t *testing.T) { + webDir := t.TempDir() + Installation = &PacksInstallationType{WebDir: webDir} + path := filepath.Join(webDir, "update.cfg") + if err := os.WriteFile(path, []byte("Date=1-1-2000\nAuto=false\nUpdateDaily=false\n"), 0o600); err != nil { + t.Fatal(err) + } + + if err := RecordPublicIndexUpdate(); err != nil { + t.Fatal(err) + } + content, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + expected := "Date=" + time.Now().Local().Format("2-1-2006") + "\nAuto=false\nUpdateDaily=false\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } + }) + + t.Run("returns write error", func(t *testing.T) { + Installation = &PacksInstallationType{WebDir: filepath.Join(t.TempDir(), "missing")} + if err := RecordPublicIndexUpdate(); err == nil { + t.Fatal("expected an error for a missing web directory") + } + }) +} + +func TestSetUpdateDaily(t *testing.T) { + t.Run("empty pack root", func(t *testing.T) { + if err := SetUpdateDaily("", true); !errors.Is(err, errs.ErrPackRootNotFound) { + t.Fatalf("expected ErrPackRootNotFound, got %v", err) + } + }) + + t.Run("missing pack root", func(t *testing.T) { + if err := SetUpdateDaily(filepath.Join(t.TempDir(), "missing"), true); !errors.Is(err, errs.ErrPackRootDoesNotExist) { + t.Fatalf("expected ErrPackRootDoesNotExist, got %v", err) + } + }) + + t.Run("missing web directory", func(t *testing.T) { + if err := SetUpdateDaily(t.TempDir(), true); !errors.Is(err, errs.ErrPackRootDoesNotExist) { + t.Fatalf("expected ErrPackRootDoesNotExist, got %v", err) + } + }) + + for _, updateDaily := range []bool{false, true} { + name := "disabled" + if updateDaily { + name = "enabled" + } + t.Run(name, func(t *testing.T) { + packRoot := t.TempDir() + webDir := filepath.Join(packRoot, ".Web") + if err := os.Mkdir(webDir, 0o755); err != nil { + t.Fatal(err) + } + path := filepath.Join(webDir, "update.cfg") + if err := os.WriteFile(path, []byte("Date=1-1-2000\nAuto=false\nUpdateDaily=true\n"), 0o600); err != nil { + t.Fatal(err) + } + + if err := SetUpdateDaily(packRoot, updateDaily); err != nil { + t.Fatal(err) + } + content, err := os.ReadFile(path) + if err != nil { + t.Fatal(err) + } + expected := "Date=1-1-2000\nAuto=false\nUpdateDaily=" + strconv.FormatBool(updateDaily) + "\n" + if string(content) != expected { + t.Fatalf("unexpected update.cfg content: %q", content) + } + }) + } + + t.Run("returns write error", func(t *testing.T) { + packRoot := t.TempDir() + webDir := filepath.Join(packRoot, ".Web") + if err := os.Mkdir(webDir, 0o755); err != nil { + t.Fatal(err) + } + if err := os.Mkdir(filepath.Join(webDir, "update.cfg"), 0o755); err != nil { + t.Fatal(err) + } + if err := SetUpdateDaily(packRoot, true); err == nil { + t.Fatal("expected an error when update.cfg is a directory") + } + }) +} From 9c8d39ff9930859264db62c33a27610609c659a4 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 11:45:45 +0200 Subject: [PATCH 4/6] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- cmd/installer/root.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmd/installer/root.go b/cmd/installer/root.go index f52f56a7..2b49e847 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -1895,7 +1895,15 @@ func (p *PacksInstallationType) writeUpdateCfg(conf *updateCfg) error { content := "Date=" + conf.Date + "\n" + "Auto=" + strconv.FormatBool(conf.Auto) + "\n" + "UpdateDaily=" + strconv.FormatBool(conf.UpdateDaily) + "\n" - return os.WriteFile(filepath.Join(p.WebDir, "update.cfg"), []byte(content), os.FileMode(0o644)) +f, err := os.OpenFile(filepath.Join(p.WebDir, "update.cfg"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) +if err != nil { + return err +} +defer f.Close() +if _, err := f.WriteString(content); err != nil { + return err +} +return f.Sync() } // RecordPublicIndexUpdate records a successful explicit public index update. From dcab4f43a1fdbcddda717b1a66cefea8e6245172 Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 11:48:39 +0200 Subject: [PATCH 5/6] Potential fix for pull request finding 'CodeQL / Writable file handle closed without error handling' Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- cmd/installer/root.go | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/cmd/installer/root.go b/cmd/installer/root.go index 2b49e847..47038b2f 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -1891,19 +1891,23 @@ func (p *PacksInstallationType) updateUpdateCfg(conf *updateCfg) error { return p.writeUpdateCfg(conf) } -func (p *PacksInstallationType) writeUpdateCfg(conf *updateCfg) error { +func (p *PacksInstallationType) writeUpdateCfg(conf *updateCfg) (retErr error) { content := "Date=" + conf.Date + "\n" + "Auto=" + strconv.FormatBool(conf.Auto) + "\n" + "UpdateDaily=" + strconv.FormatBool(conf.UpdateDaily) + "\n" -f, err := os.OpenFile(filepath.Join(p.WebDir, "update.cfg"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) -if err != nil { - return err -} -defer f.Close() -if _, err := f.WriteString(content); err != nil { - return err -} -return f.Sync() + f, err := os.OpenFile(filepath.Join(p.WebDir, "update.cfg"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o644) + if err != nil { + return err + } + defer func() { + if cerr := f.Close(); retErr == nil && cerr != nil { + retErr = cerr + } + }() + if _, err := f.WriteString(content); err != nil { + return err + } + return f.Sync() } // RecordPublicIndexUpdate records a successful explicit public index update. From 256a16cbeac8b7e08137dfa5db05ac949a9ae2ff Mon Sep 17 00:00:00 2001 From: Evgueni Driouk Date: Tue, 15 Sep 2026 14:48:29 +0200 Subject: [PATCH 6/6] Remove --daily command line flag --- cmd/commands/update_index.go | 11 ---- cmd/commands/update_index_internal_test.go | 29 --------- cmd/commands/update_index_test.go | 56 ------------------ cmd/installer/root.go | 21 ------- cmd/installer/update_cfg_internal_test.go | 68 ---------------------- 5 files changed, 185 deletions(-) diff --git a/cmd/commands/update_index.go b/cmd/commands/update_index.go index 5472c796..4847fc59 100644 --- a/cmd/commands/update_index.go +++ b/cmd/commands/update_index.go @@ -28,9 +28,6 @@ var updateIndexCmdFlags struct { // insecureSkipVerify skips TLS certificate verification for HTTPS downloads insecureSkipVerify bool - - // daily controls automatic daily public index updates - daily bool } var UpdateIndexCmd = &cobra.Command{ @@ -39,13 +36,6 @@ var UpdateIndexCmd = &cobra.Command{ Long: getLongUpdateDescription(), Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, args []string) error { - if cmd.Flags().Changed("daily") { - if err := configureInstallerGlobalCmd(cmd, args); err != nil { - return err - } - return installer.SetUpdateDaily(viper.GetString("pack-root"), updateIndexCmdFlags.daily) - } - utils.SetEncodedProgress(updateIndexCmdFlags.encodedProgress) utils.SetSkipTouch(updateIndexCmdFlags.skipTouch) @@ -78,5 +68,4 @@ func init() { UpdateIndexCmd.Flags().BoolVarP(&updateIndexCmdFlags.encodedProgress, "encoded-progress", "E", false, "reports encoded progress for files and download when used by other tools") UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.skipTouch, "skip-touch", false, "do not touch pack.idx") UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.insecureSkipVerify, "insecure-skip-verify", false, "skip verification of server's TLS certificate when downloading packs over HTTPS") - UpdateIndexCmd.Flags().BoolVar(&updateIndexCmdFlags.daily, "daily", true, "enable automatic daily public index updates") } diff --git a/cmd/commands/update_index_internal_test.go b/cmd/commands/update_index_internal_test.go index 156db0e0..de512c9d 100644 --- a/cmd/commands/update_index_internal_test.go +++ b/cmd/commands/update_index_internal_test.go @@ -12,46 +12,17 @@ import ( viperType "github.com/spf13/viper" ) -func TestUpdateIndexDailyRejectsConflictingVerbosity(t *testing.T) { - originalViper := viper - originalDaily := updateIndexCmdFlags.daily - dailyFlag := UpdateIndexCmd.Flags().Lookup("daily") - originalDailyValue := dailyFlag.Value.String() - originalDailyChanged := dailyFlag.Changed - t.Cleanup(func() { - viper = originalViper - updateIndexCmdFlags.daily = originalDaily - _ = dailyFlag.Value.Set(originalDailyValue) - dailyFlag.Changed = originalDailyChanged - }) - - viper = viperType.New() - viper.Set("quiet", true) - viper.Set("verbose", true) - updateIndexCmdFlags.daily = false - dailyFlag.Changed = true - - err := UpdateIndexCmd.RunE(UpdateIndexCmd, nil) - if err == nil || err.Error() != "both \"-q\" and \"-v\" were specified, please pick only one verboseness option" { - t.Fatalf("expected conflicting verbosity error, got %v", err) - } -} - func TestUpdateIndexRejectsMissingPackRoot(t *testing.T) { originalViper := viper originalCreatePackRoot := createPackRoot - dailyFlag := UpdateIndexCmd.Flags().Lookup("daily") - originalDailyChanged := dailyFlag.Changed t.Cleanup(func() { viper = originalViper createPackRoot = originalCreatePackRoot - dailyFlag.Changed = originalDailyChanged }) viper = viperType.New() viper.Set("pack-root", filepath.Join(t.TempDir(), "missing")) createPackRoot = false - dailyFlag.Changed = false err := UpdateIndexCmd.RunE(UpdateIndexCmd, nil) if !errors.Is(err, errs.ErrPackRootDoesNotExist) { diff --git a/cmd/commands/update_index_test.go b/cmd/commands/update_index_test.go index 84eaf4e3..6088194b 100644 --- a/cmd/commands/update_index_test.go +++ b/cmd/commands/update_index_test.go @@ -95,62 +95,6 @@ var updateIndexCmdTests = []TestCase{ } }, }, - { - name: "test disabling daily updates only changes update config", - args: []string{"update-index", "--insecure-skip-verify", "--daily=false"}, - createPackRoot: true, - setUpFunc: func(t *TestCase) { - _ = os.WriteFile(installer.Installation.PublicIndex, []byte("existing index"), 0600) - updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=true\nUpdateDaily=true\n"), 0600) - }, - validationFunc: func(t *testing.T) { - indexContent, err := os.ReadFile(installer.Installation.PublicIndex) - if err != nil { - t.Fatal(err) - } - if string(indexContent) != "existing index" { - t.Fatalf("daily flag modified public index: %q", indexContent) - } - updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - content, err := os.ReadFile(updateCfgPath) - if err != nil { - t.Fatal(err) - } - expected := "Date=1-1-2000\nAuto=true\nUpdateDaily=false\n" - if string(content) != expected { - t.Fatalf("unexpected update.cfg content: %q", content) - } - }, - }, - { - name: "test enabling daily updates only changes update config", - args: []string{"update-index", "--daily=true"}, - createPackRoot: true, - setUpFunc: func(t *TestCase) { - _ = os.WriteFile(installer.Installation.PublicIndex, []byte("existing index"), 0600) - updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - _ = os.WriteFile(updateCfgPath, []byte("Date=1-1-2000\nAuto=false\nUpdateDaily=false\n"), 0600) - }, - validationFunc: func(t *testing.T) { - indexContent, err := os.ReadFile(installer.Installation.PublicIndex) - if err != nil { - t.Fatal(err) - } - if string(indexContent) != "existing index" { - t.Fatalf("daily flag modified public index: %q", indexContent) - } - updateCfgPath := filepath.Join(installer.Installation.WebDir, "update.cfg") - content, err := os.ReadFile(updateCfgPath) - if err != nil { - t.Fatal(err) - } - expected := "Date=1-1-2000\nAuto=false\nUpdateDaily=true\n" - if string(content) != expected { - t.Fatalf("unexpected update.cfg content: %q", content) - } - }, - }, { name: "test malformed index returns read error", args: []string{"update-index"}, diff --git a/cmd/installer/root.go b/cmd/installer/root.go index 47038b2f..ca6bf5d2 100644 --- a/cmd/installer/root.go +++ b/cmd/installer/root.go @@ -1917,27 +1917,6 @@ func RecordPublicIndexUpdate() error { return Installation.updateUpdateCfg(&updateConf) } -// SetUpdateDaily changes the automatic daily update setting without modifying other pack-root files. -func SetUpdateDaily(packRoot string, updateDaily bool) error { - if len(packRoot) == 0 { - return errs.ErrPackRootNotFound - } - packRoot = filepath.Clean(packRoot) - if !utils.DirExists(packRoot) { - return errs.ErrPackRootDoesNotExist - } - webDir := filepath.Join(packRoot, ".Web") - if !utils.DirExists(webDir) { - return errs.ErrPackRootDoesNotExist - } - - installation := PacksInstallationType{WebDir: webDir} - var updateConf updateCfg - _ = installation.checkUpdateCfg(&updateConf, false) - updateConf.UpdateDaily = updateDaily - return installation.writeUpdateCfg(&updateConf) -} - // touchPackIdx updates the timestamp of the PackIdx file to the current time. // If the skip touch flag is set, the function returns immediately without making any changes. // The function temporarily removes the read-only attribute from the PackIdx file, diff --git a/cmd/installer/update_cfg_internal_test.go b/cmd/installer/update_cfg_internal_test.go index b9e4410e..4317d741 100644 --- a/cmd/installer/update_cfg_internal_test.go +++ b/cmd/installer/update_cfg_internal_test.go @@ -4,14 +4,10 @@ package installer import ( - "errors" "os" "path/filepath" - "strconv" "testing" "time" - - errs "github.com/open-cmsis-pack/cpackget/cmd/errors" ) func TestWriteUpdateCfg(t *testing.T) { @@ -90,67 +86,3 @@ func TestRecordPublicIndexUpdate(t *testing.T) { } }) } - -func TestSetUpdateDaily(t *testing.T) { - t.Run("empty pack root", func(t *testing.T) { - if err := SetUpdateDaily("", true); !errors.Is(err, errs.ErrPackRootNotFound) { - t.Fatalf("expected ErrPackRootNotFound, got %v", err) - } - }) - - t.Run("missing pack root", func(t *testing.T) { - if err := SetUpdateDaily(filepath.Join(t.TempDir(), "missing"), true); !errors.Is(err, errs.ErrPackRootDoesNotExist) { - t.Fatalf("expected ErrPackRootDoesNotExist, got %v", err) - } - }) - - t.Run("missing web directory", func(t *testing.T) { - if err := SetUpdateDaily(t.TempDir(), true); !errors.Is(err, errs.ErrPackRootDoesNotExist) { - t.Fatalf("expected ErrPackRootDoesNotExist, got %v", err) - } - }) - - for _, updateDaily := range []bool{false, true} { - name := "disabled" - if updateDaily { - name = "enabled" - } - t.Run(name, func(t *testing.T) { - packRoot := t.TempDir() - webDir := filepath.Join(packRoot, ".Web") - if err := os.Mkdir(webDir, 0o755); err != nil { - t.Fatal(err) - } - path := filepath.Join(webDir, "update.cfg") - if err := os.WriteFile(path, []byte("Date=1-1-2000\nAuto=false\nUpdateDaily=true\n"), 0o600); err != nil { - t.Fatal(err) - } - - if err := SetUpdateDaily(packRoot, updateDaily); err != nil { - t.Fatal(err) - } - content, err := os.ReadFile(path) - if err != nil { - t.Fatal(err) - } - expected := "Date=1-1-2000\nAuto=false\nUpdateDaily=" + strconv.FormatBool(updateDaily) + "\n" - if string(content) != expected { - t.Fatalf("unexpected update.cfg content: %q", content) - } - }) - } - - t.Run("returns write error", func(t *testing.T) { - packRoot := t.TempDir() - webDir := filepath.Join(packRoot, ".Web") - if err := os.Mkdir(webDir, 0o755); err != nil { - t.Fatal(err) - } - if err := os.Mkdir(filepath.Join(webDir, "update.cfg"), 0o755); err != nil { - t.Fatal(err) - } - if err := SetUpdateDaily(packRoot, true); err == nil { - t.Fatal("expected an error when update.cfg is a directory") - } - }) -}