Merge branch 'master' of https://github.com/tahoe-lafs/tahoe-lafs into 1432.osx-watchdog-stable.5

This commit is contained in:
Daira Hopwood 2016-08-18 15:50:10 +01:00
commit 6c307f68a0
10 changed files with 92 additions and 53 deletions

1
.gitignore vendored
View File

@ -9,7 +9,6 @@
# these are generated at build time, and never checked in # these are generated at build time, and never checked in
/src/allmydata/_version.py /src/allmydata/_version.py
/src/allmydata/_appname.py
# these are generated too # these are generated too
/bin/tahoe /bin/tahoe

View File

@ -30,19 +30,6 @@ def read_version_py(infname):
VERSION_PY_FILENAME = 'src/allmydata/_version.py' VERSION_PY_FILENAME = 'src/allmydata/_version.py'
version = read_version_py(VERSION_PY_FILENAME) version = read_version_py(VERSION_PY_FILENAME)
APPNAME='tahoe-lafs'
APPNAMEFILE = os.path.join('src', 'allmydata', '_appname.py')
APPNAMEFILESTR = "__appname__ = '%s'" % (APPNAME,)
try:
curappnamefilestr = open(APPNAMEFILE, 'rU').read()
except EnvironmentError:
# No file, or unreadable or something, okay then let's try to write one.
open(APPNAMEFILE, "w").write(APPNAMEFILESTR)
else:
if curappnamefilestr.strip() != APPNAMEFILESTR:
print("Error -- this setup.py file is configured with the 'application name' to be '%s', but there is already a file in place in '%s' which contains the contents '%s'. If the file is wrong, please remove it and setup.py will regenerate it and write '%s' into it." % (APPNAME, APPNAMEFILE, curappnamefilestr, APPNAMEFILESTR))
sys.exit(-1)
# Tahoe's dependencies are managed by the find_links= entry in setup.cfg and # Tahoe's dependencies are managed by the find_links= entry in setup.cfg and
# the _auto_deps.install_requires list, which is used in the call to setup() # the _auto_deps.install_requires list, which is used in the call to setup()
# below. # below.
@ -214,8 +201,8 @@ Warning: no version information found. This may cause tests to fail.
""") """)
def try_from_git(self): def try_from_git(self):
# If we change APPNAME, the release tag names should also change from then on. # If we change the release tag names, we must change this too
versions = versions_from_git(APPNAME + '-') versions = versions_from_git("tahoe-lafs-")
# setup.py might be run by either py2 or py3 (when run by tox, which # setup.py might be run by either py2 or py3 (when run by tox, which
# uses py3 on modern debian/ubuntu distros). We want this generated # uses py3 on modern debian/ubuntu distros). We want this generated
@ -241,7 +228,7 @@ setup_args = {}
if version: if version:
setup_args["version"] = version setup_args["version"] = version
setup(name=APPNAME, setup(name="tahoe-lafs", # also set in __init__.py
description='secure, decentralized, fault-tolerant file store', description='secure, decentralized, fault-tolerant file store',
long_description=open('README.rst', 'rU').read(), long_description=open('README.rst', 'rU').read(),
author='the Tahoe-LAFS project', author='the Tahoe-LAFS project',

View File

@ -30,15 +30,10 @@ except ImportError:
# branch is. This should not happen very often. # branch is. This should not happen very often.
pass pass
__appname__ = "unknown" __appname__ = "tahoe-lafs"
try:
from allmydata._appname import __appname__
except ImportError:
# We're running in a tree that hasn't run "./setup.py". This shouldn't happen.
pass
# __full_version__ is the one that you ought to use when identifying yourself in the # __full_version__ is the one that you ought to use when identifying yourself
# "application" part of the Tahoe versioning scheme: # in the "application" part of the Tahoe versioning scheme:
# https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Versioning # https://tahoe-lafs.org/trac/tahoe-lafs/wiki/Versioning
__full_version__ = __appname__ + '/' + str(__version__) __full_version__ = __appname__ + '/' + str(__version__)

View File

@ -124,6 +124,7 @@ class Client(node.Node, pollmixin.PollMixin):
node.Node.__init__(self, basedir) node.Node.__init__(self, basedir)
# All tub.registerReference must happen *after* we upcall, since # All tub.registerReference must happen *after* we upcall, since
# that's what does tub.setLocation() # that's what does tub.setLocation()
self._magic_folder = None
self.started_timestamp = time.time() self.started_timestamp = time.time()
self.logSource="Client" self.logSource="Client"
self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy() self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy()

View File

@ -2,6 +2,7 @@
import sys, os import sys, os
import os.path import os.path
from collections import deque from collections import deque
from datetime import datetime
import time import time
from twisted.internet import defer, reactor, task from twisted.internet import defer, reactor, task
@ -22,6 +23,7 @@ from allmydata.util.progress import PercentProgress
from allmydata.util.encodingutil import listdir_filepath, to_filepath, \ from allmydata.util.encodingutil import listdir_filepath, to_filepath, \
extend_filepath, unicode_from_filepath, unicode_segments_from, \ extend_filepath, unicode_from_filepath, unicode_segments_from, \
quote_filepath, quote_local_unicode_path, quote_output, FilenameEncodingError quote_filepath, quote_local_unicode_path, quote_output, FilenameEncodingError
from allmydata.util.time_format import format_time
from allmydata.immutable.upload import FileName, Data from allmydata.immutable.upload import FileName, Data
from allmydata import magicfolderdb, magicpath from allmydata import magicfolderdb, magicpath
@ -82,7 +84,18 @@ class MagicFolder(service.MultiService):
self.uploader = Uploader(client, local_path_u, db, upload_dirnode, pending_delay, clock) self.uploader = Uploader(client, local_path_u, db, upload_dirnode, pending_delay, clock)
self.downloader = Downloader(client, local_path_u, db, collective_dirnode, self.downloader = Downloader(client, local_path_u, db, collective_dirnode,
upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending, umask) upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending, umask,
self.set_public_status)
self._public_status = (False, ['Magic folder has not yet started'])
def get_public_status(self):
"""
For the web UI, basically.
"""
return self._public_status
def set_public_status(self, status, *messages):
self._public_status = (status, messages)
def startService(self): def startService(self):
# TODO: why is this being called more than once? # TODO: why is this being called more than once?
@ -719,7 +732,8 @@ class Downloader(QueueMixin, WriteFileMixin):
scan_interval = 3 scan_interval = 3
def __init__(self, client, local_path_u, db, collective_dirnode, def __init__(self, client, local_path_u, db, collective_dirnode,
upload_readonly_dircap, clock, is_upload_pending, umask): upload_readonly_dircap, clock, is_upload_pending, umask,
status_reporter):
QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock, delay=self.scan_interval) QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock, delay=self.scan_interval)
if not IDirectoryNode.providedBy(collective_dirnode): if not IDirectoryNode.providedBy(collective_dirnode):
@ -733,6 +747,7 @@ class Downloader(QueueMixin, WriteFileMixin):
self._upload_readonly_dircap = upload_readonly_dircap self._upload_readonly_dircap = upload_readonly_dircap
self._is_upload_pending = is_upload_pending self._is_upload_pending = is_upload_pending
self._umask = umask self._umask = umask
self._status_reporter = status_reporter
@defer.inlineCallbacks @defer.inlineCallbacks
def start_downloading(self): def start_downloading(self):
@ -750,9 +765,16 @@ class Downloader(QueueMixin, WriteFileMixin):
break break
except Exception as e: except Exception as e:
self._status_reporter(
False, "Initial scan has failed",
"Last tried at %s" % self.nice_current_time(),
)
twlog.msg("Magic Folder failed initial scan: %s" % (e,)) twlog.msg("Magic Folder failed initial scan: %s" % (e,))
yield task.deferLater(self._clock, self.scan_interval, lambda: None) yield task.deferLater(self._clock, self.scan_interval, lambda: None)
def nice_current_time(self):
return format_time(datetime.fromtimestamp(self._clock.seconds()).timetuple())
def stop(self): def stop(self):
self._log("stop") self._log("stop")
self._stopped = True self._stopped = True
@ -839,6 +861,10 @@ class Downloader(QueueMixin, WriteFileMixin):
scan_batch[relpath_u] += [(file_node, metadata)] scan_batch[relpath_u] += [(file_node, metadata)]
else: else:
scan_batch[relpath_u] = [(file_node, metadata)] scan_batch[relpath_u] = [(file_node, metadata)]
self._status_reporter(
True, 'Magic folder is working',
'Last scan: %s' % self.nice_current_time(),
)
d.addCallback(scan_listing) d.addCallback(scan_listing)
d.addBoth(self._logcb, "end of _scan_remote_dmd") d.addBoth(self._logcb, "end of _scan_remote_dmd")
@ -894,9 +920,17 @@ class Downloader(QueueMixin, WriteFileMixin):
x = None x = None
try: try:
x = yield self._scan(None) x = yield self._scan(None)
self._status_reporter(
True, 'Magic folder is working',
'Last scan: %s' % self.nice_current_time(),
)
except Exception as e: except Exception as e:
twlog.msg("Remote scan failed: %s" % (e,)) twlog.msg("Remote scan failed: %s" % (e,))
self._log("_scan failed: %s" % (repr(e),)) self._log("_scan failed: %s" % (repr(e),))
self._status_reporter(
False, 'Remote scan has failed: %s' % str(e),
'Last attempted at %s' % self.nice_current_time(),
)
defer.returnValue(x) defer.returnValue(x)
def _scan(self, ign): def _scan(self, ign):

