writeFileWithStatus() which shows 'Creating' for new, 'Updating' for changed and 'Unchanged' for files that won't change

This commit is contained in:
Pim van Pelt
2025-08-25 11:51:41 +02:00
parent c9c1e81619
commit 38fe915b37
5 changed files with 65 additions and 71 deletions

View File

@@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
@@ -25,11 +24,10 @@ func generateEnv(yamlFile string) {
// Create combined roots.pem file // Create combined roots.pem file
rootsPemPath := filepath.Join(logEntry.LocalDirectory, "roots.pem") rootsPemPath := filepath.Join(logEntry.LocalDirectory, "roots.pem")
err := createCombinedRootsPem(config.Roots, logEntry.ExtraRoots, rootsPemPath) err := createCombinedRootsPemWithStatus(config.Roots, logEntry.ExtraRoots, rootsPemPath)
if err != nil { if err != nil {
log.Fatalf("Failed to create %s: %v", rootsPemPath, err) log.Fatalf("Failed to create %s: %v", rootsPemPath, err)
} }
fmt.Printf("Generated %s\n", rootsPemPath)
// Build TESSERACT_ARGS string // Build TESSERACT_ARGS string
args := []string{ args := []string{
@@ -47,50 +45,32 @@ func generateEnv(yamlFile string) {
tesseractArgs := strings.Join(args, " ") tesseractArgs := strings.Join(args, " ")
envContent := fmt.Sprintf("TESSERACT_ARGS=\"%s\"\nOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n", tesseractArgs) envContent := fmt.Sprintf("TESSERACT_ARGS=\"%s\"\nOTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318\n", tesseractArgs)
err = os.WriteFile(envPath, []byte(envContent), 0644) err = writeFileWithStatus(envPath, []byte(envContent))
if err != nil { if err != nil {
log.Fatalf("Failed to write %s: %v", envPath, err) log.Fatalf("Failed to write %s: %v", envPath, err)
} }
fmt.Printf("Generated %s\n", envPath)
} }
} }
func createCombinedRootsPem(rootsFile, extraRootsFile, outputPath string) error { func createCombinedRootsPemWithStatus(rootsFile, extraRootsFile, outputPath string) error {
// Create output file // Read main roots file
outputFile, err := os.Create(outputPath) var combinedContent []byte
if err != nil {
return fmt.Errorf("failed to create output file: %v", err)
}
defer outputFile.Close()
// Copy main roots file
if rootsFile != "" { if rootsFile != "" {
rootsData, err := os.Open(rootsFile) rootsData, err := os.ReadFile(rootsFile)
if err != nil { if err != nil {
return fmt.Errorf("failed to open roots file %s: %v", rootsFile, err) return fmt.Errorf("failed to read roots file %s: %v", rootsFile, err)
}
defer rootsData.Close()
_, err = io.Copy(outputFile, rootsData)
if err != nil {
return fmt.Errorf("failed to copy roots file: %v", err)
} }
combinedContent = append(combinedContent, rootsData...)
} }
// Append extra roots file if it exists // Append extra roots file if it exists
if extraRootsFile != "" { if extraRootsFile != "" {
extraRootsData, err := os.Open(extraRootsFile) extraRootsData, err := os.ReadFile(extraRootsFile)
if err != nil { if err != nil {
return fmt.Errorf("failed to open extra roots file %s: %v", extraRootsFile, err) return fmt.Errorf("failed to read extra roots file %s: %v", extraRootsFile, err)
}
defer extraRootsData.Close()
_, err = io.Copy(outputFile, extraRootsData)
if err != nil {
return fmt.Errorf("failed to copy extra roots file: %v", err)
} }
combinedContent = append(combinedContent, extraRootsData...)
} }
return nil return writeFileWithStatus(outputPath, combinedContent)
} }

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"crypto/sha256" "crypto/sha256"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
@@ -136,27 +137,25 @@ func generateHTML(yamlFile string) {
for _, logEntry := range config.Logs { for _, logEntry := range config.Logs {
indexPath := fmt.Sprintf("%s/index.html", logEntry.LocalDirectory) indexPath := fmt.Sprintf("%s/index.html", logEntry.LocalDirectory)
file, err := os.Create(indexPath) // Execute template to buffer
var buf bytes.Buffer
err := tmpl.Execute(&buf, config)
if err != nil { if err != nil {
log.Fatalf("Failed to create %s: %v", indexPath, err) log.Fatalf("Failed to execute HTML template for %s: %v", indexPath, err)
} }
err = tmpl.Execute(file, config) // Write file with status
err = writeFileWithStatus(indexPath, buf.Bytes())
if err != nil { if err != nil {
file.Close()
log.Fatalf("Failed to write HTML to %s: %v", indexPath, err) log.Fatalf("Failed to write HTML to %s: %v", indexPath, err)
} }
file.Close()
fmt.Printf("Generated %s\n", indexPath)
// Generate log.v3.json for this log // Generate log.v3.json for this log
jsonPath := filepath.Join(logEntry.LocalDirectory, "log.v3.json") jsonPath := filepath.Join(logEntry.LocalDirectory, "log.v3.json")
err = generateLogJSON(logEntry, jsonPath) err = generateLogJSONWithStatus(logEntry, jsonPath)
if err != nil { if err != nil {
log.Fatalf("Failed to generate %s: %v", jsonPath, err) log.Fatalf("Failed to generate %s: %v", jsonPath, err)
} }
fmt.Printf("Generated %s\n", jsonPath)
} }
} }
@@ -210,7 +209,7 @@ func computeKeyInfo(logEntry *Log) error {
return nil return nil
} }
func generateLogJSON(logEntry Log, outputPath string) error { func generateLogJSONWithStatus(logEntry Log, outputPath string) error {
logJSON := LogV3JSON{ logJSON := LogV3JSON{
Description: fmt.Sprintf("%s.log.ct.ipng.ch", logEntry.ShortName), Description: fmt.Sprintf("%s.log.ct.ipng.ch", logEntry.ShortName),
SubmissionURL: fmt.Sprintf("%s/", logEntry.SubmissionPrefix), SubmissionURL: fmt.Sprintf("%s/", logEntry.SubmissionPrefix),
@@ -229,10 +228,5 @@ func generateLogJSON(logEntry Log, outputPath string) error {
return fmt.Errorf("failed to marshal JSON: %v", err) return fmt.Errorf("failed to marshal JSON: %v", err)
} }
err = os.WriteFile(outputPath, jsonData, 0644) return writeFileWithStatus(outputPath, jsonData)
if err != nil {
return fmt.Errorf("failed to write JSON file: %v", err)
}
return nil
} }

View File

@@ -97,6 +97,26 @@ func loadConfig(yamlFile string) Config {
return config return config
} }
func writeFileWithStatus(filename string, content []byte) error {
existingContent, err := os.ReadFile(filename)
if os.IsNotExist(err) {
fmt.Printf("Creating %s\n", filename)
} else if err != nil {
return fmt.Errorf("failed to read existing file %s: %v", filename, err)
} else if string(existingContent) == string(content) {
fmt.Printf("Unchanged %s\n", filename)
return nil
} else {
fmt.Printf("Updating %s\n", filename)
}
err = os.WriteFile(filename, content, 0644)
if err != nil {
return fmt.Errorf("failed to write file %s: %v", filename, err)
}
return nil
}
func showHelp() { func showHelp() {
fmt.Printf("Usage: %s [options] <command>\n\n", os.Args[0]) fmt.Printf("Usage: %s [options] <command>\n\n", os.Args[0])
fmt.Printf("Options:\n") fmt.Printf("Options:\n")

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"net/url" "net/url"
"os" "os"
@@ -113,22 +114,20 @@ func generateNginx(yamlFile string) {
outputFilename := fmt.Sprintf("%s.conf", hostname) outputFilename := fmt.Sprintf("%s.conf", hostname)
outputPath := filepath.Join(log.LocalDirectory, outputFilename) outputPath := filepath.Join(log.LocalDirectory, outputFilename)
// Create output file // Execute template to buffer
file, err := os.Create(outputPath) var buf bytes.Buffer
if err != nil { err = tmpl.Execute(&buf, data)
fmt.Fprintf(os.Stderr, "Failed to create nginx config file %s: %v\n", outputPath, err)
continue
}
defer file.Close()
// Execute template
err = tmpl.Execute(file, data)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Failed to execute nginx template for %s: %v\n", outputPath, err) fmt.Fprintf(os.Stderr, "Failed to execute nginx template for %s: %v\n", outputPath, err)
continue continue
} }
fmt.Printf("Generated nginx config: %s\n", outputPath) // Write file with status
err = writeFileWithStatus(outputPath, buf.Bytes())
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to write nginx config file %s: %v\n", outputPath, err)
continue
}
} }
} }

