-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcommon.go
More file actions
127 lines (119 loc) · 4.02 KB
/
common.go
File metadata and controls
127 lines (119 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package rubyext
import (
"context"
"path/filepath"
)
// runCommonBuild executes the standard 3-step build process.
//
// Many Ruby extension build systems follow a similar pattern:
// 1. Configure: Generate build files (Makefile, build.ninja, etc.)
// 2. Build: Compile the extension using the generated files
// 3. Find: Locate the compiled extension files (.so, .bundle, .dylib)
//
// This function provides a consistent way to execute this pattern,
// allowing builders to focus on implementing their specific logic
// for each step.
//
// # Process Flow
//
// 1. Create empty BuildResult
// 2. Calculate extension directory from extensionFile path
// 3. Call ConfigureFunc to prepare the build
// 4. Call BuildFunc to compile the extension
// 5. Call FindFunc to locate compiled files
// 6. Return BuildResult with Success=true
//
// If any step fails, processing stops and the error is returned
// with Success=false.
//
// # Parameters
//
// - ctx: Context for cancellation
// - config: Build configuration
// - extensionFile: Path to extension file (relative to config.GemDir)
// - steps: The three functions to execute
//
// # Returns
//
// Returns:
// - BuildResult with Success=true and Extensions list on success
// - BuildResult with Success=false and Error on failure
//
// The BuildResult.Output field is populated by the step functions
// as they execute.
//
// # Example
//
// Typical usage in a builder:
//
// func (b *MyBuilder) Build(ctx context.Context, config *BuildConfig, extensionFile string) (*BuildResult, error) {
// return runCommonBuild(ctx, config, extensionFile, CommonBuildSteps{
// ConfigureFunc: func(ctx context.Context, config *BuildConfig, extensionDir string, result *BuildResult) error {
// // Run ./configure or generate Makefile
// cmd := exec.CommandContext(ctx, "./configure")
// cmd.Dir = extensionDir
// output, err := cmd.CombinedOutput()
// result.Output = append(result.Output, string(output))
// return err
// },
// BuildFunc: func(ctx context.Context, config *BuildConfig, extensionDir string, result *BuildResult) error {
// // Run make
// cmd := exec.CommandContext(ctx, "make")
// cmd.Dir = extensionDir
// output, err := cmd.CombinedOutput()
// result.Output = append(result.Output, string(output))
// return err
// },
// FindFunc: func(extensionDir string) ([]string, error) {
// // Find *.so files
// return filepath.Glob(filepath.Join(extensionDir, "*.so"))
// },
// })
// }
//
// # Error Handling
//
// If any step returns an error:
// - result.Error is set to the error
// - result.Success remains false
// - The BuildResult and error are returned
// - Subsequent steps are not executed
//
// # Thread Safety
//
// This function is thread-safe as long as the provided step functions
// are thread-safe and don't share mutable state.
func runCommonBuild(ctx context.Context, config *BuildConfig, extensionFile string, steps CommonBuildSteps) (*BuildResult, error) {
result := &BuildResult{
Success: false,
Output: []string{},
}
// Calculate extension directory
extensionPath := filepath.Join(config.GemDir, extensionFile)
extensionDir := filepath.Dir(extensionPath)
// Step 1: Configure/prepare the build
if err := steps.ConfigureFunc(ctx, config, extensionDir, result); err != nil {
result.Error = err
return result, err
}
// Step 2: Build/compile the extension
if err := steps.BuildFunc(ctx, config, extensionDir, result); err != nil {
result.Error = err
return result, err
}
// Step 3: Find the built extension files
extensions, err := steps.FindFunc(extensionDir)
if err != nil {
result.Error = err
return result, err
}
finalized, err := finalizeNativeExtensions(config, extensionFile, extensionDir, extensions)
if err != nil {
result.Error = err
return result, err
}
// Success!
result.Extensions = finalized
result.Success = true
return result, nil
}