bup 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +47 -31
- data/buprc +7 -2
- data/exe/bup +3 -3
- data/lib/bup/config.rb +4 -3
- data/lib/bup/tar.rb +31 -36
- data/lib/bup/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: 3a9931bc931a38f83fe2eebebfb5939d997d685fe3bbb7fdf863860dab36c402
|
4
|
+
data.tar.gz: 701c9661de7b80acb3dec18b4ae053aec13cd41e73a4992e8f458f0cfcdaa2ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2bb473340913988672050f49f0fa8ecdede02ac622b6a9630d1cd91ea3481c487da20997c313a2ee77c60cfd3a8be305e722a430506ac79c08c53cb705770ea3
|
7
|
+
data.tar.gz: 776de0097acfe0da73daa50ab4943cafab33524508c21d70e670a95c6a89d7de1d0f22de82eba354f27086da69387985a3a962a0a540f8117b0206c4b6de4ff4
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
- Communicate the backup file base name through the environment variable BUP_FILENAME.
|
4
|
+
- Rubocop fixes or ignore files.
|
5
|
+
- Add post commands, incase you want to default copy something around.
|
6
|
+
|
7
|
+
## [0.2.0] - 2021-11-13
|
8
|
+
|
3
9
|
- List profiles.
|
4
10
|
- Bug fixes against empty backup directories.
|
5
11
|
- Bug fix to print buffers using read_nonblock from popen3 streams.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,43 +1,59 @@
|
|
1
1
|
# Bup
|
2
2
|
|
3
|
-
|
3
|
+
Bup is a simple backup driver script that uses `tar` to backup files.
|
4
|
+
The idea is to simplify creating backups, full and incremental, and leave
|
5
|
+
restoration as a project for the user to untar the file where their contents
|
6
|
+
is needed.
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
## Installation
|
8
|
-
|
9
|
-
Add this line to your application's Gemfile:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
gem 'bup'
|
13
|
-
```
|
14
|
-
|
15
|
-
And then execute:
|
16
|
-
|
17
|
-
$ bundle install
|
18
|
-
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install bup
|
8
|
+
Features like backup profiles, file dating, history rotation,
|
9
|
+
incremental backups, and post-processing scripting is provided.
|
22
10
|
|
23
11
|
## Usage
|
24
12
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
13
|
+
Create a file ~/.buprc with the default contents...
|
14
|
+
|
15
|
+
```yaml
|
16
|
+
---
|
17
|
+
profiles:
|
18
|
+
default:
|
19
|
+
description: Simple backup of critical files.
|
20
|
+
include:
|
21
|
+
- "$HOME"
|
22
|
+
exclude:
|
23
|
+
- "$HOME"
|
24
|
+
- "$HOME/backups"
|
25
|
+
lastrun: '2021-11-14T03:06:45 +0000'
|
26
|
+
destination: "$HOME/backups"
|
27
|
+
history: 2
|
28
|
+
tarcmd:
|
29
|
+
- tar
|
30
|
+
- cJvf
|
31
|
+
- "${BUP_FILENAME}.tar.xz"
|
32
|
+
post_cmds:
|
33
|
+
- - ls
|
34
|
+
- $BUP_FILENAME.tar.xz
|
35
|
+
```
|
32
36
|
|
33
|
-
|
37
|
+
This defines a single profile, "default". You can list
|
38
|
+
defined profiles by running `bup -l`. You run the default backup profile
|
39
|
+
simply by running `bup`. Other profiles must be selected on the command
|
40
|
+
line using `bup -p <profile name>`.
|
34
41
|
|
35
|
-
|
42
|
+
The default profile, as defined above, excludes both the `$HOME` and
|
43
|
+
`$HOME/backups` directories. Remove `$HOME` from the excludes list to actually
|
44
|
+
backup your entire home directory.
|
36
45
|
|
37
|
-
##
|
46
|
+
## Incremental Backups
|
38
47
|
|
39
|
-
|
48
|
+
By calling `bup -t incremental` an incremental backup will be run.
|
49
|
+
This runs `tar` with the `--newer` option included with the time
|
50
|
+
specified in the profile's `lastrun` setting. `Tar` will then exclude
|
51
|
+
files older than that time.
|
40
52
|
|
41
|
-
##
|
53
|
+
## Backup History
|
42
54
|
|
43
|
-
|
55
|
+
Before a new backup is run, previous backups are removed. If you run many
|
56
|
+
uncompleted backups, you will eventually remove all good backups from your
|
57
|
+
backup history. This behavior is desired because backups should nearly always
|
58
|
+
succeed and we want to ensure that disk pressure is kep lower than higher.
|
59
|
+
Higher disk pressure might cause a backup to fail.
|
data/buprc
CHANGED
@@ -1,15 +1,20 @@
|
|
1
1
|
---
|
2
2
|
profiles:
|
3
3
|
default:
|
4
|
-
description:
|
4
|
+
description: Simple backup of critical files.
|
5
5
|
include:
|
6
6
|
- "$HOME"
|
7
7
|
exclude:
|
8
8
|
- "$HOME"
|
9
9
|
- "$HOME/backups"
|
10
|
-
lastrun: '2021-11-
|
10
|
+
lastrun: '2021-11-14T03:06:45 +0000'
|
11
11
|
destination: "$HOME/backups"
|
12
12
|
history: 2
|
13
13
|
tarcmd:
|
14
14
|
- sudo
|
15
15
|
- tar
|
16
|
+
- cJvf
|
17
|
+
- "${BUP_FILENAME}.tar.xz"
|
18
|
+
post_cmds:
|
19
|
+
- - ls
|
20
|
+
- $BUP_FILENAME.tar.xz
|
data/exe/bup
CHANGED
@@ -23,13 +23,13 @@ OptParse.new do |opt|
|
|
23
23
|
end
|
24
24
|
|
25
25
|
opt.on("-l", "--list", "List profiles and exit.") do
|
26
|
-
config.runtime[
|
26
|
+
config.runtime["action"] = "list"
|
27
27
|
end
|
28
28
|
end.parse!
|
29
29
|
|
30
30
|
config.load(configfile) if File.exist?(configfile)
|
31
31
|
|
32
|
-
case config.runtime["action"]
|
32
|
+
case config.runtime["action"]
|
33
33
|
when "list"
|
34
34
|
config.config["profiles"].each do |key, profile|
|
35
35
|
puts "#{key} - #{profile["description"] || ""}"
|
@@ -38,4 +38,4 @@ else
|
|
38
38
|
tar = Bup::Tar.new(config)
|
39
39
|
tar.call
|
40
40
|
config.save(configfile)
|
41
|
-
end
|
41
|
+
end
|
data/lib/bup/config.rb
CHANGED
@@ -5,12 +5,13 @@ require "yaml"
|
|
5
5
|
require "date"
|
6
6
|
|
7
7
|
module Bup
|
8
|
+
# Configuration management.
|
8
9
|
class Config
|
9
|
-
@@timeformat = "%Y-%m-%dT%H:%M:%S %z"
|
10
10
|
|
11
11
|
attr_accessor :config, :runtime
|
12
12
|
|
13
13
|
def initialize
|
14
|
+
@timeformat = "%Y-%m-%dT%H:%M:%S %z"
|
14
15
|
@runtime = {
|
15
16
|
"profile" => "default",
|
16
17
|
"type" => "full"
|
@@ -45,14 +46,14 @@ module Bup
|
|
45
46
|
|
46
47
|
# Return the last run time of the backup or nil if there is none.
|
47
48
|
def lastrun(name)
|
48
|
-
DateTime.strptime(profile(name)["lastrun"] || "",
|
49
|
+
DateTime.strptime(profile(name)["lastrun"] || "", @timeformat)
|
49
50
|
rescue Date::Error
|
50
51
|
nil
|
51
52
|
end
|
52
53
|
|
53
54
|
# Return the last run time of the backup or nil if there is none.
|
54
55
|
def set_lastrun(name, date)
|
55
|
-
profile(name)["lastrun"] = date.strftime(
|
56
|
+
profile(name)["lastrun"] = date.strftime(@timeformat)
|
56
57
|
end
|
57
58
|
|
58
59
|
def profile(name)
|
data/lib/bup/tar.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "English"
|
4
|
-
require "English"
|
5
3
|
require "tempfile"
|
6
4
|
require "open3"
|
7
5
|
require "date"
|
@@ -13,9 +11,9 @@ module Bup
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def expand_string(str)
|
16
|
-
while str =~ /\${?([a-zA-Z0-
|
17
|
-
all =
|
18
|
-
nm =
|
14
|
+
while str =~ /\${?([a-zA-Z0-9_]+)}?/
|
15
|
+
all = $~[0]
|
16
|
+
nm = $~[1]
|
19
17
|
str = str.sub(all, ENV[nm] || "")
|
20
18
|
end
|
21
19
|
|
@@ -36,14 +34,13 @@ module Bup
|
|
36
34
|
# Prepare the destination directory.
|
37
35
|
def prepare_destination(profile_name)
|
38
36
|
destination = expand_string(@config.profile(profile_name)["destination"] || ".")
|
39
|
-
suffix = ".tar.xz"
|
40
37
|
type = @config.runtime["type"] || "full"
|
41
38
|
|
42
39
|
FileUtils.mkdir_p(destination) unless File.exist?(destination)
|
43
40
|
|
44
41
|
filename_base = "#{profile_name}-#{type}"
|
45
42
|
filename = File.join(destination,
|
46
|
-
"#{filename_base}-#{DateTime.now.new_offset(0).strftime("%Y%m%d%H%M%S")}
|
43
|
+
"#{filename_base}-#{DateTime.now.new_offset(0).strftime("%Y%m%d%H%M%S")}")
|
47
44
|
|
48
45
|
history = @config.profile(profile_name)["history"] || 0
|
49
46
|
|
@@ -79,12 +76,9 @@ module Bup
|
|
79
76
|
|
80
77
|
raise "Missing profile #{profile_name}." unless profile
|
81
78
|
|
82
|
-
args = @config.profile(profile_name)["tarcmd"].dup || ["tar"]
|
79
|
+
args = @config.profile(profile_name)["tarcmd"].dup || ["tar", "cJvf", "${BUP_FILENAME}.tar.xz"]
|
83
80
|
|
84
|
-
|
85
|
-
|
86
|
-
filename = prepare_destination(profile_name)
|
87
|
-
args << filename
|
81
|
+
ENV["BUP_FILENAME"] = prepare_destination(profile_name)
|
88
82
|
|
89
83
|
if @config.runtime["type"] == "incremental"
|
90
84
|
lastrun = @config.lastrun(profile_name)
|
@@ -96,38 +90,39 @@ module Bup
|
|
96
90
|
tf = build_exclude_file(profile["exclude"] || [])
|
97
91
|
|
98
92
|
args += ["--exclude-from", tf.path]
|
99
|
-
args += (@config.profile(profile_name)["include"] || ["."])
|
93
|
+
args += (@config.profile(profile_name)["include"] || ["."])
|
94
|
+
args = args.map do |str|
|
100
95
|
expand_string(str)
|
101
96
|
end
|
102
97
|
|
103
98
|
begin
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
r.each do |stream|
|
109
|
-
begin
|
110
|
-
print stream.read_nonblock(1024)
|
111
|
-
rescue EOFError
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
99
|
+
run_cmd(*args)
|
100
|
+
ensure
|
101
|
+
tf.unlink
|
102
|
+
end
|
115
103
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
104
|
+
@config.profile(profile_name)["post_cmds"].each do |args|
|
105
|
+
run_cmd(*args.map { |c| expand_string(c) })
|
106
|
+
end
|
107
|
+
end
|
121
108
|
|
122
|
-
|
123
|
-
|
124
|
-
|
109
|
+
def run_cmd(*args)
|
110
|
+
Open3.popen3(*args) do |stdin, stdout, stderr, wait_thr|
|
111
|
+
stdin.close
|
112
|
+
x = nil
|
113
|
+
while wait_thr.status
|
114
|
+
r, _w, _e = IO.select([stdout, stderr])
|
115
|
+
r.each do |stream|
|
116
|
+
print x if (x = stream.read_nonblock(1024, exception: false))
|
125
117
|
end
|
126
|
-
|
127
|
-
STDOUT.flush
|
128
118
|
end
|
129
|
-
|
130
|
-
|
119
|
+
|
120
|
+
wait_thr.join
|
121
|
+
print x if (x = stdout.read_nonblock(1024, exception: false))
|
122
|
+
|
123
|
+
print x if (x = stderr.read_nonblock(1024, exception: false))
|
124
|
+
|
125
|
+
$stdout.flush
|
131
126
|
end
|
132
127
|
end
|
133
128
|
end
|
data/lib/bup/version.rb
CHANGED