mirror of https://github.com/borgbackup/borg.git
Improved documentation.
This commit is contained in:
parent
2ca063124a
commit
f827b99ffe
|
@ -1,14 +1,19 @@
|
|||
.. -*- restructuredtext -*-
|
||||
|
||||
|
||||
What is darc?
|
||||
=============
|
||||
-------------
|
||||
Darc is a Deduplicating ARChiver written in Python. The main goal of darc is
|
||||
to provide an efficient and secure way to backup data. The data deduplication
|
||||
technique used makes darc suitable for taking daily backups.
|
||||
technique used makes darc suitable for daily backups since only actual changes
|
||||
are stored.
|
||||
|
||||
Easy to use
|
||||
~~~~~~~~~~~
|
||||
Initialze backup repository and create a backup archive::
|
||||
|
||||
$ darc init /usbdrive/my-backup.darc
|
||||
$ darc create -v /usbdrive/my-backup.darc::documents ~/Documents
|
||||
|
||||
Main features
|
||||
-------------
|
||||
~~~~~~~~~~~~~
|
||||
Space efficient storage
|
||||
Variable block size deduplication is used to reduce the number of bytes
|
||||
stored by detecting redundant data. Each file is split into a number of
|
||||
|
@ -24,28 +29,28 @@ Off-site backups
|
|||
darc is installed.
|
||||
|
||||
What do I need?
|
||||
===============
|
||||
---------------
|
||||
Darc requires Python 3.2 or above to work. Besides Python darc also requires
|
||||
msgpack-python and sufficiently recent OpenSSL (>= 1.0.0).
|
||||
|
||||
How do I install it?
|
||||
====================
|
||||
--------------------
|
||||
::
|
||||
$ python setup.py install
|
||||
|
||||
Where are the docs?
|
||||
===================
|
||||
Go to http://pythonhosted.org/darc/ for a prebuilt version of the docs. You
|
||||
-------------------
|
||||
Go to https://pythonhosted.org/darc/ for a prebuilt version of the docs. You
|
||||
can also build them yourself form the docs folder.
|
||||
|
||||
Where are the tests?
|
||||
====================
|
||||
--------------------
|
||||
The tests are in the darc/testsuite package. To run the test suite use the
|
||||
following command::
|
||||
|
||||
$ python -m darc.testsuite.run
|
||||
|
||||
Where can I get help?
|
||||
=====================
|
||||
|
||||
Send wishes, comments, patches, etc. to jonas@borgstrom.se
|
||||
---------------------
|
||||
Send questions, comments, patches, etc. to jonas@borgstrom.se. Issues and
|
||||
pull requests can also be created on https://github.com/jborg/darc
|
101
darc/archiver.py
101
darc/archiver.py
|
@ -46,6 +46,8 @@ class Archiver:
|
|||
return RepositoryServer().serve()
|
||||
|
||||
def do_init(self, args):
|
||||
"""Initialize a new repository
|
||||
"""
|
||||
print('Initializing repository at "%s"' % args.repository.orig)
|
||||
repository = self.open_repository(args.repository, create=True)
|
||||
key = key_creator(repository, args)
|
||||
|
@ -57,12 +59,16 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_change_passphrase(self, args):
|
||||
"""Change passphrase on repository key file
|
||||
"""
|
||||
repository = self.open_repository(Location(args.repository))
|
||||
manifest, key = Manifest.load(repository)
|
||||
key.change_passphrase()
|
||||
return self.exit_code
|
||||
|
||||
def do_create(self, args):
|
||||
"""Create new archive
|
||||
"""
|
||||
t0 = datetime.now()
|
||||
repository = self.open_repository(args.archive)
|
||||
manifest, key = Manifest.load(repository)
|
||||
|
@ -150,6 +156,8 @@ class Archiver:
|
|||
self.print_error('Unknown file type: %s', path)
|
||||
|
||||
def do_extract(self, args):
|
||||
"""Extract archive contents
|
||||
"""
|
||||
repository = self.open_repository(args.archive)
|
||||
manifest, key = Manifest.load(repository)
|
||||
archive = Archive(repository, key, manifest, args.archive.archive,
|
||||
|
@ -174,6 +182,8 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_delete(self, args):
|
||||
"""Delete archive
|
||||
"""
|
||||
repository = self.open_repository(args.archive)
|
||||
manifest, key = Manifest.load(repository)
|
||||
cache = Cache(repository, key, manifest)
|
||||
|
@ -182,6 +192,8 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_list(self, args):
|
||||
"""List archive or repository contents
|
||||
"""
|
||||
repository = self.open_repository(args.src)
|
||||
manifest, key = Manifest.load(repository)
|
||||
if args.src.archive:
|
||||
|
@ -214,6 +226,8 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_verify(self, args):
|
||||
"""Verify archive consistency
|
||||
"""
|
||||
repository = self.open_repository(args.archive)
|
||||
manifest, key = Manifest.load(repository)
|
||||
archive = Archive(repository, key, manifest, args.archive.archive)
|
||||
|
@ -234,6 +248,8 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_info(self, args):
|
||||
"""Show archive details such as disk space used
|
||||
"""
|
||||
repository = self.open_repository(args.archive)
|
||||
manifest, key = Manifest.load(repository)
|
||||
cache = Cache(repository, key, manifest)
|
||||
|
@ -249,6 +265,8 @@ class Archiver:
|
|||
return self.exit_code
|
||||
|
||||
def do_prune(self, args):
|
||||
"""Prune repository archives according to specified rules
|
||||
"""
|
||||
repository = self.open_repository(args.repository)
|
||||
manifest, key = Manifest.load(repository)
|
||||
cache = Cache(repository, key, manifest)
|
||||
|
@ -294,7 +312,7 @@ class Archiver:
|
|||
common_parser = argparse.ArgumentParser(add_help=False)
|
||||
common_parser.add_argument('-v', '--verbose', dest='verbose', action='store_true',
|
||||
default=False,
|
||||
help='Verbose output')
|
||||
help='verbose output')
|
||||
|
||||
parser = argparse.ArgumentParser(description='Darc - Deduplicating Archiver')
|
||||
subparsers = parser.add_subparsers(title='Available subcommands')
|
||||
|
@ -302,104 +320,113 @@ class Archiver:
|
|||
subparser = subparsers.add_parser('serve', parents=[common_parser])
|
||||
subparser.set_defaults(func=self.do_serve)
|
||||
|
||||
subparser = subparsers.add_parser('init', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('init', parents=[common_parser],
|
||||
description=self.do_init.__doc__)
|
||||
subparser.set_defaults(func=self.do_init)
|
||||
subparser.add_argument('repository',
|
||||
type=location_validator(archive=False),
|
||||
help='Repository to create')
|
||||
help='repository to create')
|
||||
subparser.add_argument('--key-file', dest='keyfile',
|
||||
action='store_true', default=False,
|
||||
help='Encrypt data using key file')
|
||||
help='enable key file based encryption')
|
||||
subparser.add_argument('--passphrase', dest='passphrase',
|
||||
action='store_true', default=False,
|
||||
help='Encrypt data using passphrase derived keys')
|
||||
help='enable passphrase based encryption')
|
||||
|
||||
subparser = subparsers.add_parser('change-passphrase', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('change-passphrase', parents=[common_parser],
|
||||
description=self.do_change_passphrase.__doc__)
|
||||
subparser.set_defaults(func=self.do_change_passphrase)
|
||||
subparser.add_argument('repository', type=location_validator(archive=False))
|
||||
|
||||
subparser = subparsers.add_parser('create', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('create', parents=[common_parser],
|
||||
description=self.do_create.__doc__)
|
||||
subparser.set_defaults(func=self.do_create)
|
||||
subparser.add_argument('-s', '--stats', dest='stats',
|
||||
action='store_true', default=False,
|
||||
help='Print statistics for the created archive')
|
||||
help='print statistics for the created archive')
|
||||
subparser.add_argument('-e', '--exclude', dest='excludes',
|
||||
type=ExcludePattern, action='append',
|
||||
help='Exclude condition')
|
||||
metavar="PATTERN", help='exclude paths matching PATTERN')
|
||||
subparser.add_argument('-c', '--checkpoint-interval', dest='checkpoint_interval',
|
||||
type=int, default=300, metavar='SECONDS',
|
||||
help='Write checkpointe ever SECONDS seconds (Default: 300)')
|
||||
help='write checkpointe ever SECONDS seconds (Default: 300)')
|
||||
subparser.add_argument('--do-not-cross-mountpoints', dest='dontcross',
|
||||
action='store_true', default=False,
|
||||
help='Do not cross mount points')
|
||||
help='do not cross mount points')
|
||||
subparser.add_argument('--numeric-owner', dest='numeric_owner',
|
||||
action='store_true', default=False,
|
||||
help='Only store numeric user and group identifiers')
|
||||
help='only store numeric user and group identifiers')
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='Archive to create')
|
||||
help='archive to create')
|
||||
subparser.add_argument('paths', metavar='PATH', nargs='+', type=str,
|
||||
help='Paths to archive')
|
||||
help='paths to archive')
|
||||
|
||||
subparser = subparsers.add_parser('extract', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('extract', parents=[common_parser],
|
||||
description=self.do_extract.__doc__)
|
||||
subparser.set_defaults(func=self.do_extract)
|
||||
subparser.add_argument('-e', '--exclude', dest='excludes',
|
||||
type=ExcludePattern, action='append',
|
||||
help='Exclude condition')
|
||||
metavar="PATTERN", help='exclude paths matching PATTERN')
|
||||
subparser.add_argument('--numeric-owner', dest='numeric_owner',
|
||||
action='store_true', default=False,
|
||||
help='Only obey numeric user and group identifiers')
|
||||
help='only obey numeric user and group identifiers')
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='Archive to extract')
|
||||
help='archive to extract')
|
||||
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
||||
help='Paths to extract')
|
||||
help='paths to extract')
|
||||
|
||||
subparser = subparsers.add_parser('delete', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('delete', parents=[common_parser],
|
||||
description=self.do_delete.__doc__)
|
||||
subparser.set_defaults(func=self.do_delete)
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='Archive to delete')
|
||||
help='archive to delete')
|
||||
|
||||
subparser = subparsers.add_parser('list', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('list', parents=[common_parser],
|
||||
description=self.do_list.__doc__)
|
||||
subparser.set_defaults(func=self.do_list)
|
||||
subparser.add_argument('src', metavar='SRC', type=location_validator(),
|
||||
help='Repository/Archive to list contents of')
|
||||
help='repository/Archive to list contents of')
|
||||
|
||||
subparser = subparsers.add_parser('verify', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('verify', parents=[common_parser],
|
||||
description=self.do_verify.__doc__)
|
||||
subparser.set_defaults(func=self.do_verify)
|
||||
subparser.add_argument('-e', '--exclude', dest='excludes',
|
||||
type=ExcludePattern, action='append',
|
||||
help='Include condition')
|
||||
metavar="PATTERN", help='exclude paths matching PATTERN')
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='Archive to verity integrity of')
|
||||
help='archive to verity integrity of')
|
||||
subparser.add_argument('paths', metavar='PATH', nargs='*', type=str,
|
||||
help='Paths to verify')
|
||||
help='paths to verify')
|
||||
|
||||
subparser = subparsers.add_parser('info', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('info', parents=[common_parser],
|
||||
description=self.do_info.__doc__)
|
||||
subparser.set_defaults(func=self.do_info)
|
||||
subparser.add_argument('archive', metavar='ARCHIVE',
|
||||
type=location_validator(archive=True),
|
||||
help='Archive to display information about')
|
||||
help='archive to display information about')
|
||||
|
||||
subparser = subparsers.add_parser('prune', parents=[common_parser])
|
||||
subparser = subparsers.add_parser('prune', parents=[common_parser],
|
||||
description=self.do_prune.__doc__)
|
||||
subparser.set_defaults(func=self.do_prune)
|
||||
subparser.add_argument('-H', '--hourly', dest='hourly', type=int, default=0,
|
||||
help='Number of hourly archives to keep')
|
||||
help='number of hourly archives to keep')
|
||||
subparser.add_argument('-d', '--daily', dest='daily', type=int, default=0,
|
||||
help='Number of daily archives to keep')
|
||||
help='number of daily archives to keep')
|
||||
subparser.add_argument('-w', '--weekly', dest='weekly', type=int, default=0,
|
||||
help='Number of daily archives to keep')
|
||||
help='number of daily archives to keep')
|
||||
subparser.add_argument('-m', '--monthly', dest='monthly', type=int, default=0,
|
||||
help='Number of monthly archives to keep')
|
||||
help='number of monthly archives to keep')
|
||||
subparser.add_argument('-y', '--yearly', dest='yearly', type=int, default=0,
|
||||
help='Number of yearly archives to keep')
|
||||
help='number of yearly archives to keep')
|
||||
subparser.add_argument('-p', '--prefix', dest='prefix', type=str,
|
||||
help='Only consider archive names starting with this prefix')
|
||||
help='only consider archive names starting with this prefix')
|
||||
subparser.add_argument('repository', metavar='REPOSITORY',
|
||||
type=location_validator(archive=False),
|
||||
help='Repository to prune')
|
||||
help='repository to prune')
|
||||
args = parser.parse_args(args or ['-h'])
|
||||
self.verbose = args.verbose
|
||||
return args.func(args)
|
||||
|
|
|
@ -37,6 +37,7 @@ clean:
|
|||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
./update_usage.sh
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
@ -138,4 +139,4 @@ gh-pages: html
|
|||
rm -rf $$GH_PAGES_CLONE
|
||||
|
||||
inotify:
|
||||
while inotifywait -r .; do make html ; done
|
||||
while inotifywait -r . --exclude usage.rst --exclude '_build/*' ; do make html ; done
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
.. include:: global.rst.inc
|
||||
.. _detailed_usage:
|
||||
|
||||
Detailed Usage
|
||||
--------------
|
||||
|
||||
|project_name| consists of a number of subcommands. Each subcommand accepts
|
||||
a number of arguments and options. The following sections will describe each
|
||||
subcommand in detail.
|
||||
|
||||
.. include:: usage.rst
|
|
@ -5,7 +5,8 @@ General Usage
|
|||
=============
|
||||
|
||||
The following examples showcases how to use |project_name| to backup some
|
||||
important files from a users home directory.
|
||||
important files from a users home directory (for more detailed information
|
||||
about each subcommand see the :ref:`detailed_usage` section).
|
||||
|
||||
Initialize a local :ref:`repository <repository_def>` to store backup
|
||||
:ref:`archives <archive_def>` in (See :ref:`encrypted_repos` and
|
||||
|
|
|
@ -5,7 +5,7 @@ Darc
|
|||
|project_name| is a Deduplicating ARChiver written in Python.
|
||||
The main goal of |project_name| is to provide an efficient and secure way
|
||||
to backup data. The data deduplication technique used makes |project_name|
|
||||
suitable for taking daily backups.
|
||||
suitable for daily backups since only actual changes are stored.
|
||||
|
||||
Main Features
|
||||
-------------
|
||||
|
@ -49,8 +49,9 @@ User's Guide
|
|||
|
||||
installation
|
||||
generalusage
|
||||
detailedusage
|
||||
faq
|
||||
definitions
|
||||
terminology
|
||||
|
||||
Contribute
|
||||
==========
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
.. _definitions:
|
||||
.. _terminology:
|
||||
.. include:: global.rst.inc
|
||||
|
||||
Definitions
|
||||
Terminology
|
||||
===========
|
||||
|
||||
.. _deduplication_def:
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/bash
|
||||
echo -n > usage.rst
|
||||
for cmd in init create extract delete prune verify change-passphrase; do
|
||||
echo -e ".. _usage_darc_$cmd:\n\ndarc $cmd\n~~~~~~\n::\n" >> usage.rst
|
||||
darc $cmd -h >> usage.rst
|
||||
done
|
|
@ -0,0 +1,147 @@
|
|||
.. _usage_darc_init:
|
||||
|
||||
darc init
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc init [-h] [-v] [--key-file] [--passphrase] repository
|
||||
|
||||
Initialize a new repository
|
||||
|
||||
positional arguments:
|
||||
repository repository to create
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
--key-file enable key file based encryption
|
||||
--passphrase enable passphrase based encryption
|
||||
.. _usage_darc_create:
|
||||
|
||||
darc create
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc create [-h] [-v] [-s] [-e PATTERN] [-c SECONDS]
|
||||
[--do-not-cross-mountpoints] [--numeric-owner]
|
||||
ARCHIVE PATH [PATH ...]
|
||||
|
||||
Create new archive
|
||||
|
||||
positional arguments:
|
||||
ARCHIVE archive to create
|
||||
PATH paths to archive
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
-s, --stats print statistics for the created archive
|
||||
-e PATTERN, --exclude PATTERN
|
||||
exclude paths matching PATTERN
|
||||
-c SECONDS, --checkpoint-interval SECONDS
|
||||
write checkpointe ever SECONDS seconds (Default: 300)
|
||||
--do-not-cross-mountpoints
|
||||
do not cross mount points
|
||||
--numeric-owner only store numeric user and group identifiers
|
||||
.. _usage_darc_extract:
|
||||
|
||||
darc extract
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc extract [-h] [-v] [-e PATTERN] [--numeric-owner]
|
||||
ARCHIVE [PATH [PATH ...]]
|
||||
|
||||
Extract archive contents
|
||||
|
||||
positional arguments:
|
||||
ARCHIVE archive to extract
|
||||
PATH paths to extract
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
-e PATTERN, --exclude PATTERN
|
||||
exclude paths matching PATTERN
|
||||
--numeric-owner only obey numeric user and group identifiers
|
||||
.. _usage_darc_delete:
|
||||
|
||||
darc delete
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc delete [-h] [-v] ARCHIVE
|
||||
|
||||
Delete archive
|
||||
|
||||
positional arguments:
|
||||
ARCHIVE archive to delete
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
.. _usage_darc_prune:
|
||||
|
||||
darc prune
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc prune [-h] [-v] [-H HOURLY] [-d DAILY] [-w WEEKLY] [-m MONTHLY]
|
||||
[-y YEARLY] [-p PREFIX]
|
||||
REPOSITORY
|
||||
|
||||
Prune repository archives according to specified rules
|
||||
|
||||
positional arguments:
|
||||
REPOSITORY repository to prune
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
-H HOURLY, --hourly HOURLY
|
||||
number of hourly archives to keep
|
||||
-d DAILY, --daily DAILY
|
||||
number of daily archives to keep
|
||||
-w WEEKLY, --weekly WEEKLY
|
||||
number of daily archives to keep
|
||||
-m MONTHLY, --monthly MONTHLY
|
||||
number of monthly archives to keep
|
||||
-y YEARLY, --yearly YEARLY
|
||||
number of yearly archives to keep
|
||||
-p PREFIX, --prefix PREFIX
|
||||
only consider archive names starting with this prefix
|
||||
.. _usage_darc_verify:
|
||||
|
||||
darc verify
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc verify [-h] [-v] [-e PATTERN] ARCHIVE [PATH [PATH ...]]
|
||||
|
||||
Verify archive consistency
|
||||
|
||||
positional arguments:
|
||||
ARCHIVE archive to verity integrity of
|
||||
PATH paths to verify
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
||||
-e PATTERN, --exclude PATTERN
|
||||
exclude paths matching PATTERN
|
||||
.. _usage_darc_change-passphrase:
|
||||
|
||||
darc change-passphrase
|
||||
~~~~~~
|
||||
::
|
||||
|
||||
usage: darc change-passphrase [-h] [-v] repository
|
||||
|
||||
Change passphrase on repository key file
|
||||
|
||||
positional arguments:
|
||||
repository
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-v, --verbose verbose output
|
5
setup.py
5
setup.py
|
@ -1,5 +1,4 @@
|
|||
# -*- encoding: utf-8 *-*
|
||||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
from glob import glob
|
||||
|
@ -45,6 +44,9 @@ except ImportError:
|
|||
if not os.path.exists(chunker_source) or not os.path.exists(hashindex_source):
|
||||
raise ImportError('The GIT version of darc needs Cython. Install Cython or use a released version')
|
||||
|
||||
with open('README.rst', 'r') as fd:
|
||||
long_description = fd.read()
|
||||
|
||||
setup(
|
||||
name='darc',
|
||||
version=darc.__release__,
|
||||
|
@ -52,6 +54,7 @@ setup(
|
|||
author_email='jonas@borgstrom.se',
|
||||
url='http://github.com/jborg/darc/',
|
||||
description='Deduplicating ARChiver written in Python',
|
||||
long_description=long_description,
|
||||
license='BSD',
|
||||
platforms=['Linux', 'MacOS X'],
|
||||
classifiers=[
|
||||
|
|
Loading…
Reference in New Issue