View File

@ -14,7 +14,7 @@ from allmydata.scripts import runner
from allmydata.client import Client from allmydata.client import Client
from allmydata.test import common_util from allmydata.test import common_util
import allmydata import allmydata
from allmydata._appname import __appname__ from allmydata import __appname__
timeout = 240 timeout = 240

View File

@ -224,6 +224,7 @@ class FakeClient(Client):
# don't upcall to Client.__init__, since we only want to initialize a # don't upcall to Client.__init__, since we only want to initialize a
# minimal subset # minimal subset
service.MultiService.__init__(self) service.MultiService.__init__(self)
self._magic_folder = None
self.all_contents = {} self.all_contents = {}
self.nodeid = "fake_nodeid" self.nodeid = "fake_nodeid"
self.nickname = u"fake_nickname \u263A" self.nickname = u"fake_nickname \u263A"

View File

@ -16,31 +16,26 @@ class MagicFolderWebApi(TokenOnlyWebApi):
req.setHeader("content-type", "application/json") req.setHeader("content-type", "application/json")
data = [] data = []
try: for item in self.client._magic_folder.uploader.get_status():
for item in self.client._magic_folder.uploader.get_status(): d = dict(
d = dict( path=item.relpath_u,
path=item.relpath_u, status=item.status_history()[-1][0],
status=item.status_history()[-1][0], kind='upload',
kind='upload', )
) for (status, ts) in item.status_history():
for (status, ts) in item.status_history(): d[status + '_at'] = ts
d[status + '_at'] = ts d['percent_done'] = item.progress.progress
d['percent_done'] = item.progress.progress data.append(d)
data.append(d)
for item in self.client._magic_folder.downloader.get_status(): for item in self.client._magic_folder.downloader.get_status():
d = dict( d = dict(
path=item.relpath_u, path=item.relpath_u,
status=item.status_history()[-1][0], status=item.status_history()[-1][0],
kind='download', kind='download',
) )
for (status, ts) in item.status_history(): for (status, ts) in item.status_history():
d[status + '_at'] = ts d[status + '_at'] = ts
d['percent_done'] = item.progress.progress d['percent_done'] = item.progress.progress
data.append(d) data.append(d)
except Exception as e:
data.append({
"error": str(e),
})
return simplejson.dumps(data) return simplejson.dumps(data)

