Skip to content

Commit 2dd1c3b

Browse files
authored
Merge branch 'main' into feat/atmos-list-upload
2 parents 80aa0b3 + 4e34c0c commit 2dd1c3b

File tree

43 files changed

+2194
-175
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2194
-175
lines changed

pkg/config/atmos.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,4 @@ settings:
1212
enabled: true
1313
endpoint: "https://us.i.posthog.com"
1414
token: "phc_7s7MrHWxPR2if1DHHDrKBRgx7SvlaoSM59fIiQueexS"
15+
logging: false

pkg/config/load.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ func setEnv(v *viper.Viper) {
122122
bindEnv(v, "settings.telemetry.enabled", "ATMOS_TELEMETRY_ENABLED")
123123
bindEnv(v, "settings.telemetry.token", "ATMOS_TELEMETRY_TOKEN")
124124
bindEnv(v, "settings.telemetry.endpoint", "ATMOS_TELEMETRY_ENDPOINT")
125+
bindEnv(v, "settings.telemetry.logging", "ATMOS_TELEMETRY_LOGGING")
125126
}
126127

127128
func bindEnv(v *viper.Viper, key ...string) {

pkg/downloader/file_downloader.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ func (fd *fileDownloader) Fetch(src, dest string, mode ClientMode, timeout time.
4444
// FetchAutoParse downloads a remote file, detects its format, and parses it.
4545
func (fd *fileDownloader) FetchAndAutoParse(src string) (any, error) {
4646
filePath := fd.tempPathGenerator()
47+
defer os.Remove(filePath)
4748

4849
if err := fd.Fetch(src, filePath, ClientModeFile, 30*time.Second); err != nil {
4950
return nil, fmt.Errorf("failed to download file '%s': %w", src, err)
@@ -52,9 +53,41 @@ func (fd *fileDownloader) FetchAndAutoParse(src string) (any, error) {
5253
return filetype.DetectFormatAndParseFile(fd.fileReader, filePath)
5354
}
5455

56+
// FetchAndParseByExtension downloads a remote file and parses it based on its extension.
57+
func (fd *fileDownloader) FetchAndParseByExtension(src string) (any, error) {
58+
filePath := fd.tempPathGenerator()
59+
defer os.Remove(filePath)
60+
61+
if err := fd.Fetch(src, filePath, ClientModeFile, 30*time.Second); err != nil {
62+
return nil, fmt.Errorf("failed to download file '%s': %w", src, err)
63+
}
64+
65+
// Create a custom reader that reads the downloaded file but uses the original URL for extension detection
66+
readFunc := func(filename string) ([]byte, error) {
67+
// Read the actual downloaded file, not the URL
68+
return fd.fileReader(filePath)
69+
}
70+
71+
// Pass the original source URL for extension detection
72+
return filetype.ParseFileByExtension(readFunc, src)
73+
}
74+
75+
// FetchAndParseRaw downloads a remote file and always returns it as a raw string.
76+
func (fd *fileDownloader) FetchAndParseRaw(src string) (any, error) {
77+
filePath := fd.tempPathGenerator()
78+
defer os.Remove(filePath)
79+
80+
if err := fd.Fetch(src, filePath, ClientModeFile, 30*time.Second); err != nil {
81+
return nil, fmt.Errorf("failed to download file '%s': %w", src, err)
82+
}
83+
84+
return filetype.ParseFileRaw(fd.fileReader, filePath)
85+
}
86+
5587
// FetchData fetches content from a given source and returns it as a byte slice.
5688
func (fd *fileDownloader) FetchData(src string) ([]byte, error) {
5789
filePath := fd.tempPathGenerator()
90+
defer os.Remove(filePath)
5891

5992
if err := fd.Fetch(src, filePath, ClientModeFile, 30*time.Second); err != nil {
6093
return nil, fmt.Errorf("failed to download file '%s': %w", src, err)

pkg/downloader/file_downloader_interface.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ type FileDownloader interface {
1616
// FetchAndAutoParse downloads a remote file, detects its format, and parses it
1717
FetchAndAutoParse(src string) (any, error)
1818

19+
// FetchAndParseByExtension downloads a remote file and parses it based on its extension
20+
FetchAndParseByExtension(src string) (any, error)
21+
22+
// FetchAndParseRaw downloads a remote file and always returns it as a raw string
23+
FetchAndParseRaw(src string) (any, error)
24+
1925
// FetchData fetches content from a given source and returns it as a byte slice
2026
FetchData(src string) ([]byte, error)
2127
}

pkg/downloader/mock_file_downloader_interface.go

Lines changed: 30 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package filetype
2+
3+
import (
4+
pathpkg "path"
5+
"path/filepath"
6+
"strings"
7+
)
8+
9+
// ParseFileByExtension parses a file based on its file extension.
10+
// It determines the format from the extension, not the content.
11+
// Supported extensions:
12+
// - .json → JSON parsing.
13+
// - .yaml, .yml → YAML parsing.
14+
// - .hcl, .tf, .tfvars → HCL parsing.
15+
// - All others (including .txt or no extension) → raw string.
16+
func ParseFileByExtension(readFileFunc func(string) ([]byte, error), filename string) (any, error) {
17+
// Extract clean filename from potential URL.
18+
cleanFilename := ExtractFilenameFromPath(filename)
19+
ext := GetFileExtension(cleanFilename)
20+
21+
// Read the file content.
22+
data, err := readFileFunc(filename)
23+
if err != nil {
24+
return nil, err
25+
}
26+
27+
// Parse based on extension.
28+
return ParseByExtension(data, ext, filename)
29+
}
30+
31+
// ParseFileRaw always returns the file content as a raw string,
32+
// regardless of the file extension or content.
33+
func ParseFileRaw(readFileFunc func(string) ([]byte, error), filename string) (any, error) {
34+
data, err := readFileFunc(filename)
35+
if err != nil {
36+
return nil, err
37+
}
38+
return string(data), nil
39+
}
40+
41+
// ParseByExtension parses data based on the provided extension.
42+
func ParseByExtension(data []byte, ext string, filename string) (any, error) {
43+
switch ext {
44+
case ".json":
45+
return parseJSON(data)
46+
case ".yaml", ".yml":
47+
return parseYAML(data)
48+
case ".hcl", ".tf", ".tfvars":
49+
return parseHCL(data, filename)
50+
default:
51+
// Return as raw string for unknown extensions.
52+
return string(data), nil
53+
}
54+
}
55+
56+
// ExtractFilenameFromPath extracts the actual filename from a path or URL.
57+
// It removes query strings and fragments from URLs.
58+
// Examples:
59+
// - "https://example.com/file.json?v=1#section" → "file.json".
60+
// - "/path/to/file.yaml" → "file.yaml".
61+
// - "file.txt" → "file.txt".
62+
func ExtractFilenameFromPath(path string) string {
63+
// Remove fragment (everything after #).
64+
if idx := strings.Index(path, "#"); idx != -1 {
65+
path = path[:idx]
66+
}
67+
68+
// Remove query string (everything after ?).
69+
if idx := strings.Index(path, "?"); idx != -1 {
70+
path = path[:idx]
71+
}
72+
73+
// For URLs, use path package instead of filepath to ensure forward slashes.
74+
// This handles URLs correctly on Windows where filepath.Base expects backslashes.
75+
if strings.Contains(path, "://") {
76+
// Use path package for URLs (always uses forward slashes).
77+
return pathpkg.Base(path)
78+
}
79+
80+
// For local files, use filepath package (handles OS-specific separators).
81+
return filepath.Base(path)
82+
}
83+
84+
// GetFileExtension returns the lowercase file extension including the dot.
85+
// Examples:
86+
// - "file.json" → ".json".
87+
// - "FILE.JSON" → ".json".
88+
// - "file.backup.json" → ".json".
89+
// - "file" → "".
90+
// - ".hidden" → "".
91+
func GetFileExtension(filename string) string {
92+
// Handle special cases.
93+
if filename == "" || filename == "." {
94+
return ""
95+
}
96+
97+
ext := filepath.Ext(filename)
98+
99+
// If the extension is the whole filename (e.g., ".env"), check if it looks like a known extension.
100+
if ext == filename {
101+
// Check if it's actually an extension (has letters after the dot).
102+
if len(ext) > 1 && !strings.Contains(ext[1:], ".") {
103+
// It looks like an extension file (e.g., ".json", ".yaml").
104+
// Check if it's a known extension.
105+
lowerExt := strings.ToLower(ext)
106+
knownExts := []string{".json", ".yaml", ".yml", ".hcl", ".tf", ".tfvars", ".txt", ".md"}
107+
for _, known := range knownExts {
108+
if lowerExt == known {
109+
return lowerExt
110+
}
111+
}
112+
}
113+
// Otherwise it's a hidden file without an extension (e.g., ".env", ".gitignore").
114+
return ""
115+
}
116+
117+
// If filename ends with a dot, there's no extension.
118+
if ext == "." {
119+
return ""
120+
}
121+
122+
return strings.ToLower(ext)
123+
}

0 commit comments

Comments
 (0)