Skip to content

Commit

Permalink
Merge pull request #15 from yury-palyanitsa/pacman-parse-with-cache
Browse files Browse the repository at this point in the history
Implement ParseWithCache in PackageManager
  • Loading branch information
viatoriche authored Sep 18, 2024
2 parents f6c606a + 02e37ec commit 353114d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 35 deletions.
5 changes: 5 additions & 0 deletions pkg/collector/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ type CtiRegistry struct {
TotalIndex cti.EntitiesMap
}

func (r *CtiRegistry) Clone() *CtiRegistry {
c := *r
return &c
}

type Collector struct {
Registry *CtiRegistry
baseDir string
Expand Down
69 changes: 53 additions & 16 deletions pkg/pacman/pacman.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package pacman

import (
"archive/zip"
"encoding/json"
"fmt"
"io"
"log/slog"
"os"
"path/filepath"

"github.com/acronis/go-cti/pkg/collector"
"github.com/acronis/go-cti/pkg/cti"
"github.com/acronis/go-cti/pkg/filesys"
_package "github.com/acronis/go-cti/pkg/package"
Expand Down Expand Up @@ -112,36 +114,70 @@ func (pacman *PackageManager) installDependencies(depends []string, replace bool
return installed, replaced, nil
}

func (pacman *PackageManager) Validate() []error {
func (pacman *PackageManager) ParseWithCache() (*parser.Parser, *collector.CtiRegistry, error) {
// TODO: Always build current package?
p, err := parser.ParsePackage(pacman.Package.Index.FilePath)
if err != nil {
return []error{fmt.Errorf("failed to parse package: %w", err)}
return nil, nil, fmt.Errorf("failed to parse package: %w", err)
}
if err := p.DumpCache(); err != nil {
return []error{fmt.Errorf("failed to dump cache: %w", err)}
}
validator := validator.MakeCtiValidator()
if err := validator.AddEntities(p.Registry.Total); err != nil {
return []error{fmt.Errorf("failed to add entities: %w", err)}
return nil, nil, fmt.Errorf("failed to dump cache: %w", err)
}
// Make a shallow clone of the resulting registry to make an enriched registry
r := p.Registry.Clone()
for _, dep := range pacman.Package.IndexLock.Packages {
idx, err := _package.ReadIndexFile(filepath.Join(pacman.DependenciesDir, dep.AppCode, _package.IndexFileName))
cacheFile := filepath.Join(pacman.DependenciesDir, dep.AppCode, parser.MetadataCacheFile)
// TODO: Automatically rebuild cache if missing?
entities, err := pacman.LoadEntitiesFromCache(cacheFile)
if err != nil {
return []error{fmt.Errorf("failed to read index file for %s: %w", dep.AppCode, err)}
return nil, nil, fmt.Errorf("failed to load cache file %s: %w", cacheFile, err)
}
// TODO: Automatically rebuild cache if missing?
if err := validator.AddFromFile(filepath.Join(idx.BaseDir, parser.MetadataCacheFile)); err != nil {
return []error{fmt.Errorf("failed to add entities from %s: %w", parser.MetadataCacheFile, err)}
for _, entity := range entities {
if entity.Values != nil {
r.Instances[entity.Cti] = entity
} else if entity.Schema != nil {
r.Types[entity.Cti] = entity
} else {
return nil, nil, fmt.Errorf("invalid entity: %s", entity.Cti)
}
// TODO: Check for duplicates?
r.TotalIndex[entity.Cti] = entity
r.Total = append(r.Total, entity)
}
}
return p, r, nil
}

func (pacman *PackageManager) LoadEntitiesFromCache(cacheFile string) (cti.Entities, error) {
f, err := os.OpenFile(cacheFile, os.O_RDONLY, 0644)
if err != nil {
return nil, fmt.Errorf("failed to open cache file %s: %w", cacheFile, err)
}
defer f.Close()

d := json.NewDecoder(f)
var entities cti.Entities
if err := d.Decode(&entities); err != nil {
return nil, fmt.Errorf("failed to decode cache file %s: %w", cacheFile, err)
}
return entities, nil
}

func (pacman *PackageManager) Validate() []error {
_, r, err := pacman.ParseWithCache()
if err != nil {
return []error{fmt.Errorf("failed to parse with cache: %w", err)}
}
validator := validator.MakeCtiValidator()
validator.LoadFromRegistry(r)
// TODO: Validation for usage of indirect dependencies
return validator.ValidateAll()
}

func (pacman *PackageManager) Pack() error {
p, err := parser.ParsePackage(pacman.Package.Index.FilePath)
p, r, err := pacman.ParseWithCache()
if err != nil {
return fmt.Errorf("failed to parse package: %w", err)
return fmt.Errorf("failed to parse with cache: %w", err)
}
archive, err := os.Create(filepath.Join(pacman.BaseDir, BundleName))
if err != nil {
Expand All @@ -153,9 +189,10 @@ func (pacman *PackageManager) Pack() error {
defer zipWriter.Close()

for _, entity := range p.Registry.Instances {
typ, ok := p.Registry.Types[cti.GetParentCti(entity.Cti)]
tId := cti.GetParentCti(entity.Cti)
typ, ok := r.Types[tId]
if !ok {
return fmt.Errorf("type %s not found", entity.Cti)
return fmt.Errorf("type %s not found", tId)
}
// TODO: Collect annotations from the entire chain of CTI types
for key, annotation := range typ.Annotations {
Expand Down
4 changes: 1 addition & 3 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,7 @@ func BuildPackageCache(path string) error {

func (p *Parser) Validate() []error {
validator := validator.MakeCtiValidator()
if err := validator.AddEntities(p.Registry.Total); err != nil {
return []error{fmt.Errorf("failed to add entities: %w", err)}
}
validator.LoadFromRegistry(p.Registry)
return validator.ValidateAll()
}

Expand Down
25 changes: 9 additions & 16 deletions pkg/validator/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"strings"

"github.com/xeipuuv/gojsonschema"

"github.com/acronis/go-cti/pkg/collector"
"github.com/acronis/go-cti/pkg/identifier"

"github.com/acronis/go-cti/pkg/cti"
Expand All @@ -28,29 +28,22 @@ func MakeCtiValidator() *CtiValidator {
}
}

func (v *CtiValidator) LoadFromRegistry(entities *collector.CtiRegistry) {
v.index = entities.TotalIndex
v.entities = entities.Total
}

func (v *CtiValidator) AddEntities(entities cti.Entities) error {
for _, entity := range entities {
if _, ok := v.index[entity.Cti]; ok {
return fmt.Errorf("attempting to add duplicate cti %s", entity.Cti)
}
v.index[entity.Cti] = entity
}
v.entities = append(v.entities, entities...)
return nil
}

func (v *CtiValidator) AddFromFile(path string) error {
f, err := os.OpenFile(path, os.O_RDONLY, 0644)
if err != nil {
return err
}
defer f.Close()

d := json.NewDecoder(f)
var entities cti.Entities
if err := d.Decode(&entities); err != nil {
return err
}
return v.AddEntities(entities)
}

func (v *CtiValidator) Reset() {
v.ctiParser = identifier.NewParser()
v.index = make(cti.EntitiesMap)
Expand Down

0 comments on commit 353114d

Please sign in to comment.