Skip to content

Commit c35838a

Browse files
committed
Go: implement basic overlay extraction
When in overlay mode, extractFile will exit early if the file isn't in the list of files that changed since the base was extracted.
1 parent 1d60cd7 commit c35838a

File tree

3 files changed

+90
-14
lines changed

3 files changed

+90
-14
lines changed

go/extractor/extractor.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ func ExtractWithFlags(buildFlags []string, patterns []string, extractTests bool)
311311

312312
extraction.WaitGroup.Wait()
313313

314+
util.WriteOverlayBaseMetadata()
315+
314316
log.Println("Done extracting packages.")
315317

316318
t := time.Now()
@@ -323,16 +325,17 @@ func ExtractWithFlags(buildFlags []string, patterns []string, extractTests bool)
323325
type Extraction struct {
324326
// A lock for preventing concurrent writes to maps and the stat trap writer, as they are not
325327
// thread-safe
326-
Lock sync.Mutex
327-
LabelKey string
328-
Label trap.Label
329-
StatWriter *trap.Writer
330-
WaitGroup sync.WaitGroup
331-
GoroutineSem *semaphore
332-
FdSem *semaphore
333-
NextFileId int
334-
FileInfo map[string]*FileInfo
335-
SeenGoMods map[string]bool
328+
Lock sync.Mutex
329+
LabelKey string
330+
Label trap.Label
331+
StatWriter *trap.Writer
332+
WaitGroup sync.WaitGroup
333+
GoroutineSem *semaphore
334+
FdSem *semaphore
335+
NextFileId int
336+
FileInfo map[string]*FileInfo
337+
SeenGoMods map[string]bool
338+
OverlayChanges map[string]bool
336339
}
337340

338341
type FileInfo struct {
@@ -379,6 +382,21 @@ func NewExtraction(buildFlags []string, patterns []string) *Extraction {
379382
}
380383
sum := hash.Sum(nil)
381384

385+
overlayChangeList := util.GetOverlayChanges()
386+
var overlayChanges map[string]bool
387+
if overlayChangeList == nil {
388+
overlayChanges = nil
389+
} else {
390+
overlayChanges = make(map[string]bool)
391+
for _, changedFilePath := range overlayChangeList {
392+
absPath, err := filepath.Abs(changedFilePath)
393+
if err != nil {
394+
log.Fatalf("Error resolving absolute path of overlay change %s: %s", changedFilePath, err.Error())
395+
}
396+
overlayChanges[absPath] = true
397+
}
398+
}
399+
382400
i := 0
383401
var path string
384402
// split compilation files into directories to avoid filling a single directory with too many files
@@ -438,10 +456,11 @@ func NewExtraction(buildFlags []string, patterns []string) *Extraction {
438456
FdSem: newSemaphore(100),
439457
// this semaphore is used to limit the number of goroutines spawned, so we
440458
// don't run into memory issues
441-
GoroutineSem: newSemaphore(MaxGoRoutines),
442-
NextFileId: 0,
443-
FileInfo: make(map[string]*FileInfo),
444-
SeenGoMods: make(map[string]bool),
459+
GoroutineSem: newSemaphore(MaxGoRoutines),
460+
NextFileId: 0,
461+
FileInfo: make(map[string]*FileInfo),
462+
SeenGoMods: make(map[string]bool),
463+
OverlayChanges: overlayChanges,
445464
}
446465
}
447466

@@ -720,6 +739,10 @@ func (extraction *Extraction) extractFile(ast *ast.File, pkg *packages.Package)
720739
return nil
721740
}
722741
path := normalizedPath(ast, fset)
742+
if extraction.OverlayChanges != nil && !extraction.OverlayChanges[path] {
743+
// This file did not change since the base was extracted
744+
return nil
745+
}
723746

724747
extraction.FdSem.acquire(3)
725748

go/extractor/util/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/extractor/util/overlays.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package util
2+
3+
import (
4+
"encoding/json"
5+
"log"
6+
"os"
7+
)
8+
9+
// If the relevant environment variable is set, indicating that we are extracting an overlay
10+
// database, GetOverlayChanges returns the list of relative paths of files that have changed (or
11+
// been deleted). Otherwise, it returns `nil`.
12+
func GetOverlayChanges() []string {
13+
if overlayChangesJsonPath, present := os.LookupEnv("CODEQL_EXTRACTOR_GO_OVERLAY_CHANGES"); present {
14+
log.Printf("Reading overlay changes from: %s", overlayChangesJsonPath)
15+
16+
file, err := os.Open(overlayChangesJsonPath)
17+
if err != nil {
18+
log.Fatalf("Failed to open overlay changes JSON file: %s", err)
19+
}
20+
defer file.Close()
21+
22+
var overlayData struct {
23+
Changes []string `json:"changes"`
24+
}
25+
26+
decoder := json.NewDecoder(file)
27+
if err := decoder.Decode(&overlayData); err != nil {
28+
log.Fatalf("Failed to decode overlay changes JSON file: %s", err)
29+
}
30+
31+
return overlayData.Changes
32+
} else {
33+
return nil
34+
}
35+
}
36+
37+
// WriteOverlayBaseMetadata creates an empty metadata file if we are extracting an overlay base;
38+
// otherwise, it does nothing.
39+
func WriteOverlayBaseMetadata() {
40+
if metadataPath, present := os.LookupEnv("CODEQL_EXTRACTOR_GO_OVERLAY_BASE_METADATA_OUT"); present {
41+
log.Printf("Writing overlay base metadata to: %s", metadataPath)
42+
43+
// In principle, we could store some metadata here and read it back when extracting the
44+
// overlay. For now, we don't need to store anything, but the CLI still requires us to write
45+
// something, so just create an empty file.
46+
file, err := os.Create(metadataPath)
47+
if err != nil {
48+
log.Fatalf("Failed to create overlay base metadata file: %s", err)
49+
}
50+
file.Close()
51+
}
52+
}

0 commit comments

Comments
 (0)