Improved documentation.

This commit is contained in:
Jonas Borgström 2013-07-05 12:32:56 +02:00
parent 2ca063124a
commit f827b99ffe
11 changed files with 260 additions and 58 deletions

View File

View File

@ -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

View File

@ -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)

View File

@ -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

11
docs/detailedusage.rst Normal file
View File

@ -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

View File

@ -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

View File

@ -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
==========

View File

@ -1,7 +1,7 @@
.. _definitions:
.. _terminology:
.. include:: global.rst.inc
Definitions
Terminology
===========
.. _deduplication_def:

6
docs/update_usage.sh Executable file
View File

@ -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

147
docs/usage.rst Normal file
View File

@ -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

View File

@ -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=[