ruborg 0.2.0 โ 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/CHANGELOG.md +22 -0
 - data/README.md +111 -14
 - data/lib/ruborg/cli.rb +156 -16
 - data/lib/ruborg/config.rb +40 -0
 - data/lib/ruborg/version.rb +1 -1
 - metadata +1 -1
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b3dfe277e22cf29ef1132f479b8e8a969e87c69b383529b7f05eb7238ac5ea07
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: fcf98cabcd5f4636fc513e69e3b446747c9ca2f054f6480f4da60416ec865f0d
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 159296240a1cec2e7791edb3689bf032569d8c1f4fda0ac5c1522e92076fec8c719dba3117326c9fcb9e074ffa295ed71a75b500657625d1ce71fab391b441c2
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: f6385fa1ff56520719b1f8b3985931b4083b3139889b34ed4d1dcb5d449eec8ba98e96f030988cf03cdcb5744f47255ef3b7a605e7bb040d6b1f2c0446ab3b81
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 
     | 
|
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            ## [Unreleased]
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
            ## [0.3.0] - 2025-10-05
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            ### Added
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Auto-initialization feature: Set `auto_init: true` in config to automatically initialize repositories on first use
         
     | 
| 
      
 14 
     | 
    
         
            +
            - Multi-repository configuration support with per-repository sources
         
     | 
| 
      
 15 
     | 
    
         
            +
            - `--repository` / `-r` option to target specific repository in multi-repo configs
         
     | 
| 
      
 16 
     | 
    
         
            +
            - `--all` option to backup all repositories at once
         
     | 
| 
      
 17 
     | 
    
         
            +
            - Repository-specific Passbolt integration (overrides global settings)
         
     | 
| 
      
 18 
     | 
    
         
            +
            - Per-source exclude patterns in multi-repo configs
         
     | 
| 
      
 19 
     | 
    
         
            +
            - BackupConfig wrapper class for multi-repo compatibility
         
     | 
| 
      
 20 
     | 
    
         
            +
            - Automatic format detection (single vs multi-repo)
         
     | 
| 
      
 21 
     | 
    
         
            +
            - Support for multiple backup sources per repository
         
     | 
| 
      
 22 
     | 
    
         
            +
            - Global settings with per-repository overrides
         
     | 
| 
      
 23 
     | 
    
         
            +
            - `log_file` configuration option to set log path in config file
         
     | 
| 
      
 24 
     | 
    
         
            +
            - Log file priority: CLI option > config file > default
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            ### Changed
         
     | 
| 
      
 27 
     | 
    
         
            +
            - Config class now detects and handles both single-repo and multi-repo formats
         
     | 
| 
      
 28 
     | 
    
         
            +
            - Backup command automatically routes to single or multi-repo implementation
         
     | 
| 
      
 29 
     | 
    
         
            +
            - Archive naming includes repository name for multi-repo configs
         
     | 
| 
      
 30 
     | 
    
         
            +
            - CLI now reads log_file from config if --log option not provided
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       10 
32 
     | 
    
         
             
            ## [0.2.0] - 2025-10-05
         
     | 
| 
       11 
33 
     | 
    
         | 
| 
       12 