View File

@@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
@@ -8,7 +9,6 @@ import (
"fmt" "fmt"
"log" "log"
"net/http" "net/http"
"os"
"strings" "strings"
) )
@@ -67,15 +67,10 @@ func generateRoots(args []string) {
log.Fatalf("Failed to parse JSON response: %v", err) log.Fatalf("Failed to parse JSON response: %v", err)
} }
// Create output file // Collect all valid certificates in a buffer
outFile, err := os.Create(outputFile) var pemBuffer bytes.Buffer
if err != nil {
log.Fatalf("Failed to create output file %s: %v", outputFile, err)
}
defer outFile.Close()
// Write each certificate as PEM
validCertCount := 0 validCertCount := 0
for _, certBase64 := range rootsResp.Certificates { for _, certBase64 := range rootsResp.Certificates {
// Decode base64 certificate // Decode base64 certificate
certBytes, err := base64.StdEncoding.DecodeString(certBase64) certBytes, err := base64.StdEncoding.DecodeString(certBase64)
@@ -102,14 +97,20 @@ func generateRoots(args []string) {
Bytes: certBytes, Bytes: certBytes,
} }
// Write PEM to file // Write PEM to buffer
err = pem.Encode(outFile, pemBlock) err = pem.Encode(&pemBuffer, pemBlock)
if err != nil { if err != nil {
log.Fatalf("Failed to write PEM certificate: %v", err) log.Fatalf("Failed to encode PEM certificate: %v", err)
} }
validCertCount++ validCertCount++
} }
// Write all certificates to file with status
err = writeFileWithStatus(outputFile, pemBuffer.Bytes())
if err != nil {
log.Fatalf("Failed to write output file %s: %v", outputFile, err)
}
fmt.Printf("Successfully wrote %d certificates to %s (out of %d total)\n", validCertCount, outputFile, len(rootsResp.Certificates)) fmt.Printf("Successfully wrote %d certificates to %s (out of %d total)\n", validCertCount, outputFile, len(rootsResp.Certificates))
} }