diff --git a/artiq/browser/datasets.py b/artiq/browser/datasets.py index 33bb44ca3..6784d18aa 100644 --- a/artiq/browser/datasets.py +++ b/artiq/browser/datasets.py @@ -1,10 +1,17 @@ +import logging +import asyncio + from PyQt5 import QtCore, QtWidgets from artiq.tools import short_format from artiq.gui.tools import LayoutWidget from artiq.gui.models import DictSyncTreeSepModel +from artiq.protocols.pc_rpc import AsyncioClient as RPCClient -# reduced read-only version of artiq.gui.datasets +# reduced read-only version of artiq.dashboard.datasets + + +logger = logging.getLogger(__name__) class Model(DictSyncTreeSepModel): @@ -16,7 +23,7 @@ class Model(DictSyncTreeSepModel): class DatasetsDock(QtWidgets.QDockWidget): - def __init__(self, datasets_sub): + def __init__(self, datasets_sub, master_host, master_port): QtWidgets.QDockWidget.__init__(self, "Datasets") self.setObjectName("Datasets") self.setFeatures(QtWidgets.QDockWidget.DockWidgetMovable | @@ -36,9 +43,17 @@ class DatasetsDock(QtWidgets.QDockWidget): QtWidgets.QAbstractItemView.SingleSelection) grid.addWidget(self.table, 1, 0) + self.table.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu) + upload_action = QtWidgets.QAction("Upload dataset to master", self.table) + upload_action.triggered.connect(self.upload_clicked) + self.table.addAction(upload_action) + self.set_model(Model(dict())) datasets_sub.add_setmodel_callback(self.set_model) + self.master_host = master_host + self.master_port = master_port + def _search_datasets(self): if hasattr(self, "table_model_filter"): self.table_model_filter.setFilterFixedString( @@ -50,6 +65,31 @@ class DatasetsDock(QtWidgets.QDockWidget): self.table_model_filter.setSourceModel(self.table_model) self.table.setModel(self.table_model_filter) + async def _upload_dataset(self, name, value,): + logger.info("Uploading dataset '%s' to master...", name) + try: + remote = RPCClient() + await remote.connect_rpc(self.master_host, self.master_port, + "master_dataset_db") + try: + await remote.set(name, value) + finally: + remote.close_rpc() + except: + logger.error("Failed uploading dataset '%s'", + name, exc_info=True) + else: + logger.info("Finished uploading dataset '%s'", name) + + def upload_clicked(self): + idx = self.table.selectedIndexes() + if idx: + idx = self.table_model_filter.mapToSource(idx[0]) + key = self.table_model.index_to_key(idx) + if key is not None: + persist, value = self.table_model.backing_store[key] + asyncio.ensure_future(self._upload_dataset(key, value)) + def save_state(self): return bytes(self.table.header().saveState()) diff --git a/artiq/frontend/artiq_browser.py b/artiq/frontend/artiq_browser.py index 9307b69f2..7fd479ac2 100755 --- a/artiq/frontend/artiq_browser.py +++ b/artiq/frontend/artiq_browser.py @@ -14,6 +14,7 @@ from artiq.tools import verbosity_args, atexit_register_coroutine from artiq.gui import state, applets, models, log from artiq.browser import datasets, files, experiments + logger = logging.getLogger(__name__) @@ -30,6 +31,13 @@ def get_argparser(): parser.add_argument("--browse-root", default="", help="root path for directory tree " "(default %(default)s)") + parser.add_argument( + "-s", "--server", default="::1", + help="hostname or IP of the master to connect to " + "when uploading datasets") + parser.add_argument( + "--port", default=3251, type=int, + help="TCP port to use to connect to the master") parser.add_argument("select", metavar="SELECT", nargs="?", help="directory to browse or file to load") verbosity_args(parser) @@ -37,7 +45,8 @@ def get_argparser(): class Browser(QtWidgets.QMainWindow): - def __init__(self, datasets_sub, browse_root, select): + def __init__(self, datasets_sub, browse_root, select, + master_host, master_port): QtWidgets.QMainWindow.__init__(self) icon = QtGui.QIcon(os.path.join(artiq_dir, "gui", "logo.svg")) @@ -69,7 +78,8 @@ class Browser(QtWidgets.QMainWindow): self.applets = applets.AppletsDock(self, datasets_sub) atexit_register_coroutine(self.applets.stop) - self.datasets = datasets.DatasetsDock(datasets_sub) + self.datasets = datasets.DatasetsDock( + datasets_sub, master_host, master_port) self.log = log.LogDock(None, "log") self.log.setFeatures(self.log.DockWidgetMovable | @@ -139,7 +149,8 @@ def main(): smgr = state.StateManager(args.db_file) - main_window = Browser(datasets_sub, args.browse_root, args.select) + main_window = Browser(datasets_sub, args.browse_root, args.select, + args.server, args.port) widget_log_handler.callback = main_window.log.append_message smgr.register(main_window)