Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
166c9dbc47
|
||
|
|
28d1b0d0d0
|
||
|
|
cd80c941ad
|
||
|
|
29958896a2
|
||
|
|
d815b0832a
|
||
|
|
e6ac9e6cab
|
||
|
|
9298f4232c
|
||
|
|
1dca989310
|
||
|
|
9a68a8660d
|
||
|
|
73de4f8d25
|
||
|
|
baf5b07d23
|
||
|
|
8b30fefed3
|
||
|
|
2a5562d1a9
|
||
|
|
7091118663
|
||
|
|
3113e182c7
|
||
|
|
8fc3c42a5e
|
||
|
|
0671f86579
|
||
|
|
2f207efcf9
|
||
|
|
3cbca8e4d8
|
||
|
|
54880651be
|
||
|
|
793a30fad8
|
||
|
|
871dd0f49a
|
||
|
|
30e4416f8f
|
||
|
|
d0f888cbb4
|
||
|
|
7ef29cf551
|
||
|
|
4f5499eba9
|
||
|
|
fc165fccbf
|
||
|
|
d79ea56c0f
|
||
|
|
5189910131
|
||
|
|
7d4c43f8ff
|
||
|
|
ac7e6ec21b
|
||
|
|
578d992a19
|
||
|
|
e2d8897a45
|
||
|
|
dadc4b0265
|
||
|
|
7e7d11c520
|
||
|
|
22e0556b50
|
||
|
|
2b91178e94
|
||
|
|
2c2649113d
|
||
|
|
0f4a100ac7
|
||
|
|
60d83151dc
|
||
|
|
47aec456be
|
||
|
|
c715188973
|
||
|
|
57613649c2
|
||
|
|
67dbb49a67
|
||
|
|
e62a668f3e
|
||
|
|
bd8934d57f
|
||
|
|
96fe3c7813
|
||
|
|
9fdb959540
|
||
|
|
eb889beee7
|
||
|
|
2a37eb4172
|
||
|
|
45a07205a1
|
||
|
|
9390cd2de8
|
||
|
|
77661c0964
|
||
|
|
e3a970217f
|
||
|
|
8968fcd1a8
|
||
|
|
35b87c859e
|
||
|
|
f3d5ebd276
|
||
|
|
fb726a80ab
|
||
|
|
4701ee0b05
|
||
|
|
dd779d242b
|
||
|
|
22a3e8d60f
|
||
|
|
a26182cedd
|
||
|
|
5b3558c282
|
||
|
|
4e6adf3c56
|
||
|
|
ffed2dec90
|
||
|
|
169f824d83
|
||
|
|
f77ff2d24f
|
||
|
|
ffe2b69c99
|
||
|
|
82b0ea88fa
|
||
|
|
970d3dde1e
|
||
|
|
4d23bde906
|
||
|
|
ff70358496
|
||
|
|
6f1e91e2cd
|
||
|
|
b3fee0d022
|
||
|
|
d63eb8f771
|
||
|
|
f95cd86cdc
|
||
|
|
f37cd89b4e
|
||
|
|
d1b429d37a
|
||
|
|
56df958c5b
|
||
|
|
d6d9fbf6e4
|
||
|
|
cee4d13837
|
||
|
|
252617e4f2
|
||
|
|
809545b172
|
||
|
|
b34627fe58
|
||
|
|
cd558e8608
|
||
|
|
ffbf8ece91
|
||
|
|
78760bdda3
|
||
|
|
6c07c147ae
|
||
|
|
5ddd374350
|
||
|
|
3d3fbbcbd9
|
||
|
|
4f3d83f458
|
||
|
|
d48eaabbd3
|
||
|
|
525f381094
|
||
|
|
e1ba388296
|
||
|
|
e84cf81b13
|
||
|
|
7664fa1b33
|
||
|
|
98cb7f5822
|
||
|
|
b957200deb
|
||
|
|
9e90d620e6
|
||
|
|
06620a4dba
|
||
|
|
ba97b25e25
|
||
|
|
335ad348e5
|
||
|
|
df18e383ed
|
||
|
|
7eb71bc924
|
||
|
|
c25ef52393
|
||
|
|
24a59bde2d
|
||
|
|
88e6a9a141
|
||
|
|
38c090e257
|
||
|
|
0dd7b887f7
|
||
|
|
7684bc43b0
|
||
|
|
a07fce1b6c
|
||
|
|
11c1ab0952
|
||
|
|
a42ade4f2b
|
||
|
|
c6432c1350
|
||
|
|
fa1d8f410e
|
||
|
|
8b9087cdf6
|
||
|
|
3c155e62a2
|
||
|
|
5a4a26f9a7
|
||
|
|
ca0e3d133f
|
||
|
|
cc788735dd
|
||
|
|
631ffa85d3
|
||
|
|
fe2d66c24c
|
||
|
|
97419c30f9
|
||
|
|
c6871ac81a
|
||
|
|
90120031e2
|
||
|
|
d61ffa199a
|
||
|
|
a4c4b88193
|
||
|
|
eb8bdde1fc
|
||
|
|
5d17aaf03a
|
||
|
|
d181d2970f
|
||
|
|
84e6d58493
|
||
|
|
d2e982469b
|
||
|
|
0dde6b8df9
|
||
|
|
e45ae1b1b6
|
||
|
|
d1ccc33d0a
|
||
|
|
8b52115b4a
|
||
|
|
c02fd658bc
|
||
|
|
7d0125344f
|
||
|
|
3f2e133eff
|
||
|
|
d2e03f89ca
|
||
|
|
92ecc95f72
|
||
|
|
3e5e3cb066
|
||
|
|
bd74cf0e14
|
||
|
|
1a251f61af
|
||
|
|
661a5d4232
|
||
|
|
642d807d61
|
||
|
|
b08b0474ac
|
||
|
|
b4dee0ccd2
|
||
|
|
da07c602b5
|
||
|
|
b4294a5792 | ||
|
|
b79e929f2d | ||
|
|
2bcab8f3ab | ||
|
|
fbd9520845 |
@@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
__pycache__/
|
||||
test/
|
||||
@@ -1,30 +1,38 @@
|
||||
#Arch Linux PKGBUILD
|
||||
#
|
||||
#Maintainer: Daniele Fucini <dfucini@gmail.com>
|
||||
#
|
||||
# PKGBUILD
|
||||
|
||||
pkgname=simple-backup
|
||||
pkgver=2.0.0.r3.gc61c704
|
||||
pkgrel=1
|
||||
# Maintainer: Daniele Fucini <dfucini [at] gmail [dot] com>
|
||||
|
||||
pkgname=simple_backup
|
||||
pkgdesc='Simple backup script that uses rsync to copy files'
|
||||
pkgver=4.2.0
|
||||
pkgrel=1
|
||||
url="https://git.shouldnt.work/fuxino/${pkgname}"
|
||||
arch=('any')
|
||||
url="https://github.com/Fuxino/simple-backup.git"
|
||||
license=('GPL3')
|
||||
makedepends=('git')
|
||||
depends=('python3'
|
||||
license=('GPL-3.0-or-later')
|
||||
makedepends=('git'
|
||||
'python-setuptools'
|
||||
'python-build'
|
||||
'python-installer')
|
||||
depends=('python>=3.10'
|
||||
'rsync')
|
||||
install=${pkgname}.install
|
||||
source=(git+https://github.com/Fuxino/${pkgname}.git)
|
||||
sha256sums=('SKIP')
|
||||
optdepends=('python-systemd: use systemd log'
|
||||
'python-dbus: for desktop notifications'
|
||||
'python-paramiko: for remote backup through ssh')
|
||||
conflicts=('simple_backup-git')
|
||||
source=(git+${url}?signed#tag=${pkgver})
|
||||
validpgpkeys=('7E12BC1FF3B6EDB2CD8053EB981A2B2A3BBF5514')
|
||||
sha256sums=('6c674f7981e3e5222594bdb735d4fb02ca2fcc829de57ea8f92ce71e679853f9')
|
||||
|
||||
pkgver()
|
||||
{
|
||||
cd "$pkgname"
|
||||
git describe --long --tags | sed 's/\([^-]*-g\)/r\1/;s/-/./g'
|
||||
build()
|
||||
{
|
||||
cd ${srcdir}/${pkgname}
|
||||
python -m build --wheel --no-isolation
|
||||
}
|
||||
|
||||
package()
|
||||
{
|
||||
install -Dm755 "${srcdir}/${pkgname}/${pkgname}.py" "${pkgdir}/usr/bin/${pkgname}"
|
||||
install -Dm644 "${srcdir}/${pkgname}/config" "${pkgdir}/etc/${pkgname}/config"
|
||||
cd ${srcdir}/${pkgname}
|
||||
python -m installer --destdir=${pkgdir} dist/*.whl
|
||||
install -Dm644 ${pkgname}/${pkgname}.conf ${pkgdir}/usr/share/doc/${pkgname}/${pkgname}.conf
|
||||
install -Dm644 man/${pkgname}.1 ${pkgdir}/usr/share/man/man1/${pkgname}.1
|
||||
}
|
||||
|
||||
@@ -1,10 +1,74 @@
|
||||
# simple-backup
|
||||
simple_backup
|
||||
============
|
||||
A simple backup script
|
||||
|
||||
## Description
|
||||
simple-backup is a Python script that allows you to backup your files.
|
||||
It reads from a configuration file the files/directories that must be copied,
|
||||
the destination directory for the backup and a few other options.
|
||||
simple_backup is a Python script that allows you to backup your files.
|
||||
Parameters like input files/directories, output directory etc. can be specified in a configuration file, or on the command line.
|
||||
Run:
|
||||
|
||||
```bash
|
||||
simple_backup -h
|
||||
```
|
||||
|
||||
to print all possible command line options.
|
||||
|
||||
## Dependencies
|
||||
rsync is used to perform the backup.
|
||||
The script uses rsync to actually run the backup, so you will have to install it on your system. For example on Arch Linux:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu rsync
|
||||
```
|
||||
|
||||
Optional dependencies are systemd-python to enable using systemd journal for logging, dbus-python for desktop notifications, and paramiko for remote backup.
|
||||
|
||||
## Install
|
||||
To install the program, first clone the repository:
|
||||
|
||||
```bash
|
||||
git clone https://git.shouldnt.work/fuxino/simple_backup.git
|
||||
```
|
||||
|
||||
Then install the tools required to build the package:
|
||||
|
||||
```bash
|
||||
pip install --upgrade build
|
||||
```
|
||||
|
||||
Finally, run:
|
||||
|
||||
```bash
|
||||
cd simple_backup
|
||||
python -m build --wheel
|
||||
python -m pip install dist/*.whl
|
||||
```
|
||||
|
||||
For Arch Linux and Arch-based distros, two packages are available in the AUR (aur.archlinux.org):
|
||||
- **simple_backup** for the release version
|
||||
- **simple_backup-git** for the git version
|
||||
|
||||
## Old backups
|
||||
The number of old backups to keep can be set with the --keep (or -k) argument (or in the configuration file).
|
||||
Old backups are only removed if rsync completes successfully, so that they are not deleted when the new backup may be incomplete.
|
||||
The only rsync error that is ignored is return code 24 (source files vanished during the transfer), which is common when backing up a live system.
|
||||
|
||||
## Remote backup
|
||||
> **Warning**
|
||||
> This feature is experimental
|
||||
|
||||
It's possible to use a remote server as destination for the backup. Just use the --ssh-user and --ssh-host arguments (or set them in the configuration file).
|
||||
For this to work, rsync must be installed on the server too.
|
||||
|
||||
### Server authentication
|
||||
The best way to handle the authentication is to have an ssh agent running on your system, otherwise if a passphrase is necessary to unlock the ssh key, it will be necessary to enter it more than once.
|
||||
If needed, it's possible to specify the ssh key location with the --keyfile argument or in the configuration file.
|
||||
|
||||
To be able to connect to the user's ssh agent when running simple_backup with sudo, make sure to preserve the SSH_AUTH_SOCK environment variable. For example:
|
||||
|
||||
```bash
|
||||
sudo --preserve-env=SSH_AUTH_SOCK -s simple_backup [options]
|
||||
```
|
||||
|
||||
or by editing the sudoers file.
|
||||
If SSH key authentication is not available, password authentication will be used instead.
|
||||
Check the man page for more details.
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
#Example config file for my_backup
|
||||
|
||||
# WARNING: Values should NOT be quoted, e.g. use inputs=/some/dir instead of inputs="/some/dir"
|
||||
|
||||
#Input directories. Use a comma to separate items
|
||||
inputs=/home/my_home,/etc
|
||||
|
||||
#Output directory
|
||||
backup_dir=/media/Backup
|
||||
|
||||
#Exclude patterns. Use a comma to separate items
|
||||
exclude=.gvfs,.cache*,[Cc]ache*,.thumbnails*,[Tt]rash*,*.backup*,*~,.dropbox*
|
||||
|
||||
#Number of snapshots to keep (use -1 to keep all)
|
||||
keep=-1
|
||||
@@ -0,0 +1,216 @@
|
||||
.TH SIMPLE_BACKUP 1 2026-10-08 SIMPLE_BACKUP 4.3.0
|
||||
.SH NAME
|
||||
simple_backup \- Backup files and folders using rsync
|
||||
.SH SYNOPSIS
|
||||
.B simple_backup
|
||||
\-h, \-\-help
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
.B simple_backup
|
||||
[\-c, \-\-config FILE]
|
||||
[\-i, \-\-input INPUT [INPUT...]]
|
||||
[\-o, \-\-output DIR]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
.RS 14 [\-e, \-\-exclude FILE|DIR|PATTERN [FILE|...]]
|
||||
[\-k, \-\-keep N]
|
||||
[\-\-ssh\-host HOSTNAME]
|
||||
[\-\-ssh\-user USERNAME]
|
||||
[\-\-keyfile FILE]
|
||||
.PD 0
|
||||
.P
|
||||
.PD
|
||||
[\-s, \-\-checksum]
|
||||
[\-z, \-\-compress]
|
||||
[\-\-remove\-before\-backup]
|
||||
.RE
|
||||
.SH DESCRIPTION
|
||||
.B simple_backup
|
||||
is a python script for performing backup of files and folders.
|
||||
.P
|
||||
It uses rsync to copy the files to the specified location. Parameters for the backup such as
|
||||
input files/directories, output location and files or folders to exclude can be specified
|
||||
in a configuration file (default location $HOME/.config/simple_backup/simple_backup.conf)
|
||||
or directly on the command line.
|
||||
.P
|
||||
Parameters specified on the command line will override those in the configuration file.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Print a short help message and exit.
|
||||
.TP
|
||||
.B \-c, \-\-config FILE
|
||||
Specify the configuration file, useful to specify a different one from the default.
|
||||
.TP
|
||||
.B \-i, \-\-input INPUT [INPUT...]
|
||||
Specify the files and directories to backup. Multiple inputs can be specified, just separate
|
||||
them with a space. If filenames or paths contain spaces, don't forget to escape them,
|
||||
or to use single or double quotes around them.
|
||||
.TP
|
||||
.B \-o, \-\-output DIR
|
||||
Specify the directory where the files will be copied. The program will automatically
|
||||
create a subdirectory called \(aqsimple_backup\(aq (if it does not already exist) and
|
||||
inside this directory the actual backup directory (using the current date and time, for example
|
||||
\(aq2026\-10\-08_17\-34\-47\(aq).
|
||||
.RS
|
||||
.P
|
||||
Backups are best stored on a Linux filesystem (e.g. ext4 or btrfs). FAT and exFAT filesystems
|
||||
are supported, but they don\(aqt support hard links, so each backup will be a full copy instead
|
||||
of only storing files that changed since the previous one. File ownership and permissions are
|
||||
not preserved either.
|
||||
.RE
|
||||
.TP
|
||||
.B \-e, \-\-exclude FILE|DIR|PATTERN [FILE|...]]
|
||||
Specify files, directories or patterns to exclude from the backup. Matching files and directories
|
||||
will not be copied. Multiple elements can be specified, in the same way as for the \-\-input option.
|
||||
.TP
|
||||
.B \-k, \-\-keep N
|
||||
Specify how many old backups (so excluding the current one) will be kept. The default behavior
|
||||
is to keep them all (same as N=\-1).
|
||||
Old backups are only removed if rsync completes successfully, to avoid deleting them when the
|
||||
new backup may be incomplete. rsync return code 24 (source files vanished during the transfer)
|
||||
is treated as success, while any other error (including return code 23, partial transfer due to error)
|
||||
will prevent old backups from being removed. This does not apply when using \-\-remove\-before\-backup.
|
||||
.TP
|
||||
.B \-u, \-\-user USERNAME
|
||||
Explicitly specify the user running the backup (in case it is needed for home directory expansion).
|
||||
.TP
|
||||
.B \-\-ssh\-host HOSTNAME
|
||||
Hostname of the server where to copy the files in case of remote backup through SSH.
|
||||
.TP
|
||||
.B \-\-ssh\-user USERNAME
|
||||
Username for connecting to the server in case of remote backup.
|
||||
.TP
|
||||
.B \-\-keyfile FILE
|
||||
Location of the SSH key for server authentication.
|
||||
.TP
|
||||
.B \-s, \-\-checksums
|
||||
Same as rsync option \(aq\-\-checksum\(aq, use checksums instead of mod\-time and size
|
||||
to skip files.
|
||||
.TP
|
||||
.B \-z, \-\-compress
|
||||
Compress data during transfer (rsync \(aq\-\-compress\(aq option). Useful for remote backup
|
||||
if saving bandwith is needed.
|
||||
.TP
|
||||
.B \-\-remove\-before\-backup
|
||||
Remove old backups (if necessary) before creating the new backup. Useful to free some space
|
||||
before performing the backup.
|
||||
Default behavior is to remove old backups after successfully completing the backup.
|
||||
Note that if the backup fails after old backups have been removed, only the backups kept
|
||||
according to \-\-keep will be left, and the new backup may be incomplete. In particular, with
|
||||
\-\-keep 0 there will be no complete backup available until the next successful one.
|
||||
.TP
|
||||
.B \-\-no\-syslog
|
||||
Don't use systemd journal for logging.
|
||||
.TP
|
||||
.B \-\-rsync\-options OPTIONS [OPTION...]
|
||||
By default, the following rsync options are used:
|
||||
.RS
|
||||
.P
|
||||
\-a \-r \-v \-h \-s \-H \-X
|
||||
.P
|
||||
Using \-\-rsync\-options it is possible to manually select which options to use. Supported values are the following:
|
||||
.P
|
||||
\-a, \-l, \-p, \-t, \-g, \-o, \-c, \-h, \-D, \-H, \-X, \-s
|
||||
.P
|
||||
Options \-r, \-v, \-\-ignore\-missing\-args and \-\-mkpath are used in any case. Note that options must be specified without dash (\-), for example:
|
||||
.P
|
||||
.EX
|
||||
simple_backup \-\-rsync\-options a l p
|
||||
.EE
|
||||
.P
|
||||
Check
|
||||
.BR rsync (1)
|
||||
for details about the options.
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-remote\-sudo
|
||||
Run rsync on the remote server with sudo. This is needed if you want to preserve the owner of the files/folders to be copied (rsync \-\-owner option). For this to work the user used to login to the server obviously need to be allowed to use sudo. In addition, the user need to be able to run rsync with sudo without a password. To do this, /etc/sudoers on the server need to be edited adding a line like this one:
|
||||
.RS
|
||||
.P
|
||||
<username> ALL=NOPASSWD:<path/to/rsync>
|
||||
.P
|
||||
To be able to remove old backups generated with \-\-remote\-sudo (see \-\-keep option), also
|
||||
.BR rm (1)
|
||||
needs to be allowed to run without password in the same way.
|
||||
.RE
|
||||
.TP
|
||||
.B \-\-numeric\-ids
|
||||
Use rsync \-\-numeric\-ids option. This causes rsync to use numeric uid/gid instead of trying to map uid/gid names from the local machine to the server.
|
||||
.SH CONFIGURATION
|
||||
An example configuration file is provided at \(aq/usr/share/doc/simple_backup/simple_backup.conf\(aq.
|
||||
Copy it to the default location ($HOME/.config/simple_backup) and edit it as needed.
|
||||
.SH REMOTE BACKUP
|
||||
It is possible to choose a directory on a remote server as destination for the backup. The files
|
||||
are copied by rsync through SSH. Server hostname and username must be specified, either in the
|
||||
configuration file, or on the command line (\(aq\-\-ssh\-host\(aq and \(aq\-\-ssh\-user\(aq options).
|
||||
.P
|
||||
The output directory is a path on the server. A leading \(aq~\(aq and relative paths refer to the
|
||||
home directory of the user on the server. On the command line, quote \(aq~\(aq so that the local
|
||||
shell doesn\(aqt expand it, for example:
|
||||
.P
|
||||
.EX
|
||||
simple_backup \-\-ssh\-host server \-\-ssh\-user user \-o \(aq~/backups\(aq
|
||||
.EE
|
||||
.SS AUTHENTICATION
|
||||
For authentication, it is possible to use SSH key or password.
|
||||
.P
|
||||
When using SSH key, the best way to connect to the server is to have an SSH agent running.
|
||||
Otherwise, if the SSH key is encrypted, it will be necessary to enter the passphrase more
|
||||
than once. It is possible to specify the SSH key to use with the option \(aq\-\-keyfile\(aq,
|
||||
if necessary.
|
||||
.P
|
||||
When running
|
||||
.B simple_backup
|
||||
with
|
||||
.B sudo,
|
||||
in order to connect to the user\(aqs SSH agent it is necessary to preserve the \(aqSSH_AUTH_SOCK\(aq environment variable, for example:
|
||||
.P
|
||||
.EX
|
||||
sudo --preserve-env=SSH_AUTH_SOCK -s simple_backup [options]
|
||||
.EE
|
||||
.P
|
||||
It is also possible to make this permanent by editing the
|
||||
.B sudoers
|
||||
file (see
|
||||
.BR sudoers (5))
|
||||
.P
|
||||
If SSH key authentication is not available, password authentication will be used instead.
|
||||
Note that in this case
|
||||
.B sshpass
|
||||
(if available) will be used to send the password to rsync, to avoid prompting the user for
|
||||
the password multiple
|
||||
times. This can pose some security risks, see
|
||||
.BR sshpass (1)
|
||||
for details. For this reason, use SSH key authentication if possible.
|
||||
.SH EXIT STATUS
|
||||
.TP
|
||||
.B 0
|
||||
The backup was completed without errors. This includes rsync return code 24 (some source files
|
||||
vanished during the transfer), which only logs a warning.
|
||||
.TP
|
||||
.B 1
|
||||
No valid inputs selected for backup.
|
||||
.TP
|
||||
.B 2
|
||||
Backup failed because output directory for storing the backup does not exist.
|
||||
.TP
|
||||
.B 3
|
||||
Permission denied to access the output directory.
|
||||
.TP
|
||||
.B 4
|
||||
rsync error (rsync returned a value other than 0 or 24).
|
||||
.TP
|
||||
.B 5
|
||||
SSH connection failed.
|
||||
.TP
|
||||
.B 6
|
||||
Bad configuration file or options (for example, only one of SSH host and SSH user specified).
|
||||
.SH SEE ALSO
|
||||
.BR rsync (1)
|
||||
.SH AUTHORS
|
||||
.MT https://git.shouldnt.work/fuxino
|
||||
Daniele Fucini
|
||||
.ME
|
||||
@@ -0,0 +1,48 @@
|
||||
[build-system]
|
||||
requires = ['setuptools>=77']
|
||||
build-backend = 'setuptools.build_meta'
|
||||
|
||||
[project]
|
||||
name = "simple_backup"
|
||||
dynamic = ["version"]
|
||||
description = "Simple backup script that uses rsync to copy files"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
license = "GPL-3.0-or-later"
|
||||
license-files = ["LICENSE"]
|
||||
authors = [
|
||||
{ name = "Daniele Fucini", email = "dfucini@gmail.com" }
|
||||
]
|
||||
maintainers = [
|
||||
{ name = "Daniele Fucini", email = "dfucini@gmail.com" }
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
"Natural Language :: English",
|
||||
"Operating System :: POSIX :: Linux",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: 3.13",
|
||||
"Programming Language :: Python :: 3.14",
|
||||
"Topic :: System :: Archiving :: Backup",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
JOURNAL = ["systemd-python"]
|
||||
NOTIFICATIONS = ["dbus-python"]
|
||||
REMOTE = ["paramiko>=3.2"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://git.shouldnt.work/fuxino/simple_backup"
|
||||
|
||||
[project.scripts]
|
||||
simple_backup = "simple_backup.simple_backup:simple_backup"
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["simple_backup"]
|
||||
|
||||
[tool.setuptools.dynamic]
|
||||
version = { attr = "simple_backup.__version__" }
|
||||
@@ -1,7 +0,0 @@
|
||||
post_install() {
|
||||
echo "An example configuration file is found in /etc/simple_backup/config."
|
||||
}
|
||||
|
||||
post_upgrade() {
|
||||
post_install
|
||||
}
|
||||
@@ -1,585 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
# Import libraries
|
||||
from sys import exit, argv
|
||||
|
||||
import os
|
||||
from os.path import expanduser, isfile, isdir, islink, exists
|
||||
from shutil import move, rmtree
|
||||
|
||||
import subprocess
|
||||
|
||||
from datetime import datetime
|
||||
from tempfile import mkstemp
|
||||
|
||||
class Backup():
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Backup, self).__init__(*args, **kwargs)
|
||||
|
||||
self.log_path = ''
|
||||
self.logfile = None
|
||||
self.err_path = ''
|
||||
self.errfile = None
|
||||
self.warn_path = ''
|
||||
self.warnfile = None
|
||||
self.homedir = ''
|
||||
self.backup_dev = ''
|
||||
self.backup_dir = ''
|
||||
self.last_backup = ''
|
||||
self.inputs = ''
|
||||
self.inputs_path = ''
|
||||
self.exclude_path = ''
|
||||
self.exclude = ''
|
||||
self.options = ''
|
||||
self.user = ''
|
||||
self.keep = -1
|
||||
self.n_in = 0
|
||||
|
||||
# Help function
|
||||
def help_function(self):
|
||||
print('simple_backup, version 2.0.0')
|
||||
print('')
|
||||
print('Usage: {} [OPTIONS]'.format(argv[0]))
|
||||
print('')
|
||||
print('Options:')
|
||||
print('-h, --help Print this help and exit.')
|
||||
print('-c, --config CONFIG_FILE Use the specified configuration file')
|
||||
print(' instead of the default one.')
|
||||
print(' All other options are ignored.')
|
||||
print('-i, --input INPUT [INPUT...] Specify a file/dir to include in the backup.')
|
||||
print('-d, --directory DIR Specify the output directory for the backup.')
|
||||
print('-e, --exclude PATTERN [PATTERN...] Specify a file/dir/pattern to exclude from')
|
||||
print(' the backup.')
|
||||
print('-k, --keep NUMBER Specify the number of old backups to keep.')
|
||||
print(' Default: keep all.')
|
||||
print('-u, --user USER User performing the backup.')
|
||||
print(' Useful when running with "sudo"')
|
||||
print('-s, --checksum Use the checksum rsync option to compare files')
|
||||
print(' (MUCH slower).')
|
||||
print('')
|
||||
print('If no option is given, the program uses the default')
|
||||
print('configuration file: $HOMEDIR/.simple_backup/config.')
|
||||
print('')
|
||||
print('Report bugs to dfucini@gmail.com')
|
||||
|
||||
exit(0)
|
||||
|
||||
# Function to read configuration file
|
||||
def read_conf(self, config=None):
|
||||
if config is None:
|
||||
config = self.homedir + '/.simple_backup/config'
|
||||
|
||||
if not isfile(config):
|
||||
# If default config file doesn't exist, exit
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: Configuration file not found'
|
||||
print(err_message)
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
else:
|
||||
if not isfile(config):
|
||||
# If the provided configuration file doesn't exist, exit
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: Configuration file not found'
|
||||
print(err_message)
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
|
||||
# Create temporary files
|
||||
inputs_handle, self.inputs_path = mkstemp(prefix='tmp_inputs', text=True)
|
||||
exclude_handle, self.exclude_path = mkstemp(prefix='tmp_exclude', text=True)
|
||||
|
||||
# Open temporary files
|
||||
self.inputs = open(self.inputs_path, 'w')
|
||||
self.exclude = open(self.exclude_path, 'w')
|
||||
|
||||
# Parse the configuration file
|
||||
with open(config, 'r') as fp:
|
||||
line = fp.readline()
|
||||
|
||||
while line:
|
||||
if line[:7] == 'inputs=':
|
||||
line = line[7:].rstrip()
|
||||
input_values = line.split(',')
|
||||
n_in = 0
|
||||
for i in input_values:
|
||||
if not exists(i):
|
||||
warn_message = 'Warning: input "' + i + '" not found. Skipping'
|
||||
print(warn_message)
|
||||
self.warnfile.write(warn_message)
|
||||
self.warnfile.write('\n')
|
||||
else:
|
||||
self.inputs.write(i)
|
||||
self.inputs.write('\n')
|
||||
self.n_in = self.n_in + 1
|
||||
elif line[:11] == 'backup_dir=':
|
||||
line = line[11:].rstrip()
|
||||
self.backup_dev = line
|
||||
elif line[:8] == 'exclude=':
|
||||
line = line[8:].rstrip()
|
||||
exclude_values = line.split(',')
|
||||
for i in exclude_values:
|
||||
self.exclude.write(i)
|
||||
self.exclude.write('\n')
|
||||
elif line[:5] == 'keep=':
|
||||
line = line[5:].rstrip()
|
||||
self.keep = int(line)
|
||||
|
||||
line = fp.readline()
|
||||
|
||||
fp.close()
|
||||
self.inputs.close()
|
||||
self.exclude.close()
|
||||
|
||||
# If the backup directory is not set or doesn't exist, exit
|
||||
if self.backup_dev == '' or not isdir(self.backup_dev):
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: Output folder "' + self.backup_dev + '" not found'
|
||||
print(err_message)
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
|
||||
self.backup_dir = self.backup_dev + '/simple_backup'
|
||||
date = str(datetime.now())
|
||||
|
||||
# Create the backup subdirectory using date
|
||||
if isdir(self.backup_dir):
|
||||
# If previous backups exist, save link to the last backup
|
||||
self.last_backup = self.backup_dir + '/last_backup'
|
||||
if islink(self.last_backup):
|
||||
try:
|
||||
self.last_backup = os.readlink(self.last_backup)
|
||||
except:
|
||||
print('An error occurred when reading the last_backup link')
|
||||
exit(1)
|
||||
else:
|
||||
self.last_backup = ''
|
||||
|
||||
self.backup_dir = self.backup_dir + '/' + date
|
||||
|
||||
try:
|
||||
os.makedirs(self.backup_dir)
|
||||
except PermissionError as e:
|
||||
print(str(e))
|
||||
exit(1)
|
||||
except:
|
||||
print('Failed to create backup directory')
|
||||
exit(1)
|
||||
|
||||
return
|
||||
|
||||
# Function to parse options
|
||||
def parse_options(self):
|
||||
# Create temporary files
|
||||
inputs_handle, self.inputs_path = mkstemp(prefix='tmp_inputs', text=True)
|
||||
exclude_handle, self.exclude_path = mkstemp(prefix='tmp_exclude', text=True)
|
||||
|
||||
# Open temporary files
|
||||
self.inputs = open(self.inputs_path, 'w')
|
||||
self.exclude = open(self.exclude_path, 'w')
|
||||
|
||||
i = 1
|
||||
while i < len(argv):
|
||||
var = argv[i]
|
||||
|
||||
if var == '-h' or var == '--help':
|
||||
self.help_function()
|
||||
elif var == '-i' or var == '--input':
|
||||
val = argv[i+1]
|
||||
while i < len(argv) - 1 and val[0] != '-':
|
||||
inp = val
|
||||
|
||||
if not exists(inp):
|
||||
warn_message = 'Warning: input "' + inp + '" not found. Skipping'
|
||||
print(warn_message)
|
||||
self.warnfile.write(warn_message)
|
||||
self.warnfile.write('\n')
|
||||
else:
|
||||
self.n_in = self.n_in + 1
|
||||
self.inputs.write(inp)
|
||||
self.inputs.write('\n')
|
||||
|
||||
i = i + 1
|
||||
val = argv[i+1]
|
||||
elif var == '-d' or var == '--directory':
|
||||
self.backup_dev = argv[i+1]
|
||||
|
||||
if not exists(self.backup_dev) or not isdir(self.backup_dev):
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: output folder "' + self.backup_dev + '" not found'
|
||||
print(err_message)
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
if self.user is not None:
|
||||
pass
|
||||
# chown $USER:$USER $LOG && chmod 644 $LOG
|
||||
# chown $USER:$USER $ERR && chmod 644 $ERR
|
||||
# chown $USER:$USER $WARN && chmod 644 $WARN
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
|
||||
self.backup_dir = self.backup_dev + '/simple_backup'
|
||||
date = str(datetime.now())
|
||||
|
||||
# Create the backup subdirectory using date
|
||||
if isdir(self.backup_dir):
|
||||
#If previous backups exist, save link to the last backup
|
||||
self.last_backup = self.backup_dir + '/last_backup'
|
||||
if islink(self.last_backup):
|
||||
try:
|
||||
self.last_backup = os.readlink(self.last_backup)
|
||||
except:
|
||||
print('An error occurred when reading the last_backup link')
|
||||
exit(1)
|
||||
else:
|
||||
self.last_backup = ''
|
||||
|
||||
self.backup_dir = self.backup_dir + '/' + date
|
||||
|
||||
try:
|
||||
os.makedirs(self.backup_dir)
|
||||
except PermissionError as e:
|
||||
print(str(e))
|
||||
exit(1)
|
||||
except:
|
||||
print('Failed to create backup directory')
|
||||
exit(1)
|
||||
|
||||
i = i + 1
|
||||
elif var == '-e' or var == '--exclude':
|
||||
val = argv[i+1]
|
||||
while i < len(argv) - 1 and val[0] != '-':
|
||||
exc = val
|
||||
self.exclude.write(exc)
|
||||
self.exclude.write('\n')
|
||||
|
||||
i = i + 1
|
||||
val = argv[i+1]
|
||||
elif var == '-k' or var == '--keep':
|
||||
self.keep = int(argv[i+1])
|
||||
|
||||
i = i + 1
|
||||
elif var == '-c' or var == '--config':
|
||||
self.read_conf(argv[i+1])
|
||||
|
||||
i = i + 1
|
||||
elif var == '-u' or var == '--user':
|
||||
self.homedir = '/home/' + argv[i+1]
|
||||
if not isdir(self.homedir):
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: user "' + argv[i+1] + '"doesn\'t exist'
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
if self.user is not None:
|
||||
pass
|
||||
# chown $USER:$USER $LOG && chmod 644 $LOG
|
||||
# chown $USER:$USER $ERR && chmod 644 $ERR
|
||||
# chown $USER:$USER $WARN && chmod 644 $WARN
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
|
||||
if not isdir(self.homedir + '/.simple_backup'):
|
||||
try:
|
||||
os.makedir(self.homedir + '/.simple_backup')
|
||||
print('Created directory "' + self.homedir + '/.simple_backup".')
|
||||
except:
|
||||
print('Failed to create .simple_backup directory in HOME')
|
||||
exit(1)
|
||||
|
||||
self.user = argv[i+1]
|
||||
|
||||
i = i + 1
|
||||
elif var == '-s' or var == '--checksum':
|
||||
self.options = '-arcvh -H -X'
|
||||
else:
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
self.logfile.write(log_message)
|
||||
self.logfile.write('\n')
|
||||
print('Backup failed')
|
||||
err_message = 'Error: Option "' + var + '" not recognised. Use "simple-backup -h" to see available options'
|
||||
self.errfile.write(err_message)
|
||||
self.errfile.write('\n')
|
||||
|
||||
self.logfile.close()
|
||||
self.errfile.close()
|
||||
self.warnfile.close()
|
||||
|
||||
move(self.log_path, self.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(self.err_path, self.homedir + '/.simple_backup/errors.log')
|
||||
move(self.warn_path, self.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
|
||||
i = i + 1
|
||||
|
||||
self.inputs.close()
|
||||
self.exclude.close()
|
||||
|
||||
return
|
||||
|
||||
def exec_(self):
|
||||
print('Copying files. This may take a long time...')
|
||||
|
||||
if self.last_backup == '':
|
||||
rsync = 'rsync ' + self.options + ' --exclude-from=' + self.exclude_path +\
|
||||
' --files-from=' + self.inputs_path + ' / "' + self.backup_dir +\
|
||||
'" --ignore-missing-args >> ' + self.log_path + ' 2>> ' + self.err_path
|
||||
else:
|
||||
rsync = 'rsync ' + self.options + ' --link-dest="' + self.last_backup + '" --exclude-from=' +\
|
||||
self.exclude_path + ' --files-from=' + self.inputs_path + ' / "' + self.backup_dir +\
|
||||
'" --ignore-missing-args >> ' + self.log_path + ' 2>> ' + self.err_path
|
||||
|
||||
subprocess.run(rsync, shell=True)
|
||||
|
||||
return
|
||||
|
||||
def main():
|
||||
|
||||
backup = Backup()
|
||||
|
||||
# Create temporary log files
|
||||
log_handle, backup.log_path = mkstemp(prefix='tmp_log', text=True)
|
||||
err_handle, backup.err_path = mkstemp(prefix='tmp_err', text=True)
|
||||
warn_handle, backup.warn_path = mkstemp(prefix='tmp_warn', text=True)
|
||||
|
||||
# Open log files
|
||||
backup.logfile = open(backup.log_path, 'w')
|
||||
backup.errfile = open(backup.err_path, 'w')
|
||||
backup.warnfile = open(backup.warn_path, 'w')
|
||||
|
||||
# Set homedir and default options
|
||||
backup.homedir = expanduser('~')
|
||||
backup.options = '-arvh -H -X'
|
||||
|
||||
# Check number of parameters
|
||||
if len(argv) == 1:
|
||||
# If simple backup directory doesn't exist, create it and exit
|
||||
if not isdir(backup.homedir + '/.simple_backup'):
|
||||
try:
|
||||
os.makedir(backup.homedir + '/.simple_backup')
|
||||
print('Created directory "' + backup.homedir + '/.simple_backup".')
|
||||
print('Copy there the sample configuration and edit it')
|
||||
print('to your needs before running the backup,')
|
||||
print('or pass options on the command line.')
|
||||
except:
|
||||
print('Failed to create .simple_backup directory in HOME')
|
||||
|
||||
exit(1)
|
||||
|
||||
# Read configuration file
|
||||
backup.read_conf()
|
||||
else:
|
||||
backup.parse_options()
|
||||
|
||||
if backup.n_in > 0 and (backup.backup_dir == '' or
|
||||
not isdir(backup.backup_dir)):
|
||||
#If the backup directory is not set or doesn't exist, exit
|
||||
log_message = str(datetime.now()) + ': Backup failed (see errors.log)'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
err_message = 'Error: Output folder "' + backup.backup_dev.getBackupDev + '" not found'
|
||||
backup.errfile.write(err_message)
|
||||
backup.errfile.write('\n')
|
||||
|
||||
backup.logfile.close()
|
||||
backup.errfile.close()
|
||||
backup.warnfile.close()
|
||||
|
||||
move(backup.log_path, backup.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(backup.err_path, backup.homedir + '/.simple_backup/errors.log')
|
||||
move(backup.warn_path, backup.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(1)
|
||||
elif backup.n_in == 0 and backup.backup_dir == '':
|
||||
if not isdir(backup.homedir + '/.simple_backup'):
|
||||
try:
|
||||
os.makedir(backup.homedir + '/.simple_backup')
|
||||
print('Created directory "' + backup.homedir + '/.simple_backup".')
|
||||
print('Copy there the sample configuration and edit it')
|
||||
print('to your needs before running the backup')
|
||||
print('or pass options on the command line.')
|
||||
except:
|
||||
print('Failed to create .simple_backup directory in HOME')
|
||||
|
||||
exit(1)
|
||||
|
||||
backup.read_conf(backup.homedir + '/.simple_backup/config')
|
||||
|
||||
if backup.n_in == 0:
|
||||
log_message = str(datetime.now()) + ': Backup finished (no files copied)'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Backup finished (no files copied')
|
||||
warn_message = 'Warning: no valid input selected. Nothing to do'
|
||||
backup.warnfile.write(warn_message)
|
||||
backup.warnfile.write('\n')
|
||||
print(warn_message)
|
||||
|
||||
backup.logfile.close()
|
||||
backup.errfile.close()
|
||||
backup.warnfile.close()
|
||||
|
||||
move(backup.log_path, backup.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(backup.err_path, backup.homedir + '/.simple_backup/errors.log')
|
||||
move(backup.warn_path, backup.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
exit(0)
|
||||
|
||||
log_message = str(datetime.now()) + ': Starting backup'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Starting backup...')
|
||||
|
||||
#If specified, keep the last n backups and remove the others. Default: keep all
|
||||
if backup.keep > -1:
|
||||
try:
|
||||
dirs = os.listdir(backup.backup_dev + '/simple_backup')
|
||||
except:
|
||||
print('Failed to list backup directory')
|
||||
exit(1)
|
||||
if dirs.count('last_backup') > 0:
|
||||
dirs.remove('last_backup')
|
||||
n_backup = len(dirs) - 1
|
||||
|
||||
if n_backup > backup.keep:
|
||||
log_message = str(datetime.now()) + ': Removing old backups'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Removing old backups...')
|
||||
dirs.sort()
|
||||
|
||||
err_flag = 0
|
||||
|
||||
for i in range(n_backup-backup.keep):
|
||||
try:
|
||||
rmtree(backup.backup_dev + '/simple_backup/' + dirs[i])
|
||||
log_message = 'Removed backup: ' + dirs[i]
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
except:
|
||||
err_message = 'Error while removing backup ' + dirs[i]
|
||||
backup.errfile.write(err_message)
|
||||
backup.errfile.write('\n')
|
||||
err_flag = 1
|
||||
|
||||
if err_flag:
|
||||
print(err_message)
|
||||
|
||||
backup.logfile.close()
|
||||
backup.errfile.close()
|
||||
backup.warnfile.close()
|
||||
|
||||
backup.exec_()
|
||||
|
||||
# Update the logs
|
||||
backup.logfile = open(backup.log_path, 'a')
|
||||
|
||||
if os.stat(backup.err_path).st_size > 0:
|
||||
log_message = str(datetime.now()) + ': Backup finished with errors'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Backup finished with errors')
|
||||
elif os.stat(backup.warn_path).st_size > 0:
|
||||
log_message = str(datetime.now()) + ': Backup finished with warnings'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Backup finished (warnings)')
|
||||
else:
|
||||
log_message = str(datetime.now()) + ': Backup finished'
|
||||
backup.logfile.write(log_message)
|
||||
backup.logfile.write('\n')
|
||||
print('Backup finished')
|
||||
|
||||
backup.logfile.close()
|
||||
|
||||
# Copy log files in home directory
|
||||
move(backup.log_path, backup.homedir + '/.simple_backup/simple_backup.log')
|
||||
move(backup.err_path, backup.homedir + '/.simple_backup/errors.log')
|
||||
move(backup.warn_path, backup.homedir + '/.simple_backup/warnings.log')
|
||||
|
||||
if islink(backup.backup_dev + '/simple_backup/last_backup'):
|
||||
try:
|
||||
os.remove(backup.backup_dev + '/simple_backup/last_backup')
|
||||
except:
|
||||
print('Failed to remove last_backup link')
|
||||
|
||||
try:
|
||||
os.symlink(backup.backup_dir, backup.backup_dev + '/simple_backup/last_backup')
|
||||
except:
|
||||
print('Failed to create last_backup link')
|
||||
|
||||
# Delete temporary files
|
||||
try:
|
||||
os.remove(backup.inputs_path)
|
||||
os.remove(backup.exclude_path)
|
||||
except:
|
||||
print('Failed to remove temporary files')
|
||||
|
||||
exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,3 @@
|
||||
"""Init."""
|
||||
|
||||
__version__ = '4.3.0'
|
||||
@@ -0,0 +1,22 @@
|
||||
# Example config file for simple_backup
|
||||
|
||||
[backup]
|
||||
# Files and directories to backup. Multiple items can be separated using a comma (','). It is possible to use wildcards (i.e. '*' to match multiple characters and '~' for the user's home directory).
|
||||
inputs=/home/user
|
||||
|
||||
# Output directory. For remote backups, this is a path on the server ('~' and relative paths refer to the home directory on the server).
|
||||
backup_dir=/media/Backup
|
||||
|
||||
# Files, directories and patterns to exclude from the backup. Multiple items can be separated using a comma.
|
||||
exclude=*.bak
|
||||
|
||||
# Number of old backups (i.e. excluding the one that's being created) to keep (use -1 to keep all)
|
||||
keep=-1
|
||||
|
||||
# Uncomment the following section to enable backup to remote server through ssh
|
||||
# [server]
|
||||
# ssh_host=
|
||||
# ssh_user=
|
||||
# ssh_keyfile=
|
||||
# remote_sudo=false
|
||||
# numeric_ids=false
|
||||
Executable
+1031
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user