View File

@ -186,6 +186,25 @@ class Root(rend.Page):
def data_my_nickname(self, ctx, data): def data_my_nickname(self, ctx, data):
return self.client.nickname return self.client.nickname
def render_magic_folder(self, ctx, data):
if self.client._magic_folder is None:
return T.p()
(ok, messages) = self.client._magic_folder.get_public_status()
if ok:
ctx.fillSlots("magic_folder_status", "yes")
ctx.fillSlots("magic_folder_status_alt", "working")
else:
ctx.fillSlots("magic_folder_status", "no")
ctx.fillSlots("magic_folder_status_alt", "not working")
status = T.ul()
for msg in messages:
status[T.li[str(msg)]]
return ctx.tag[status]
def render_services(self, ctx, data): def render_services(self, ctx, data):
ul = T.ul() ul = T.ul()
try: try:

View File

@ -159,6 +159,14 @@
</div><!--/span--> </div><!--/span-->
</div><!--/row--> </div><!--/row-->
</div> </div>
<div n:render="magic_folder" class="row-fluid">
<h2>
<div class="status-indicator"><img><n:attr name="src">img/connected-<n:slot name="magic_folder_status" />.png</n:attr><n:attr name="alt"><n:slot name="magic_folder_status_alt" /></n:attr></img></div>
Magic Folder
</h2>
</div><!--/row-->
<div class="row-fluid"> <div class="row-fluid">
<h2> <h2>
Connected to <span n:render="string" n:data="connected_storage_servers" /> Connected to <span n:render="string" n:data="connected_storage_servers" />