34 
     | 
    
         
             
            ### Added
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -15,6 +15,8 @@ A friendly Ruby frontend for [Borg Backup](https://www.borgbackup.org/). Ruborg 
     | 
|
| 
       15 
15 
     | 
    
         
             
            - ๐๏ธ **Selective Restore** - Restore individual files or directories from archives
         
     | 
| 
       16 
16 
     | 
    
         
             
            - ๐งน **Auto-cleanup** - Optionally remove source files after successful backup
         
     | 
| 
       17 
17 
     | 
    
         
             
            - ๐ **Logging** - Comprehensive logging with daily rotation
         
     | 
| 
      
 18 
     | 
    
         
            +
            - ๐๏ธ **Multi-Repository** - Manage multiple backup repositories with different sources
         
     | 
| 
      
 19 
     | 
    
         
            +
            - ๐ **Auto-initialization** - Automatically initialize repositories on first use
         
     | 
| 
       18 
20 
     | 
    
         
             
            - โ
 **Well-tested** - Comprehensive test suite with RSpec
         
     | 
| 
       19 
21 
     | 
    
         | 
| 
       20 
22 
     | 
    
         
             
            ## Prerequisites
         
     | 
| 
         @@ -63,7 +65,9 @@ gem install ruborg 
     | 
|
| 
       63 
65 
     | 
    
         | 
| 
       64 
66 
     | 
    
         
             
            ## Configuration
         
     | 
| 
       65 
67 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
      
 68 
     | 
    
         
            +
            Ruborg supports two configuration formats: **single repository** (legacy) and **multi-repository** (recommended for complex setups).
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            ### Single Repository Configuration
         
     | 
| 
       67 
71 
     | 
    
         | 
| 
       68 
72 
     | 
    
         
             
            ```yaml
         
     | 
| 
       69 
73 
     | 
    
         
             
            # Repository path
         
     | 
| 
         @@ -73,15 +77,11 @@ repository: /path/to/borg/repository 
     | 
|
| 
       73 
77 
     | 
    
         
             
            backup_paths:
         
     | 
| 
       74 
78 
     | 
    
         
             
              - /home/user/documents
         
     | 
| 
       75 
79 
     | 
    
         
             
              - /home/user/projects
         
     | 
| 
       76 
     | 
    
         
            -
              - /etc
         
     | 
| 
       77 
80 
     | 
    
         | 
| 
       78 
81 
     | 
    
         
             
            # Exclude patterns
         
     | 
| 
       79 
82 
     | 
    
         
             
            exclude_patterns:
         
     | 
| 
       80 
83 
     | 
    
         
             
              - "*.tmp"
         
     | 
| 
       81 
84 
     | 
    
         
             
              - "*.log"
         
     | 
| 
       82 
     | 
    
         
            -
              - "*/.cache/*"
         
     | 
| 
       83 
     | 
    
         
            -
              - "*/node_modules/*"
         
     | 
| 
       84 
     | 
    
         
            -
              - "*/.git/*"
         
     | 
| 
       85 
85 
     | 
    
         | 
| 
       86 
86 
     | 
    
         
             
            # Compression algorithm (lz4, zstd, zlib, lzma, none)
         
     | 
| 
       87 
87 
     | 
    
         
             
            compression: lz4
         
     | 
| 
         @@ -92,9 +92,62 @@ encryption: repokey 
     | 
|
| 
       92 
92 
     | 
    
         
             
            # Passbolt integration (optional)
         
     | 
| 
       93 
93 
     | 
    
         
             
            passbolt:
         
     | 
| 
       94 
94 
     | 
    
         
             
              resource_id: "your-passbolt-resource-uuid"
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
            # Auto-initialize repository (optional, default: false)
         
     | 
| 
      
 97 
     | 
    
         
            +
            auto_init: true
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
            # Log file path (optional, default: ~/.ruborg/logs/ruborg.log)
         
     | 
| 
      
 100 
     | 
    
         
            +
            log_file: /var/log/ruborg.log
         
     | 
| 
      
 101 
     | 
    
         
            +
            ```
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
            ### Multi-Repository Configuration
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
            For managing multiple repositories with different sources:
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
            ```yaml
         
     | 
| 
      
 108 
     | 
    
         
            +
            # Global settings (applied to all repositories unless overridden)
         
     | 
| 
      
 109 
     | 
    
         
            +
            compression: lz4
         
     | 
| 
      
 110 
     | 
    
         
            +
            encryption: repokey
         
     | 
| 
      
 111 
     | 
    
         
            +
            auto_init: true
         
     | 
| 
      
 112 
     | 
    
         
            +
            passbolt:
         
     | 
| 
      
 113 
     | 
    
         
            +
              resource_id: "global-passbolt-id"
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
            # Multiple repositories
         
     | 
| 
      
 116 
     | 
    
         
            +
            repositories:
         
     | 
| 
      
 117 
     | 
    
         
            +
              - name: documents
         
     | 
| 
      
 118 
     | 
    
         
            +
                path: /mnt/backup/documents
         
     | 
| 
      
 119 
     | 
    
         
            +
                sources:
         
     | 
| 
      
 120 
     | 
    
         
            +
                  - name: home-docs
         
     | 
| 
      
 121 
     | 
    
         
            +
                    paths:
         
     | 
| 
      
 122 
     | 
    
         
            +
                      - /home/user/documents
         
     | 
| 
      
 123 
     | 
    
         
            +
                    exclude:
         
     | 
| 
      
 124 
     | 
    
         
            +
                      - "*.tmp"
         
     | 
| 
      
 125 
     | 
    
         
            +
                  - name: work-docs
         
     | 
| 
      
 126 
     | 
    
         
            +
                    paths:
         
     | 
| 
      
 127 
     | 
    
         
            +
                      - /home/user/work
         
     | 
| 
      
 128 
     | 
    
         
            +
                    exclude:
         
     | 
| 
      
 129 
     | 
    
         
            +
                      - "*.log"
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
              - name: databases
         
     | 
| 
      
 132 
     | 
    
         
            +
                path: /mnt/backup/databases
         
     | 
| 
      
 133 
     | 
    
         
            +
                # Repository-specific passbolt (overrides global)
         
     | 
| 
      
 134 
     | 
    
         
            +
                passbolt:
         
     | 
| 
      
 135 
     | 
    
         
            +
                  resource_id: "db-specific-passbolt-id"
         
     | 
| 
      
 136 
     | 
    
         
            +
                sources:
         
     | 
| 
      
 137 
     | 
    
         
            +
                  - name: mysql
         
     | 
| 
      
 138 
     | 
    
         
            +
                    paths:
         
     | 
| 
      
 139 
     | 
    
         
            +
                      - /var/lib/mysql/dumps
         
     | 
| 
      
 140 
     | 
    
         
            +
                  - name: postgres
         
     | 
| 
      
 141 
     | 
    
         
            +
                    paths:
         
     | 
| 
      
 142 
     | 
    
         
            +
                      - /var/lib/postgresql/dumps
         
     | 
| 
       95 
143 
     | 
    
         
             
            ```
         
     | 
| 
       96 
144 
     | 
    
         | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
      
 145 
     | 
    
         
            +
            **Multi-repo benefits:**
         
     | 
| 
      
 146 
     | 
    
         
            +
            - Organize backups by type (documents, databases, media)
         
     | 
| 
      
 147 
     | 
    
         
            +
            - Different encryption keys per repository
         
     | 
| 
      
 148 
     | 
    
         
            +
            - Multiple sources per repository
         
     | 
| 
      
 149 
     | 
    
         
            +
            - Per-source exclude patterns
         
     | 
| 
      
 150 
     | 
    
         
            +
            - Repository-specific settings override global ones
         
     | 
| 
       98 
151 
     | 
    
         | 
| 
       99 
152 
     | 
    
         
             
            ## Usage
         
     | 
| 
       100 
153 
     | 
    
         | 
| 
         @@ -110,6 +163,7 @@ ruborg init /path/to/repository --passbolt-id "resource-uuid" 
     | 
|
| 
       110 
163 
     | 
    
         | 
| 
       111 
164 
     | 
    
         
             
            ### Create a Backup
         
     | 
| 
       112 
165 
     | 
    
         | 
| 
      
 166 
     | 
    
         
            +
            **Single repository:**
         
     | 
| 
       113 
167 
     | 
    
         
             
            ```bash
         
     | 
| 
       114 
168 
     | 
    
         
             
            # Using default configuration (ruborg.yml)
         
     | 
| 
       115 
169 
     | 
    
         
             
            ruborg backup
         
     | 
| 
         @@ -124,6 +178,18 @@ ruborg backup --name "my-backup-2025-10-04" 
     | 
|
| 
       124 
178 
     | 
    
         
             
            ruborg backup --remove-source
         
     | 
| 
       125 
179 
     | 
    
         
             
            ```
         
     | 
| 
       126 
180 
     | 
    
         | 
| 
      
 181 
     | 
    
         
            +
            **Multi-repository:**
         
     | 
| 
      
 182 
     | 
    
         
            +
            ```bash
         
     | 
| 
      
 183 
     | 
    
         
            +
            # Backup specific repository
         
     | 
| 
      
 184 
     | 
    
         
            +
            ruborg backup --repository documents
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
            # Backup all repositories
         
     | 
| 
      
 187 
     | 
    
         
            +
            ruborg backup --all
         
     | 
| 
      
 188 
     | 
    
         
            +
             
     | 
| 
      
 189 
     | 
    
         
            +
            # Backup specific repository with custom name
         
     | 
| 
      
 190 
     | 
    
         
            +
            ruborg backup --repository databases --name "db-backup-2025-10-05"
         
     | 
| 
      
 191 
     | 
    
         
            +
            ```
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
       127 
193 
     | 
    
         
             
            ### List Archives
         
     | 
| 
       128 
194 
     | 
    
         | 
| 
       129 
195 
     | 
    
         
             
            ```bash
         
     | 
| 
         @@ -151,13 +217,23 @@ ruborg info 
     | 
|
| 
       151 
217 
     | 
    
         | 
| 
       152 
218 
     | 
    
         
             
            ## Logging
         
     | 
| 
       153 
219 
     | 
    
         | 
| 
       154 
     | 
    
         
            -
            Ruborg automatically logs all operations  
     | 
| 
      
 220 
     | 
    
         
            +
            Ruborg automatically logs all operations with daily rotation. Log file location priority:
         
     | 
| 
      
 221 
     | 
    
         
            +
             
     | 
| 
      
 222 
     | 
    
         
            +
            1. **CLI option** (highest priority): `--log /path/to/custom.log`
         
     | 
| 
      
 223 
     | 
    
         
            +
            2. **Config file**: `log_file: /path/to/log.log`
         
     | 
| 
      
 224 
     | 
    
         
            +
            3. **Default**: `~/.ruborg/logs/ruborg.log`
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
            **Examples:**
         
     | 
| 
       155 
227 
     | 
    
         | 
| 
       156 
228 
     | 
    
         
             
            ```bash
         
     | 
| 
       157 
     | 
    
         
            -
             
     | 
| 
      
 229 
     | 
    
         
            +
            # Use CLI option (overrides config)
         
     | 
| 
      
 230 
     | 
    
         
            +
            ruborg backup --log /var/log/ruborg.log
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
            # Or set in config file
         
     | 
| 
      
 233 
     | 
    
         
            +
            log_file: /var/log/ruborg.log
         
     | 
| 
       158 
234 
     | 
    
         
             
            ```
         
     | 
| 
       159 
235 
     | 
    
         | 
| 
       160 
     | 
    
         
            -
            Logs include 
     | 
| 
      
 236 
     | 
    
         
            +
            **Logs include:**
         
     | 
| 
       161 
237 
     | 
    
         
             
            - Operation start/completion timestamps
         
     | 
| 
       162 
238 
     | 
    
         
             
            - Paths being backed up
         
     | 
| 
       163 
239 
     | 
    
         
             
            - Archive names created
         
     | 
| 
         @@ -191,20 +267,41 @@ passbolt: 
     | 
|
| 
       191 
267 
     | 
    
         | 
| 
       192 
268 
     | 
    
         
             
            Ruborg will automatically retrieve the passphrase when performing backup operations.
         
     | 
| 
       193 
269 
     | 
    
         | 
| 
      
 270 
     | 
    
         
            +
            ## Auto-initialization
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
            Set `auto_init: true` in your configuration file to automatically initialize the repository on first use:
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
            ```yaml
         
     | 
| 
      
 275 
     | 
    
         
            +
            repository: /path/to/borg/repository
         
     | 
| 
      
 276 
     | 
    
         
            +
            auto_init: true
         
     | 
| 
      
 277 
     | 
    
         
            +
            passbolt:
         
     | 
| 
      
 278 
     | 
    
         
            +
              resource_id: "your-passbolt-resource-uuid"
         
     | 
| 
      
 279 
     | 
    
         
            +
            backup_paths:
         
     | 
| 
      
 280 
     | 
    
         
            +
              - /path/to/backup
         
     | 
| 
      
 281 
     | 
    
         
            +
            ```
         
     | 
| 
      
 282 
     | 
    
         
            +
             
     | 
| 
      
 283 
     | 
    
         
            +
            When enabled, ruborg will automatically run `borg init` if the repository doesn't exist when you run `backup`, `list`, or `info` commands. The passphrase will be retrieved from Passbolt if configured.
         
     | 
| 
      
 284 
     | 
    
         
            +
             
     | 
| 
       194 
285 
     | 
    
         
             
            ## Command Reference
         
     | 
| 
       195 
286 
     | 
    
         | 
| 
       196 
287 
     | 
    
         
             
            | Command | Description | Options |
         
     | 
| 
       197 
288 
     | 
    
         
             
            |---------|-------------|---------|
         
     | 
| 
       198 
289 
     | 
    
         
             
            | `init REPOSITORY` | Initialize a new Borg repository | `--passphrase`, `--passbolt-id`, `--log` |
         
     | 
| 
       199 
     | 
    
         
            -
            | `backup` | Create a backup using config file | `--config`, `--name`, `--remove-source`, `--log` |
         
     | 
| 
       200 
     | 
    
         
            -
            | `list` | List all archives in repository | `--config`, `--log` |
         
     | 
| 
       201 
     | 
    
         
            -
            | `restore ARCHIVE` | Restore files from archive | `--config`, `--destination`, `--path`, `--log` |
         
     | 
| 
       202 
     | 
    
         
            -
            | `info` | Show repository information | `--config`, `--log` |
         
     | 
| 
      
 290 
     | 
    
         
            +
            | `backup` | Create a backup using config file | `--config`, `--name`, `--remove-source`, `--repository`, `--all`, `--log` |
         
     | 
| 
      
 291 
     | 
    
         
            +
            | `list` | List all archives in repository | `--config`, `--repository`, `--log` |
         
     | 
| 
      
 292 
     | 
    
         
            +
            | `restore ARCHIVE` | Restore files from archive | `--config`, `--destination`, `--path`, `--repository`, `--log` |
         
     | 
| 
      
 293 
     | 
    
         
            +
            | `info` | Show repository information | `--config`, `--repository`, `--log` |
         
     | 
| 
       203 
294 
     | 
    
         | 
| 
       204 
295 
     | 
    
         
             
            ### Global Options
         
     | 
| 
       205 
296 
     | 
    
         | 
| 
       206 
297 
     | 
    
         
             
            - `--config`: Path to configuration file (default: `ruborg.yml`)
         
     | 
| 
       207 
     | 
    
         
            -
            - `--log`: Path to log file (default: `~/.ruborg/logs/ruborg.log`)
         
     | 
| 
      
 298 
     | 
    
         
            +
            - `--log`: Path to log file (overrides config, default: `~/.ruborg/logs/ruborg.log`)
         
     | 
| 
      
 299 
     | 
    
         
            +
            - `--repository` / `-r`: Repository name (required for multi-repo configs)
         
     | 
| 
      
 300 
     | 
    
         
            +
             
     | 
| 
      
 301 
     | 
    
         
            +
            ### Multi-Repository Options
         
     | 
| 
      
 302 
     | 
    
         
            +
             
     | 
| 
      
 303 
     | 
    
         
            +
            - `--all`: Backup all repositories (multi-repo config only)
         
     | 
| 
      
 304 
     | 
    
         
            +
            - `--repository NAME`: Target specific repository by name
         
     | 
| 
       208 
305 
     | 
    
         | 
| 
       209 
306 
     | 
    
         
             
            ## Development
         
     | 
| 
       210 
307 
     | 
    
         | 
    
        data/lib/ruborg/cli.rb
    CHANGED
    
    | 
         @@ -7,10 +7,21 @@ module Ruborg 
     | 
|
| 
       7 
7 
     | 
    
         
             
              class CLI < Thor
         
     | 
| 
       8 
8 
     | 
    
         
             
                class_option :config, type: :string, default: "ruborg.yml", desc: "Path to configuration file"
         
     | 
| 
       9 
9 
     | 
    
         
             
                class_option :log, type: :string, desc: "Path to log file"
         
     | 
| 
      
 10 
     | 
    
         
            +
                class_option :repository, type: :string, aliases: "-r", desc: "Repository name (for multi-repo configs)"
         
     | 
| 
       10 
11 
     | 
    
         | 
| 
       11 
12 
     | 
    
         
             
                def initialize(*args)
         
     | 
| 
       12 
13 
     | 
    
         
             
                  super
         
     | 
| 
       13 
     | 
    
         
            -
                   
     | 
| 
      
 14 
     | 
    
         
            +
                  # Priority: CLI option > config file > default
         
     | 
| 
      
 15 
     | 
    
         
            +
                  log_path = options[:log]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  unless log_path
         
     | 
| 
      
 17 
     | 
    
         
            +
                    # Try to load config to get log_file setting
         
     | 
| 
      
 18 
     | 
    
         
            +
                    config_path = options[:config] || "ruborg.yml"
         
     | 
| 
      
 19 
     | 
    
         
            +
                    if File.exist?(config_path)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      config_data = YAML.load_file(config_path) rescue {}
         
     | 
| 
      
 21 
     | 
    
         
            +
                      log_path = config_data["log_file"]
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @logger = RuborgLogger.new(log_file: log_path)
         
     | 
| 
       14 
25 
     | 
    
         
             
                end
         
     | 
| 
       15 
26 
     | 
    
         | 
| 
       16 
27 
     | 
    
         
             
                desc "init REPOSITORY", "Initialize a new Borg repository"
         
     | 
| 
         @@ -31,26 +42,16 @@ module Ruborg 
     | 
|
| 
       31 
42 
     | 
    
         
             
                desc "backup", "Create a backup using configuration file"
         
     | 
| 
       32 
43 
     | 
    
         
             
                option :name, type: :string, desc: "Archive name"
         
     | 
| 
       33 
44 
     | 
    
         
             
                option :remove_source, type: :boolean, default: false, desc: "Remove source files after successful backup"
         
     | 
| 
      
 45 
     | 
    
         
            +
                option :all, type: :boolean, default: false, desc: "Backup all repositories (multi-repo config only)"
         
     | 
| 
       34 
46 
     | 
    
         
             
                def backup
         
     | 
| 
       35 
47 
     | 
    
         
             
                  @logger.info("Starting backup operation with config: #{options[:config]}")
         
     | 
| 
       36 
48 
     | 
    
         
             
                  config = Config.new(options[:config])
         
     | 
| 
       37 
     | 
    
         
            -
                  @logger.info("Backing up paths: #{config.backup_paths.join(', ')}")
         
     | 
| 
       38 
     | 
    
         
            -
                  passphrase = fetch_passphrase_from_config(config)
         
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                  repo = Repository.new(config.repository, passphrase: passphrase)
         
     | 
| 
       41 
     | 
    
         
            -
                  backup = Backup.new(repo, config: config)
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                  archive_name = options[:name] || Time.now.strftime("%Y-%m-%d_%H-%M-%S")
         
     | 
| 
       44 
     | 
    
         
            -
                  @logger.info("Creating archive: #{archive_name}")
         
     | 
| 
       45 
     | 
    
         
            -
                  backup.create(name: options[:name], remove_source: options[:remove_source])
         
     | 
| 
       46 
     | 
    
         
            -
                  @logger.info("Backup created successfully: #{archive_name}")
         
     | 
| 
       47 
49 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
                  if  
     | 
| 
       49 
     | 
    
         
            -
                     
     | 
| 
      
 50 
     | 
    
         
            +
                  if config.multi_repo?
         
     | 
| 
      
 51 
     | 
    
         
            +
                    backup_multi_repo(config)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  else
         
     | 
| 
      
 53 
     | 
    
         
            +
                    backup_single_repo(config)
         
     | 
| 
       50 
54 
     | 
    
         
             
                  end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  puts "Backup created successfully"
         
     | 
| 
       53 
     | 
    
         
            -
                  puts "Source files removed" if options[:remove_source]
         
     | 
| 
       54 
55 
     | 
    
         
             
                rescue Error => e
         
     | 
| 
       55 
56 
     | 
    
         
             
                  @logger.error("Backup failed: #{e.message}")
         
     | 
| 
       56 
57 
     | 
    
         
             
                  error_exit(e)
         
     | 
| 
         @@ -63,6 +64,14 @@ module Ruborg 
     | 
|
| 
       63 
64 
     | 
    
         
             
                  passphrase = fetch_passphrase_from_config(config)
         
     | 
| 
       64 
65 
     | 
    
         | 
| 
       65 
66 
     | 
    
         
             
                  repo = Repository.new(config.repository, passphrase: passphrase)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                  # Auto-initialize repository if configured
         
     | 
| 
      
 69 
     | 
    
         
            +
                  if config.auto_init? && !repo.exists?
         
     | 
| 
      
 70 
     | 
    
         
            +
                    @logger.info("Auto-initializing repository at #{config.repository}")
         
     | 
| 
      
 71 
     | 
    
         
            +
                    repo.create
         
     | 
| 
      
 72 
     | 
    
         
            +
                    puts "Repository auto-initialized at #{config.repository}"
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
       66 
75 
     | 
    
         
             
                  repo.list
         
     | 
| 
       67 
76 
     | 
    
         
             
                  @logger.info("Successfully listed archives")
         
     | 
| 
       68 
77 
     | 
    
         
             
                rescue Error => e
         
     | 
| 
         @@ -102,6 +111,14 @@ module Ruborg 
     | 
|
| 
       102 
111 
     | 
    
         
             
                  passphrase = fetch_passphrase_from_config(config)
         
     | 
| 
       103 
112 
     | 
    
         | 
| 
       104 
113 
     | 
    
         
             
                  repo = Repository.new(config.repository, passphrase: passphrase)
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                  # Auto-initialize repository if configured
         
     | 
| 
      
 116 
     | 
    
         
            +
                  if config.auto_init? && !repo.exists?
         
     | 
| 
      
 117 
     | 
    
         
            +
                    @logger.info("Auto-initializing repository at #{config.repository}")
         
     | 
| 
      
 118 
     | 
    
         
            +
                    repo.create
         
     | 
| 
      
 119 
     | 
    
         
            +
                    puts "Repository auto-initialized at #{config.repository}"
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       105 
122 
     | 
    
         
             
                  repo.info
         
     | 
| 
       106 
123 
     | 
    
         
             
                  @logger.info("Successfully retrieved repository information")
         
     | 
| 
       107 
124 
     | 
    
         
             
                rescue Error => e
         
     | 
| 
         @@ -129,5 +146,128 @@ module Ruborg 
     | 
|
| 
       129 
146 
     | 
    
         
             
                  puts "Error: #{error.message}"
         
     | 
| 
       130 
147 
     | 
    
         
             
                  exit 1
         
     | 
| 
       131 
148 
     | 
    
         
             
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                # Single repository backup (legacy)
         
     | 
| 
      
 151 
     | 
    
         
            +
                def backup_single_repo(config)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  @logger.info("Backing up paths: #{config.backup_paths.join(', ')}")
         
     | 
| 
      
 153 
     | 
    
         
            +
                  passphrase = fetch_passphrase_from_config(config)
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                  repo = Repository.new(config.repository, passphrase: passphrase)
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                  # Auto-initialize repository if configured
         
     | 
| 
      
 158 
     | 
    
         
            +
                  if config.auto_init? && !repo.exists?
         
     | 
| 
      
 159 
     | 
    
         
            +
                    @logger.info("Auto-initializing repository at #{config.repository}")
         
     | 
| 
      
 160 
     | 
    
         
            +
                    repo.create
         
     | 
| 
      
 161 
     | 
    
         
            +
                    puts "Repository auto-initialized at #{config.repository}"
         
     | 
| 
      
 162 
     | 
    
         
            +
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  backup = Backup.new(repo, config: config)
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                  archive_name = options[:name] || Time.now.strftime("%Y-%m-%d_%H-%M-%S")
         
     | 
| 
      
 167 
     | 
    
         
            +
                  @logger.info("Creating archive: #{archive_name}")
         
     | 
| 
      
 168 
     | 
    
         
            +
                  backup.create(name: options[:name], remove_source: options[:remove_source])
         
     | 
| 
      
 169 
     | 
    
         
            +
                  @logger.info("Backup created successfully: #{archive_name}")
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                  if options[:remove_source]
         
     | 
| 
      
 172 
     | 
    
         
            +
                    @logger.info("Removed source files: #{config.backup_paths.join(', ')}")
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                  puts "Backup created successfully"
         
     | 
| 
      
 176 
     | 
    
         
            +
                  puts "Source files removed" if options[:remove_source]
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                # Multi-repository backup
         
     | 
| 
      
 180 
     | 
    
         
            +
                def backup_multi_repo(config)
         
     | 
| 
      
 181 
     | 
    
         
            +
                  global_settings = config.global_settings
         
     | 
| 
      
 182 
     | 
    
         
            +
                  repos_to_backup = if options[:all]
         
     | 
| 
      
 183 
     | 
    
         
            +
                                      config.repositories
         
     | 
| 
      
 184 
     | 
    
         
            +
                                    elsif options[:repository]
         
     | 
| 
      
 185 
     | 
    
         
            +
                                      repo_config = config.get_repository(options[:repository])
         
     | 
| 
      
 186 
     | 
    
         
            +
                                      raise ConfigError, "Repository '#{options[:repository]}' not found" unless repo_config
         
     | 
| 
      
 187 
     | 
    
         
            +
                                      [repo_config]
         
     | 
| 
      
 188 
     | 
    
         
            +
                                    else
         
     | 
| 
      
 189 
     | 
    
         
            +
                                      raise ConfigError, "Please specify --repository or --all for multi-repo config"
         
     | 
| 
      
 190 
     | 
    
         
            +
                                    end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                  repos_to_backup.each do |repo_config|
         
     | 
| 
      
 193 
     | 
    
         
            +
                    backup_repository(repo_config, global_settings)
         
     | 
| 
      
 194 
     | 
    
         
            +
                  end
         
     | 
| 
      
 195 
     | 
    
         
            +
                end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                def backup_repository(repo_config, global_settings)
         
     | 
| 
      
 198 
     | 
    
         
            +
                  repo_name = repo_config["name"]
         
     | 
| 
      
 199 
     | 
    
         
            +
                  puts "\n--- Backing up repository: #{repo_name} ---"
         
     | 
| 
      
 200 
     | 
    
         
            +
                  @logger.info("Backing up repository: #{repo_name}")
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                  # Merge global settings with repo-specific settings (repo-specific takes precedence)
         
     | 
| 
      
 203 
     | 
    
         
            +
                  merged_config = global_settings.merge(repo_config)
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                  passphrase = fetch_passphrase_for_repo(merged_config)
         
     | 
| 
      
 206 
     | 
    
         
            +
                  repo = Repository.new(repo_config["path"], passphrase: passphrase)
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                  # Auto-initialize if configured
         
     | 
| 
      
 209 
     | 
    
         
            +
                  auto_init = merged_config["auto_init"] || false
         
     | 
| 
      
 210 
     | 
    
         
            +
                  if auto_init && !repo.exists?
         
     | 
| 
      
 211 
     | 
    
         
            +
                    @logger.info("Auto-initializing repository at #{repo_config['path']}")
         
     | 
| 
      
 212 
     | 
    
         
            +
                    repo.create
         
     | 
| 
      
 213 
     | 
    
         
            +
                    puts "Repository auto-initialized at #{repo_config['path']}"
         
     | 
| 
      
 214 
     | 
    
         
            +
                  end
         
     | 
| 
      
 215 
     | 
    
         
            +
             
     | 
| 
      
 216 
     | 
    
         
            +
                  # Create backup config wrapper
         
     | 
| 
      
 217 
     | 
    
         
            +
                  backup_config = BackupConfig.new(repo_config, merged_config)
         
     | 
| 
      
 218 
     | 
    
         
            +
                  backup = Backup.new(repo, config: backup_config)
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                  archive_name = options[:name] || "#{repo_name}-#{Time.now.strftime('%Y-%m-%d_%H-%M-%S')}"
         
     | 
| 
      
 221 
     | 
    
         
            +
                  @logger.info("Creating archive: #{archive_name}")
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                  sources = repo_config["sources"] || []
         
     | 
| 
      
 224 
     | 
    
         
            +
                  @logger.info("Backing up #{sources.size} source(s)")
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                  backup.create(name: archive_name, remove_source: options[:remove_source])
         
     | 
| 
      
 227 
     | 
    
         
            +
                  @logger.info("Backup created successfully: #{archive_name}")
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                  puts "โ Backup created: #{archive_name}"
         
     | 
| 
      
 230 
     | 
    
         
            +
                  puts "  Sources removed" if options[:remove_source]
         
     | 
| 
      
 231 
     | 
    
         
            +
                end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                def fetch_passphrase_for_repo(repo_config)
         
     | 
| 
      
 234 
     | 
    
         
            +
                  passbolt_config = repo_config["passbolt"]
         
     | 
| 
      
 235 
     | 
    
         
            +
                  return nil if passbolt_config.nil? || passbolt_config.empty?
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                  Passbolt.new(resource_id: passbolt_config["resource_id"]).get_password
         
     | 
| 
      
 238 
     | 
    
         
            +
                end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
                # Wrapper class to adapt multi-repo config to existing Backup class
         
     | 
| 
      
 241 
     | 
    
         
            +
                class BackupConfig
         
     | 
| 
      
 242 
     | 
    
         
            +
                  def initialize(repo_config, merged_settings)
         
     | 
| 
      
 243 
     | 
    
         
            +
                    @repo_config = repo_config
         
     | 
| 
      
 244 
     | 
    
         
            +
                    @merged_settings = merged_settings
         
     | 
| 
      
 245 
     | 
    
         
            +
                  end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                  def backup_paths
         
     | 
| 
      
 248 
     | 
    
         
            +
                    sources = @repo_config["sources"] || []
         
     | 
| 
      
 249 
     | 
    
         
            +
                    sources.flat_map do |source|
         
     | 
| 
      
 250 
     | 
    
         
            +
                      source["paths"] || []
         
     | 
| 
      
 251 
     | 
    
         
            +
                    end
         
     | 
| 
      
 252 
     | 
    
         
            +
                  end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                  def exclude_patterns
         
     | 
| 
      
 255 
     | 
    
         
            +
                    patterns = []
         
     | 
| 
      
 256 
     | 
    
         
            +
                    sources = @repo_config["sources"] || []
         
     | 
| 
      
 257 
     | 
    
         
            +
                    sources.each do |source|
         
     | 
| 
      
 258 
     | 
    
         
            +
                      patterns += (source["exclude"] || [])
         
     | 
| 
      
 259 
     | 
    
         
            +
                    end
         
     | 
| 
      
 260 
     | 
    
         
            +
                    patterns += (@merged_settings["exclude_patterns"] || [])
         
     | 
| 
      
 261 
     | 
    
         
            +
                    patterns.uniq
         
     | 
| 
      
 262 
     | 
    
         
            +
                  end
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                  def compression
         
     | 
| 
      
 265 
     | 
    
         
            +
                    @merged_settings["compression"] || "lz4"
         
     | 
| 
      
 266 
     | 
    
         
            +
                  end
         
     | 
| 
      
 267 
     | 
    
         
            +
             
     | 
| 
      
 268 
     | 
    
         
            +
                  def encryption_mode
         
     | 
| 
      
 269 
     | 
    
         
            +
                    @merged_settings["encryption"] || "repokey"
         
     | 
| 
      
 270 
     | 
    
         
            +
                  end
         
     | 
| 
      
 271 
     | 
    
         
            +
                end
         
     | 
| 
       132 
272 
     | 
    
         
             
              end
         
     | 
| 
       133 
273 
     | 
    
         
             
            end
         
     | 
    
        data/lib/ruborg/config.rb
    CHANGED
    
    | 
         @@ -11,6 +11,7 @@ module Ruborg 
     | 
|
| 
       11 
11 
     | 
    
         
             
                def initialize(config_path)
         
     | 
| 
       12 
12 
     | 
    
         
             
                  @config_path = config_path
         
     | 
| 
       13 
13 
     | 
    
         
             
                  load_config
         
     | 
| 
      
 14 
     | 
    
         
            +
                  detect_format
         
     | 
| 
       14 
15 
     | 
    
         
             
                end
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
                def load_config
         
     | 
| 
         @@ -21,6 +22,7 @@ module Ruborg 
     | 
|
| 
       21 
22 
     | 
    
         
             
                  raise ConfigError, "Invalid YAML syntax: #{e.message}"
         
     | 
| 
       22 
23 
     | 
    
         
             
                end
         
     | 
| 
       23 
24 
     | 
    
         | 
| 
      
 25 
     | 
    
         
            +
                # Legacy single-repo accessors (for backward compatibility)
         
     | 
| 
       24 
26 
     | 
    
         
             
                def repository
         
     | 
| 
       25 
27 
     | 
    
         
             
                  @data["repository"]
         
     | 
| 
       26 
28 
     | 
    
         
             
                end
         
     | 
| 
         @@ -44,5 +46,43 @@ module Ruborg 
     | 
|
| 
       44 
46 
     | 
    
         
             
                def passbolt_integration
         
     | 
| 
       45 
47 
     | 
    
         
             
                  @data["passbolt"] || {}
         
     | 
| 
       46 
48 
     | 
    
         
             
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                def auto_init?
         
     | 
| 
      
 51 
     | 
    
         
            +
                  @data["auto_init"] || false
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def log_file
         
     | 
| 
      
 55 
     | 
    
         
            +
                  @data["log_file"]
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                # New multi-repo support
         
     | 
| 
      
 59 
     | 
    
         
            +
                def multi_repo?
         
     | 
| 
      
 60 
     | 
    
         
            +
                  @multi_repo
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def repositories
         
     | 
| 
      
 64 
     | 
    
         
            +
                  return [] unless multi_repo?
         
     | 
| 
      
 65 
     | 
    
         
            +
                  @data["repositories"] || []
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                def get_repository(name)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  return nil unless multi_repo?
         
     | 
| 
      
 70 
     | 
    
         
            +
                  repositories.find { |r| r["name"] == name }
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                def repository_names
         
     | 
| 
      
 74 
     | 
    
         
            +
                  return [] unless multi_repo?
         
     | 
| 
      
 75 
     | 
    
         
            +
                  repositories.map { |r| r["name"] }
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                def global_settings
         
     | 
| 
      
 79 
     | 
    
         
            +
                  @data.slice("passbolt", "compression", "encryption", "auto_init")
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                private
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def detect_format
         
     | 
| 
      
 85 
     | 
    
         
            +
                  @multi_repo = @data.key?("repositories")
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
       47 
87 
     | 
    
         
             
              end
         
     | 
| 
       48 
88 
     | 
    
         
             
            end
         
     | 
    
        data/lib/ruborg/version.rb
    CHANGED