diff --git a/README.md b/README.md index 2f18d6c..f4ba8fa 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # simple_backup - +## build +```sh +$ go build -o backup git.lhk.o-r.kr/freerer2/simple_backup/cmd +``` \ No newline at end of file diff --git a/cmd/main.go b/cmd/main.go index eae2c74..72db51a 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -230,7 +230,7 @@ func main() { mode = backup.CompareHash } - backupOpts := backup.BackupOptions{ + backupOpts := backup.Options{ DryRun: opts.DryRun, Verbose: opts.Verbose, Force: opts.Force, diff --git a/internal/backup/backup.go b/internal/backup/backup.go index b8afd7a..a4a6d78 100644 --- a/internal/backup/backup.go +++ b/internal/backup/backup.go @@ -31,7 +31,7 @@ type Progress struct { type ProgressCallback func(Progress) -type BackupOptions struct { +type Options struct { DryRun bool Verbose bool Force bool @@ -42,24 +42,24 @@ type BackupOptions struct { dirCache *path.DirCache } -type BackupMeta struct { +type Meta struct { LastBackup time.Time `json:"lastBackup"` Files map[string]string `json:"files"` // 파일 경로 -> 해시 또는 수정 시간 } -func loadBackupMeta(dst string) (*BackupMeta, error) { - metaPath := filepath.Join(dst, constants.MetaFileName) +func loadBackupMeta(src string) (*Meta, error) { + metaPath := filepath.Join(src, constants.MetaFileName) data, err := os.ReadFile(metaPath) if err != nil { if os.IsNotExist(err) { - return &BackupMeta{ + return &Meta{ Files: make(map[string]string), }, nil } return nil, fmt.Errorf("메타 파일을 읽을 수 없습니다: %w", err) } - var meta BackupMeta + var meta Meta if err := json.Unmarshal(data, &meta); err != nil { return nil, fmt.Errorf("메타 파일을 파싱할 수 없습니다: %w", err) } @@ -70,8 +70,8 @@ func loadBackupMeta(dst string) (*BackupMeta, error) { return &meta, nil } -func saveBackupMeta(dst string, meta *BackupMeta) error { - metaPath := filepath.Join(dst, constants.MetaFileName) +func saveBackupMeta(src string, meta *Meta) error { + metaPath := filepath.Join(src, constants.MetaFileName) data, err := json.MarshalIndent(meta, "", " ") if err != nil { return fmt.Errorf("메타 데이터를 직렬화할 수 없습니다: %w", err) @@ -104,7 +104,7 @@ func calculateFileHash(path string) (string, error) { return fmt.Sprintf("%x", h.Sum(nil)), nil } -func RunBackup(ctx context.Context, src, dst string, opts BackupOptions) error { +func RunBackup(ctx context.Context, src, dst string, opts Options) error { if opts.dirCache == nil { opts.dirCache = path.NewDirCache() } @@ -118,10 +118,10 @@ func RunBackup(ctx context.Context, src, dst string, opts BackupOptions) error { } // 증분 백업을 위한 메타데이터 로드 - var meta *BackupMeta + var meta *Meta var err error if opts.Incremental { - meta, err = loadBackupMeta(dst) + meta, err = loadBackupMeta(src) if err != nil { return err } @@ -236,9 +236,25 @@ func RunBackup(ctx context.Context, src, dst string, opts BackupOptions) error { return fmt.Errorf("원본 파일 정보를 읽을 수 없습니다: %w", err) } - if srcInfo.Size() == dstInfo.Size() && srcInfo.ModTime().Equal(dstInfo.ModTime()) { - opts.Logger.Printf("건너뜀 (동일): %s\n", relPath) - continue + switch opts.CompareMode { + case CompareTime: + if srcInfo.Size() == dstInfo.Size() && srcInfo.ModTime().Equal(dstInfo.ModTime()) { + opts.Logger.Printf("건너뜀 (시간 동일): %s\n", relPath) + continue + } + case CompareHash: + srcHash, err := calculateFileHash(srcPath) + if err != nil { + return fmt.Errorf("원본 파일 해시를 계산할 수 없습니다: %w", err) + } + dstHash, err := calculateFileHash(dstPath) + if err != nil { + return fmt.Errorf("대상 파일 해시를 계산할 수 없습니다: %w", err) + } + if srcHash == dstHash { + opts.Logger.Printf("건너뜀 (해시 동일): %s\n", relPath) + continue + } } } } @@ -254,7 +270,7 @@ func RunBackup(ctx context.Context, src, dst string, opts BackupOptions) error { // 증분 백업 메타데이터 저장 if opts.Incremental && !opts.DryRun { meta.LastBackup = time.Now() - if err := saveBackupMeta(dst, meta); err != nil { + if err := saveBackupMeta(src, meta); err != nil { return err } }