diff --git a/api/published_file_missing_test.go b/api/published_file_missing_test.go index 6d7b77f8..e25beee5 100644 --- a/api/published_file_missing_test.go +++ b/api/published_file_missing_test.go @@ -220,7 +220,8 @@ func (s *PublishedFileMissingSuite) TestPublishedFileGoMissing(c *C) { c.Assert(resp.Code, Equals, 200, Commentf("Failed to update publish: %s", resp.Body.String())) // Now check if the file is actually accessible in the published location - publishedStorage := s.context.GetPublishedStorage("") + publishedStorage, err := s.context.GetPublishedStorage("") + c.Assert(err, IsNil) publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath() // Expected file path: hrt/pool/main/h/hrt-libblobbyclient1/hrt-libblobbyclient1_20250926.152427+hrtdeb11_amd64.deb @@ -332,7 +333,8 @@ func (s *PublishedFileMissingSuite) TestConcurrentPublishRace(c *C) { c.Assert(err, IsNil) // Check published files - publishedStorage := s.context.GetPublishedStorage("") + publishedStorage, err := s.context.GetPublishedStorage("") + c.Assert(err, IsNil) publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath() missingFiles := []string{} @@ -446,7 +448,8 @@ func (s *PublishedFileMissingSuite) TestIdenticalPackageRace(c *C) { c.Logf("[iter %d] All operations complete", iter) // Check the shared pool location - publishedStorage := s.context.GetPublishedStorage("") + publishedStorage, err := s.context.GetPublishedStorage("") + c.Assert(err, IsNil) publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath() poolSubdir := string(packageName[0]) @@ -663,7 +666,8 @@ func (s *PublishedFileMissingSuite) TestConcurrentSnapshotPublishToSamePrefix(c c.Assert(bullseyePublishCode, Equals, expectedCode, Commentf("Bullseye publish/update should succeed")) // Verify ALL package files exist in the published pool - publishedStorage := s.context.GetPublishedStorage("") + publishedStorage, err := s.context.GetPublishedStorage("") + c.Assert(err, IsNil) publicPath := publishedStorage.(aptly.FileSystemPublishedStorage).PublicPath() missingFiles := []string{} diff --git a/api/repos.go b/api/repos.go index ea0748f9..336e4c9c 100644 --- a/api/repos.go +++ b/api/repos.go @@ -60,7 +60,12 @@ func reposServeInAPIMode(c *gin.Context) { storage = "filesystem:" + storage } - publicPath := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage).PublicPath() + ps, err := context.GetPublishedStorage(storage) + if err != nil { + AbortWithJSONError(c, http.StatusNotFound, err) + return + } + publicPath := ps.(aptly.FileSystemPublishedStorage).PublicPath() c.FileFromFS(pkgpath, http.Dir(publicPath)) } diff --git a/aptly/interfaces.go b/aptly/interfaces.go index 412daecd..1412c719 100644 --- a/aptly/interfaces.go +++ b/aptly/interfaces.go @@ -95,8 +95,8 @@ type FileSystemPublishedStorage interface { // PublishedStorageProvider is a thing that returns PublishedStorage by name type PublishedStorageProvider interface { - // GetPublishedStorage returns PublishedStorage by name - GetPublishedStorage(name string) PublishedStorage + // GetPublishedStorage returns PublishedStorage by name, or an error if the storage is not configured + GetPublishedStorage(name string) (PublishedStorage, error) } // BarType used to differentiate between different progress bars diff --git a/cmd/publish_snapshot.go b/cmd/publish_snapshot.go index 0f251d28..63f33a91 100644 --- a/cmd/publish_snapshot.go +++ b/cmd/publish_snapshot.go @@ -190,9 +190,11 @@ func aptlyPublishSnapshotOrRepo(cmd *commander.Command, args []string) error { context.Progress().Printf("\n%s been successfully published.\n", message) - if localStorage, ok := context.GetPublishedStorage(storage).(aptly.FileSystemPublishedStorage); ok { - context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n", - localStorage.PublicPath()) + if ps, err := context.GetPublishedStorage(storage); err == nil { + if localStorage, ok := ps.(aptly.FileSystemPublishedStorage); ok { + context.Progress().Printf("Please setup your webserver to serve directory '%s' with autoindexing.\n", + localStorage.PublicPath()) + } } context.Progress().Printf("Now you can add following line to apt sources:\n") diff --git a/cmd/serve.go b/cmd/serve.go index be974b00..16951c51 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -97,7 +97,11 @@ func aptlyServe(cmd *commander.Command, args []string) error { } } - publicPath := context.GetPublishedStorage("").(aptly.FileSystemPublishedStorage).PublicPath() + ps, err := context.GetPublishedStorage("") + if err != nil { + return err + } + publicPath := ps.(aptly.FileSystemPublishedStorage).PublicPath() ShutdownContext() fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen) diff --git a/context/context.go b/context/context.go index 503cad29..febe7f89 100644 --- a/context/context.go +++ b/context/context.go @@ -116,7 +116,12 @@ func (context *AptlyContext) config() *utils.ConfigStructure { if err != nil { fmt.Fprintf(os.Stderr, "Config file not found, creating default config at %s\n\n", homeLocation) - _ = utils.SaveConfigRaw(homeLocation, aptly.AptlyConf) + defaultConfig := aptly.AptlyConf + if len(defaultConfig) == 0 { + defaultConfig = []byte("root_dir: \"\"") + } + + _ = utils.SaveConfigRaw(homeLocation, defaultConfig) err = utils.LoadConfig(homeLocation, &utils.Config) if err != nil { Fatal(fmt.Errorf("error loading config file %s: %s", homeLocation, err)) @@ -407,8 +412,8 @@ func (context *AptlyContext) PackagePool() aptly.PackagePool { return context.packagePool } -// GetPublishedStorage returns instance of PublishedStorage -func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedStorage { +// GetPublishedStorage returns instance of PublishedStorage, or an error if the storage is not configured +func (context *AptlyContext) GetPublishedStorage(name string) (aptly.PublishedStorage, error) { context.Lock() defer context.Unlock() @@ -419,14 +424,14 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto } else if strings.HasPrefix(name, "filesystem:") { params, ok := context.config().FileSystemPublishRoots[name[11:]] if !ok { - Fatal(fmt.Errorf("published local storage %v not configured", name[11:])) + return nil, fmt.Errorf("published local storage %v not configured", name[11:]) } publishedStorage = files.NewPublishedStorage(params.RootDir, params.LinkMethod, params.VerifyMethod) } else if strings.HasPrefix(name, "s3:") { params, ok := context.config().S3PublishRoots[name[3:]] if !ok { - Fatal(fmt.Errorf("published S3 storage %v not configured", name[3:])) + return nil, fmt.Errorf("published S3 storage %v not configured", name[3:]) } var err error @@ -436,39 +441,39 @@ func (context *AptlyContext) GetPublishedStorage(name string) aptly.PublishedSto params.EncryptionMethod, params.PlusWorkaround, params.DisableMultiDel, params.ForceSigV2, params.ForceVirtualHostedStyle, params.Debug) if err != nil { - Fatal(err) + return nil, err } } else if strings.HasPrefix(name, "swift:") { params, ok := context.config().SwiftPublishRoots[name[6:]] if !ok { - Fatal(fmt.Errorf("published Swift storage %v not configured", name[6:])) + return nil, fmt.Errorf("published Swift storage %v not configured", name[6:]) } var err error publishedStorage, err = swift.NewPublishedStorage(params.UserName, params.Password, params.AuthURL, params.Tenant, params.TenantID, params.Domain, params.DomainID, params.TenantDomain, params.TenantDomainID, params.Container, params.Prefix) if err != nil { - Fatal(err) + return nil, err } } else if strings.HasPrefix(name, "azure:") { params, ok := context.config().AzurePublishRoots[name[6:]] if !ok { - Fatal(fmt.Errorf("published Azure storage %v not configured", name[6:])) + return nil, fmt.Errorf("published Azure storage %v not configured", name[6:]) } var err error publishedStorage, err = azure.NewPublishedStorage( params.AccountName, params.AccountKey, params.Container, params.Prefix, params.Endpoint) if err != nil { - Fatal(err) + return nil, err } } else { - Fatal(fmt.Errorf("unknown published storage format: %v", name)) + return nil, fmt.Errorf("unknown published storage format: %v", name) } context.publishedStorages[name] = publishedStorage } - return publishedStorage + return publishedStorage, nil } // UploadPath builds path to upload storage diff --git a/context/context_test.go b/context/context_test.go index 16ecbb2b..db8eae67 100644 --- a/context/context_test.go +++ b/context/context_test.go @@ -1,8 +1,6 @@ package context import ( - "fmt" - "os" "reflect" "testing" @@ -80,10 +78,9 @@ func (s *AptlyContextSuite) SetUpTest(c *C) { func (s *AptlyContextSuite) TestGetPublishedStorageBadFS(c *C) { // https://github.com/aptly-dev/aptly/issues/711 - // This will fail on account of us not having a config, so the - // storage never exists. - c.Assert(func() { s.context.GetPublishedStorage("filesystem:fuji") }, - FatalErrorPanicMatches, - &FatalError{ReturnCode: 1, Message: fmt.Sprintf("error loading config file %s/.aptly.conf: invalid yaml (EOF) or json (EOF)", - os.Getenv("HOME"))}) + // https://github.com/aptly-dev/aptly/issues/1477 + // GetPublishedStorage must return an error (not panic) when the + // requested storage is not configured. + _, err := s.context.GetPublishedStorage("filesystem:fuji") + c.Assert(err, NotNil) } diff --git a/deb/publish.go b/deb/publish.go index ac02508a..9e4c5ac3 100644 --- a/deb/publish.go +++ b/deb/publish.go @@ -824,9 +824,12 @@ func (p *PublishedRepo) GetSkelFiles(skelDir string, component string) (map[stri // Publish publishes snapshot (repository) contents, links package files, generates Packages & Release files, signs them func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageProvider aptly.PublishedStorageProvider, collectionFactory *CollectionFactory, signer pgp.Signer, progress aptly.Progress, forceOverwrite bool, skelDir string) error { - publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage) + publishedStorage, err := publishedStorageProvider.GetPublishedStorage(p.Storage) + if err != nil { + return err + } - err := publishedStorage.MkDir(filepath.Join(p.Prefix, "pool")) + err = publishedStorage.MkDir(filepath.Join(p.Prefix, "pool")) if err != nil { return err } @@ -1200,7 +1203,10 @@ func (p *PublishedRepo) Publish(packagePool aptly.PackagePool, publishedStorageP // It can remove prefix fully, and part of pool (for specific component) func (p *PublishedRepo) RemoveFiles(publishedStorageProvider aptly.PublishedStorageProvider, removePrefix bool, removePoolComponents []string, progress aptly.Progress) error { - publishedStorage := publishedStorageProvider.GetPublishedStorage(p.Storage) + publishedStorage, err := publishedStorageProvider.GetPublishedStorage(p.Storage) + if err != nil { + return err + } // I. Easy: remove whole prefix (meta+packages) if removePrefix { @@ -1213,7 +1219,7 @@ func (p *PublishedRepo) RemoveFiles(publishedStorageProvider aptly.PublishedStor } // II. Medium: remove metadata, it can't be shared as prefix/distribution as unique - err := publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution), progress) + err = publishedStorage.RemoveDirs(filepath.Join(p.Prefix, "dists", p.Distribution), progress) if err != nil { return err } @@ -1573,7 +1579,10 @@ func (collection *PublishedRepoCollection) CleanupAfterMultiDistToggle(published } // true→false: directly remove the per-distribution pool directories. - publishedStorage := publishedStorageProvider.GetPublishedStorage(published.Storage) + publishedStorage, err := publishedStorageProvider.GetPublishedStorage(published.Storage) + if err != nil { + return err + } for _, component := range cleanComponents { poolDir := filepath.Join(published.Prefix, "pool", published.Distribution, component) if err := publishedStorage.RemoveDirs(poolDir, progress); err != nil { @@ -1599,7 +1608,10 @@ func (collection *PublishedRepoCollection) CleanupPrefixComponentFiles(published distribution := published.Distribution rootPath := filepath.Join(prefix, "dists", distribution) - publishedStorage := publishedStorageProvider.GetPublishedStorage(published.Storage) + publishedStorage, err := publishedStorageProvider.GetPublishedStorage(published.Storage) + if err != nil { + return err + } sort.Strings(cleanComponents) publishedComponents := published.Components() diff --git a/deb/publish_test.go b/deb/publish_test.go index 5d4cb752..7ad63e4d 100644 --- a/deb/publish_test.go +++ b/deb/publish_test.go @@ -61,12 +61,12 @@ type FakeStorageProvider struct { storages map[string]aptly.PublishedStorage } -func (p *FakeStorageProvider) GetPublishedStorage(name string) aptly.PublishedStorage { +func (p *FakeStorageProvider) GetPublishedStorage(name string) (aptly.PublishedStorage, error) { storage, ok := p.storages[name] if !ok { - panic(fmt.Sprintf("unknown storage: %#v", name)) + return nil, fmt.Errorf("unknown storage: %#v", name) } - return storage + return storage, nil } type PublishedRepoSuite struct {