diff --git a/examples/config.py b/examples/config.py index df1ec79b..faf704bf 100644 --- a/examples/config.py +++ b/examples/config.py @@ -98,28 +98,48 @@ keyaliases['com.example.app'] = 'example' # the @ prefix. keyaliases['com.example.another.plugin'] = '@com.example.another' + # The full path to the root of the repository. It must be specified in # rsync/ssh format for a remote host/path. This is used for syncing a locally # generated repo to the server that is it hosted on. It must end in the # standard public repo name of "/fdroid", but can be in up to three levels of # sub-directories (i.e. /var/www/packagerepos/fdroid). +# # serverwebroot = 'user@example:/var/www/fdroid' + # optionally specific which identity file to use when using rsync over SSH +# # identity_file = '~/.ssh/fdroid_id_rsa' + +# If you are running the repo signing process on a completely offline machine, +# which provides the best security, then you can specify a folder to sync the +# repo to when running `fdroid server update`. This is most likely going to +# be a USB thumb drive, SD Card, or some other kind of removable media. Make +# sure it is mounted before running `fdroid server update`. Using the +# standard folder called 'fdroid' as the specified folder is recommended, like +# with serverwebroot. +# +# local_copy_dir = '/media/MyUSBThumbDrive/fdroid' + + # To upload the repo to an Amazon S3 bucket using `fdroid server update`. # Warning, this deletes and recreates the whole fdroid/ directory each # time. This is based on apache-libcloud, which supports basically all cloud # storage services, so it should be easy to port the fdroid server tools to # any of them. +# # awsbucket = 'myawsfdroid' # awsaccesskeyid = 'SEE0CHAITHEIMAUR2USA' # awssecretkey = 'yourverysecretkeywordpassphraserighthere' + # If you want to force 'fdroid server' to use a non-standard serverwebroot +# # nonstandardwebroot = False + # Wiki details wiki_protocol = "http" wiki_server = "server" diff --git a/fdroidserver/server.py b/fdroidserver/server.py index bddc4b0f..3efe5603 100644 --- a/fdroidserver/server.py +++ b/fdroidserver/server.py @@ -140,6 +140,20 @@ def update_serverwebroot(repo_section): sys.exit(1) +def update_localcopy(repo_section, local_copy_dir): + rsyncargs = ['rsync', '--update', '--recursive', '--delete'] + # use stricter rsync checking on all files since people using offline mode + # are already prioritizing security above ease and speed + rsyncargs += ['--checksum'] + if options.verbose: + rsyncargs += ['--verbose'] + if options.quiet: + rsyncargs += ['--quiet'] + # local_copy_dir is guaranteed to have a trailing slash in main() below + if subprocess.call(rsyncargs + [repo_section, local_copy_dir]) != 0: + sys.exit(1) + + def main(): global config, options @@ -147,6 +161,8 @@ def main(): parser = OptionParser() parser.add_option("-i", "--identity-file", default=None, help="Specify an identity file to provide to SSH for rsyncing") + parser.add_option("--local-copy-dir", default=None, + help="Specify a local folder to sync the repo to") parser.add_option("-v", "--verbose", action="store_true", default=False, help="Spew out even more information than normal") parser.add_option("-q", "--quiet", action="store_true", default=False, @@ -171,15 +187,49 @@ def main(): if config.get('serverwebroot'): serverwebroot = config['serverwebroot'] host, fdroiddir = serverwebroot.rstrip('/').split(':') - serverrepobase = os.path.basename(fdroiddir) - if serverrepobase != 'fdroid' and standardwebroot: + repobase = os.path.basename(fdroiddir) + if standardwebroot and repobase != 'fdroid': logging.error('serverwebroot does not end with "fdroid", ' + 'perhaps you meant one of these:\n\t' + serverwebroot.rstrip('/') + '/fdroid\n\t' - + serverwebroot.rstrip('/').rstrip(serverrepobase) + 'fdroid') + + serverwebroot.rstrip('/').rstrip(repobase) + 'fdroid') sys.exit(1) - elif not config.get('awsbucket'): - logging.warn('No serverwebroot or awsbucket set! Edit your config.py to set one or both.') + + if options.local_copy_dir is not None: + local_copy_dir = options.local_copy_dir + elif config.get('local_copy_dir'): + local_copy_dir = config['local_copy_dir'] + else: + local_copy_dir = None + if local_copy_dir is not None: + fdroiddir = local_copy_dir.rstrip('/') + if os.path.exists(fdroiddir) and not os.path.isdir(fdroiddir): + logging.error('local_copy_dir must be directory, not a file!') + sys.exit(1) + if not os.path.exists(os.path.dirname(fdroiddir)): + logging.error('The root dir for local_copy_dir "' + + os.path.dirname(fdroiddir) + + '" does not exist!') + sys.exit(1) + if not os.path.isabs(fdroiddir): + logging.error('local_copy_dir must be an absolute path!') + sys.exit(1) + repobase = os.path.basename(fdroiddir) + if standardwebroot and repobase != 'fdroid': + logging.error('local_copy_dir does not end with "fdroid", ' + + 'perhaps you meant: ' + fdroiddir + '/fdroid') + sys.exit(1) + if local_copy_dir[-1] != '/': + local_copy_dir += '/' + local_copy_dir = local_copy_dir.replace('//', '/') + if not os.path.exists(fdroiddir): + os.mkdir(fdroiddir) + + if not config.get('awsbucket') \ + and not config.get('serverwebroot') \ + and local_copy_dir is None: + logging.warn('No serverwebroot, local_copy_dir, or awsbucket set!' + + 'Edit your config.py to set at least one.') sys.exit(1) repo_sections = ['repo'] @@ -205,6 +255,8 @@ def main(): update_serverwebroot(repo_section) if config.get('awsbucket'): update_awsbucket(repo_section) + if local_copy_dir is not None: + update_localcopy(repo_section, local_copy_dir) sys.exit(0) diff --git a/tests/run-tests b/tests/run-tests index 72b8b3f3..8cccc044 100755 --- a/tests/run-tests +++ b/tests/run-tests @@ -70,6 +70,41 @@ if [ -z $aapt ]; then aapt=`ls -1 $ANDROID_HOME/build-tools/*/aapt | sort | tail -1` fi +#------------------------------------------------------------------------------# +echo_header "test config checks of local_copy_dir" + +REPOROOT=`create_test_dir` +cd $REPOROOT +$fdroid init +$fdroid update --create-metadata +$fdroid server update --local-copy-dir=/tmp/fdroid + +# now test the errors work +set +e +$fdroid server update --local-copy-dir=thisisnotanabsolutepath +if [ $? -eq 0 ]; then + echo "This should have failed because thisisnotanabsolutepath is not an absolute path!" + exit 1 +else + echo "testing absolute path checker passed" +fi +$fdroid server update --local-copy-dir=/tmp/IReallyDoubtThisPathExistsasdfasdf +if [ $? -eq 0 ]; then + echo "This should have failed because the path does not end with 'fdroid'!" + exit 1 +else + echo "testing dirname exists checker passed" +fi +$fdroid server update --local-copy-dir=/tmp/IReallyDoubtThisPathExistsasdfasdf/fdroid +if [ $? -eq 0 ]; then + echo "This should have failed because the dirname path does not exist!" + exit 1 +else + echo "testing dirname exists checker passed" +fi +set -e + + #------------------------------------------------------------------------------# echo_header "setup a new repo from scratch using ANDROID_HOME"