Skip to content

Commit 6c47e38

Browse files
Add project cache
This adds cache for project packages. It can be enabled with "project_cache: 1" in newtrc.yml. Once enabled, packages list for each repo will be stored in .cache directory and read from there on subsequent executions. This allows to substantially strip time required to find packages in each repo. Cache will be used as long as current repo hash matches the cache.
1 parent 4f847e5 commit 6c47e38

File tree

5 files changed

+190
-31
lines changed

5 files changed

+190
-31
lines changed

newt/cache/cache.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package cache
21+
22+
import (
23+
"encoding/gob"
24+
"fmt"
25+
"mynewt.apache.org/newt/newt/interfaces"
26+
"mynewt.apache.org/newt/newt/repo"
27+
"mynewt.apache.org/newt/util"
28+
"os"
29+
"path/filepath"
30+
)
31+
32+
type ProjectCache struct {
33+
baseDir string
34+
}
35+
36+
func InitCache(projDir string) *ProjectCache {
37+
pc := ProjectCache{}
38+
pc.baseDir = filepath.Join(projDir, ".cache")
39+
40+
if _, err := os.Stat(pc.baseDir); os.IsNotExist(err) {
41+
if err := os.Mkdir(pc.baseDir, 0754); err != nil {
42+
return nil
43+
}
44+
}
45+
46+
return &pc
47+
}
48+
49+
func (pc *ProjectCache) getPackagesFile(repo *repo.Repo) string {
50+
return fmt.Sprintf(filepath.Join(pc.baseDir, repo.Name()))
51+
}
52+
53+
func (pc *ProjectCache) AddPackages(repo *repo.Repo, pkgMap map[string]interfaces.PackageInterface) {
54+
cacheName := pc.getPackagesFile(repo)
55+
var dirList []string
56+
57+
hash, err := repo.CurrentHash()
58+
if err != nil {
59+
return
60+
}
61+
62+
for _, v := range pkgMap {
63+
dirList = append(dirList, v.BasePath())
64+
}
65+
66+
f, err := os.Create(cacheName)
67+
if err != nil {
68+
util.OneTimeWarning("Failed to create cache file for \"%s\"", repo.Name())
69+
return
70+
}
71+
72+
defer f.Close()
73+
74+
enc := gob.NewEncoder(f)
75+
enc.Encode(hash)
76+
enc.Encode(dirList)
77+
}
78+
79+
func (pc *ProjectCache) GetPackagesDirs(repo *repo.Repo) []string {
80+
cacheName := pc.getPackagesFile(repo)
81+
var dirList []string
82+
83+
f, err := os.Open(cacheName)
84+
if err != nil {
85+
if !os.IsNotExist(err) {
86+
util.OneTimeWarning("Failed to open cache file for \"%s\"", repo.Name())
87+
}
88+
return nil
89+
}
90+
91+
defer f.Close()
92+
93+
var hash string
94+
95+
enc := gob.NewDecoder(f)
96+
err = enc.Decode(&hash)
97+
if err != nil {
98+
util.OneTimeWarning("Failed to read cache for \"%s\"", repo.Name())
99+
return nil
100+
}
101+
102+
currHash, _ := repo.CurrentHash()
103+
if hash != currHash {
104+
return nil
105+
}
106+
107+
err = enc.Decode(&dirList)
108+
if err != nil {
109+
util.OneTimeWarning("Failed to read cache for \"%s\"", repo.Name())
110+
return nil
111+
}
112+
113+
return dirList
114+
}

newt/pkg/localpackage.go

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -449,8 +449,34 @@ func LocalPackageSpecialName(dirName string) bool {
449449
return ok
450450
}
451451

