Skip to content

Commit 7493226

Browse files
committed
Add some config draft code
1 parent 344c24f commit 7493226

File tree

5 files changed

+915
-1
lines changed

5 files changed

+915
-1
lines changed

pkg/frontend/vcs/config/config.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
6+
"gopkg.in/yaml.v3"
7+
)
8+
9+
// PyroscopeConfig represents the structure of .pyroscope.yaml configuration file
10+
type PyroscopeConfig struct {
11+
SourceCode SourceCodeConfig `yaml:"source_code"`
12+
}
13+
14+
// SourceCodeConfig contains source code mapping configuration
15+
type SourceCodeConfig struct {
16+
Language string `yaml:"language"`
17+
Mappings []MappingConfig `yaml:"mappings"`
18+
}
19+
20+
// MappingConfig represents a single source code path mapping
21+
type MappingConfig struct {
22+
Path string `yaml:"path"`
23+
Type string `yaml:"type"`
24+
Local *LocalMappingConfig `yaml:"local,omitempty"`
25+
GitHub *GitHubMappingConfig `yaml:"github,omitempty"`
26+
}
27+
28+
// LocalMappingConfig contains configuration for local path mappings
29+
type LocalMappingConfig struct {
30+
Path string `yaml:"path"`
31+
}
32+
33+
// GitHubMappingConfig contains configuration for GitHub repository mappings
34+
type GitHubMappingConfig struct {
35+
Owner string `yaml:"owner"`
36+
Repo string `yaml:"repo"`
37+
Ref string `yaml:"ref"`
38+
Path string `yaml:"path"`
39+
}
40+
41+
// ParsePyroscopeConfig parses a .pyroscope.yaml configuration from bytes
42+
func ParsePyroscopeConfig(data []byte) (*PyroscopeConfig, error) {
43+
var config PyroscopeConfig
44+
if err := yaml.Unmarshal(data, &config); err != nil {
45+
return nil, fmt.Errorf("failed to parse pyroscope config: %w", err)
46+
}
47+
48+
// Validate the configuration
49+
if err := config.Validate(); err != nil {
50+
return nil, fmt.Errorf("invalid pyroscope config: %w", err)
51+
}
52+
53+
return &config, nil
54+
}
55+
56+
// Validate checks if the configuration is valid
57+
func (c *PyroscopeConfig) Validate() error {
58+
if c.SourceCode.Language == "" {
59+
return fmt.Errorf("source_code.language is required")
60+
}
61+
62+
for i, mapping := range c.SourceCode.Mappings {
63+
if err := mapping.Validate(); err != nil {
64+
return fmt.Errorf("mapping[%d]: %w", i, err)
65+
}
66+
}
67+
68+
return nil
69+
}
70+
71+
// Validate checks if a mapping configuration is valid
72+
func (m *MappingConfig) Validate() error {
73+
if m.Path == "" {
74+
return fmt.Errorf("path is required")
75+
}
76+
77+
if m.Type == "" {
78+
return fmt.Errorf("type is required")
79+
}
80+
81+
switch m.Type {
82+
case "local":
83+
if m.Local == nil {
84+
return fmt.Errorf("local configuration is required when type is 'local'")
85+
}
86+
if m.Local.Path == "" {
87+
return fmt.Errorf("local.path is required")
88+
}
89+
case "github":
90+
if m.GitHub == nil {
91+
return fmt.Errorf("github configuration is required when type is 'github'")
92+
}
93+
if m.GitHub.Owner == "" {
94+
return fmt.Errorf("github.owner is required")
95+
}
96+
if m.GitHub.Repo == "" {
97+
return fmt.Errorf("github.repo is required")
98+
}
99+
if m.GitHub.Ref == "" {
100+
return fmt.Errorf("github.ref is required")
101+
}
102+
if m.GitHub.Path == "" {
103+
return fmt.Errorf("github.path is required")
104+
}
105+
default:
106+
return fmt.Errorf("unsupported type '%s', must be 'local' or 'github'", m.Type)
107+
}
108+
109+
return nil
110+
}
111+
112+
// FindMapping finds a mapping configuration that matches the given path
113+
// Returns nil if no matching mapping is found
114+
func (c *PyroscopeConfig) FindMapping(path string) *MappingConfig {
115+
// Find the longest matching prefix
116+
var bestMatch *MappingConfig
117+
var bestMatchLen int
118+
119+
for i := range c.SourceCode.Mappings {
120+
mapping := &c.SourceCode.Mappings[i]
121+
if len(mapping.Path) > bestMatchLen && hasPrefix(path, mapping.Path) {
122+
bestMatch = mapping
123+
bestMatchLen = len(mapping.Path)
124+
}
125+
}
126+
127+
return bestMatch
128+
}
129+
130+
// hasPrefix checks if path starts with prefix, considering path separators
131+
func hasPrefix(path, prefix string) bool {
132+
// Empty prefix doesn't match anything
133+
if prefix == "" {
134+
return false
135+
}
136+
137+
if len(path) < len(prefix) {
138+
return false
139+
}
140+
141+
if path[:len(prefix)] != prefix {
142+
return false
143+
}
144+
145+
// Exact match
146+
if len(path) == len(prefix) {
147+
return true
148+
}
149+
150+
// Check that the next character is a path separator
151+
nextChar := path[len(prefix)]
152+
return nextChar == '/' || nextChar == '\\'
153+
}

0 commit comments

Comments
 (0)