class CSShellCmd(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self.serverURL = ""
        self.serverName = ""
        self.modificator = None
        self.connected = False
        self.dirty = False
        self.root = "/"

        self.do_connect("")

    def update_prompt(self):
        if self.connected:
            self.prompt = "[" + colorize(self.serverName,
                                         "green") + ":" + self.root + " ]% "
        else:
            self.prompt = "[" + colorize("disconnected",
                                         "red") + ":" + self.root + " ]% "

    def do_connect(self, line):
        """connect
    Connect to the CS
    Usage: connect <URL> (Connect to the CS at the specified URL)
           connect       (Connect to the default CS URL of your config)
    """
        if line == "":
            self.serverURL = gConfigurationData.getMasterServer()
            self.serverName = gConfigurationData.getName()
        else:
            self.serverURL = self.serverName = line

        if self.serverURL == None:
            print "Unable to connect to the default server. Maybe you don't have a proxy ?"
            return self.do_disconnect("")

        print "Trying to connect to " + self.serverURL + "...",

        self.modificator = Modificator(RPCClient(self.serverURL))
        rv = self.modificator.loadFromRemote()
        rv2 = self.modificator.loadCredentials()

        if rv['OK'] == False or rv2['OK'] == False:
            print "failed: ",
            if rv['OK'] == False: print rv['Message']
            else: print rv2['Message']
            self.connected = False
            self.update_prompt()
        else:
class CSShellCmd(cmd.Cmd):

  def __init__(self):
    cmd.Cmd.__init__(self)
    self.serverURL   = ""
    self.serverName  = ""
    self.modificator = None
    self.connected   = False
    self.dirty       = False
    self.root        = "/"

    self.do_connect("")

  def update_prompt(self):
    if self.connected:
      self.prompt = "[" + colorize(self.serverName, "green") + ":" + self.root + " ]% "
    else:
      self.prompt = "[" + colorize("disconnected", "red") + ":" + self.root + " ]% "

  def do_connect(self, line):
    """connect
    Connect to the CS
    Usage: connect <URL> (Connect to the CS at the specified URL)
           connect       (Connect to the default CS URL of your config)
    """
    if line == "":
      self.serverURL  = gConfigurationData.getMasterServer()
      self.serverName = gConfigurationData.getName()
    else:
      self.serverURL  = self.serverName = line

    if self.serverURL == None:
      print "Unable to connect to the default server. Maybe you don't have a proxy ?"
      return self.do_disconnect("")

    print "Trying to connect to " + self.serverURL + "...",

    self.modificator = Modificator(RPCClient(self.serverURL))
    rv               = self.modificator.loadFromRemote()
    rv2              = self.modificator.loadCredentials()

    if rv['OK'] == False or rv2['OK'] == False:
      print "failed: ",
      if rv['OK'] == False: print rv['Message']
      else:                 print rv2['Message']
      self.connected = False
      self.update_prompt()
    else:
Example #3
0
class CSCLI(CLI):
    def __init__(self):
        CLI.__init__(self)
        self.connected = False
        self.masterURL = "unset"
        self.writeEnabled = False
        self.modifiedData = False
        self.rpcClient = None
        self.do_connect()
        if self.connected:
            self.modificator = Modificator(self.rpcClient)
        else:
            self.modificator = Modificator()
        self.indentSpace = 20
        self.backupFilename = "dataChanges"
        # store history
        histfilename = os.path.basename(sys.argv[0])
        historyFile = os.path.expanduser("~/.dirac/%s.history" %
                                         histfilename[0:-3])
        mkDir(os.path.dirname(historyFile))
        if os.path.isfile(historyFile):
            readline.read_history_file(historyFile)
        readline.set_history_length(1000)
        atexit.register(readline.write_history_file, historyFile)

    def start(self):
        if self.connected:
            self.modificator.loadFromRemote()
            retVal = self.modificator.loadCredentials()
            if not retVal['OK']:
                print("There was an error gathering your credentials")
                print(retVal['Message'])
                self._setStatus(False)
        try:
            self.cmdloop()
        except KeyboardInterrupt:
            gLogger.warn("Received a keyboard interrupt.")
            self.do_quit("")

    def _setConnected(self, connected, writeEnabled):
        self.connected = connected
        self.modifiedData = False
        self.writeEnabled = writeEnabled
        if connected:
            if writeEnabled:
                self.prompt = "(%s)-%s> " % (self.masterURL,
                                             colorize("Connected", "green"))
            else:
                self.prompt = "(%s)-%s> " % (
                    self.masterURL, colorize("Connected (RO)", "yellow"))
        else:
            self.prompt = "(%s)-%s> " % (self.masterURL,
                                         colorize("Disconnected", "red"))

    def do_quit(self, dummy):
        """
    Exits the application without sending changes to server

    Usage: quit
    """
        print()
        if self.modifiedData:
            print("Changes are about to be written to file for later use.")
            self.do_writeToFile(self.backupFilename)
            print("Changes written to %s.cfg" % self.backupFilename)
        sys.exit(0)

    def _setStatus(self, connected=True):
        if not connected:
            self.masterURL = "unset"
            self._setConnected(False, False)
        else:
            retVal = self.rpcClient.writeEnabled()
            if retVal['OK']:
                if retVal['Value']:
                    self._setConnected(True, True)
                else:
                    self._setConnected(True, False)
            else:
                print("Server returned an error: %s" % retVal['Message'])
                self._setConnected(True, False)

    def _tryConnection(self):
        print("Trying connection to %s" % self.masterURL)
        try:
            self.rpcClient = ConfigurationClient(url=self.masterURL)
            self._setStatus()
        except Exception as x:
            gLogger.error("Couldn't connect to master CS server",
                          "%s (%s)" % (self.masterURL, str(x)))
            self._setStatus(False)

    def do_connect(self, args=''):
        """
    Connects to configuration master server (in specified url if provided).

    Usage: connect <url>
    """
        if not args or not isinstance(args, six.string_types):
            self.masterURL = gConfigurationData.getMasterServer()
            if self.masterURL != "unknown" and self.masterURL:
                self._tryConnection()
            else:
                self._setStatus(False)
        else:
            splitted = args.split()
            if len(splitted) == 0:
                print("Must specify witch url to connect")
                self._setStatus(False)
            else:
                self.masterURL = splitted[0].strip()
                self._tryConnection()

    def do_sections(self, args):
        """
    Shows all sections with their comments.
    If no section is specified, root is taken.

    Usage: sections <section>
    """
        try:
            argList = args.split()
            if argList:
                baseSection = argList[0].strip()
            else:
                baseSection = "/"
            if not self.modificator.existsSection(baseSection):
                print("Section %s does not exist" % baseSection)
                return
            sectionList = self.modificator.getSections(baseSection)
            if not sectionList:
                print("Section %s is empty" % baseSection)
                return
            for section in sectionList:
                section = "%s/%s" % (baseSection, section)
                self.printPair(section, self.modificator.getComment(section),
                               " #")
        except Exception:
            _showTraceback()

    def do_options(self, args):
        """
    Shows all options and values of a specified section

    Usage: options <section>
    """
        try:
            argList = args.split()
            if argList:
                section = argList[0].strip()
            else:
                print("Which section?")
                return
            if not self.modificator.existsSection(section):
                print("Section %s does not exist" % section)
                return
            optionsList = self.modificator.getOptions(section)
            if not optionsList:
                print("Section %s has no options" % section)
                return
            for option in optionsList:
                _printComment(
                    self.modificator.getComment("%s/%s" % (section, option)))
                self.printPair(
                    option,
                    self.modificator.getValue("%s/%s" % (section, option)),
                    "=")
        except Exception:
            _showTraceback()

    def do_get(self, args):
        """
    Shows value and comment for specified option in section

    Usage: get <path to option>
    """
        try:
            argList = args.split()
            if argList:
                optionPath = argList[0].strip()
            else:
                print("Which option?")
                return
            if self.modificator.existsOption(optionPath):
                option = optionPath.split("/")[-1]
                _printComment(self.modificator.getComment(optionPath))
                self.printPair(option, self.modificator.getValue(optionPath),
                               "=")
            else:
                print("Option %s does not exist" % optionPath)
        except Exception:
            _showTraceback()

    def do_writeToServer(self, dummy):
        """
    Sends changes to server.

    Usage: writeToServer
    """
        if not self.connected:
            print("You are not connected!")
            return
        try:
            if not self.writeEnabled:
                print("This server can't receive data modifications")
                return
            if not self.modifiedData:
                while True:
                    choice = six.moves.input(
                        "Data has not been modified, do you still want to upload changes? yes/no [no]: "
                    )
                    choice = choice.lower()
                    if choice in ("yes", "y"):
                        break
                    else:
                        print("Commit aborted")
                        return

            choice = six.moves.input(
                "Do you really want to send changes to server? yes/no [no]: ")
            choice = choice.lower()
            if choice in ("yes", "y"):
                print("Uploading changes to %s (It may take some seconds)..." %
                      self.masterURL)
                response = self.modificator.commit()
                if response['OK']:
                    self.modifiedData = False
                    print("Data sent to server.")
                    self.modificator.loadFromRemote()
                else:
                    print("Error sending data, server said: %s" %
                          response['Message'])
                return
            else:
                print("Commit aborted")
        except Exception as x:
            _showTraceback()
            print("Could not upload changes. ", str(x))

    def do_set(self, args):
        """
    Sets option's value

    Usage: set <optionPath> <value>...

    From second argument until the last one is considered option's value

    NOTE: If specified section does not exist it is created.
    """
        try:
            argsList = args.split()
            if len(argsList) < 2:
                print("Must specify option and value to use")
                return
            optionPath = argsList[0].strip()
            value = " ".join(argsList[1:]).strip()
            self.modificator.setOptionValue(optionPath, value)
            self.modifiedData = True
        except Exception as x:
            print("Cannot insert value: ", str(x))

    def do_removeOption(self, args):
        """
    Removes an option.

    Usage: removeOption <option>

    There can be empty sections.
    """
        try:
            argsList = args.split()
            if len(argsList) < 1:
                print("Must specify option to delete")
                return
            optionPath = argsList[0].strip()
            choice = six.moves.input(
                "Are you sure you want to delete %s? yes/no [no]: " %
                optionPath)
            choice = choice.lower()
            if choice in ("yes", "y", "true"):
                if self.modificator.removeOption(optionPath):
                    self.modifiedData = True
                else:
                    print("Can't be deleted")
            else:
                print("Aborting removal.")
        except Exception as x:
            print("Error removing option, %s" % str(x))

    def do_removeSection(self, args):
        """
    Removes a section.

    Usage: removeSection <section>
    """
        try:
            argsList = args.split()
            if len(argsList) < 1:
                print("Must specify section to delete")
                return
            section = argsList[0].strip()
            choice = six.moves.input(
                "Are you sure you want to delete %s? yes/no [no]: " % section)
            choice = choice.lower()
            if choice in ("yes", "y", "true"):
                if self.modificator.removeSection(section):
                    self.modifiedData = True
                else:
                    print("Can't be deleted")
            else:
                print("Aborting removal.")
        except Exception as x:
            print("Error removing section, %s" % str(x))

    def do_setComment(self, args):
        """
    Sets option or section's comment. Requested entry MUST exist.

    Usage: set <option/section> <comment>...

    From third argument until the last one is considered option's comment.
    """
        try:
            argsList = args.split()
            if len(argsList) < 2:
                print("Must specify option and value to use")
                return
            entryPath = argsList[0].strip()
            value = " ".join(argsList[1:]).strip()
            self.modificator.setComment(entryPath, value)
            self.modifiedData = True
        except Exception as x:
            print("Cannot insert comment: ", str(x))

    def do_writeToFile(self, args):
        """
    Writes modification to file for later use.

    Usage: writeToFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
        try:
            if len(args) == 0:
                print("Filename to write must be specified!")
                return
            filename = args.split()[0].strip()
            filename = _appendExtensionIfMissing(filename)
            self.modificator.dumpToFile(filename)
        except Exception as x:
            print("Couldn't write to file %s: %s" % (filename, str(x)))

    def do_readFromFile(self, args):
        """
    Reads data from filename to be used. Actual data will be replaced!

    Usage: readFromFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
        try:
            if len(args) == 0:
                print("Filename to read must be specified!")
                return
            filename = args.split()[0].strip()
            filename = _appendExtensionIfMissing(filename)
            self.modificator.loadFromFile(filename)
            self.modifiedData = True
        except Exception as x:
            print("Couldn't read from file %s: %s" % (filename, str(x)))

    def do_mergeFromFile(self, args):
        """
    Reads data from filename and merges it with current data.
    Data read from file has more precedence that current one.

    Usage: mergeFromFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
        try:
            if len(args) == 0:
                print("Filename to read must be specified!")
                return
            filename = args.split()[0].strip()
            filename = _appendExtensionIfMissing(filename)
            self.modificator.mergeFromFile(filename)
            self.modifiedData = True
        except Exception as x:
            _showTraceback()
            print("Couldn't read from file %s: %s" % (filename, str(x)))

    def do_showData(self, dummy):
        """
    Shows the current modified configuration
    Usage: showData
    """
        print(self.modificator)

    def do_showHistory(self, args):
        """
    Shows the last commit history
    Usage: showHistory <update limit>
    """
        try:
            argsList = args.split()
            limit = 100
            if len(argsList) > 0:
                limit = int(argsList[0])
            history = self.modificator.getHistory(limit)
            print("%s recent commits:" % limit)
            for entry in history:
                self.printPair(entry[0], entry[1], "@")
        except Exception:
            _showTraceback()

    def do_showDiffWithServer(self, dummy):
        """
    Shows diff with lastest version in server
    Usage: showDiffWithServer
    """
        try:
            diffData = self.modificator.showCurrentDiff()
            print("Diff with latest from server ( + local - remote )")
            for line in diffData:
                if line[0] in ('-'):
                    print(colorize(line, "red"))
                elif line[0] in ('+'):
                    print(colorize(line, "green"))
                elif line[0] in ('?'):
                    print(colorize(line, "yellow"), end=' ')
        except Exception:
            _showTraceback()

    def do_showDiffBetweenVersions(self, args):
        """
    Shows diff between two versions
    Usage: showDiffBetweenVersions <version 1 with spaces> <version 2 with spaces>
    """
        try:
            argsList = args.split()
            if len(argsList) < 4:
                print("What are the two versions to compare?")
                return
            v1 = " ".join(argsList[0:2])
            v2 = " ".join(argsList[2:4])
            print("Comparing '%s' with '%s' " % (v1, v2))
            diffData = self.modificator.getVersionDiff(v1, v2)
            print("Diff with latest from server ( + %s - %s )" % (v2, v1))
            for line in diffData:
                if line[0] in ('-'):
                    print(colorize(line, "red"))
                elif line[0] in ('+'):
                    print(colorize(line, "green"))
                elif line[0] in ('?'):
                    print(colorize(line, "yellow"), end=' ')
                else:
                    print(line)
        except Exception:
            _showTraceback()

    def do_rollbackToVersion(self, args):
        """
    rolls back to user selected version of the configuration
    Usage: rollbackToVersion <version with spaces>>
    """
        try:
            argsList = args.split()
            if len(argsList) < 2:
                print("What version to rollback?")
                return
            version = " ".join(argsList[0:2])
            choice = six.moves.input(
                "Do you really want to rollback to version %s? yes/no [no]: " %
                version)
            choice = choice.lower()
            if choice in ("yes", "y"):
                response = self.modificator.rollbackToVersion(version)
                if response['OK']:
                    self.modifiedData = False
                    print("Rolled back.")
                    self.modificator.loadFromRemote()
                else:
                    print("Error sending data, server said: %s" %
                          response['Message'])
        except Exception:
            _showTraceback()

    def do_mergeWithServer(self, dummy):
        """
    Shows diff with lastest version in server
    Usage: diffWithServer
    """
        try:
            choice = six.moves.input(
                "Do you want to merge with server configuration? yes/no [no]: "
            )
            choice = choice.lower()
            if choice in ("yes", "y"):
                retVal = self.modificator.mergeWithServer()
                if retVal['OK']:
                    print("Merged")
                else:
                    print("There was an error: ", retVal['Message'])
            else:
                print("Merge aborted")
        except Exception:
            _showTraceback()
Example #4
0
class CSCLI(cmd.Cmd):
    def __init__(self):
        cmd.Cmd.__init__(self)
        self.connected = False
        self.masterURL = "unset"
        self.writeEnabled = False
        self.modifiedData = False
        self.rpcClient = None
        self.do_connect()
        if self.connected:
            self.modificator = Modificator(self.rpcClient)
        else:
            self.modificator = Modificator()
        self.identSpace = 20
        self.backupFilename = "dataChanges"
        self._initSignals()
        #User friendly hack
        self.do_exit = self.do_quit

    def start(self):
        if self.connected:
            self.modificator.loadFromRemote()
            retVal = self.modificator.loadCredentials()
            if not retVal['OK']:
                print "There was an error gathering your credentials"
                print retVal['Message']
                self._setStatus(False)
        try:
            self.cmdloop()
        except KeyboardInterrupt:
            gLogger.warn("Received a keyboard interrupt.")
            self.do_quit("")

    def _initSignals(self):
        """
    Registers signal handlers
    """
        for sigNum in (signal.SIGINT, signal.SIGQUIT, signal.SIGKILL,
                       signal.SIGTERM):
            try:
                signal.signal(sigNum, self.do_quit)
            except:
                pass

    def _setConnected(self, connected, writeEnabled):
        self.connected = connected
        self.modifiedData = False
        self.writeEnabled = writeEnabled
        if connected:
            if writeEnabled:
                self.prompt = "(%s)-%s> " % (self.masterURL,
                                             colorize("Connected", "green"))
            else:
                self.prompt = "(%s)-%s> " % (
                    self.masterURL, colorize("Connected (RO)", "yellow"))
        else:
            self.prompt = "(%s)-%s> " % (self.masterURL,
                                         colorize("Disconnected", "red"))

    def _printPair(self, key, value, separator=":"):
        valueList = value.split("\n")
        print "%s%s%s %s" % (key, " " * (self.identSpace - len(key)),
                             separator, valueList[0].strip())
        for valueLine in valueList[1:-1]:
            print "%s  %s" % (" " * self.identSpace, valueLine.strip())

    def do_quit(self, dummy):
        """
    Exits the application without sending changes to server

    Usage: quit
    """
        if self.modifiedData:
            print "Changes are about to be written to file for later use."
            self.do_writeToFile(self.backupFilename)
            print "Changes written to %s.cfg" % self.backupFilename
        sys.exit(0)

    def do_EOF(self, args):
        """
    Accepts ctrl^D to quit CLI
    """
        print ""
        self.do_quit(args)

    def do_help(self, args):
        """
    Shows help information

    Usage: help <command>

    If no command is specified all commands are shown

    """
        if len(args) == 0:
            print "\nAvailable commands:\n"
            attrList = dir(self)
            attrList.sort()
            for attribute in attrList:
                if attribute.find("do_") == 0:
                    self._printPair(attribute[3:],
                                    getattr(self, attribute).__doc__[1:])
                    print ""
        else:
            command = args.split()[0].strip()
            try:
                obj = getattr(self, "do_%s" % command)
            except:
                print "There's no such %s command" % command
                return
            self._printPair(command, obj.__doc__[1:])


#  def retrieveData( self ):
#    if not self.connected:
#      return False
#    response = self.rpcClient.dumpCompressed()
#    if response[ 'Status' ] == 'OK':
#      self.cDataHolder.loadFromCompressedSource( response[ 'Value' ] )
#      gLogger.info( "Data retrieved from server." )
#      return True
#    else:
#      gLogger.error( "Can't retrieve updated data from server." )
#      return False

    def _setStatus(self, connected=True):
        if not connected:
            self.masterURL = "unset"
            self._setConnected(False, False)
        else:
            retVal = self.rpcClient.writeEnabled()
            if retVal['OK']:
                if retVal['Value'] == True:
                    self._setConnected(True, True)
                else:
                    self._setConnected(True, False)
            else:
                print "Server returned an error: %s" % retVal['Message']
                self._setConnected(True, False)

    def _tryConnection(self):
        print "Trying connection to %s" % self.masterURL
        try:
            self.rpcClient = RPCClient(self.masterURL)
            self._setStatus()
        except Exception, x:
            gLogger.error("Couldn't connect to %s (%s)" %
                          (self.masterURL, str(x)))
            self._setStatus(False)
Example #5
0
class CSCLI( cmd.Cmd ):

  def __init__( self ):
    cmd.Cmd.__init__( self )
    self.connected = False
    self.masterURL = "unset"
    self.writeEnabled = False
    self.modifiedData = False
    self.rpcClient = None
    self.do_connect()
    if self.connected:
      self.modificator = Modificator ( self.rpcClient )
    else:
      self.modificator = Modificator()
    self.identSpace = 20
    self.backupFilename = "dataChanges"
    self._initSignals()
    #User friendly hack
    self.do_exit = self.do_quit
    # store history
    histfilename = os.path.basename(sys.argv[0])
    historyFile = os.path.expanduser( "~/.dirac/%s.history" % histfilename[0:-3])
    if not os.path.exists( os.path.dirname(historyFile) ):
      os.makedirs( os.path.dirname(historyFile) )
    if os.path.isfile( historyFile ):
      readline.read_history_file( historyFile )
    readline.set_history_length(1000)
    atexit.register( readline.write_history_file, historyFile )


  def start( self ):
    if self.connected:
      self.modificator.loadFromRemote()
      retVal = self.modificator.loadCredentials()
      if not retVal[ 'OK' ]:
        print "There was an error gathering your credentials"
        print retVal[ 'Message' ]
        self._setStatus( False )
    try:
      self.cmdloop()
    except KeyboardInterrupt:
      gLogger.warn( "Received a keyboard interrupt." )
      self.do_quit( "" )

  def _initSignals( self ):
    """
    Registers signal handlers
    """
    for sigNum in ( signal.SIGINT, signal.SIGQUIT, signal.SIGKILL, signal.SIGTERM ):
      try:
        signal.signal( sigNum, self.do_quit )
      except:
        pass

  def _setConnected( self, connected, writeEnabled ):
    self.connected = connected
    self.modifiedData = False
    self.writeEnabled = writeEnabled
    if connected:
      if writeEnabled:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected", "green" ) )
      else:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected (RO)", "yellow" ) )
    else:
      self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Disconnected", "red" ) )


  def _printPair( self, key, value, separator = ":" ):
    valueList = value.split( "\n" )
    print "%s%s%s %s" % ( key, " " * ( self.identSpace - len( key ) ), separator, valueList[0].strip() )
    for valueLine in valueList[ 1:-1 ]:
      print "%s  %s" % ( " " * self.identSpace, valueLine.strip() )

  def do_quit( self, dummy ):
    """
    Exits the application without sending changes to server

    Usage: quit
    """
    if self.modifiedData:
      print "Changes are about to be written to file for later use."
      self.do_writeToFile( self.backupFilename )
      print "Changes written to %s.cfg" % self.backupFilename
    sys.exit( 0 )

  def do_EOF( self, args ):
    """
    Accepts ctrl^D to quit CLI
    """
    print ""
    self.do_quit( args )

  def do_help( self, args ):
    """
    Shows help information

    Usage: help <command>

    If no command is specified all commands are shown

    """
    if len( args ) == 0:
      print "\nAvailable commands:\n"
      attrList = dir( self )
      attrList.sort()
      for attribute in attrList:
        if attribute.find( "do_" ) == 0:
          self._printPair( attribute[ 3: ], getattr( self, attribute ).__doc__[ 1: ] )
          print ""
    else:
      command = args.split()[0].strip()
      try:
        obj = getattr( self, "do_%s" % command )
      except:
        print "There's no such %s command" % command
        return
      self._printPair( command, obj.__doc__[1:] )

#  def retrieveData( self ):
#    if not self.connected:
#      return False
#    response = self.rpcClient.dumpCompressed()
#    if response[ 'Status' ] == 'OK':
#      self.cDataHolder.loadFromCompressedSource( response[ 'Value' ] )
#      gLogger.info( "Data retrieved from server." )
#      return True
#    else:
#      gLogger.error( "Can't retrieve updated data from server." )
#      return False

  def _setStatus( self, connected = True ):
    if not connected:
      self.masterURL = "unset"
      self._setConnected( False, False )
    else:
      retVal = self.rpcClient.writeEnabled()
      if retVal[ 'OK' ]:
        if retVal[ 'Value' ] == True:
          self._setConnected( True, True )
        else:
          self._setConnected( True, False )
      else:
        print "Server returned an error: %s" % retVal[ 'Message' ]
        self._setConnected( True, False )

  def _tryConnection( self ):
    print "Trying connection to %s" % self.masterURL
    try:
      self.rpcClient = RPCClient( self.masterURL )
      self._setStatus()
    except Exception, x:
      gLogger.error( "Couldn't connect to master CS server", "%s (%s)" % ( self.masterURL, str( x ) ) )
      self._setStatus( False )
Example #6
0
class CSShellCLI(CLI):
    def __init__(self):
        CLI.__init__(self)
        self.serverURL = ""
        self.serverName = ""
        self.modificator = None
        self.connected = False
        self.dirty = False
        self.root = "/"

        self.do_connect("")

    def update_prompt(self):
        if self.connected:
            self.prompt = "[" + colorize(self.serverName, "green") + ":" + self.root + " ]% "
        else:
            self.prompt = "[" + colorize("disconnected", "red") + ":" + self.root + " ]% "

    def do_connect(self, line):
        """connect
    Connect to the CS
    Usage: connect <URL> (Connect to the CS at the specified URL)
           connect       (Connect to the default CS URL of your config)
    """
        if line == "":
            self.serverURL = gConfigurationData.getMasterServer()
            self.serverName = gConfigurationData.getName()
        else:
            self.serverURL = self.serverName = line

        if self.serverURL == None:
            print "Unable to connect to the default server. Maybe you don't have a proxy ?"
            return self.do_disconnect("")

        print "Trying to connect to " + self.serverURL + "...",

        self.modificator = Modificator(RPCClient(self.serverURL))
        rv = self.modificator.loadFromRemote()
        rv2 = self.modificator.loadCredentials()

        if rv["OK"] == False or rv2["OK"] == False:
            print "failed: ",
            if rv["OK"] == False:
                print rv["Message"]
            else:
                print rv2["Message"]
            self.connected = False
            self.update_prompt()
        else:
            self.connected = True
            self.update_prompt()
            print "done."

    def do_disconnect(self, _line):
        """Disconnect from CS"""
        if self.connected and self.dirty:
            res = raw_input("Do you want to commit your changes into the CS ? [y/N] ")
            if res.lower() in ["y", "yes"]:
                self.do_commit("")

        self.serverURL = self.serverName = ""
        self.modificator = None
        self.connected = False
        self.update_prompt()

    def do_ls(self, line):
        """ls
    List the sections and options of CS of the current root"""
        if self.connected:
            secs = self.modificator.getSections(self.root)
            opts = self.modificator.getOptions(self.root)
            if line.startswith("-") and "l" in line:
                for i in secs:
                    print colorize(i, "blue") + "  "
                for i in opts:
                    print i + " "
            else:
                for i in secs:
                    print colorize(i, "blue") + "  ",
                for i in opts:
                    print i + " ",
                print ""

    def do_cd(self, line):
        """cd
    Go one directory deeper in the CS"""
        # Check if invariant holds
        if self.connected:
            assert self.root == "/" or not self.root.endswith("/")
            assert self.root.startswith("/")
            secs = self.modificator.getSections(self.root)
            if line == "..":
                self.root = os.path.dirname(self.root)
                self.update_prompt()
            else:
                if os.path.normpath(line) in secs:
                    if self.root == "/":
                        self.root = self.root + os.path.normpath(line)
                    else:
                        self.root = self.root + "/" + os.path.normpath(line)
                    self.update_prompt()
                else:
                    print "cd: no such section: " + line

    def complete_cd(self, text, _line, _begidx, _endidx):
        secs = self.modificator.getSections(self.root)
        return [(s + "/") for s in secs if s.startswith(text)]

    def do_cat(self, line):
        """cat
    Read the content of an option in the CS"""
        if self.connected:
            opts = self.modificator.getOptionsDict(self.root)

            if line in opts.keys():
                print opts[line]
            else:
                print "cat: No such option"

    def complete_cat(self, text, _line, _begidx, _endidx):
        opts = self.modificator.getOptions(self.root)
        return [o for o in opts if o.startswith(text)]

    do_less = do_cat
    complete_less = complete_cat

    def do_mkdir(self, line):
        """mkdir
    Create a new section in the CS"""
        if self.connected:
            self.modificator.createSection(self.root + "/" + line)
            self.dirty = True

    complete_mkdir = complete_cd

    def do_rmdir(self, line):
        """rmdir
    Delete a section in the CS"""
        if self.connected:
            self.modificator.removeSection(self.root + "/" + line)
            self.dirty = True

    complete_rmdir = complete_cd

    def do_rm(self, line):
        """rm
    Delete an option in the CS"""
        if self.connected:
            self.modificator.removeOption(self.root + "/" + line)
            self.dirty = True

    complete_rm = complete_cat

    def do_set(self, line):
        """set
    Set an option in the CS (or create it if it does not exists)
    Usage: set <str> to set a string option (will be stored as a string in CS)
           set <str>,<str>,... to set a list option (will be stored as a list in CS)
    """
        if self.connected:
            line = line.split(" ", 2)
            if len(line) != 2:
                print "Usage: set <key> <value>"
            else:
                self.modificator.setOptionValue(self.root + "/" + line[0], line[1])
                self.dirty = True

    complete_set = complete_cat

    def do_unset(self, line):
        """unset
    Unset an option in the CS: Making the option equal to the
    empty string."""
        if self.connected:
            self.modificator.setOptionValue(self.root + "/" + line, "")
            self.dirty = True

    complete_unset = complete_cat

    def do_commit(self, _line):
        """commit
    Commit the modifications to the CS"""
        if self.connected and self.dirty:
            self.modificator.commit()

    def default(self, line):
        """Override [Cmd.default(line)] function."""
        if line == "EOF":
            if self.prompt:
                print
            return self.do_quit(line)
        else:
            cmd.Cmd.default(self, line)

    def do_quit(self, _line):
        """quit
    Quit"""
        self.do_disconnect("")
        CLI.do_quit(self, _line)
Example #7
0
class CSShellCLI(CLI):
    def __init__(self):
        CLI.__init__(self)
        self.serverURL = ""
        self.serverName = ""
        self.modificator = None
        self.connected = False
        self.dirty = False
        self.root = "/"

        self.do_connect("")

    def update_prompt(self):
        if self.connected:
            self.prompt = "[" + colorize(self.serverName,
                                         "green") + ":" + self.root + " ]% "
        else:
            self.prompt = "[" + colorize("disconnected",
                                         "red") + ":" + self.root + " ]% "

    def do_connect(self, line):
        """connect
    Connect to the CS
    Usage: connect <URL> (Connect to the CS at the specified URL)
           connect       (Connect to the default CS URL of your config)
    """
        if line == "":
            self.serverURL = gConfigurationData.getMasterServer()
            self.serverName = gConfigurationData.getName()
        else:
            self.serverURL = self.serverName = line

        if self.serverURL == None:
            print(
                "Unable to connect to the default server. Maybe you don't have a proxy ?"
            )
            return self.do_disconnect("")

        print("Trying to connect to " + self.serverURL + "...", end=' ')

        self.modificator = Modificator(RPCClient(self.serverURL))
        rv = self.modificator.loadFromRemote()
        rv2 = self.modificator.loadCredentials()

        if rv['OK'] == False or rv2['OK'] == False:
            print("failed: ", end=' ')
            if rv['OK'] is False:
                print(rv['Message'])
            else:
                print(rv2['Message'])
            self.connected = False
            self.update_prompt()
        else:
            self.connected = True
            self.update_prompt()
            print("done.")

    def do_disconnect(self, _line):
        """Disconnect from CS"""
        if self.connected and self.dirty:
            res = raw_input(
                "Do you want to commit your changes into the CS ? [y/N] ")
            if res.lower() in ["y", "yes"]:
                self.do_commit("")

        self.serverURL = self.serverName = ""
        self.modificator = None
        self.connected = False
        self.update_prompt()

    def do_ls(self, line):
        """ls
    List the sections and options of CS of the current root"""
        if self.connected:
            secs = self.modificator.getSections(self.root)
            opts = self.modificator.getOptions(self.root)
            if line.startswith("-") and "l" in line:
                for i in secs:
                    print(colorize(i, "blue") + "  ")
                for i in opts:
                    print(i + " ")
            else:
                for i in secs:
                    print(colorize(i, "blue") + "  ", end=' ')
                for i in opts:
                    print(i + " ", end=' ')
                print("")

    def do_cd(self, line):
        """cd
    Go one directory deeper in the CS"""
        # Check if invariant holds
        if self.connected:
            assert (self.root == "/" or not self.root.endswith("/"))
            assert (self.root.startswith("/"))
            secs = self.modificator.getSections(self.root)
            if line == "..":
                self.root = os.path.dirname(self.root)
                self.update_prompt()
            else:
                if os.path.normpath(line) in secs:
                    if self.root == "/":
                        self.root = self.root + os.path.normpath(line)
                    else:
                        self.root = self.root + "/" + os.path.normpath(line)
                    self.update_prompt()
                else:
                    print("cd: no such section: " + line)

    def complete_cd(self, text, _line, _begidx, _endidx):
        secs = self.modificator.getSections(self.root)
        return [(s + "/") for s in secs if s.startswith(text)]

    def do_cat(self, line):
        """cat
    Read the content of an option in the CS"""
        if self.connected:
            opts = self.modificator.getOptionsDict(self.root)

            if line in opts.keys():
                print(opts[line])
            else:
                print("cat: No such option")

    def complete_cat(self, text, _line, _begidx, _endidx):
        opts = self.modificator.getOptions(self.root)
        return [o for o in opts if o.startswith(text)]

    do_less = do_cat
    complete_less = complete_cat

    def do_mkdir(self, line):
        """mkdir
    Create a new section in the CS"""
        if self.connected:
            self.modificator.createSection(self.root + "/" + line)
            self.dirty = True

    complete_mkdir = complete_cd

    def do_rmdir(self, line):
        """rmdir
    Delete a section in the CS"""
        if self.connected:
            self.modificator.removeSection(self.root + "/" + line)
            self.dirty = True

    complete_rmdir = complete_cd

    def do_rm(self, line):
        """rm
    Delete an option in the CS"""
        if self.connected:
            self.modificator.removeOption(self.root + "/" + line)
            self.dirty = True

    complete_rm = complete_cat

    def do_set(self, line):
        """set
    Set an option in the CS (or create it if it does not exists)
    Usage: set <str> to set a string option (will be stored as a string in CS)
           set <str>,<str>,... to set a list option (will be stored as a list in CS)
    """
        if self.connected:
            line = line.split(" ", 2)
            if len(line) != 2:
                print("Usage: set <key> <value>")
            else:
                self.modificator.setOptionValue(self.root + "/" + line[0],
                                                line[1])
                self.dirty = True

    complete_set = complete_cat

    def do_unset(self, line):
        """unset
    Unset an option in the CS: Making the option equal to the
    empty string."""
        if self.connected:
            self.modificator.setOptionValue(self.root + "/" + line, "")
            self.dirty = True

    complete_unset = complete_cat

    def do_commit(self, _line):
        """commit
    Commit the modifications to the CS"""
        if self.connected and self.dirty:
            self.modificator.commit()

    def default(self, line):
        """Override [Cmd.default(line)] function."""
        if line == "EOF":
            if self.prompt:
                print()
            return self.do_quit(line)
        else:
            cmd.Cmd.default(self, line)

    def do_quit(self, _line):
        """quit
    Quit"""
        self.do_disconnect("")
        CLI.do_quit(self, _line)
Example #8
0
class CSCLI( CLI ):

  def __init__( self ):
    CLI.__init__( self )
    self.connected = False
    self.masterURL = "unset"
    self.writeEnabled = False
    self.modifiedData = False
    self.rpcClient = None
    self.do_connect()
    if self.connected:
      self.modificator = Modificator ( self.rpcClient )
    else:
      self.modificator = Modificator()
    self.indentSpace = 20
    self.backupFilename = "dataChanges"
    # store history
    histfilename = os.path.basename(sys.argv[0])
    historyFile = os.path.expanduser( "~/.dirac/%s.history" % histfilename[0:-3])
    if not os.path.exists( os.path.dirname(historyFile) ):
      os.makedirs( os.path.dirname(historyFile) )
    if os.path.isfile( historyFile ):
      readline.read_history_file( historyFile )
    readline.set_history_length(1000)
    atexit.register( readline.write_history_file, historyFile )


  def start( self ):
    if self.connected:
      self.modificator.loadFromRemote()
      retVal = self.modificator.loadCredentials()
      if not retVal[ 'OK' ]:
        print "There was an error gathering your credentials"
        print retVal[ 'Message' ]
        self._setStatus( False )
    try:
      self.cmdloop()
    except KeyboardInterrupt:
      gLogger.warn( "Received a keyboard interrupt." )
      self.do_quit( "" )

  def _setConnected( self, connected, writeEnabled ):
    self.connected = connected
    self.modifiedData = False
    self.writeEnabled = writeEnabled
    if connected:
      if writeEnabled:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected", "green" ) )
      else:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected (RO)", "yellow" ) )
    else:
      self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Disconnected", "red" ) )

  def do_quit( self, dummy ):
    """
    Exits the application without sending changes to server

    Usage: quit
    """
    print
    if self.modifiedData:
      print "Changes are about to be written to file for later use."
      self.do_writeToFile( self.backupFilename )
      print "Changes written to %s.cfg" % self.backupFilename
    sys.exit( 0 )


#  def retrieveData( self ):
#    if not self.connected:
#      return False
#    response = self.rpcClient.dumpCompressed()
#    if response[ 'Status' ] == 'OK':
#      self.cDataHolder.loadFromCompressedSource( response[ 'Value' ] )
#      gLogger.info( "Data retrieved from server." )
#      return True
#    else:
#      gLogger.error( "Can't retrieve updated data from server." )
#      return False

  def _setStatus( self, connected = True ):
    if not connected:
      self.masterURL = "unset"
      self._setConnected( False, False )
    else:
      retVal = self.rpcClient.writeEnabled()
      if retVal[ 'OK' ]:
        if retVal[ 'Value' ] == True:
          self._setConnected( True, True )
        else:
          self._setConnected( True, False )
      else:
        print "Server returned an error: %s" % retVal[ 'Message' ]
        self._setConnected( True, False )

  def _tryConnection( self ):
    print "Trying connection to %s" % self.masterURL
    try:
      self.rpcClient = RPCClient( self.masterURL )
      self._setStatus()
    except Exception, x:
      gLogger.error( "Couldn't connect to master CS server", "%s (%s)" % ( self.masterURL, str( x ) ) )
      self._setStatus( False )
Example #9
0
class CSCLI( CLI ):

  def __init__( self ):
    CLI.__init__( self )
    self.connected = False
    self.masterURL = "unset"
    self.writeEnabled = False
    self.modifiedData = False
    self.rpcClient = None
    self.do_connect()
    if self.connected:
      self.modificator = Modificator ( self.rpcClient )
    else:
      self.modificator = Modificator()
    self.indentSpace = 20
    self.backupFilename = "dataChanges"
    # store history
    histfilename = os.path.basename(sys.argv[0])
    historyFile = os.path.expanduser( "~/.dirac/%s.history" % histfilename[0:-3])
    mkDir(os.path.dirname(historyFile))
    if os.path.isfile( historyFile ):
      readline.read_history_file( historyFile )
    readline.set_history_length(1000)
    atexit.register( readline.write_history_file, historyFile )


  def start( self ):
    if self.connected:
      self.modificator.loadFromRemote()
      retVal = self.modificator.loadCredentials()
      if not retVal[ 'OK' ]:
        print "There was an error gathering your credentials"
        print retVal[ 'Message' ]
        self._setStatus( False )
    try:
      self.cmdloop()
    except KeyboardInterrupt:
      gLogger.warn( "Received a keyboard interrupt." )
      self.do_quit( "" )

  def _setConnected( self, connected, writeEnabled ):
    self.connected = connected
    self.modifiedData = False
    self.writeEnabled = writeEnabled
    if connected:
      if writeEnabled:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected", "green" ) )
      else:
        self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Connected (RO)", "yellow" ) )
    else:
      self.prompt = "(%s)-%s> " % ( self.masterURL, colorize( "Disconnected", "red" ) )

  def do_quit( self, dummy ):
    """
    Exits the application without sending changes to server

    Usage: quit
    """
    print
    if self.modifiedData:
      print "Changes are about to be written to file for later use."
      self.do_writeToFile( self.backupFilename )
      print "Changes written to %s.cfg" % self.backupFilename
    sys.exit( 0 )


#  def retrieveData( self ):
#    if not self.connected:
#      return False
#    response = self.rpcClient.dumpCompressed()
#    if response[ 'Status' ] == 'OK':
#      self.cDataHolder.loadFromCompressedSource( response[ 'Value' ] )
#      gLogger.info( "Data retrieved from server." )
#      return True
#    else:
#      gLogger.error( "Can't retrieve updated data from server." )
#      return False

  def _setStatus( self, connected = True ):
    if not connected:
      self.masterURL = "unset"
      self._setConnected( False, False )
    else:
      retVal = self.rpcClient.writeEnabled()
      if retVal[ 'OK' ]:
        if retVal[ 'Value' ] == True:
          self._setConnected( True, True )
        else:
          self._setConnected( True, False )
      else:
        print "Server returned an error: %s" % retVal[ 'Message' ]
        self._setConnected( True, False )

  def _tryConnection( self ):
    print "Trying connection to %s" % self.masterURL
    try:
      self.rpcClient = RPCClient( self.masterURL )
      self._setStatus()
    except Exception as x:
      gLogger.error( "Couldn't connect to master CS server", "%s (%s)" % ( self.masterURL, str( x ) ) )
      self._setStatus( False )

  def do_connect( self, args = '' ):
    """
    Connects to configuration master server (in specified url if provided).

    Usage: connect <url>
    """
    if not args or type( args ) not in types.StringTypes:
      self.masterURL = gConfigurationData.getMasterServer()
      if self.masterURL != "unknown" and self.masterURL:
        self._tryConnection()
      else:
        self._setStatus( False )
    else:
      splitted = args.split()
      if len( splitted ) == 0:
        print "Must specify witch url to connect"
        self._setStatus( False )
      else:
        self.masterURL = splitted[0].strip()
        self._tryConnection()

  def do_sections( self, args ):
    """
    Shows all sections with their comments.
    If no section is specified, root is taken.

    Usage: sections <section>
    """
    try:
      argList = args.split()
      if argList:
        baseSection = argList[0].strip()
      else:
        baseSection = "/"
      if not self.modificator.existsSection( baseSection ):
        print "Section %s does not exist" % baseSection
        return
      sectionList = self.modificator.getSections( baseSection )
      if not sectionList:
        print "Section %s is empty" % baseSection
        return
      for section in sectionList:
        section = "%s/%s" % ( baseSection, section )
        self.printPair( section, self.modificator.getComment( section ) , " #" )
    except:
      _showTraceback()

  def do_options( self, args ):
    """
    Shows all options and values of a specified section

    Usage: options <section>
    """
    try:
      argList = args.split()
      if argList:
        section = argList[0].strip()
      else:
        print "Which section?"
        return
      if not self.modificator.existsSection( section ):
        print "Section %s does not exist" % section
        return
      optionsList = self.modificator.getOptions( section )
      if not optionsList:
        print "Section %s has no options" % section
        return
      for option in optionsList:
        _printComment( self.modificator.getComment( "%s/%s" % ( section, option ) ) )
        self.printPair( option, self.modificator.getValue( "%s/%s" % ( section, option ) ), "=" )
    except:
      _showTraceback()

  def do_get( self, args ):
    """
    Shows value and comment for specified option in section

    Usage: get <path to option>
    """
    try:
      argList = args.split()
      if argList:
        optionPath = argList[0].strip()
      else:
        print "Which option?"
        return
      if self.modificator.existsOption( optionPath ):
        option = optionPath.split( "/" )[-1]
        _printComment( self.modificator.getComment( optionPath ) )
        self.printPair( option, self.modificator.getValue( optionPath ), "=" )
      else:
        print "Option %s does not exist" % optionPath
    except:
      _showTraceback()

  def do_writeToServer( self, dummy ):
    """
    Sends changes to server.

    Usage: writeToServer
    """
    if not self.connected:
      print "You are not connected!"
      return
    try:
      if not self.writeEnabled:
        print "This server can't receive data modifications"
        return
      if not self.modifiedData:
        while True:
          choice = raw_input( "Data has not been modified, do you still want to upload changes? yes/no [no]: " )
          choice = choice.lower()
          if choice in ( "yes", "y" ):
            break
          else:
            print "Commit aborted"
            return

      choice = raw_input( "Do you really want to send changes to server? yes/no [no]: " )
      choice = choice.lower()
      if choice in ( "yes", "y" ):
        print "Uploading changes to %s (It may take some seconds)..." % self.masterURL
        response = self.modificator.commit()
        if response[ 'OK' ]:
          self.modifiedData = False
          print "Data sent to server."
          self.modificator.loadFromRemote()
        else:
          print "Error sending data, server said: %s" % response['Message']
        return
      else:
        print "Commit aborted"
    except Exception as x:
      _showTraceback()
      print "Could not upload changes. ", str( x )

  def do_set( self, args ):
    """
    Sets option's value

    Usage: set <optionPath> <value>...

    From second argument until the last one is considered option's value

    NOTE: If specified section does not exist it is created.
    """
    try:
      argsList = args.split()
      if len( argsList ) < 2:
        print "Must specify option and value to use"
        return
      optionPath = argsList[0].strip()
      value = " ".join( argsList[1:] ).strip()
      self.modificator.setOptionValue( optionPath, value )
      self.modifiedData = True
    except Exception as x:
      print "Cannot insert value: ", str( x )

  def do_removeOption( self, args ):
    """
    Removes an option.

    Usage: removeOption <option>

    There can be empty sections.
    """
    try:
      argsList = args.split()
      if len( argsList ) < 1:
        print "Must specify option to delete"
        return
      optionPath = argsList[0].strip()
      choice = raw_input( "Are you sure you want to delete %s? yes/no [no]: " % optionPath )
      choice = choice.lower()
      if choice in ( "yes", "y", "true" ):
        if self.modificator.removeOption( optionPath ):
          self.modifiedData = True
        else:
          print "Can't be deleted"
      else:
        print "Aborting removal."
    except Exception as x:
      print "Error removing option, %s" % str( x )

  def do_removeSection( self, args ):
    """
    Removes a section.

    Usage: removeSection <section>
    """
    try:
      argsList = args.split()
      if len( argsList ) < 1:
        print "Must specify section to delete"
        return
      section = argsList[0].strip()
      choice = raw_input( "Are you sure you want to delete %s? yes/no [no]: " % section )
      choice = choice.lower()
      if choice in ( "yes", "y", "true" ):
        if self.modificator.removeSection( section ):
          self.modifiedData = True
        else:
          print "Can't be deleted"
      else:
        print "Aborting removal."
    except Exception as x:
      print "Error removing section, %s" % str( x )

  def do_setComment( self, args ):
    """
    Sets option or section's comment. Requested entry MUST exist.

    Usage: set <option/section> <comment>...

    From third argument until the last one is considered option's comment.
    """
    try:
      argsList = args.split()
      if len( argsList ) < 2:
        print "Must specify option and value to use"
        return
      entryPath = argsList[0].strip()
      value = " ".join( argsList[1:] ).strip()
      self.modificator.setComment( entryPath, value )
      self.modifiedData = True
    except Exception as x:
      print "Cannot insert comment: ", str( x )

  def do_writeToFile( self, args ):
    """
    Writes modification to file for later use.

    Usage: writeToFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
    try:
      if len( args ) == 0:
        print "Filename to write must be specified!"
        return
      filename = args.split()[0].strip()
      filename = _appendExtensionIfMissing( filename )
      self.modificator.dumpToFile( filename )
    except Exception as x:
      print "Couldn't write to file %s: %s" % ( filename, str( x ) )

  def do_readFromFile( self, args ):
    """
    Reads data from filename to be used. Actual data will be replaced!

    Usage: readFromFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
    try:
      if len( args ) == 0:
        print "Filename to read must be specified!"
        return
      filename = args.split()[0].strip()
      filename = _appendExtensionIfMissing( filename )
      self.modificator.loadFromFile( filename )
      self.modifiedData = True
    except Exception as x:
      print "Couldn't read from file %s: %s" % ( filename, str( x ) )

  def do_mergeFromFile( self, args ):
    """
    Reads data from filename and merges it with current data.
    Data read from file has more precedence that current one.

    Usage: mergeFromFile <filename>.cfg

    Note that if a file extension is specified, it is replaced by .cfg suffix.
    If not it is added automatically
    """
    try:
      if len( args ) == 0:
        print "Filename to read must be specified!"
        return
      filename = args.split()[0].strip()
      filename = _appendExtensionIfMissing( filename )
      self.modificator.mergeFromFile( filename )
      self.modifiedData = True
    except Exception as x:
      _showTraceback()
      print "Couldn't read from file %s: %s" % ( filename, str( x ) )

  def do_showData( self, dummy ):
    """
    Shows the current modified configuration
    Usage: showData
    """
    print self.modificator

  def do_showHistory( self, args ):
    """
    Shows the last commit history
    Usage: showHistory <update limit>
    """
    try:
      argsList = args.split()
      limit = 100
      if len( argsList ) > 0:
        limit = int( argsList[0] )
      history = self.modificator.getHistory( limit )
      print "%s recent commits:" % limit
      for entry in history:
        self.printPair( entry[0], entry[1], "@" )
    except:
      _showTraceback()

  def do_showDiffWithServer( self, dummy ):
    """
    Shows diff with lastest version in server
    Usage: showDiffWithServer
    """
    try:
      diffData = self.modificator.showCurrentDiff()
      print "Diff with latest from server ( + local - remote )"
      for line in diffData:
        if line[0] in ( '-' ):
          print colorize( line, "red" )
        elif line[0] in ( '+' ):
          print colorize( line, "green" )
        elif line[0] in ( '?' ):
          print colorize( line, "yellow" ),
        else:
          print line
    except:
      _showTraceback()

  def do_showDiffBetweenVersions( self, args ):
    """
    Shows diff between two versions
    Usage: showDiffBetweenVersions <version 1 with spaces> <version 2 with spaces>
    """
    try:
      argsList = args.split()
      if len( argsList ) < 4:
        print "What are the two versions to compare?"
        return
      v1 = " ".join ( argsList[0:2] )
      v2 = " ".join ( argsList[2:4] )
      print "Comparing '%s' with '%s' " % ( v1, v2 )
      diffData = self.modificator.getVersionDiff( v1, v2 )
      print "Diff with latest from server ( + %s - %s )" % ( v2, v1 )
      for line in diffData:
        if line[0] in ( '-' ):
          print colorize( line, "red" )
        elif line[0] in ( '+' ):
          print colorize( line, "green" )
        elif line[0] in ( '?' ):
          print colorize( line, "yellow" ),
        else:
          print line
    except:
      _showTraceback()

  def do_rollbackToVersion( self, args ):
    """
    rolls back to user selected version of the configuration
    Usage: rollbackToVersion <version with spaces>>
    """
    try:
      argsList = args.split()
      if len( argsList ) < 2:
        print "What version to rollback?"
        return
      version = " ".join ( argsList[0:2] )
      choice = raw_input( "Do you really want to rollback to version %s? yes/no [no]: " % version )
      choice = choice.lower()
      if choice in ( "yes", "y" ):
        response = self.modificator.rollbackToVersion( version )
        if response[ 'OK' ]:
          self.modifiedData = False
          print "Rolled back."
          self.modificator.loadFromRemote()
        else:
          print "Error sending data, server said: %s" % response['Message']
    except:
      _showTraceback()

  def do_mergeWithServer( self, dummy ):
    """
    Shows diff with lastest version in server
    Usage: diffWithServer
    """
    try:
      choice = raw_input( "Do you want to merge with server configuration? yes/no [no]: " )
      choice = choice.lower()
      if choice in ( "yes", "y" ):
        retVal = self.modificator.mergeWithServer()
        if retVal[ 'OK' ]:
          print "Merged"
        else:
          print "There was an error: ", retVal[ 'Message' ]
      else:
        print "Merge aborted"
    except:
      _showTraceback()