Compare commits
3 Commits
v0.2
...
05c9eb6669
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
05c9eb6669 | ||
|
|
565e40c9be | ||
|
|
607922be19 |
@@ -181,6 +181,7 @@ Config is JSON (HJSON with comments supported). Default path depends on OS:
|
||||
| backup_timeout | `60` | Stream timeout in minutes (1-1440) |
|
||||
| compression_level | `9` | Gzip level (1-9) |
|
||||
| exclude_patterns | `[]` | Regex patterns to exclude from backup |
|
||||
| filename_prefix | `backup` | Prefix for backup filename in Content-Disposition header |
|
||||
|
||||
## Architecture & Key Patterns
|
||||
|
||||
@@ -278,4 +279,3 @@ Init scripts provided in `contrib/`:
|
||||
|
||||
See `TODO.org` for current backlog:
|
||||
- Consider alternative compression algorithms (bz2, xz, lzo, lz4)
|
||||
- Configurable filename prefix for `Content-Disposition` header
|
||||
|
||||
@@ -56,6 +56,7 @@ AI suggests to fill this section with useful information, despite that all optio
|
||||
| backup_timeout | 60 | Timeout in minutes for backup streaming operations. | If a backup takes longer than this, the connection will be terminated. Useful for large backups. Range: 1-1440 minutes (1 day max). |
|
||||
| compression_level | 9 | Gzip compression level for tar.gz archives. | 1 (fastest) to 9 (best compression). Higher values produce smaller files but take longer to compress. |
|
||||
| exclude_patterns | [] | Regex patterns to exclude from backup. | E.g., `[".*\\.tmp$", "/node_modules/"]`. Files matching any pattern are skipped. |
|
||||
| filename_prefix | "backup" | Prefix for backup filename in Content-Disposition header. | E.g., "mybackup" produces `mybackup-20260325-092341.tar.gz`. |
|
||||
|
||||
## Best practices
|
||||
|
||||
|
||||
6
TODO.org
6
TODO.org
@@ -9,6 +9,6 @@
|
||||
- [ ] lz4 for speed, xz for better compression
|
||||
- [ ] Add compression_algorithm config option
|
||||
|
||||
** TODO Configurable filename prefix
|
||||
- [ ] Move "backup" prefix to config (currently hardcoded in newServer.go)
|
||||
- [ ] Default: "backup", e.g., "backup-20260325-092341.tar.gz"
|
||||
** DONE Configurable filename prefix
|
||||
- [X] Move "backup" prefix to config (currently hardcoded in newServer.go)
|
||||
- [X] Default: "backup", e.g., "backup-20260325-092341.tar.gz"
|
||||
|
||||
@@ -33,5 +33,17 @@
|
||||
"directories": [
|
||||
"/path/to/directory1",
|
||||
"/path/to/directory2"
|
||||
]
|
||||
],
|
||||
|
||||
/* Backup streaming timeout in minutes. */
|
||||
"backup_timeout": 60,
|
||||
|
||||
/* Gzip compression level (1-9, where 9 is best compression). */
|
||||
"compression_level": 9,
|
||||
|
||||
/* Regex patterns to exclude from backup. */
|
||||
"exclude_patterns": [],
|
||||
|
||||
/* Prefix for backup filename in Content-Disposition header. */
|
||||
"filename_prefix": "backup"
|
||||
}
|
||||
|
||||
@@ -128,6 +128,13 @@ func LoadConfig(path string) error {
|
||||
return errors.New("Option password is not set")
|
||||
}
|
||||
|
||||
// FilenamePrefix: default.
|
||||
if C.FilenamePrefix == "" {
|
||||
C.FilenamePrefix = "backup"
|
||||
|
||||
log.Warnf("Config option filename_prefix is not set, fallback to %s", C.FilenamePrefix)
|
||||
}
|
||||
|
||||
// Compile exclude patterns.
|
||||
excludePatterns = make([]*regexp.Regexp, 0, len(C.ExcludePatterns))
|
||||
|
||||
|
||||
@@ -170,6 +170,27 @@ func TestLoadConfigNoHTTPS(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadConfigFilenamePrefixCustom tests custom filename prefix.
|
||||
func TestLoadConfigFilenamePrefixCustom(t *testing.T) {
|
||||
config := `{
|
||||
"user": "test",
|
||||
"password": "test",
|
||||
"directories": ["../../test_data/test1/foo"],
|
||||
"nohttps": true,
|
||||
"filename_prefix": "mybackup"
|
||||
}`
|
||||
tmpFile := writeTempConfig(t, config)
|
||||
|
||||
err := LoadConfig(tmpFile)
|
||||
if err != nil {
|
||||
t.Errorf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
if C.FilenamePrefix != "mybackup" {
|
||||
t.Errorf("C.FilenamePrefix should be mybackup, got %s", C.FilenamePrefix)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLoadConfigDefaultValues tests default values are set correctly.
|
||||
func TestLoadConfigDefaultValues(t *testing.T) {
|
||||
config := `{
|
||||
@@ -201,6 +222,10 @@ func TestLoadConfigDefaultValues(t *testing.T) {
|
||||
if C.LogLevel != "info" {
|
||||
t.Errorf("C.LogLevel should default to info, got %s", C.LogLevel)
|
||||
}
|
||||
|
||||
if C.FilenamePrefix != "backup" {
|
||||
t.Errorf("C.FilenamePrefix should default to backup, got %s", C.FilenamePrefix)
|
||||
}
|
||||
}
|
||||
|
||||
// writeTempConfig is a helper to write a temp config file for testing.
|
||||
|
||||
@@ -82,7 +82,7 @@ func NewServer(configPath string) (*http.Server, error) {
|
||||
}()
|
||||
|
||||
timestamp := time.Now().Format("20060102-150405")
|
||||
filename := fmt.Sprintf("backup-%s.tar.gz", timestamp)
|
||||
filename := fmt.Sprintf("%s-%s.tar.gz", C.FilenamePrefix, timestamp)
|
||||
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+filename)
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
@@ -99,6 +99,17 @@ func NewServer(configPath string) (*http.Server, error) {
|
||||
log.Infof("Backup completed: client=%s user=%s files=%d bytes=%d duration=%s", clientIP, username, len(files), bytesWritten, duration)
|
||||
})
|
||||
|
||||
// Decision about which mode (http or https) to run made in cmd/backer/main.go, where we run server.ListenAndServe()
|
||||
// or server.ListenAndServeTLS() depending on value of C.NoHTTPS.
|
||||
if C.NoHTTPS {
|
||||
return &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", C.Address, C.Port),
|
||||
Handler: withServerHeader(mux),
|
||||
ReadHeaderTimeout: 5 * time.Second,
|
||||
WriteTimeout: time.Duration(C.BackupTimeout) * time.Minute,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", C.Address, C.Port),
|
||||
Handler: withServerHeader(mux),
|
||||
|
||||
@@ -17,6 +17,7 @@ type (
|
||||
BackupTimeout int `json:"backup_timeout"` // Timeout in minutes for backup streaming.
|
||||
CompressionLevel int `json:"compression_level"` // Gzip compression level (1-9, default 9).
|
||||
ExcludePatterns []string `json:"exclude_patterns"` // Regex patterns to exclude from backup.
|
||||
FilenamePrefix string `json:"filename_prefix"` // Prefix for backup filename (default: "backup").
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ func CreateTarGzStream(ctx context.Context, filepaths []string) io.ReadCloser {
|
||||
}
|
||||
|
||||
header.Format = tar.FormatGNU
|
||||
header.Name = strings.TrimPrefix(filepath.Clean(fpath), string(filepath.Separator))
|
||||
header.Name = strings.TrimPrefix(filepath.ToSlash(filepath.Clean(fpath)), "/")
|
||||
|
||||
mode := st.Mode()
|
||||
|
||||
|
||||
1
llms.txt
1
llms.txt
@@ -61,6 +61,7 @@ curl -u user:pass https://server:8086/archive -o backup.tar.gz
|
||||
| backup_timeout | 60 | Stream timeout in minutes (1-1440) |
|
||||
| compression_level | 9 | Gzip level (1-9) |
|
||||
| exclude_patterns | [] | Regex patterns to exclude from backup |
|
||||
| filename_prefix | backup | Prefix for backup filename in Content-Disposition header |
|
||||
|
||||
## Key Patterns
|
||||
|
||||
|
||||
Reference in New Issue
Block a user