mirror of
https://github.com/Valkyrie00/bold-brew.git
synced 2026-03-14 22:35:53 +01:00
refactor(services): introduce DataProvider pattern for data loading
Extract data loading logic into a dedicated DataProvider service that handles all data retrieval operations (formulae, casks, analytics, cache). BrewService now delegates to DataProvider via interface for better testability and separation of concerns. Also centralizes cache file name constants in dataprovider.go for maintainability.
This commit is contained in:
parent
c97c470d2f
commit
1440949df3
3 changed files with 363 additions and 285 deletions
|
|
@ -65,6 +65,9 @@ type BrewServiceInterface interface {
|
|||
// BrewService provides methods to interact with Homebrew, including
|
||||
// retrieving formulae, casks, and handling analytics.
|
||||
type BrewService struct {
|
||||
// Data provider for loading packages
|
||||
dataProvider DataProviderInterface
|
||||
|
||||
// Formula lists
|
||||
all *[]models.Formula
|
||||
installed *[]models.Formula
|
||||
|
|
@ -87,6 +90,7 @@ type BrewService struct {
|
|||
// NewBrewService creates a new instance of BrewService with initialized package lists.
|
||||
var NewBrewService = func() BrewServiceInterface {
|
||||
return &BrewService{
|
||||
dataProvider: NewDataProvider(),
|
||||
all: new([]models.Formula),
|
||||
installed: new([]models.Formula),
|
||||
remote: new([]models.Formula),
|
||||
|
|
@ -135,4 +139,3 @@ func (s *BrewService) UpdateHomebrew() error {
|
|||
cmd := exec.Command("brew", "update")
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,320 +2,65 @@ package services
|
|||
|
||||
import (
|
||||
"bbrew/internal/models"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// SetupData initializes the BrewService by loading installed packages, remote formulae, casks, and analytics data.
|
||||
// Uses the DataProvider for all data retrieval operations.
|
||||
func (s *BrewService) SetupData(forceDownload bool) error {
|
||||
// Load formulae
|
||||
if err := s.loadInstalled(forceDownload); err != nil {
|
||||
// Load installed formulae
|
||||
installed, err := s.dataProvider.LoadInstalledFormulae(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load installed formulae: %w", err)
|
||||
}
|
||||
*s.installed = installed
|
||||
|
||||
if err := s.loadRemote(forceDownload); err != nil {
|
||||
// Load remote formulae
|
||||
remote, err := s.dataProvider.LoadRemoteFormulae(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load remote formulae: %w", err)
|
||||
}
|
||||
*s.remote = remote
|
||||
|
||||
if err := s.loadAnalytics(forceDownload); err != nil {
|
||||
// Load formulae analytics
|
||||
analytics, err := s.dataProvider.LoadFormulaeAnalytics(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load formulae analytics: %w", err)
|
||||
}
|
||||
s.analytics = analytics
|
||||
|
||||
// Load casks
|
||||
if err := s.loadInstalledCasks(forceDownload); err != nil {
|
||||
// Load installed casks
|
||||
installedCasks, err := s.dataProvider.LoadInstalledCasks(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load installed casks: %w", err)
|
||||
}
|
||||
*s.installedCasks = installedCasks
|
||||
|
||||
if err := s.loadRemoteCasks(forceDownload); err != nil {
|
||||
// Load remote casks
|
||||
remoteCasks, err := s.dataProvider.LoadRemoteCasks(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load remote casks: %w", err)
|
||||
}
|
||||
*s.remoteCasks = remoteCasks
|
||||
|
||||
if err := s.loadCaskAnalytics(forceDownload); err != nil {
|
||||
// Load cask analytics
|
||||
caskAnalytics, err := s.dataProvider.LoadCaskAnalytics(forceDownload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load cask analytics: %w", err)
|
||||
}
|
||||
s.caskAnalytics = caskAnalytics
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadInstalled retrieves installed formulae, optionally using cache.
|
||||
func (s *BrewService) loadInstalled(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "installed.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 10); data != nil {
|
||||
*s.installed = make([]models.Formula, 0)
|
||||
if err := json.Unmarshal(data, &s.installed); err == nil {
|
||||
s.markFormulaeAsInstalled()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("brew", "info", "--json=v1", "--installed")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s.installed = make([]models.Formula, 0)
|
||||
if err := json.Unmarshal(output, &s.installed); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.markFormulaeAsInstalled()
|
||||
writeCacheFile(cacheFile, output)
|
||||
return nil
|
||||
}
|
||||
|
||||
// markFormulaeAsInstalled sets LocallyInstalled and LocalPath for all installed formulae.
|
||||
func (s *BrewService) markFormulaeAsInstalled() {
|
||||
prefix := s.GetPrefixPath()
|
||||
for i := range *s.installed {
|
||||
(*s.installed)[i].LocallyInstalled = true
|
||||
(*s.installed)[i].LocalPath = filepath.Join(prefix, "Cellar", (*s.installed)[i].Name)
|
||||
}
|
||||
}
|
||||
|
||||
// loadInstalledCasks retrieves installed casks, optionally using cache.
|
||||
func (s *BrewService) loadInstalledCasks(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "installed-casks.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 10); data != nil {
|
||||
var response struct {
|
||||
Casks []models.Cask `json:"casks"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &response); err == nil {
|
||||
*s.installedCasks = response.Casks
|
||||
s.markCasksAsInstalled()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get list of installed cask names
|
||||
listCmd := exec.Command("brew", "list", "--cask")
|
||||
listOutput, err := listCmd.Output()
|
||||
if err != nil {
|
||||
*s.installedCasks = make([]models.Cask, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
caskNames := strings.Split(strings.TrimSpace(string(listOutput)), "\n")
|
||||
if len(caskNames) == 0 || (len(caskNames) == 1 && caskNames[0] == "") {
|
||||
*s.installedCasks = make([]models.Cask, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get info for each installed cask
|
||||
args := append([]string{"info", "--json=v2", "--cask"}, caskNames...)
|
||||
infoCmd := exec.Command("brew", args...)
|
||||
infoOutput, err := infoCmd.Output()
|
||||
if err != nil {
|
||||
*s.installedCasks = make([]models.Cask, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Casks []models.Cask `json:"casks"`
|
||||
}
|
||||
if err := json.Unmarshal(infoOutput, &response); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s.installedCasks = response.Casks
|
||||
s.markCasksAsInstalled()
|
||||
writeCacheFile(cacheFile, infoOutput)
|
||||
return nil
|
||||
}
|
||||
|
||||
// markCasksAsInstalled sets LocallyInstalled and IsCask for all installed casks.
|
||||
func (s *BrewService) markCasksAsInstalled() {
|
||||
for i := range *s.installedCasks {
|
||||
(*s.installedCasks)[i].LocallyInstalled = true
|
||||
(*s.installedCasks)[i].IsCask = true
|
||||
}
|
||||
}
|
||||
|
||||
// loadRemote retrieves the list of remote Homebrew formulae from the API and caches them locally.
|
||||
func (s *BrewService) loadRemote(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "formula.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 1000); data != nil {
|
||||
*s.remote = make([]models.Formula, 0)
|
||||
if err := json.Unmarshal(data, &s.remote); err == nil && len(*s.remote) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(FormulaeAPIURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s.remote = make([]models.Formula, 0)
|
||||
if err := json.Unmarshal(body, s.remote); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFile, body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadRemoteCasks retrieves the list of remote Homebrew casks from the API and caches them locally.
|
||||
func (s *BrewService) loadRemoteCasks(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "cask.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 1000); data != nil {
|
||||
*s.remoteCasks = make([]models.Cask, 0)
|
||||
if err := json.Unmarshal(data, &s.remoteCasks); err == nil && len(*s.remoteCasks) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(CaskAPIURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s.remoteCasks = make([]models.Cask, 0)
|
||||
if err := json.Unmarshal(body, s.remoteCasks); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFile, body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadAnalytics retrieves the analytics data for Homebrew formulae from the API and caches them locally.
|
||||
func (s *BrewService) loadAnalytics(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "analytics.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 100); data != nil {
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(data, &analytics); err == nil && len(analytics.Items) > 0 {
|
||||
s.analytics = make(map[string]models.AnalyticsItem)
|
||||
for _, f := range analytics.Items {
|
||||
s.analytics[f.Formula] = f
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(AnalyticsAPIURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(body, &analytics); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.analytics = make(map[string]models.AnalyticsItem)
|
||||
for _, f := range analytics.Items {
|
||||
s.analytics[f.Formula] = f
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFile, body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadCaskAnalytics retrieves the analytics data for Homebrew casks from the API and caches them locally.
|
||||
func (s *BrewService) loadCaskAnalytics(forceDownload bool) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const cacheFile = "cask-analytics.json"
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFile, 100); data != nil {
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(data, &analytics); err == nil && len(analytics.Items) > 0 {
|
||||
s.caskAnalytics = make(map[string]models.AnalyticsItem)
|
||||
for _, c := range analytics.Items {
|
||||
if c.Cask != "" {
|
||||
s.caskAnalytics[c.Cask] = c
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(CaskAnalyticsAPIURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(body, &analytics); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.caskAnalytics = make(map[string]models.AnalyticsItem)
|
||||
for _, c := range analytics.Items {
|
||||
if c.Cask != "" {
|
||||
s.caskAnalytics[c.Cask] = c
|
||||
}
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFile, body)
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadTapPackagesCache loads cached tap packages from disk.
|
||||
// Delegates to the DataProvider.
|
||||
func (s *BrewService) LoadTapPackagesCache() map[string]models.Package {
|
||||
result := make(map[string]models.Package)
|
||||
|
||||
const cacheFile = "tap_packages.json"
|
||||
if data := readCacheFile(cacheFile, 10); data != nil {
|
||||
var packages []models.Package
|
||||
if err := json.Unmarshal(data, &packages); err == nil {
|
||||
for _, pkg := range packages {
|
||||
result[pkg.Name] = pkg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
return s.dataProvider.LoadTapPackagesCache()
|
||||
}
|
||||
|
||||
// SaveTapPackagesToCache saves tap packages to disk cache.
|
||||
// Delegates to the DataProvider.
|
||||
func (s *BrewService) SaveTapPackagesToCache(packages []models.Package) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(packages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeCacheFile("tap_packages.json", data)
|
||||
return nil
|
||||
return s.dataProvider.SaveTapPackagesToCache(packages)
|
||||
}
|
||||
|
|
|
|||
330
internal/services/dataprovider.go
Normal file
330
internal/services/dataprovider.go
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
package services
|
||||
|
||||
import (
|
||||
"bbrew/internal/models"
|
||||
"encoding/json"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Cache file names
|
||||
const (
|
||||
cacheFileInstalled = "installed.json"
|
||||
cacheFileInstalledCasks = "installed-casks.json"
|
||||
cacheFileFormulae = "formula.json"
|
||||
cacheFileCasks = "cask.json"
|
||||
cacheFileAnalytics = "analytics.json"
|
||||
cacheFileCaskAnalytics = "cask-analytics.json"
|
||||
cacheFileTapPackages = "tap_packages.json"
|
||||
)
|
||||
|
||||
// DataProviderInterface defines the contract for data loading operations.
|
||||
type DataProviderInterface interface {
|
||||
// Formulae
|
||||
LoadInstalledFormulae(forceDownload bool) ([]models.Formula, error)
|
||||
LoadRemoteFormulae(forceDownload bool) ([]models.Formula, error)
|
||||
LoadFormulaeAnalytics(forceDownload bool) (map[string]models.AnalyticsItem, error)
|
||||
|
||||
// Casks
|
||||
LoadInstalledCasks(forceDownload bool) ([]models.Cask, error)
|
||||
LoadRemoteCasks(forceDownload bool) ([]models.Cask, error)
|
||||
LoadCaskAnalytics(forceDownload bool) (map[string]models.AnalyticsItem, error)
|
||||
|
||||
// Tap packages cache
|
||||
LoadTapPackagesCache() map[string]models.Package
|
||||
SaveTapPackagesToCache(packages []models.Package) error
|
||||
}
|
||||
|
||||
// DataProvider implements DataProviderInterface.
|
||||
type DataProvider struct {
|
||||
prefixPath string
|
||||
}
|
||||
|
||||
// NewDataProvider creates a new DataProvider instance.
|
||||
func NewDataProvider() *DataProvider {
|
||||
return &DataProvider{}
|
||||
}
|
||||
|
||||
// getPrefixPath returns the Homebrew prefix path, caching it.
|
||||
func (d *DataProvider) getPrefixPath() string {
|
||||
if d.prefixPath != "" {
|
||||
return d.prefixPath
|
||||
}
|
||||
cmd := exec.Command("brew", "--prefix")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
d.prefixPath = "Unknown"
|
||||
return d.prefixPath
|
||||
}
|
||||
d.prefixPath = strings.TrimSpace(string(output))
|
||||
return d.prefixPath
|
||||
}
|
||||
|
||||
// LoadInstalledFormulae retrieves installed formulae, optionally using cache.
|
||||
func (d *DataProvider) LoadInstalledFormulae(forceDownload bool) ([]models.Formula, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileInstalled, 10); data != nil {
|
||||
var formulae []models.Formula
|
||||
if err := json.Unmarshal(data, &formulae); err == nil {
|
||||
d.markFormulaeAsInstalled(&formulae)
|
||||
return formulae, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command("brew", "info", "--json=v1", "--installed")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var formulae []models.Formula
|
||||
if err := json.Unmarshal(output, &formulae); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.markFormulaeAsInstalled(&formulae)
|
||||
writeCacheFile(cacheFileInstalled, output)
|
||||
return formulae, nil
|
||||
}
|
||||
|
||||
// markFormulaeAsInstalled sets LocallyInstalled and LocalPath for formulae.
|
||||
func (d *DataProvider) markFormulaeAsInstalled(formulae *[]models.Formula) {
|
||||
prefix := d.getPrefixPath()
|
||||
for i := range *formulae {
|
||||
(*formulae)[i].LocallyInstalled = true
|
||||
(*formulae)[i].LocalPath = filepath.Join(prefix, "Cellar", (*formulae)[i].Name)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadInstalledCasks retrieves installed casks, optionally using cache.
|
||||
func (d *DataProvider) LoadInstalledCasks(forceDownload bool) ([]models.Cask, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileInstalledCasks, 10); data != nil {
|
||||
var response struct {
|
||||
Casks []models.Cask `json:"casks"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &response); err == nil {
|
||||
d.markCasksAsInstalled(&response.Casks)
|
||||
return response.Casks, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get list of installed cask names
|
||||
listCmd := exec.Command("brew", "list", "--cask")
|
||||
listOutput, err := listCmd.Output()
|
||||
if err != nil {
|
||||
return []models.Cask{}, nil // No casks installed
|
||||
}
|
||||
|
||||
caskNames := strings.Split(strings.TrimSpace(string(listOutput)), "\n")
|
||||
if len(caskNames) == 0 || (len(caskNames) == 1 && caskNames[0] == "") {
|
||||
return []models.Cask{}, nil
|
||||
}
|
||||
|
||||
// Get info for each installed cask
|
||||
args := append([]string{"info", "--json=v2", "--cask"}, caskNames...)
|
||||
infoCmd := exec.Command("brew", args...)
|
||||
infoOutput, err := infoCmd.Output()
|
||||
if err != nil {
|
||||
return []models.Cask{}, nil
|
||||
}
|
||||
|
||||
var response struct {
|
||||
Casks []models.Cask `json:"casks"`
|
||||
}
|
||||
if err := json.Unmarshal(infoOutput, &response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.markCasksAsInstalled(&response.Casks)
|
||||
writeCacheFile(cacheFileInstalledCasks, infoOutput)
|
||||
return response.Casks, nil
|
||||
}
|
||||
|
||||
// markCasksAsInstalled sets LocallyInstalled and IsCask for casks.
|
||||
func (d *DataProvider) markCasksAsInstalled(casks *[]models.Cask) {
|
||||
for i := range *casks {
|
||||
(*casks)[i].LocallyInstalled = true
|
||||
(*casks)[i].IsCask = true
|
||||
}
|
||||
}
|
||||
|
||||
// LoadRemoteFormulae retrieves remote formulae from API, optionally using cache.
|
||||
func (d *DataProvider) LoadRemoteFormulae(forceDownload bool) ([]models.Formula, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileFormulae, 1000); data != nil {
|
||||
var formulae []models.Formula
|
||||
if err := json.Unmarshal(data, &formulae); err == nil && len(formulae) > 0 {
|
||||
return formulae, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(FormulaeAPIURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var formulae []models.Formula
|
||||
if err := json.Unmarshal(body, &formulae); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFileFormulae, body)
|
||||
return formulae, nil
|
||||
}
|
||||
|
||||
// LoadRemoteCasks retrieves remote casks from API, optionally using cache.
|
||||
func (d *DataProvider) LoadRemoteCasks(forceDownload bool) ([]models.Cask, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileCasks, 1000); data != nil {
|
||||
var casks []models.Cask
|
||||
if err := json.Unmarshal(data, &casks); err == nil && len(casks) > 0 {
|
||||
return casks, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(CaskAPIURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var casks []models.Cask
|
||||
if err := json.Unmarshal(body, &casks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFileCasks, body)
|
||||
return casks, nil
|
||||
}
|
||||
|
||||
// LoadFormulaeAnalytics retrieves formulae analytics from API, optionally using cache.
|
||||
func (d *DataProvider) LoadFormulaeAnalytics(forceDownload bool) (map[string]models.AnalyticsItem, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileAnalytics, 100); data != nil {
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(data, &analytics); err == nil && len(analytics.Items) > 0 {
|
||||
result := make(map[string]models.AnalyticsItem)
|
||||
for _, f := range analytics.Items {
|
||||
result[f.Formula] = f
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(AnalyticsAPIURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(body, &analytics); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]models.AnalyticsItem)
|
||||
for _, f := range analytics.Items {
|
||||
result[f.Formula] = f
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFileAnalytics, body)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LoadCaskAnalytics retrieves cask analytics from API, optionally using cache.
|
||||
func (d *DataProvider) LoadCaskAnalytics(forceDownload bool) (map[string]models.AnalyticsItem, error) {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !forceDownload {
|
||||
if data := readCacheFile(cacheFileCaskAnalytics, 100); data != nil {
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(data, &analytics); err == nil && len(analytics.Items) > 0 {
|
||||
result := make(map[string]models.AnalyticsItem)
|
||||
for _, c := range analytics.Items {
|
||||
if c.Cask != "" {
|
||||
result[c.Cask] = c
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := fetchFromAPI(CaskAnalyticsAPIURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
analytics := models.Analytics{}
|
||||
if err := json.Unmarshal(body, &analytics); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]models.AnalyticsItem)
|
||||
for _, c := range analytics.Items {
|
||||
if c.Cask != "" {
|
||||
result[c.Cask] = c
|
||||
}
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFileCaskAnalytics, body)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// LoadTapPackagesCache loads cached tap packages from disk.
|
||||
func (d *DataProvider) LoadTapPackagesCache() map[string]models.Package {
|
||||
result := make(map[string]models.Package)
|
||||
|
||||
if data := readCacheFile(cacheFileTapPackages, 10); data != nil {
|
||||
var packages []models.Package
|
||||
if err := json.Unmarshal(data, &packages); err == nil {
|
||||
for _, pkg := range packages {
|
||||
result[pkg.Name] = pkg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// SaveTapPackagesToCache saves tap packages to disk cache.
|
||||
func (d *DataProvider) SaveTapPackagesToCache(packages []models.Package) error {
|
||||
if err := ensureCacheDir(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
data, err := json.Marshal(packages)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
writeCacheFile(cacheFileTapPackages, data)
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue