Skip to content

Commit 0b91616

Browse files
committed
fix: Critical fixes
1 parent 1a21e91 commit 0b91616

13 files changed

Lines changed: 409 additions & 218 deletions

File tree

cmd/pace/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
package main
22

33
import (
4-
"fmt"
54
"os"
65

76
"github.com/azuyamat/pace/internal/command"
7+
"github.com/azuyamat/pace/internal/logger"
88
)
99

1010
func main() {
1111
err := command.RootCommand.Run(os.Args[1:])
1212
if err != nil {
13-
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
13+
logger.Error("%s", err.Error())
1414
os.Exit(1)
1515
}
1616
}

config.pace

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,29 @@
1-
task build {
2-
command "go build -o bin/main ./..."
3-
inputs ["**/*.go"]
4-
outputs ["bin/main"]
1+
task test {
2+
command "echo 'Test out pace'"
3+
description "A simple test task"
4+
5+
dependencies ["extra", "extraJeff", "echoTime"]
6+
working_dir "./internal/runner"
7+
parallel true
58
}
9+
10+
task extra {
11+
command "echo 'This is an extra task'"
12+
description "An extra task for demonstration"
13+
working_dir "./internal"
14+
parallel true
15+
}
16+
17+
task extraJeff {
18+
command "echo 'This is another extra task'"
19+
description "Another extra task for demonstration"
20+
working_dir "./internal/runner"
21+
parallel true
22+
}
23+
24+
task echoTime {
25+
command "date"
26+
description "Echo the current date and time"
27+
working_dir "./"
28+
parallel false
29+
}

internal/command/run.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55

66
gear "github.com/azuyamat/gear/command"
77
"github.com/azuyamat/pace/internal/config"
8-
"github.com/azuyamat/pace/internal/logger"
98
"github.com/azuyamat/pace/internal/runner"
109
)
1110

@@ -28,7 +27,6 @@ func runHandler(ctx *gear.Context, args gear.ValidatedArgs) error {
2827

2928
task, exists := config.GetTaskOrDefault(taskName)
3029
if !exists {
31-
logger.Error("Task '%s' not found", taskName)
3230
return fmt.Errorf("task '%s' not found", taskName)
3331
}
3432

internal/config/config.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package config
22

33
import (
4+
"fmt"
45
"os"
56
"path/filepath"
67

@@ -90,13 +91,33 @@ func (cfg *Config) GetHook(name string) (models.Hook, bool) {
9091
}
9192

9293
func processImports(cfg *Config, baseDir string) error {
94+
visited := make(map[string]bool)
95+
return processImportsRecursive(cfg, baseDir, visited)
96+
}
97+
98+
func processImportsRecursive(cfg *Config, baseDir string, visited map[string]bool) error {
9399
for _, importPath := range cfg.Imports {
94100
fullPath := filepath.Join(baseDir, importPath)
101+
absPath, err := filepath.Abs(fullPath)
102+
if err != nil {
103+
return fmt.Errorf("failed to resolve import path %q: %v", fullPath, err)
104+
}
105+
106+
if visited[absPath] {
107+
return fmt.Errorf("circular import detected: %q", absPath)
108+
}
109+
110+
visited[absPath] = true
111+
95112
importedCfg, err := ParseFile(fullPath)
96113
if err != nil {
97114
return err
98115
}
99116

117+
if err := processImportsRecursive(importedCfg, filepath.Dir(fullPath), visited); err != nil {
118+
return err
119+
}
120+
100121
importField(importedCfg.Tasks, cfg.Tasks)
101122
importField(importedCfg.Hooks, cfg.Hooks)
102123
importField(importedCfg.Constants, cfg.Constants)

internal/config/resolver.go

Lines changed: 13 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,52 @@
11
package config
22

33
import (
4-
"fmt"
54
"os"
65
"regexp"
76
"strings"
7+
8+
"github.com/azuyamat/pace/internal/logger"
89
)
910

1011
var varPattern = regexp.MustCompile(`\$\{([^}]+)\}`)
1112

1213
type Resolver struct {
13-
config *Config
14+
config *Config
15+
unresolvedVars map[string]bool
1416
}
1517

1618
func NewResolver(config *Config) *Resolver {
17-
return &Resolver{config: config}
19+
return &Resolver{
20+
config: config,
21+
unresolvedVars: make(map[string]bool),
22+
}
1823
}
1924

20-
// ResolveString resolves variable references in a string
2125
func (r *Resolver) ResolveString(input string) string {
2226
return varPattern.ReplaceAllStringFunc(input, func(match string) string {
23-
// Extract variable name from ${VAR}
2427
varName := match[2 : len(match)-1]
2528

26-
// Check in constants first
2729
if value, exists := r.config.Constants[varName]; exists {
2830
return value
2931
}
3032

31-
// Check in globals
3233
if value, exists := r.config.Globals[varName]; exists {
3334
return value
3435
}
3536

36-
// Check environment variables
3737
if value := os.Getenv(varName); value != "" {
3838
return value
3939
}
4040

41-
// Return original if not found
41+
if !r.unresolvedVars[varName] {
42+
logger.Warning("Unresolved variable: ${%s}", varName)
43+
r.unresolvedVars[varName] = true
44+
}
45+
4246
return match
4347
})
4448
}
4549

46-
// ResolveStringSlice resolves variables in a slice of strings
4750
func (r *Resolver) ResolveStringSlice(slice []string) []string {
4851
result := make([]string, len(slice))
4952
for i, s := range slice {
@@ -111,40 +114,3 @@ func ExpandEnvVars(s string) string {
111114

112115
return result.String()
113116
}
114-
115-
// EvaluateCondition evaluates simple conditional expressions
116-
func EvaluateCondition(condition string) (bool, error) {
117-
condition = strings.TrimSpace(condition)
118-
119-
// Handle OS checks: OS == "windows" or OS == "linux"
120-
if strings.Contains(condition, "OS") {
121-
osPattern := regexp.MustCompile(`OS\s*==\s*"([^"]+)"`)
122-
matches := osPattern.FindStringSubmatch(condition)
123-
if len(matches) > 1 {
124-
targetOS := strings.ToLower(matches[1])
125-
currentOS := strings.ToLower(os.Getenv("GOOS"))
126-
if currentOS == "" {
127-
currentOS = "windows" // Default for this system
128-
}
129-
return currentOS == targetOS, nil
130-
}
131-
}
132-
133-
// Handle environment variable checks: ENV_VAR == "value"
134-
envPattern := regexp.MustCompile(`([A-Z_][A-Z0-9_]*)\s*==\s*"([^"]+)"`)
135-
matches := envPattern.FindStringSubmatch(condition)
136-
if len(matches) > 2 {
137-
envVar := matches[1]
138-
expectedValue := matches[2]
139-
actualValue := os.Getenv(envVar)
140-
return actualValue == expectedValue, nil
141-
}
142-
143-
// Handle boolean environment variables: ENV_VAR
144-
if matched, _ := regexp.MatchString(`^[A-Z_][A-Z0-9_]*$`, condition); matched {
145-
value := os.Getenv(condition)
146-
return value != "" && value != "0" && strings.ToLower(value) != "false", nil
147-
}
148-
149-
return false, fmt.Errorf("unable to evaluate condition: %s", condition)
150-
}

internal/logger/logger.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,24 @@ func (l *Logger) Debug(format string, args ...interface{}) {
107107
fmt.Printf("%s %s %s %s\n", l.timestamp(), badge, icon, coloredMsg)
108108
}
109109

110+
func (l *Logger) TaskOutput(taskName string, format string, args ...interface{}) {
111+
if !l.enabled || l.level > LevelInfo {
112+
return
113+
}
114+
msg := fmt.Sprintf(format, args...)
115+
taskBadge := ColorCyan.Wrap("[" + taskName + "]")
116+
fmt.Printf("%s %s %s\n", l.timestamp(), taskBadge, ColorWhite.Wrap(msg))
117+
}
118+
119+
func (l *Logger) TaskError(taskName string, format string, args ...interface{}) {
120+
if !l.enabled || l.level > LevelInfo {
121+
return
122+
}
123+
msg := fmt.Sprintf(format, args...)
124+
taskBadge := ColorRed.Wrap("[" + taskName + "]")
125+
fmt.Printf("%s %s %s\n", l.timestamp(), taskBadge, ColorRed.Bright().Wrap(msg))
126+
}
127+
110128
func (l *Logger) Print(format string, args ...interface{}) {
111129
msg := fmt.Sprintf(format, args...)
112130
fmt.Println(msg)

0 commit comments

Comments
 (0)