# -*- coding: utf-8 -*- # ***************************************************************************** # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Module authors: # Markus Zolliker # # ***************************************************************************** import os import sys import shutil from glob import glob from os.path import join, abspath, dirname, expanduser, exists, islink from configparser import ConfigParser from servman import ServiceManager ENV_KEYS = { 'NICOS_CACHE_PORT', 'NICOS_DAEMON_PORT', 'FRAPPY_MAIN_PORT', 'FRAPPY_STICK_PORT', 'FRAPPY_ADDONS_PORT', 'SEA_PORT', } def copy_all(srcdir, dstdir): """copy all files from srcdir to dstdir""" files = glob(join(srcdir, '*')) for src in files: shutil.copy2(src, dstdir) return files class NicosManager(ServiceManager): group = 'nicos' services = ('cache', 'daemon', 'poller') def do_create(self, ins, nr=None, *args): """TODO: redo""" self.get_info() if ins == 'all' or ins == 'check': inslist = list(self.info) else: inslist = [ins] for ins_i in inslist: env = self.env[ins_i] base = join(env['NICOS_ROOT'], env['NICOS_PACKAGE'], ins) nicos_conf = join(base, 'nicos.conf') content = { 'nicos': { 'setup_subdirs': '%s, common, frappy' % ins, 'logging_path': '%s/%s' % (env['NICOS_LOG'], ins), 'pid_path': '%s/%s' % (env['NICOS_LOG'], ins), }, 'environment': { key: env[key] for key in env if key in ENV_KEYS } } try: cp = ConfigParser() cp.optionsxform = str cp.read(nicos_conf) if set(cp.sections) != set(content): oldcontent = None else: oldcontent = {key: cp[key] for key in content} except FileNotFoundError: oldcontent = None if content != oldcontent: cp = ConfigParser() cp.optionsxform = str for key, sdict in content.items(): cp[key] = sdict cp.write(nicos_conf + 'x') # pdir = self.start_dir # if ins is None or ins == 'common': # raise ValueError("nothing to do") # insdict = {info['cache']['port'] % 100: ins_i for ins_i, info in self.info.items()} # nrdict = {v: k for k, v in insdict.items()} # if nr is not None: # nr = int(nr) # if ins == 'all': # if nr is not None: # raise ValueError("'nicos create all' has no argument") # action = 'update' # else: # if nr is None: # nr = nrdict.get(ins) # if nr is None: # raise ValueError('%s not known, has to specified' % ins) # if insdict.get(nr, ins) != ins: # raise ValueError('%d conflicts with %s' % (nr, insdict[nr])) # action = 'create' if ins in insdict.values() else 'update' # insdict = {nr: ins} # for nr, ins in insdict.items(): # print('%s %3d %s %s' % (action, nr, ins, pdir)) # os.makedirs(join(pdir, ins), exist_ok=True) # with open(join(pdir, ins, 'nicos.conf'), 'w') as f: # f.write(NICOS_CONF % dict(insnr='%02d' % nr, ins=ins, sea=8630 + nr, # logroot=os.environ.get('NICOS_LOG'))) # shutil.copyfile(join(pdir, 'common', 'guiconfig.py'), join(pdir, ins, 'guiconfig.py')) @staticmethod def extra_info(ins): try: datadir = join(os.environ.get('NICOS_DATA', '.'), ins) datadir = join(datadir, os.readlink(join(datadir, 'current'))) except FileNotFoundError: return None return 'nicos data: %s' % datadir @staticmethod def linked_dir(current_wd): link = join(current_wd, 'data') if islink(link): return join(link, os.readlink(link)) if exists(link): raise ValueError('%s is not a symlink' % link) return None @staticmethod def handle_linked(target, wd=None): if not target: print('no links from %s' % os.getcwd()) return targetdir = abspath(join(target, '..')) analist_file = join(targetdir, 'data_links.txt') linked_from = [] if exists(analist_file): with open(analist_file) as f: for line in f: line = line.strip() if line and line != wd: if islink(join(line, 'data')): linked_from.append(line) if wd: linked_from.append(wd) linked_from = '\n'.join(linked_from) if wd: with open(analist_file, 'w') as f: f.write('%s\n' % linked_from) print('links to %s from:\n%s' % (target, linked_from)) @staticmethod def make_symlink(ins): data = join(os.environ['NICOS_DATA'], ins) target = join(data, os.readlink(join(data, 'current')), 'data') link = join(os.getcwd(), 'data') if islink(link): os.remove(link) elif exists(link): raise ValueError('%s is not a symlink' % link) os.symlink(target, link, True) NicosManager.handle_linked(target, os.getcwd()) @staticmethod def copy_linked(datadir=None): src = NicosManager.linked_dir(os.getcwd()) if src: if not datadir: if src.rsplit('/', 1)[-1] != 'data': raise ValueError('%s is already a copy' % src) datadir = dirname(src) else: if not datadir: raise ValueError('missing data dir') src = join(datadir, 'data') dst = join(os.getcwd(), '%s_%s_data' % tuple(datadir.rsplit('/', 2)[-2:])) os.makedirs(dst, exist_ok=True) n = len(copy_all(src, dst)) print('copy %d files to %s' % (n, dst)) # copy scripts src = join(datadir, 'scripts') dst = join(dst, 'scripts') os.makedirs(dst, exist_ok=True) n = len(copy_all(src, dst)) print('copy %d files to %s' % (n, dst)) @staticmethod def do_link(ins, *args): """make/show symlink to nicos data in current wd""" if ins is None: NicosManager.handle_linked(NicosManager.linked_dir(os.getcwd())) else: NicosManager.make_symlink(ins) sys.exit(0) @staticmethod def do_copy(ins, year_prop, *args): """copy nicos data to current wd""" if ins is None: NicosManager.copy_linked() else: data = join(os.environ['NICOS_DATA'], ins) if year_prop: year, sep, proposal = year_prop.rpartition('/') if year: src = join(data, year, proposal) else: # get proposal from most recent year src = next(reversed(sorted(glob(join(data, '*', proposal))))) else: src = join(data, os.readlink(join(data, 'current'))) NicosManager.copy_linked(src) def prepare_start(self, ins): start_dir, env = super().prepare_start(ins) instr = '%s.%s' % (env['NICOS_PACKAGE'], ins) env['INSTRUMENT'] = instr start_dir = env.get('NICOS_START', start_dir) return start_dir, env def prepare_client(self, ins): self.check_running(ins, 'daemon') env = self.prepare_start(ins)[1] os.environ.update(env) os.chdir(join(os.environ['NICOS_ROOT'], env['NICOS_PACKAGE'])) def run_client(self, ins, main, app, **kwargs): serverhost = os.environ.get('NICOS_SERVER_HOST', 'localhost') sys.argv[:] = [app, 'guest:guest@%s:%d' % (serverhost, self.info[ins]['daemon'])] sys.exit(main(sys.argv, **kwargs)) def do_cli(self, ins): self.prepare_client(ins) from nicos.clients.cli import main os.environ['NICOS_HISTORY_FILE'] = expanduser('~/.nicoshistory_%s' % ins) self.run_client(ins, main, 'nicos-client', userpath=expanduser('~/.config/nicos_client_%s' % ins)) def do_gui(self, ins): self.prepare_client(ins) from nicos.clients.gui.main import main print('starting nicos gui %s' % ins, expanduser('~/.config/nicos_%s' % ins)) self.run_client(ins, main, 'nicos-gui', instance=ins)