452+
func ReadPackage(repo *repo.Repo, pkgMap map[string]interfaces.PackageInterface,
453+
pkgPath string) ([]string, error) {
454+
455+
var warnings []string
456+
457+
pkg, err := LoadLocalPackage(repo, pkgPath)
458+
if err != nil {
459+
warnings = append(warnings, err.Error())
460+
return warnings, nil
461+
}
462+
463+
if oldPkg, ok := pkgMap[pkg.Name()]; ok {
464+
oldlPkg := oldPkg.(*LocalPackage)
465+
warnings = append(warnings,
466+
fmt.Sprintf("Multiple packages with same pkg.name=%s "+
467+
"in repo %s; path1=%s path2=%s", oldlPkg.Name(), repo.Name(),
468+
oldlPkg.BasePath(), pkg.BasePath()))
469+
470+
return warnings, nil
471+
}
472+
473+
pkgMap[pkg.Name()] = pkg
474+
475+
return warnings, nil
476+
}
477+
452478
func ReadLocalPackageRecursive(repo *repo.Repo,
453-
pkgList map[string]interfaces.PackageInterface, basePath string,
479+
pkgMap map[string]interfaces.PackageInterface, basePath string,
454480
pkgName string, searchedMap map[string]struct{}) ([]string, error) {
455481

456482
var warnings []string
@@ -465,7 +491,7 @@ func ReadLocalPackageRecursive(repo *repo.Repo,
465491
continue
466492
}
467493

468-
subWarnings, err := ReadLocalPackageRecursive(repo, pkgList,
494+
subWarnings, err := ReadLocalPackageRecursive(repo, pkgMap,
469495
basePath, filepath.Join(pkgName, name), searchedMap)
470496
warnings = append(warnings, subWarnings...)
471497
if err != nil {
@@ -477,39 +503,21 @@ func ReadLocalPackageRecursive(repo *repo.Repo,
477503
return warnings, nil
478504
}
479505

480-
pkg, err := LoadLocalPackage(repo, filepath.Join(basePath, pkgName))
481-
if err != nil {
482-
warnings = append(warnings, err.Error())
483-
return warnings, nil
484-
}
506+
var subWarnings []string
507+
subWarnings, err = ReadPackage(repo, pkgMap, filepath.Join(basePath, pkgName))
508+
warnings = append(warnings, subWarnings...)
485509

486-
if oldPkg, ok := pkgList[pkg.Name()]; ok {
487-
oldlPkg := oldPkg.(*LocalPackage)
488-
warnings = append(warnings,
489-
fmt.Sprintf("Multiple packages with same pkg.name=%s "+
490-
"in repo %s; path1=%s path2=%s", oldlPkg.Name(), repo.Name(),
491-
oldlPkg.BasePath(), pkg.BasePath()))
492-
493-
return warnings, nil
494-
}
495-
496-
pkgList[pkg.Name()] = pkg
497-
498-
return warnings, nil
510+
return warnings, err
499511
}
500512

501-
func ReadLocalPackages(repo *repo.Repo, basePath string) (
502-
*map[string]interfaces.PackageInterface, []string, error) {
503-
504-
pkgMap := &map[string]interfaces.PackageInterface{}
505-
513+
func ReadLocalPackages(repo *repo.Repo, pkgMap map[string]interfaces.PackageInterface, basePath string) ([]string, error) {
506514
// Keep track of which directories we have traversed. Prevent infinite
507515
// loops caused by symlink cycles by not inspecting the same directory
508516
// twice.
509517
searchedMap := map[string]struct{}{}
510518

511-
warnings, err := ReadLocalPackageRecursive(repo, *pkgMap,
519+
warnings, err := ReadLocalPackageRecursive(repo, pkgMap,
512520
basePath, "", searchedMap)
513521

514-
return pkgMap, warnings, err
522+
return warnings, err
515523
}

newt/project/project.go

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package project
2121

2222
import (
2323
"fmt"
24+
"mynewt.apache.org/newt/newt/cache"
2425
"os"
2526
"path"
2627
"path/filepath"
@@ -57,6 +58,8 @@ type Project struct {
5758
// Base path of the project
5859
BasePath string
5960

61+
cache *cache.ProjectCache
62+
6063
packages interfaces.PackageList
6164

6265
// Contains all the repos that form this project. Each repo is in one of
@@ -634,6 +637,13 @@ func (proj *Project) Init(dir string, download bool) error {
634637
return err
635638
}
636639

640+
if util.EnableProjectCache {
641+
proj.cache = cache.InitCache(proj.BasePath)
642+
if proj.cache == nil {
643+
util.OneTimeWarning("Failed to initialize project cache")
644+
}
645+
}
646+
637647
return nil
638648
}
639649

@@ -741,12 +751,37 @@ func (proj *Project) loadPackageList() error {
741751
// packages / store them in the project package list.
742752
repos := proj.Repos()
743753
for name, repo := range repos {
744-
list, warnings, err := pkg.ReadLocalPackages(repo, repo.Path())
745-
if err == nil {
746-
proj.packages[name] = list
754+
pkgMap := &map[string]interfaces.PackageInterface{}
755+
756+
var dirList []string
757+
758+
if proj.cache != nil {
759+
dirList = proj.cache.GetPackagesDirs(repo)
747760
}
748761

749-
proj.warnings = append(proj.warnings, warnings...)
762+
if proj.cache != nil && dirList != nil {
763+
log.Debug("Using cache for packages in \"%s\"\n", repo.Name())
764+
for _, pkgPath := range dirList {
765+
warnings, err := pkg.ReadPackage(repo, *pkgMap, pkgPath)
766+
if err == nil {
767+
proj.packages[name] = pkgMap
768+
}
769+
770+
proj.warnings = append(proj.warnings, warnings...)
771+
}
772+
} else {
773+
log.Debug("Not using cache for packages in \"%s\"\n", repo.Name())
774+
warnings, err := pkg.ReadLocalPackages(repo, *pkgMap, repo.Path())
775+
if err == nil {
776+
proj.packages[name] = pkgMap
777+
}
778+
779+
if proj.cache != nil {
780+
proj.cache.AddPackages(repo, *pkgMap)
781+
}
782+
783+
proj.warnings = append(proj.warnings, warnings...)
784+
}
750785
}
751786

752787
return nil

newt/settings/settings.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func processNewtrc(yc ycfg.YCfg) {
5959

6060
util.SkipNewtCompat, _ = yc.GetValBoolDflt("skip_newt_compat", nil, false)
6161
util.SkipSyscfgRepoHash, _ = yc.GetValBoolDflt("skip_syscfg_repo_hash", nil, false)
62+
util.EnableProjectCache, _ = yc.GetValBoolDflt("project_cache", nil, false)
6263
}
6364

6465
func readNewtrc() ycfg.YCfg {

util/util.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ var ShallowCloneDepth int
5151
var logFile *os.File
5252
var SkipNewtCompat bool
5353
var SkipSyscfgRepoHash bool
54+
var EnableProjectCache bool
5455

5556
func ParseEqualsPair(v string) (string, string, error) {
5657
s := strings.Split(v, "=")

0 commit comments

Comments
 (0)