|
1 | 1 | package main |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "encoding/xml" |
5 | 6 | "flag" |
6 | 7 | "fmt" |
| 8 | + "io" |
7 | 9 | "log" |
8 | 10 | "net/http" |
9 | 11 | "os" |
@@ -147,87 +149,81 @@ func main() { |
147 | 149 | } |
148 | 150 |
|
149 | 151 | func debugCmd(ctx *PlanContext) { |
150 | | - fmt.Println("=== Plan Debug Info ===") |
| 152 | + writeDebugInfo(os.Stdout, ctx) |
| 153 | +} |
| 154 | + |
| 155 | +func writeDebugInfo(w io.Writer, ctx *PlanContext) { |
| 156 | + fmt.Fprintln(w, "=== Plan Debug Info ===") |
151 | 157 |
|
152 | 158 | // Build Info |
153 | | - fmt.Println("\n-- Build Information --") |
| 159 | + fmt.Fprintln(w, "\n-- Build Information --") |
154 | 160 | if info, ok := debug.ReadBuildInfo(); ok { |
155 | | - fmt.Printf("Go Version: %s\n", info.GoVersion) |
| 161 | + fmt.Fprintf(w, "Go Version: %s\n", info.GoVersion) |
156 | 162 | for _, setting := range info.Settings { |
157 | 163 | if setting.Key == "vcs.revision" { |
158 | | - fmt.Printf("Git Revision: %s\n", setting.Value) |
| 164 | + fmt.Fprintf(w, "Git Revision: %s\n", setting.Value) |
159 | 165 | } |
160 | 166 | if setting.Key == "vcs.time" { |
161 | | - fmt.Printf("Git Time: %s\n", setting.Value) |
| 167 | + fmt.Fprintf(w, "Git Time: %s\n", setting.Value) |
162 | 168 | } |
163 | 169 | if setting.Key == "vcs.modified" && setting.Value == "true" { |
164 | | - fmt.Println("Git Status: dirty") |
| 170 | + fmt.Fprintln(w, "Git Status: dirty") |
165 | 171 | } |
166 | 172 | } |
167 | 173 | } else { |
168 | | - fmt.Println("Build info not available.") |
| 174 | + fmt.Fprintln(w, "Build info not available.") |
169 | 175 | } |
170 | | - fmt.Printf("OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH) |
| 176 | + fmt.Fprintf(w, "OS/Arch: %s/%s\n", runtime.GOOS, runtime.GOARCH) |
171 | 177 |
|
172 | 178 | // Context Info |
173 | | - fmt.Println("\n-- Context --") |
| 179 | + fmt.Fprintln(w, "\n-- Context --") |
174 | 180 | cwd, _ := os.Getwd() |
175 | | - fmt.Printf("Working Dir: %s\n", cwd) |
176 | | - fmt.Printf("Plan Dir: %s\n", ctx.PlanDir) |
177 | | - fmt.Printf("Plan File: %s\n", ctx.PlanFile) |
178 | | - fmt.Printf("Output Dir: %s\n", ctx.OutputDir) |
179 | | - fmt.Printf("Creation: %s\n", ctx.CreationTime.Format(time.RFC3339)) |
| 181 | + fmt.Fprintf(w, "Working Dir: %s\n", cwd) |
| 182 | + fmt.Fprintf(w, "Plan Dir: %s\n", ctx.PlanDir) |
| 183 | + fmt.Fprintf(w, "Plan File: %s\n", ctx.PlanFile) |
| 184 | + fmt.Fprintf(w, "Output Dir: %s\n", ctx.OutputDir) |
| 185 | + fmt.Fprintf(w, "Creation: %s\n", ctx.CreationTime.Format(time.RFC3339)) |
180 | 186 |
|
181 | 187 | // Configuration |
182 | | - fmt.Println("\n-- Configuration --") |
183 | | - fmt.Printf("Username: %s\n", ctx.Config.Username) |
184 | | - fmt.Printf("FullName: %s\n", ctx.Config.FullName) |
185 | | - fmt.Printf("Title: %s\n", ctx.Config.Title) |
186 | | - fmt.Printf("Timezone: %s\n", ctx.Config.Timezone) |
| 188 | + fmt.Fprintln(w, "\n-- Configuration --") |
| 189 | + fmt.Fprintf(w, "Username: %s\n", ctx.Config.Username) |
| 190 | + fmt.Fprintf(w, "FullName: %s\n", ctx.Config.FullName) |
| 191 | + fmt.Fprintf(w, "Title: %s\n", ctx.Config.Title) |
| 192 | + fmt.Fprintf(w, "Timezone: %s\n", ctx.Config.Timezone) |
187 | 193 |
|
188 | 194 | tmplStatus := "Default (Embedded)" |
189 | 195 | if len(ctx.Template) > 0 { |
190 | | - // Simple check to see if it matches default is hard since default is embedded in another package |
191 | | - // But if initContext loaded it from disk, we know. |
192 | | - // Actually initContext sets ctx.Template to file content if found, else empty string? |
193 | | - // Re-reading initContext: |
194 | | - // tmplContent is set ONLY if os.ReadFile succeeds. |
195 | | - // But render.New defaults if passed empty string. |
196 | | - // So if ctx.Template is NOT empty, it was loaded from file. |
197 | 196 | tmplStatus = "Custom (Loaded from file)" |
198 | | - } else { |
199 | | - // It might still be empty string in ctx, but renderer uses default. |
200 | | - tmplStatus = "Default (Embedded)" |
201 | 197 | } |
202 | | - fmt.Printf("Template: %s\n", tmplStatus) |
| 198 | + fmt.Fprintf(w, "Template: %s\n", tmplStatus) |
203 | 199 |
|
204 | 200 | // Git Status of Plan |
205 | | - fmt.Println("\n-- Plan Git Status --") |
| 201 | + fmt.Fprintln(w, "\n-- Plan Git Status --") |
206 | 202 | if _, err := exec.LookPath("git"); err == nil { |
207 | 203 | cmd := exec.Command("git", "status", "-s", ctx.PlanFile) |
208 | 204 | cmd.Dir = ctx.PlanDir |
209 | 205 | out, err := cmd.CombinedOutput() |
210 | 206 | if err == nil { |
211 | 207 | status := strings.TrimSpace(string(out)) |
212 | 208 | if status == "" { |
213 | | - fmt.Println("Status: Clean") |
| 209 | + fmt.Fprintln(w, "Status: Clean") |
214 | 210 | } else { |
215 | | - fmt.Printf("Status: %s\n", status) |
| 211 | + fmt.Fprintf(w, "Status: %s\n", status) |
216 | 212 | } |
217 | 213 | } else { |
218 | | - fmt.Printf("Status: Error checking git status (%v)\n", err) |
| 214 | + fmt.Fprintf(w, "Status: Error checking git status (%v)\n", err) |
219 | 215 | } |
220 | 216 |
|
221 | 217 | cmdLog := exec.Command("git", "log", "-1", "--format=%h - %s (%an)", ctx.PlanFile) |
222 | 218 | cmdLog.Dir = ctx.PlanDir |
223 | 219 | outLog, errLog := cmdLog.CombinedOutput() |
224 | 220 | if errLog == nil { |
225 | | - fmt.Printf("Last Commit: %s", string(outLog)) |
| 221 | + fmt.Fprintf(w, "Last Commit: %s", string(outLog)) |
226 | 222 | } else { |
227 | | - fmt.Println("Last Commit: (None or not a git repo)") |
| 223 | + fmt.Fprintln(w, "Last Commit: (None or not a git repo)") |
228 | 224 | } |
229 | 225 | } else { |
230 | | - fmt.Println("Git not found in PATH") |
| 226 | + fmt.Fprintln(w, "Git not found in PATH") |
231 | 227 | } |
232 | 228 | } |
233 | 229 |
|
@@ -539,6 +535,17 @@ func build(ctx *PlanContext) { |
539 | 535 | log.Fatalf("Failed to encode RSS: %v", err) |
540 | 536 | } |
541 | 537 |
|
| 538 | + // Generate Debug Page |
| 539 | + var debugBuf bytes.Buffer |
| 540 | + writeDebugInfo(&debugBuf, ctx) |
| 541 | + |
| 542 | + // Reuse renderer to wrap in template |
| 543 | + // We wrap the raw text in a <pre> block for the content |
| 544 | + debugContent := fmt.Sprintf("# Debug Info\n\n```text\n%s\n```", debugBuf.String()) |
| 545 | + if err := renderAndWrite(ctx, []byte(debugContent), time.Now(), filepath.Join(ctx.OutputDir, "debug", "index.html")); err != nil { |
| 546 | + log.Printf("Warning: Failed to generate debug page: %v", err) |
| 547 | + } |
| 548 | + |
542 | 549 | fmt.Println("Build complete.") |
543 | 550 | } |
544 | 551 |
|
|
0 commit comments