Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
"eamodio.gitlens",
"streetsidesoftware.code-spell-checker",
"esbenp.prettier-vscode"
]
}
],
"settings": {
"terminal.integrated.cwd": "/workspaces/backup"
}
},
"workspaceFolder": "/workspaces/backup"
}
}
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Makefile to build the project and place the binary in the dist/ directory

# Build command with common flags
BUILD_CMD = CGO_ENABLED=0 go build -ldflags="-s -w"
BUILD_CMD = CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -tags=prod
PACKAGE = ./backup/main.go

.PHONY: build clean test lint tidy checksums release sanity-check check-mod-tidy lint-config-check lint-fix format check-clean
Expand Down Expand Up @@ -67,3 +67,16 @@ release: release-linux-amd64 release-darwin-amd64 release-windows-amd64 checksum
printf "%-40s %-15s %-64s\n" "$$file" "Size: $$size bytes" "Checksum: $$checksum"; \
fi; \
done

report-size: build
go install github.com/Zxilly/go-size-analyzer/cmd/gsa@latest
gsa --web --listen=":8910" --open dist/backup

report-coverage:
@mkdir -p coverage
@go test ./... -count=1 -coverprofile=coverage/coverage.out -coverpkg=./backup/...
@echo
@echo "Coverage Summary:"
@go tool cover -func=coverage/coverage.out
@go tool cover -html=coverage/coverage.out -o coverage/coverage.html
@echo "Coverage report generated at coverage/coverage.html"
92 changes: 0 additions & 92 deletions backup/cmd/backup.go

This file was deleted.

6 changes: 2 additions & 4 deletions backup/cmd/check.go → backup/cmd/check-coverage.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
"github.com/spf13/cobra"
)

func AddCheckCommands(rootCmd *cobra.Command) {
func buildCheckCoverageCommand() *cobra.Command {
var fs = afero.NewOsFs()

var checkCmd = &cobra.Command{
return &cobra.Command{
Use: "check-coverage",
Short: "Check path coverage",
Run: func(cmd *cobra.Command, args []string) {
Expand All @@ -27,6 +27,4 @@ func AddCheckCommands(rootCmd *cobra.Command) {
}
},
}

rootCmd.AddCommand(checkCmd)
}
17 changes: 7 additions & 10 deletions backup/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ import (
"gopkg.in/yaml.v3"
)

// AddConfigCommands binds the config command and its subcommands to the root command.
func AddConfigCommands(rootCmd *cobra.Command) {
// configCmd represents the config command.
func buildConfigCommand() *cobra.Command {
var configCmd = &cobra.Command{
Use: "config",
Short: "Manage configuration",
Expand All @@ -21,8 +19,7 @@ func AddConfigCommands(rootCmd *cobra.Command) {
},
}

// Extend the config subcommand with the show verb.
var showCmd = &cobra.Command{
var showVerb = &cobra.Command{
Use: "show",
Short: "Show resolved configuration",
Run: func(cmd *cobra.Command, args []string) {
Expand All @@ -38,8 +35,7 @@ func AddConfigCommands(rootCmd *cobra.Command) {
},
}

// Extend the config subcommand with the validate verb.
var validateCmd = &cobra.Command{
var validateVerb = &cobra.Command{
Use: "validate",
Short: "Validate configuration",
Run: func(cmd *cobra.Command, args []string) {
Expand All @@ -49,7 +45,8 @@ func AddConfigCommands(rootCmd *cobra.Command) {
},
}

rootCmd.AddCommand(configCmd)
configCmd.AddCommand(showCmd)
configCmd.AddCommand(validateCmd)
configCmd.AddCommand(showVerb)
configCmd.AddCommand(validateVerb)

return configCmd
}
29 changes: 29 additions & 0 deletions backup/cmd/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package cmd

import (
"fmt"

"backup-rsync/backup/internal"

"github.com/spf13/cobra"
)

func listCommands(cfg internal.Config) {
logPath := internal.GetLogPath(false)
for _, job := range cfg.Jobs {
jobLogPath := fmt.Sprintf("%s/job-%s.log", logPath, job.Name)
internal.ExecuteJob(job, false, true, jobLogPath)
}
}

func buildListCommand() *cobra.Command {
return &cobra.Command{
Use: "list",
Short: "List the commands that will be executed",
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
cfg := internal.LoadResolvedConfig(configPath)
listCommands(cfg)
},
}
}
8 changes: 5 additions & 3 deletions backup/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@ func Execute() {

rootCmd.PersistentFlags().String("config", "config.yaml", "Path to the configuration file")

AddConfigCommands(rootCmd)
AddBackupCommands(rootCmd)
AddCheckCommands(rootCmd)
rootCmd.AddCommand(buildListCommand())
rootCmd.AddCommand(buildRunCommand())
rootCmd.AddCommand(buildSimulateCommand())
rootCmd.AddCommand(buildConfigCommand())
rootCmd.AddCommand(buildCheckCoverageCommand())

err := rootCmd.Execute()
if err != nil {
Expand Down
19 changes: 19 additions & 0 deletions backup/cmd/run.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"backup-rsync/backup/internal"

"github.com/spf13/cobra"
)

func buildRunCommand() *cobra.Command {
return &cobra.Command{
Use: "run",
Short: "Execute the sync jobs",
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
cfg := internal.LoadResolvedConfig(configPath)
internal.ExecuteSyncJobs(cfg, false)
},
}
}
19 changes: 19 additions & 0 deletions backup/cmd/simulate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package cmd

import (
"backup-rsync/backup/internal"

"github.com/spf13/cobra"
)

func buildSimulateCommand() *cobra.Command {
return &cobra.Command{
Use: "simulate",
Short: "Simulate the sync jobs",
Run: func(cmd *cobra.Command, args []string) {
configPath, _ := cmd.Flags().GetString("config")
cfg := internal.LoadResolvedConfig(configPath)
internal.ExecuteSyncJobs(cfg, true)
},
}
}
50 changes: 49 additions & 1 deletion backup/internal/helper.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,56 @@
// Package internal provides helper functions for internal use within the application.
package internal

import "strings"
import (
"fmt"
"log"
"os"
"strings"
"time"
)

func NormalizePath(path string) string {
return strings.TrimSuffix(strings.ReplaceAll(path, "//", "/"), "/")
}

const FilePermission = 0644
const LogDirPermission = 0755

func GetLogPath(create bool) string {
logPath := "logs/sync-" + time.Now().Format("2006-01-02T15-04-05")
if create {
err := os.MkdirAll(logPath, LogDirPermission)
if err != nil {
log.Fatalf("Failed to create log directory: %v", err)
}
}

return logPath
}

func ExecuteSyncJobs(cfg Config, simulate bool) {
logPath := GetLogPath(true)

overallLogPath := logPath + "/summary.log"

overallLogFile, err := os.OpenFile(overallLogPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, FilePermission)
if err != nil {
log.Fatalf("Failed to open overall log file: %v", err)
}

defer func() {
err := overallLogFile.Close()
if err != nil {
log.Fatalf("Failed to close overall log file: %v", err)
}
}()

overallLogger := log.New(overallLogFile, "", log.LstdFlags)

for _, job := range cfg.Jobs {
jobLogPath := fmt.Sprintf("%s/job-%s.log", logPath, job.Name)
status := ExecuteJob(job, simulate, false, jobLogPath)
overallLogger.Printf("STATUS [%s]: %s", job.Name, status)
fmt.Printf("Status [%s]: %s\n", job.Name, status)
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.