You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by kl...@apache.org on 2017/07/23 23:46:59 UTC
[2/2] mesos git commit: Moved new Mesos CLI to 'src/python/cli_new'.
Moved new Mesos CLI to 'src/python/cli_new'.
This change allows us to have all Python files under
only two directories : 'src/python/' and 'support/'. This
will improve the structure of our Python code in the future
by sharing configuration files and virtual environments.
Review: https://reviews.apache.org/r/60899
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/09fa758b
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/09fa758b
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/09fa758b
Branch: refs/heads/master
Commit: 09fa758b89d3149ae8910d84377a2656064903a6
Parents: 2d19111
Author: Kevin Klues <kl...@gmail.com>
Authored: Sun Jul 23 16:42:55 2017 -0700
Committer: Kevin Klues <kl...@gmail.com>
Committed: Sun Jul 23 16:45:41 2017 -0700
----------------------------------------------------------------------
src/cli_new/.gitignore | 2 -
src/cli_new/README.md | 83 ----
src/cli_new/activate | 4 -
src/cli_new/bin/main.py | 155 -------
src/cli_new/bin/mesos | 6 -
src/cli_new/bin/mesos-cli-tests | 6 -
src/cli_new/bin/settings.py | 47 ---
src/cli_new/bootstrap | 107 -----
src/cli_new/deactivate | 4 -
src/cli_new/lib/cli/__init__.py | 24 --
src/cli_new/lib/cli/config.py | 64 ---
src/cli_new/lib/cli/docopt.py | 90 ----
src/cli_new/lib/cli/exceptions.py | 25 --
src/cli_new/lib/cli/http.py | 77 ----
src/cli_new/lib/cli/plugins/__init__.py | 22 -
src/cli_new/lib/cli/plugins/base.py | 177 --------
src/cli_new/lib/cli/plugins/config/__init__.py | 22 -
src/cli_new/lib/cli/plugins/config/main.py | 98 -----
src/cli_new/lib/cli/tests/__init__.py | 23 -
src/cli_new/lib/cli/tests/base.py | 422 ------------------
src/cli_new/lib/cli/tests/constants.py | 25 --
src/cli_new/lib/cli/tests/tests.py | 65 ---
src/cli_new/lib/cli/util.py | 259 ------------
src/cli_new/mesos.bash_completion | 46 --
src/cli_new/pip-requirements.txt | 16 -
src/cli_new/pylint.config | 26 --
src/cli_new/tests/main.py | 35 --
src/python/cli_new/README.md | 83 ++++
src/python/cli_new/activate | 4 +
src/python/cli_new/bin/main.py | 155 +++++++
src/python/cli_new/bin/mesos | 6 +
src/python/cli_new/bin/mesos-cli-tests | 6 +
src/python/cli_new/bin/settings.py | 47 +++
src/python/cli_new/bootstrap | 107 +++++
src/python/cli_new/deactivate | 4 +
src/python/cli_new/lib/cli/__init__.py | 24 ++
src/python/cli_new/lib/cli/config.py | 64 +++
src/python/cli_new/lib/cli/docopt.py | 90 ++++
src/python/cli_new/lib/cli/exceptions.py | 25 ++
src/python/cli_new/lib/cli/http.py | 77 ++++
src/python/cli_new/lib/cli/plugins/__init__.py | 22 +
src/python/cli_new/lib/cli/plugins/base.py | 177 ++++++++
.../cli_new/lib/cli/plugins/config/__init__.py | 22 +
.../cli_new/lib/cli/plugins/config/main.py | 98 +++++
src/python/cli_new/lib/cli/tests/__init__.py | 23 +
src/python/cli_new/lib/cli/tests/base.py | 423 +++++++++++++++++++
src/python/cli_new/lib/cli/tests/constants.py | 25 ++
src/python/cli_new/lib/cli/tests/tests.py | 65 +++
src/python/cli_new/lib/cli/util.py | 259 ++++++++++++
src/python/cli_new/mesos.bash_completion | 46 ++
src/python/cli_new/pip-requirements.txt | 16 +
src/python/cli_new/pylint.config | 26 ++
src/python/cli_new/tests/main.py | 35 ++
support/mesos-style.py | 2 +-
54 files changed, 1930 insertions(+), 1931 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/.gitignore
----------------------------------------------------------------------
diff --git a/src/cli_new/.gitignore b/src/cli_new/.gitignore
deleted file mode 100644
index 3ce5f74..0000000
--- a/src/cli_new/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.virtualenv
-*.pyc
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/README.md
----------------------------------------------------------------------
diff --git a/src/cli_new/README.md b/src/cli_new/README.md
deleted file mode 100644
index c5475c7..0000000
--- a/src/cli_new/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Mesos CLI
-
-## Prerequisites
-
-Make sure you have the following prerequisites
-installed on your system before you begin.
-
-```
-python 2.6 or 2.7
-virtualenv
-```
-
-## Getting Started
-
-Once you you have the prerequisites installed, simply
-run the `bootstrap` script from this directory to set
-up a python virtual environment and start running the tool.
-
-```
-$ ./bootstrap
-
-...
-
-Setup complete!
-
-To begin working, simply activate your virtual environment,
-run the CLI, and then deactivate the virtual environment
-when you are done.
-
- $ source activate
- $ mesos <command> [<args>...]
- $ source deactivate
-```
-
-**NOTE:** The virtual environment will also setup bash
-autocomplete for all `mesos` commands.
-
-
-## Running tests
-
-To run the unit tests developed for the Mesos CLI, use
-`mesos-cli-tests`:
-
-```
-$ ./bootstrap
-
-...
-
-Setup complete!
-
-To begin working, simply activate your virtual environment,
-run the CLI, and then deactivate the virtual environment
-when you are done.
-
- $ source activate
- $ mesos-cli-tests
-
-Running the Mesos CLI unit tests
-
-...
-
-OK
-```
-
-
-## Setting up your configuration
-
-In order to use this tool, you will need to create a
-configuration file in your home directory under
-`~/.mesos/config.toml`. A template for this config can be
-seen below:
-
-```
-# The `plugins` is an array listing the absolute paths of the
-# plugins you want to add to the CLI.
-plugins = [
- "</absolute/path/to/plugin-1/directory>",
- "</absolute/path/to/plugin-2/directory>"
-]
-```
-
-You can override the location of this configuration file using
-the environment variable `MESOS_CLI_CONFIG`.
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/activate
----------------------------------------------------------------------
diff --git a/src/cli_new/activate b/src/cli_new/activate
deleted file mode 100644
index 65df76f..0000000
--- a/src/cli_new/activate
+++ /dev/null
@@ -1,4 +0,0 @@
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-source ${DIR}/.virtualenv/bin/activate
-source ${DIR}/.virtualenv/bin/postactivate
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/bin/main.py
----------------------------------------------------------------------
diff --git a/src/cli_new/bin/main.py b/src/cli_new/bin/main.py
deleted file mode 100644
index 5313038..0000000
--- a/src/cli_new/bin/main.py
+++ /dev/null
@@ -1,155 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-This is the main executable of the mesos-cli.
-"""
-
-import sys
-
-import settings
-
-import cli
-
-from cli.docopt import docopt
-from cli.exceptions import CLIException
-
-
-VERSION = "Mesos " + settings.VERSION + " CLI"
-
-SHORT_HELP = "Perform operations on a running Mesos cluster."
-
-USAGE = \
-"""Mesos CLI
-
-Usage:
- mesos (-h | --help)
- mesos --version
- mesos <command> [<args>...]
-
-Options:
- -h --help Show this screen.
- --version Show version info.
-
-Commands:
-{commands}
-See 'mesos help <command>' for more information on a specific command.
-"""
-
-
-def autocomplete(cmds, plugins, config, argv):
- """
- Perform autocomplete for the given input arguments. If not
- completing a top level command (or "help"), this function passes
- the arguments down to the appropriate plugins for per-plugin
- autocompletion.
- """
-
- option = "default"
- current_word = argv[0]
- argv = argv[1:]
-
- if len(argv) > 0 and argv[0] == "help":
- argv = argv[1:]
-
- comp_words = list(cmds.keys()) + ["help"]
- comp_words = cli.util.completions(comp_words, current_word, argv)
- if comp_words != None:
- return (option, comp_words)
-
- plugin = cli.util.get_module(plugins, argv[0])
- plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
-
- return plugin_class(settings, config).__autocomplete_base__(
- current_word,
- argv[1:])
-
-
-def main(argv):
- """
- This is the main function for the Mesos CLI.
- """
-
- # Load the CLI config.
- config = cli.config.Config(settings)
-
- plugins = cli.util.import_modules(
- cli.util.join_plugin_paths(settings, config),
- "plugins")
-
- cmds = {
- cli.util.get_module(plugins, plugin).PLUGIN_NAME:
- cli.util.get_module(plugins, plugin).SHORT_HELP
- for plugin in plugins.keys()
- }
-
- # Parse all incoming arguments using docopt.
- command_strings = ""
- if cmds != {}:
- command_strings = cli.util.format_commands_help(cmds)
- usage = USAGE.format(commands=command_strings)
-
- arguments = docopt(usage, argv=argv, version=VERSION, options_first=True)
-
- cmd = arguments["<command>"]
- argv = arguments["<args>"]
-
- # Use the meta-command `__autocomplete__` to perform
- # autocompletion on the remaining arguments.
- if cmd == "__autocomplete__":
- option = "default"
- comp_words = []
-
- # If there is an error performing the autocomplete, treat it
- # as if we were just unable to complete any words. This avoids
- # passing the erroring stack trace back as the list of words
- # to complete on.
- try:
- option, comp_words = autocomplete(cmds, plugins, config, argv)
- except Exception:
- pass
-
- print option
- print " ".join(comp_words)
-
- # Use the meta-command "help" to print help information for the
- # supplied command and its subcommands.
- elif cmd == "help":
- if len(argv) > 0 and argv[0] in cmds:
- plugin = cli.util.get_module(plugins, argv[0])
- plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
- plugin_class(settings, config).main(argv[1:] + ["--help"])
- else:
- main(["--help"])
-
- # Run the command through its plugin.
- elif cmd in cmds.keys():
- plugin = cli.util.get_module(plugins, cmd)
- plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
- plugin_class(settings, config).main(argv)
-
- # Print help information if no commands match.
- else:
- main(["--help"])
-
-
-if __name__ == "__main__":
- try:
- main(sys.argv[1:])
- except CLIException as exception:
- sys.exit("Error: {error}.".format(error=str(exception)))
- except KeyboardInterrupt:
- pass
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/bin/mesos
----------------------------------------------------------------------
diff --git a/src/cli_new/bin/mesos b/src/cli_new/bin/mesos
deleted file mode 100755
index c5152a2..0000000
--- a/src/cli_new/bin/mesos
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-CURRDIR="$(cd "$(dirname "$0")" && pwd)"
-
-source ${CURRDIR}/../activate
-python ${CURRDIR}/main.py "$@"
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/bin/mesos-cli-tests
----------------------------------------------------------------------
diff --git a/src/cli_new/bin/mesos-cli-tests b/src/cli_new/bin/mesos-cli-tests
deleted file mode 100755
index 07659e0..0000000
--- a/src/cli_new/bin/mesos-cli-tests
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env bash
-
-CURRDIR="$(cd "$(dirname "$0")" && pwd)"
-
-source ${CURRDIR}/../activate
-python ${CURRDIR}/../tests/main.py "$@"
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/bin/settings.py
----------------------------------------------------------------------
diff --git a/src/cli_new/bin/settings.py b/src/cli_new/bin/settings.py
deleted file mode 100644
index d42df04..0000000
--- a/src/cli_new/bin/settings.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-This file defines the default settings of the mesos-cli. It also takes care
-of updating the default configuration from reading environment variables or
-parsing a configuration file.
-"""
-
-import os
-
-
-# There is no version module included in this package. However,
-# when creating an executable using pyinstaller, a version.py
-# file will be autogenerated and inserted into the PYTHONPATH.
-# When this happens we import it to set the VERSION.
-try:
- # pylint: disable=F0401,W0611
- from version import VERSION
-except Exception:
- VERSION = "Development"
-
-# The top-level directory of this project.
-PROJECT_DIR = os.path.join(os.path.dirname(__file__), os.pardir)
-
-# The builtin plugins.
-PLUGINS = [
- os.path.join(PROJECT_DIR, "lib", "mesos", "plugins", "config")
-]
-
-DEFAULT_MESOS_CLI_CONFIG = os.path.join(
- os.path.expanduser("~"),
- ".mesos",
- "config.toml")
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/bootstrap
----------------------------------------------------------------------
diff --git a/src/cli_new/bootstrap b/src/cli_new/bootstrap
deleted file mode 100755
index 4193d3f..0000000
--- a/src/cli_new/bootstrap
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env bash
-
-# This script sets up a Python virtualenv for the Mesos CLI.
-# This creates a new virtualenv, installs the necessary Python
-# dependencies inside the virtualenv, and enables bash auto
-# completion for the Mesos CLI.
-
-set -e
-trap "exit 1" INT
-
-CURRDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-: ${VIRTUALENV_NAME:="mesos-cli"}
-: ${VIRTUALENV_DIRECTORY:="${CURRDIR}/.virtualenv"}
-
-: ${PYTHON:="$(which python)"}
-: ${VIRTUALENV:="$(which virtualenv)"}
-
-OLD_PYTHONPATH="${PYTHONPATH}"
-PYTHONPATH=""
-
-# If we already have a virtual environment activated,
-# bail out and advise the user to deactivate.
-OLD_VIRTUAL_ENV="${VIRTUAL_ENV}"
-if [ "${OLD_VIRTUAL_ENV}" != "" ]; then
- echo "Please deactivate your current virtual environment in order to continue!"
- echo "source deactivate"
- exit 1
-fi
-
-# Verify that python and virtualenv are installed.
-if [ "${PYTHON}" = "" ]; then
- echo "You must have python installed in order to continue..."
- exit 1
-fi
-
-if [ "${VIRTUALENV}" = "" ]; then
- # Search for a locally installed virtualenv.
- # See https://docs.python.org/2/library/site.html#site.USER_SITE for details.
- VIRTUALENV=$(${PYTHON} -c "import site; print site.USER_SITE")/virtualenv.py
-
- if [ ! -f "${VIRTUALENV}" ]; then
- echo "You must have virtualenv installed in order to continue..."
- exit 1
- fi
-fi
-
-PYTHON_MAJOR=$(${PYTHON} -c 'import sys; print(sys.version_info[0])')
-PYTHON_MINOR=$(${PYTHON} -c 'import sys; print(sys.version_info[1])')
-
-if [ "${PYTHON_MAJOR}" != "2" ] || [ "${PYTHON_MINOR}" -lt "6" ]; then
- echo "You must be running python 2.6 or 2.7 in order to continue."
- echo "Consider running as 'PYTHON=python2 ./bootstrap' or similar."
- exit 1
-fi
-
-# Set up a virtual environment for the CLI.
-${PYTHON} ${VIRTUALENV} --python=${PYTHON} \
- --clear \
- --no-site-packages \
- --prompt="(${VIRTUALENV_NAME}) " \
- ${VIRTUALENV_DIRECTORY} || true
-
-source ${VIRTUALENV_DIRECTORY}/bin/activate
-SITE_PACKAGES=$(python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")
-echo ${SITE_PACKAGES}
-echo "${CURRDIR}/lib" > ${SITE_PACKAGES}/_virtualenv_path_extensions.pth
-echo "${CURRDIR}/../python/lib" >> ${SITE_PACKAGES}/_virtualenv_path_extensions.pth
-pip install --upgrade pip
-pip install -r ${CURRDIR}/pip-requirements.txt
-deactivate
-
-# Add custom postactivate / predeactivate scripts to add / remove
-# the bin directory of this project to the current path in the
-# virtual environment (as well as setup bash auto completion).
-cat > ${VIRTUALENV_DIRECTORY}/bin/postactivate << EOF
-#!/usr/bin/env bash
-PROJECT_BIN="${CURRDIR}/bin"
-PATH="\${PROJECT_BIN}:\${PATH}"
-PYTHONPATH=""
-
-EOF
-cat ${CURRDIR}/mesos.bash_completion >> ${VIRTUALENV_DIRECTORY}/bin/postactivate
-
-cat > ${VIRTUALENV_DIRECTORY}/bin/predeactivate << EOF
-#!/usr/bin/env bash
-PROJECT_BIN="${CURDRDIR}/bin"
-PATH=\${PATH/":\${PROJECT_BIN}"/}
-PATH=\${PATH/"\${PROJECT_BIN}:"/}
-PYTHONPATH="${OLD_PYTHONPATH}"
-
-complete -r mesos
-EOF
-
-if [ "${VIRTUALENV_DIRECTORY}" = "${CURRDIR}/.virtualenv" ]; then
- # Print some info about the sucess of the installation.
- echo ""
- echo "Setup complete!"
- echo ""
- echo "To begin working, simply activate your virtual"
- echo "environment and deactivate it when you are done."
- echo ""
- echo " $ source activate"
- echo " $ mesos <command> [<args>...]"
- echo " $ source deactivate"
- echo ""
-fi
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/deactivate
----------------------------------------------------------------------
diff --git a/src/cli_new/deactivate b/src/cli_new/deactivate
deleted file mode 100644
index 3dbe167..0000000
--- a/src/cli_new/deactivate
+++ /dev/null
@@ -1,4 +0,0 @@
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-
-source ${DIR}/.virtualenv/bin/predeactivate
-deactivate
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/__init__.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/__init__.py b/src/cli_new/lib/cli/__init__.py
deleted file mode 100644
index e594b30..0000000
--- a/src/cli_new/lib/cli/__init__.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Mesos CLI Module
-"""
-
-from . import config
-from . import exceptions
-from . import plugins
-from . import util
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/config.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/config.py b/src/cli_new/lib/cli/config.py
deleted file mode 100644
index 36a32f9..0000000
--- a/src/cli_new/lib/cli/config.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Config class to manage the configuration file.
-"""
-
-import os
-import toml
-
-from cli.exceptions import CLIException
-
-
-class Config(object):
- """
- The Config class loads the configuration file on initialization and has
- one method for each element that can be specified in the config file.
- """
-
- def __init__(self, settings):
- # Load the configuration file path for the CLI.
- if os.environ.get("MESOS_CLI_CONFIG"):
- self.path = os.environ["MESOS_CLI_CONFIG"]
- else:
- self.path = settings.DEFAULT_MESOS_CLI_CONFIG
-
- # Load the configuration file as a TOML file.
- try:
- self.data = toml.load(self.path)
- except Exception as exception:
- raise CLIException("Error loading config file as TOML: {error}"
- .format(error=exception))
-
- def plugins(self):
- """
- Parse the plugins listed in the configuration file and return them.
- """
- # Allow extra plugins to be pulled in from the configuration file.
- if "plugins" in self.data:
- if not isinstance(self.data["plugins"], list):
- raise CLIException("Unable to parse config file '{path}':"
- " 'plugins' field must be a list"
- .format(path=self.path))
-
- for plugin in self.data["plugins"]:
- if not os.path.exists(plugin):
- raise CLIException("Plugin path not found: {path}"
- .format(path=plugin))
- return self.data["plugins"]
-
- return []
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/docopt.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/docopt.py b/src/cli_new/lib/cli/docopt.py
deleted file mode 100644
index 86a4e9c..0000000
--- a/src/cli_new/lib/cli/docopt.py
+++ /dev/null
@@ -1,90 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Unfortunately, docopt doesn't support multi-word commands. This is
-important for supporting things like:
-
-mesos cluster ps <args>...
-
-However, it looks like some plans are in place for supporting it in the
-future: https://github.com/docopt/docopt/issues/41
-
-The proposal is to add a "program" keyword argument to docopt to specify the
-full set of words used to represent the command. Since this is not yet
-supported officially, we include the hack below to make it work for us. We
-essentially intercept the call to docopt and make it work with such a "program"
-argument.
-
-To make it work, we inspect the value of "program" and search and replace all
-instances of it in the usage string with a transformed version of it to make it
-a single word (i.e. we replace all spaces with dashes: echo $program | s/
-/-/g). This essentially turns all multi-word commands in the usage string into
-dash-separated single words (e.g., s/mesos cluster ps/mesos-cluster-ps/g). With
-this in place, we then pass this usage string to the original docopt for
-parsing.
-
-Unfortunately, doing things this way means that docopt (by default) will print
-the usage string containing the dashes. To avoid this, we intercept all paths
-where docopt does the printing itself, and transform the usage string back to
-its original form.
-
-Hopefully we can remove this brutal hack at some point in the future
-once docopt supports the "program" argument natively.
-"""
-
-from __future__ import absolute_import
-import os
-import sys
-
-# pylint: disable=F0401
-from docopt import docopt as real_docopt, DocoptExit
-
-
-def docopt(usage, **keywords):
- """ A wrapper around the real docopt parser. """
- new_usage = usage
-
- if "program" in keywords:
- program = keywords.pop("program")
- new_usage = usage.replace(program, program.replace(" ", "-"))
-
- try:
- stdout = sys.stdout
-
- with open(os.devnull, 'w') as nullfile:
- sys.stdout = nullfile
- arguments = real_docopt(new_usage, **keywords)
- sys.stdout = stdout
-
- return arguments
-
- except DocoptExit:
- sys.stdout = stdout
- print >> sys.stderr, usage.strip()
- sys.exit(1)
-
- except SystemExit:
- sys.stdout = stdout
-
- if "argv" in keywords and any(h in ("-h", "--help")
- for h in keywords["argv"]):
- print usage.strip()
- elif "version" in keywords and any(v in ("--version")
- for v in keywords["argv"]):
- print keywords["version"].strip()
-
- sys.exit()
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/exceptions.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/exceptions.py b/src/cli_new/lib/cli/exceptions.py
deleted file mode 100644
index c78f4a9..0000000
--- a/src/cli_new/lib/cli/exceptions.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-CLIException Class
-"""
-
-class CLIException(Exception):
- """
- Exceptions class to handle all CLI errors.
- """
- pass
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/http.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/http.py b/src/cli_new/lib/cli/http.py
deleted file mode 100644
index 03d6031..0000000
--- a/src/cli_new/lib/cli/http.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-A collection of http related functions used by the CLI and its Plugins.
-"""
-
-import json
-import urllib2
-import time
-
-from cli.exceptions import CLIException
-
-
-def read_endpoint(addr, endpoint):
- """
- Read the specified endpoint and return the results.
- """
- try:
- url = "http://{addr}/{endpoint}".format(addr=addr, endpoint=endpoint)
-
- http_response = urllib2.urlopen(url).read().decode("utf-8")
- except Exception as exception:
- raise CLIException("{error}".format(error=str(exception)))
-
- return http_response
-
-
-def get_json(addr, endpoint, condition=None, timeout=5):
- """
- Return the contents of the 'endpoint' at 'addr' as JSON data
- subject to the condition specified in 'condition'. If we are
- unable to read the data or unable to meet the condition within
- 'timeout' seconds we throw an error.
- """
- start_time = time.time()
-
- while True:
- data = None
-
- try:
- data = read_endpoint(addr, endpoint)
- except Exception as exception:
- pass
-
- if data:
- try:
- data = json.loads(data)
- except Exception as exception:
- raise CLIException("Could not load JSON from '{data}': {error}"
- .format(data=data, error=str(exception)))
-
- if not condition:
- return data
-
- if condition(data):
- return data
-
- if time.time() - start_time > timeout:
- raise CLIException("Failed to get data within {seconds} seconds:"
- " {error}"
- .format(seconds=str(timeout), error=exception))
-
- time.sleep(0.1)
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/plugins/__init__.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/plugins/__init__.py b/src/cli_new/lib/cli/plugins/__init__.py
deleted file mode 100644
index e743772..0000000
--- a/src/cli_new/lib/cli/plugins/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Plugins Module
-"""
-
-# pylint: disable=W0401
-from .base import *
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/plugins/base.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/plugins/base.py b/src/cli_new/lib/cli/plugins/base.py
deleted file mode 100644
index edbe1ec..0000000
--- a/src/cli_new/lib/cli/plugins/base.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Plugin's Base Class
-"""
-
-import sys
-
-import cli
-
-from cli.docopt import docopt
-
-
-PLUGIN_NAME = "base-plugin"
-PLUGIN_CLASS = "PluginBase"
-
-VERSION = "Mesos Plugin Base 1.0"
-
-SHORT_HELP = "This is the base plugin from which all other plugins inherit."
-
-USAGE = \
-"""
-{short_help}
-
-Usage:
- mesos {plugin} (-h | --help)
- mesos {plugin} --version
- mesos {plugin} <command> (-h | --help)
- mesos {plugin} <command> [<args>...] [options]
-
-Options:
- -h --help Show this screen.
- --version Show version info.
-
-Commands:
-{commands}
-"""
-
-SUBCOMMAND_USAGE = \
-"""{short_help}
-
-Usage:
- mesos {plugin} {command} (-h | --help)
- mesos {plugin} {command} --version
- mesos {plugin} {command} {arguments} [options]
-
-Options:
-{flags}
-
-Description:
-{long_help}
-"""
-
-
-class PluginBase(object):
- """
- Base class from which all CLI plugins should inherit.
- """
- # pylint: disable=R0903
- COMMANDS = {}
-
- def __setup__(self, command, argv):
- pass
-
- def __module_reference__(self):
- return sys.modules[self.__module__]
-
- def __init__(self, settings, config):
- # pylint: disable=C0103
- self.PLUGIN_NAME = PLUGIN_NAME
- self.PLUGIN_CLASS = PLUGIN_CLASS
- self.VERSION = VERSION
- self.SHORT_HELP = SHORT_HELP
- self.USAGE = USAGE
-
- module = self.__module_reference__()
- if hasattr(module, "PLUGIN_NAME"):
- self.PLUGIN_NAME = getattr(module, "PLUGIN_NAME")
- if hasattr(module, "PLUGIN_CLASS"):
- self.PLUGIN_CLASS = getattr(module, "PLUGIN_CLASS")
- if hasattr(module, "VERSION"):
- self.VERSION = getattr(module, "VERSION")
- if hasattr(module, "SHORT_HELP"):
- self.SHORT_HELP = getattr(module, "SHORT_HELP")
- if hasattr(module, "USAGE"):
- self.USAGE = getattr(module, "USAGE")
-
- self.settings = settings
- self.config = config
-
- def __autocomplete__(self, command, current_word, argv):
- # pylint: disable=W0612,W0613,R0201
- return ("default", [])
-
- def __autocomplete_base__(self, current_word, argv):
- option = "default"
-
- # <command>
- comp_words = list(self.COMMANDS.keys())
- comp_words = cli.util.completions(comp_words, current_word, argv)
- if comp_words != None:
- return (option, comp_words)
-
- # <args>...
- # pylint: disable=R0204
- comp_words = self.__autocomplete__(argv[0], current_word, argv[1:])
-
- # In general, we expect a tuple to be returned from __autocomplete__,
- # with the first element being a valid autocomplete option, and the
- # second being a list of completion words. However, in the common
- # case we usually use the default option, so it's OK for a plugin to
- # just return a list. We will add the "default" option for them.
- if isinstance(comp_words, tuple):
- option, comp_words = comp_words
-
- return (option, comp_words)
-
- def main(self, argv):
- """
- Main method takes argument from top level mesos and parses them
- to call the appropriate method.
- """
- command_strings = cli.util.format_commands_help(self.COMMANDS)
-
- usage = self.USAGE.format(
- plugin=self.PLUGIN_NAME,
- short_help=self.SHORT_HELP,
- commands=command_strings)
-
- arguments = docopt(
- usage,
- argv=argv,
- version=self.VERSION,
- program="mesos " + self.PLUGIN_NAME,
- options_first=True)
-
- cmd = arguments["<command>"]
- argv = arguments["<args>"]
-
- if cmd in self.COMMANDS.keys():
- if "external" not in self.COMMANDS[cmd]:
- argument_format, short_help, long_help, flag_format = \
- cli.util.format_subcommands_help(self.COMMANDS[cmd])
-
- usage = SUBCOMMAND_USAGE.format(
- plugin=self.PLUGIN_NAME,
- command=cmd,
- arguments=argument_format,
- flags=flag_format,
- short_help=short_help,
- long_help=long_help)
-
- arguments = docopt(
- usage,
- argv=argv,
- program="mesos " + self.PLUGIN_NAME + " " + cmd,
- version=self.VERSION,
- options_first=True)
-
- self.__setup__(cmd, argv)
- getattr(self, cmd.replace("-", "_"))(arguments)
- else:
- self.main(["--help"])
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/plugins/config/__init__.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/plugins/config/__init__.py b/src/cli_new/lib/cli/plugins/config/__init__.py
deleted file mode 100644
index cf5673d..0000000
--- a/src/cli_new/lib/cli/plugins/config/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Config module.
-"""
-
-# pylint: disable=wildcard-import
-from .main import *
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/plugins/config/main.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/plugins/config/main.py b/src/cli_new/lib/cli/plugins/config/main.py
deleted file mode 100644
index 41bdb60..0000000
--- a/src/cli_new/lib/cli/plugins/config/main.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-The config plugin.
-"""
-
-import os
-import sys
-
-import cli
-
-from cli.exceptions import CLIException
-from cli.plugins import PluginBase
-from cli.util import Table
-
-
-PLUGIN_NAME = "config"
-PLUGIN_CLASS = "Config"
-
-VERSION = "Mesos CLI Config Plugin"
-
-SHORT_HELP = "Interacts with the Mesos CLI configuration file"
-
-
-class Config(PluginBase):
- """
- The config plugin.
- """
-
- COMMANDS = {
- "plugins": {
- "arguments": [],
- "flags": {},
- "short_help": "Print the plugins that can be used.",
- "long_help": "Print the plugins that can be used."
- },
- "show": {
- "arguments": [],
- "flags": {},
- "short_help": "Show the contents of the configuration file.",
- "long_help": "Show the contents of the configuration file."
- }
- }
-
- def plugins(self, argv):
- """
- Parse and load the builtin plugins and the ones in the configuration
- file. If this method is called using 'mesos config plugins', it
- displays the plugins that can be used.
- """
- # pylint: disable=unused-argument
- plugins_table = Table(["NAME", "DESCRIPTION"])
-
- # Load the plugins
- plugins = cli.util.import_modules(
- cli.util.join_plugin_paths(self.settings, self.config),
- "plugins")
-
- for plugin in plugins:
- plugins_table.add_row([
- cli.util.get_module(plugins, plugin).PLUGIN_NAME,
- cli.util.get_module(plugins, plugin).SHORT_HELP
- ])
- sys.stdout.write("{}\n".format(plugins_table))
-
- def show(self, argv):
- """
- Show the contents of the configuration file.
- """
- # pylint: disable=unused-argument
- config_file = self.config.path
- if not os.path.isfile(config_file):
- raise CLIException("Unable to show the config file,"
- " '{path}' does not exist"
- .format(path=config_file))
-
- with open(config_file, 'r') as stream:
- try:
- sys.stdout.write("{stream}\n"
- .format(stream=stream.read().rstrip()))
- except Exception as exception:
- raise CLIException("Unable to read config file '{path}':"
- " {error}"
- .format(path=config_file, error=exception))
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/tests/__init__.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/tests/__init__.py b/src/cli_new/lib/cli/tests/__init__.py
deleted file mode 100644
index 0daf288..0000000
--- a/src/cli_new/lib/cli/tests/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Mesos CLI unit tests module.
-"""
-
-# pylint: disable=W0401
-from .base import *
-from .tests import *
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/tests/base.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/tests/base.py b/src/cli_new/lib/cli/tests/base.py
deleted file mode 100644
index 62a4ee8..0000000
--- a/src/cli_new/lib/cli/tests/base.py
+++ /dev/null
@@ -1,422 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Set of classes and helper functions for building unit tests for the Mesos CLI.
-"""
-
-import os
-import shutil
-import StringIO
-import subprocess
-import sys
-import tempfile
-import unittest
-
-import parse
-
-import cli.http as http
-
-from cli.tests.constants import DEFAULT_AGENT_IP
-from cli.tests.constants import DEFAULT_AGENT_PORT
-from cli.tests.constants import DEFAULT_MASTER_IP
-from cli.tests.constants import DEFAULT_MASTER_PORT
-
-from cli.exceptions import CLIException
-
-# Timeout used when creating, killing, and getting data from objects that are
-# part of our test infrastructure.
-TIMEOUT = 5
-
-
-class CLITestCase(unittest.TestCase):
- """
- Base class for CLI TestCases.
- """
-
- @classmethod
- def setUpClass(cls):
- print "\n{class_name}".format(class_name=cls.__name__)
-
- @staticmethod
- def default_mesos_build_dir():
- """
- Returns the default path of the Mesos build directory. Useful when
- we wish to use some binaries such as mesos-execute.
- """
- tests_dir = os.path.dirname(__file__)
- cli_dir = os.path.dirname(tests_dir)
- lib_dir = os.path.dirname(cli_dir)
- cli_new_dir = os.path.dirname(lib_dir)
- src_dir = os.path.dirname(cli_new_dir)
- mesos_dir = os.path.dirname(src_dir)
- build_dir = os.path.join(mesos_dir, "build")
-
- if os.path.isdir(build_dir):
- return build_dir
- else:
- raise CLIException("The Mesos build directory"
- " does not exist: {path}"
- .format(path=build_dir))
-
-# This value is set to the correct path when running tests/main.py. We
-# set it here to make sure that CLITestCase has a MESOS_BUILD_DIR member.
-CLITestCase.MESOS_BUILD_DIR = ""
-
-
-class Executable(object):
- """
- This class defines the base class for launching an executable for
- the CLI unit tests. It will be subclassed by (at least) a
- 'Master', 'Agent', and 'Task' subclass.
- """
- def __init__(self):
- self.name = ""
- self.executable = ""
- self.flags = {}
- self.proc = None
-
- def __del__(self):
- if hasattr(self, "proc"):
- self.kill()
-
- def launch(self):
- """
- Launch 'self.executable'. We assume it is in the system PATH.
- """
- if self.proc is not None:
- raise CLIException("{name} already launched"
- .format(name=self.name.capitalize()))
-
- try:
- flags = ["--{key}={value}".format(key=key, value=value)
- for key, value in self.flags.iteritems()]
-
- proc = subprocess.Popen(
- [self.executable] + flags,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- except Exception as exception:
- raise CLIException("Failed to launch '{executable}': {error}"
- .format(executable=self.executable,
- error=exception))
-
- if proc.poll():
- raise CLIException("Failed to launch '{executable}': {error}"
- .format(executable=self.executable,
- error=proc.stdout.read()))
-
- self.proc = proc
-
- def kill(self):
- """
- Kills a previously launched executable.
- """
- if self.proc is None:
- return
-
- try:
- self.proc.kill()
- self.proc.wait()
- self.proc = None
- except Exception as exception:
- raise CLIException("Could not kill {name}: {error}"
- .format(name=self.name, error=exception))
-
-
-class Master(Executable):
- """
- This class defines the functions necessary to launch a master in
- the CLI unit tests.
- """
- count = 0
-
- def __init__(self, flags=None):
- super(Master, self).__init__()
-
- if Master.count > 0:
- raise CLIException("Creating more than one master"
- " is currently not possible")
-
- Master.count += 1
-
- if flags is None:
- flags = {}
-
- if "ip" not in flags:
- flags["ip"] = DEFAULT_MASTER_IP
- if "port" not in flags:
- flags["port"] = DEFAULT_MASTER_PORT
- if "work_dir" not in flags:
- flags["work_dir"] = tempfile.mkdtemp()
-
- self.flags = flags
- self.name = "master"
- self.addr = "{ip}:{port}".format(ip=flags["ip"], port=flags["port"])
- self.executable = os.path.join(
- CLITestCase.MESOS_BUILD_DIR,
- "bin",
- "mesos-{name}.sh".format(name=self.name))
-
- def __del__(self):
- super(Master, self).__del__()
-
- if hasattr(self, "flags"):
- shutil.rmtree(self.flags["work_dir"])
-
- Master.count -= 1
-
-
-class Agent(Executable):
- """
- This class defines the functions necessary to launch an agent in
- the CLI unit tests.
- """
- count = 0
-
- def __init__(self, flags=None):
- super(Agent, self).__init__()
-
- if Agent.count > 0:
- raise CLIException("Creating more than one agent"
- " is currently not possible")
-
- Agent.count += 1
-
- if flags is None:
- flags = {}
-
- if "ip" not in flags:
- flags["ip"] = DEFAULT_AGENT_IP
- if "port" not in flags:
- flags["port"] = DEFAULT_AGENT_PORT
- if "master" not in flags:
- flags["master"] = "{ip}:{port}".format(
- ip=DEFAULT_MASTER_IP,
- port=DEFAULT_MASTER_PORT)
- if "work_dir" not in flags:
- flags["work_dir"] = tempfile.mkdtemp()
- if "runtime_dir" not in flags:
- flags["runtime_dir"] = tempfile.mkdtemp()
- # Disabling systemd support on Linux to run without sudo.
- if "linux" in sys.platform and "systemd_enable_support" not in flags:
- flags["systemd_enable_support"] = "false"
-
- self.flags = flags
- self.name = "agent"
- self.addr = "{ip}:{port}".format(ip=flags["ip"], port=flags["port"])
- self.executable = os.path.join(
- CLITestCase.MESOS_BUILD_DIR,
- "bin",
- "mesos-{name}.sh".format(name=self.name))
-
- def __del__(self):
- super(Agent, self).__del__()
-
- if hasattr(self, "flags"):
- shutil.rmtree(self.flags["work_dir"])
- shutil.rmtree(self.flags["runtime_dir"])
-
- Agent.count -= 1
-
- # pylint: disable=arguments-differ
- def launch(self, timeout=TIMEOUT):
- """
- After starting the agent, we need to make sure it has
- successfully registered with the master before proceeding.
- """
- super(Agent, self).launch()
-
- try:
- # pylint: disable=missing-docstring
- def single_slave(data):
- return len(data["slaves"]) == 1
-
- http.get_json(self.flags["master"], "slaves", single_slave, timeout)
- except Exception as exception:
- stdout = ""
- if self.proc.poll():
- stdout = "\n{output}".format(output=self.proc.stdout.read())
- self.proc = None
-
- raise CLIException("Could not get '/slaves' endpoint as JSON with"
- " only 1 agent in it: {error}{stdout}"
- .format(error=exception, stdout=stdout))
-
- # pylint: disable=arguments-differ
- def kill(self, timeout=TIMEOUT):
- """
- After killing the agent, we need to make sure it has
- successfully unregistered from the master before proceeding.
- """
- super(Agent, self).kill()
-
- if self.proc is None:
- return
-
- try:
- # pylint: disable=missing-docstring
- def no_slaves(data):
- return len(data["slaves"]) == 0
-
- http.get_json(self.flags["master"], "slaves", no_slaves, timeout)
- except Exception as exception:
- raise CLIException("Could not get '/slaves' endpoint as"
- " JSON with 0 agents in it: {error}"
- .format(error=exception))
-
-
-class Task(Executable):
- """
- This class defines the functions necessary to launch a task in
- the CLI unit tests.
- """
- count = 0
-
- def __init__(self, flags=None):
- super(Task, self).__init__()
-
- if flags is None:
- flags = {}
-
- if "master" not in flags:
- flags["master"] = "{ip}:{port}".format(
- ip=DEFAULT_MASTER_IP,
- port=DEFAULT_MASTER_PORT)
- if "name" not in flags:
- flags["name"] = "task-{id}".format(id=Task.count)
- Task.count += 1
- if "command" not in flags:
- raise CLIException("No command supplied when creating task")
-
- self.flags = flags
- self.name = "task"
- self.executable = os.path.join(
- CLITestCase.MESOS_BUILD_DIR,
- "src",
- "mesos-execute")
-
- def __wait_for_containers(self, condition, timeout=TIMEOUT):
- """
- Wait for the agent's '/containers' endpoint
- to return data subject to 'condition'.
- """
- try:
- data = http.get_json(self.flags["master"], "slaves")
- except Exception as exception:
- raise CLIException("Could not get '/slaves' endpoint"
- " as JSON: {error}"
- .format(error=exception))
-
- if len(data["slaves"]) != 1:
- raise CLIException("More than one agent detected when"
- " reading from '/slaves' endpoint")
-
- try:
- agent = parse.parse(
- "slave({id})@{addr}",
- data["slaves"][0]["pid"])
- except Exception as exception:
- raise CLIException("Unable to parse agent info: {error}"
- .format(error=exception))
-
- try:
- data = http.get_json(
- agent["addr"],
- "containers",
- condition,
- timeout)
- except Exception as exception:
- raise CLIException("Could not get '/containers' endpoint as"
- " JSON subject to condition: {error}"
- .format(error=exception))
-
- # pylint: disable=arguments-differ
- def launch(self, timeout=TIMEOUT):
- """
- After starting the task, we need to make sure its container
- has actually been added to the agent before proceeding.
- """
- super(Task, self).launch()
-
- try:
- # pylint: disable=missing-docstring
- def container_exists(data):
- return any(container["executor_id"] == self.flags["name"]
- for container in data)
-
- self.__wait_for_containers(container_exists, timeout)
- except Exception as exception:
- stdout = ""
- if self.proc.poll():
- stdout = "\n{output}".format(output=self.proc.stdout.read())
- self.proc = None
-
- raise CLIException("Waiting for container '{name}'"
- " failed: {error}{stdout}"
- .format(name=self.flags["name"],
- error=exception,
- stdout=stdout))
-
- # pylint: disable=arguments-differ
- def kill(self, timeout=TIMEOUT):
- """
- After killing the task, we need to make sure its container has
- actually been removed from the agent before proceeding.
- """
- super(Task, self).kill()
-
- if self.proc is None:
- return
-
- try:
- # pylint: disable=missing-docstring
- def container_does_not_exist(data):
- return not any(container["executor_id"] == self.flags["name"]
- for container in data)
-
- self.__wait_for_containers(container_does_not_exist, timeout)
- except Exception as exception:
- raise CLIException("Container with name '{name}' still"
- " exists after timeout: {error}"
- .format(name=self.flags["name"],
- error=exception))
-
-
-def capture_output(command, argv, extra_args=None):
- """
- Redirect the output of a command to a string and return it.
- """
- if not extra_args:
- extra_args = {}
-
- stdout = sys.stdout
- sys.stdout = StringIO.StringIO()
-
- try:
- command(argv, **extra_args)
- except Exception as exception:
- # Fix stdout in case something goes wrong
- sys.stdout = stdout
- raise CLIException("Could not get command output: {error}"
- .format(error=exception))
-
- sys.stdout.seek(0)
- output = sys.stdout.read().strip()
- sys.stdout = stdout
-
- return output
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/tests/constants.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/tests/constants.py b/src/cli_new/lib/cli/tests/constants.py
deleted file mode 100644
index 5d45d94..0000000
--- a/src/cli_new/lib/cli/tests/constants.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-A collection of constants useful for the CLI unit tests.
-"""
-
-DEFAULT_MASTER_IP = "127.0.0.1"
-DEFAULT_MASTER_PORT = "9090"
-
-DEFAULT_AGENT_IP = "127.0.0.1"
-DEFAULT_AGENT_PORT = "9091"
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/tests/tests.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/tests/tests.py b/src/cli_new/lib/cli/tests/tests.py
deleted file mode 100644
index 79e1036..0000000
--- a/src/cli_new/lib/cli/tests/tests.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-Tests that test the test infrastructure itself.
-"""
-
-from cli.tests import capture_output
-from cli.tests import CLITestCase
-from cli.tests import Agent
-from cli.tests import Master
-from cli.tests import Task
-
-
-class TestInfrastructure(CLITestCase):
- """
- This class tests the functionality of the test
- infrastructure used to run all other CLI tests.
- """
- def test_launch_binaries(self):
- """
- Tests the launching and killing of
- a mesos master, agent, and task.
- """
- master = Master()
- master.launch()
-
- agent = Agent()
- agent.launch()
-
- task = Task({"command": "sleep 1000"})
- task.launch()
-
- task.kill()
- agent.kill()
- master.kill()
-
- def test_capture_output(self):
- """
- Tests the ability to capture the output
- from an arbitrary CLI sub-command.
- """
- template = "Arguments: {args}"
- arguments = ["argument1", "argument2"]
-
- # pylint: disable=missing-docstring
- def command(args):
- print template.format(args=args)
-
- output = capture_output(command, arguments)
-
- self.assertEqual(output, template.format(args=arguments))
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/lib/cli/util.py
----------------------------------------------------------------------
diff --git a/src/cli_new/lib/cli/util.py b/src/cli_new/lib/cli/util.py
deleted file mode 100644
index 7371f83..0000000
--- a/src/cli_new/lib/cli/util.py
+++ /dev/null
@@ -1,259 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-A collection of helper functions used by the CLI and its Plugins.
-"""
-
-import imp
-import importlib
-import os
-import re
-import textwrap
-
-from cli.exceptions import CLIException
-
-
-def import_modules(package_paths, module_type):
- """
- Looks for python packages under `package_paths` and imports
- them as modules. Returns a dictionary of the basename of the
- `package_paths` to the imported modules.
- """
- modules = {}
- for package_path in package_paths:
- # We put the imported module into the namespace of
- # "mesos.<module_type>.<>" to keep it from cluttering up
- # the import namespace elsewhere.
- package_name = os.path.basename(package_path)
- package_dir = os.path.dirname(package_path)
- module_name = "cli." + module_type + "." + package_name
- try:
- module = importlib.import_module(module_name)
- except Exception:
- obj, filename, data = imp.find_module(package_name, [package_dir])
- module = imp.load_module(module_name, obj, filename, data)
- modules[package_name] = module
-
- return modules
-
-
-def get_module(modules, import_path):
- """
- Given a modules dictionary returned by `import_modules()`,
- return a reference to the module at `import_path` relative
- to the base module. For example, get_module(modules, "example.stuff")
- will return a reference to the "stuff" module inside the
- imported "example" plugin.
- """
- import_path = import_path.split('.')
- try:
- module = modules[import_path[0]]
- if len(import_path) > 1:
- module = getattr(module, ".".join(import_path[1:]))
- except Exception as exception:
- raise CLIException("Unable to get module: {error}"
- .format(error=str(exception)))
-
- return module
-
-
-def completions(comp_words, current_word, argv):
- """
- Helps autocomplete by returning the appropriate
- completion words under three conditions.
-
- 1) Returns `comp_words` if the completion word is
- potentially in that list.
- 2) Returns an empty list if there is no possible
- completion.
- 3) Returns `None` if the autocomplete is already done.
- """
- comp_words += ["-h", "--help", "--version"]
-
- if len(argv) == 0:
- return comp_words
-
- if len(argv) == 1:
- if argv[0] not in comp_words and current_word:
- return comp_words
-
- if argv[0] in comp_words and current_word:
- return comp_words
-
- if argv[0] not in comp_words and not current_word:
- return []
-
- if argv[0] in comp_words and not current_word:
- return None
-
- if len(argv) > 1 and argv[0] not in comp_words:
- return []
-
- if len(argv) > 1 and argv[0] in comp_words:
- return None
-
- raise CLIException("Unreachable")
-
-
-def format_commands_help(cmds):
- """
- Helps format plugin commands for display.
- """
- longest_cmd_name = max(cmds.keys(), key=len)
-
- help_string = ""
- for cmd in sorted(cmds.keys()):
- # For the top-level entry point, `cmds` is a single-level
- # dictionary with `short_help` as the values. For plugins,
- # `cmds` is a two-level dictionary, where `short_help` is a
- # field in each sub-dictionary.
- short_help = cmds[cmd]
- if isinstance(short_help, dict):
- short_help = short_help["short_help"]
-
- num_spaces = len(longest_cmd_name) - len(cmd) + 2
- help_string += " %s%s%s\n" % (cmd, " " * num_spaces, short_help)
-
- return help_string
-
-
-def format_subcommands_help(cmd):
- """
- Helps format plugin subcommands for display.
- """
- arguments = " ".join(cmd["arguments"])
- short_help = cmd["short_help"]
- long_help = textwrap.dedent(cmd["long_help"].rstrip())
- long_help = " " + "\n ".join(long_help.split('\n'))
- flags = cmd["flags"]
- flags["-h --help"] = "Show this screen."
- flag_string = ""
-
- if len(flags.keys()) != 0:
- longest_flag_name = max(flags.keys(), key=len)
- for flag in sorted(flags.keys()):
- num_spaces = len(longest_flag_name) - len(flag) + 2
- flag_string += " %s%s%s\n" % (flag, " " * num_spaces, flags[flag])
-
- return (arguments, short_help, long_help, flag_string)
-
-
-def join_plugin_paths(settings, config):
- """
- Return all the plugin paths combined
- from both settings and the config file.
- """
- builtin_paths = settings.PLUGINS
-
- try:
- config_paths = config.plugins()
- except Exception as exception:
- raise CLIException("Error: {error}.".format(error=str(exception)))
-
- return builtin_paths + config_paths
-
-
-class Table(object):
- """
- Defines a custom table structure for printing to the terminal.
- """
- def __init__(self, columns):
- """
- Initialize a table with a list of column names
- to act as headers for each column in the table.
- """
- if not isinstance(columns, list):
- raise CLIException("Column headers must be supplied as a list")
-
- for column in columns:
- if re.search(r"(\s)\1{2,}", column):
- raise CLIException("Column headers cannot have more"
- " than one space between words")
-
- self.table = [columns]
- self.padding = [len(column) for column in columns]
-
- def __getitem__(self, index):
- return list(self.table[index])
-
- def dimensions(self):
- """
- Returns the dimensions of the table as (<num-rows>, <num-columns>).
- """
- return (len(self.table), len(self.table[0]))
-
- def add_row(self, row):
- """
- Add a row to the table. Input must be a list where each entry
- corresponds to its respective column in order.
- """
- if len(row) != len(self.table[0]):
- raise CLIException("Number of entries and columns do not match!")
-
- # Adjust padding for each column.
- for index, elem in enumerate(row):
- if len(elem) > self.padding[index]:
- self.padding[index] = len(elem)
-
- self.table.append(row)
-
- def __str__(self):
- """
- Convert a table to string for printing.
- """
- table_string = ""
- for r_index, row in enumerate(self.table):
- for index, entry in enumerate(row):
- table_string += "%s%s" % \
- (entry, " " * (self.padding[index] - len(entry) + 2))
-
- if r_index != len(self.table) - 1:
- table_string += "\n"
-
- return table_string
-
- @staticmethod
- def parse(string):
- """
- Parse a string previously printed as a `Table` back into a `Table`.
- """
- lines = string.split("\n")
-
- # Find the location and contents of column headers in the string.
- # Assume only single spaces between words in column headers.
- matches = re.finditer(r"([\w\d]+\s?[\w\d]+)+", lines[0])
- columns = [(m.start(), m.group()) for m in matches]
-
- # Build a table from the column header contents.
- table = Table([c[1] for c in columns])
-
- # Fill in the subsequent rows.
- for line in lines[1:]:
- row = []
- start_indices = [c[0] for c in columns]
-
- for i, start_index in enumerate(start_indices):
- if i + 1 < len(start_indices):
- column = line[start_index:start_indices[i + 1]]
- else:
- column = line[start_index:]
-
- row.append(str(column.strip()))
-
- table.add_row(row)
-
- return table
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/mesos.bash_completion
----------------------------------------------------------------------
diff --git a/src/cli_new/mesos.bash_completion b/src/cli_new/mesos.bash_completion
deleted file mode 100644
index 2121181..0000000
--- a/src/cli_new/mesos.bash_completion
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/usr/bin/env bash
-
-# This bash completion script works by invoking the mesos command itself with a
-# "magic" subcommand called "__autocomplete__" and then forwarding all of the
-# arguments to it. The mesos command takes care of parsing the arguments and
-# returning the list of valid completions for the current word.
-_mesos() {
- local cur cmd args rets
- local option words
- local OIFS
-
- cur="${COMP_WORDS[${COMP_CWORD}]}"
- cmd="${COMP_WORDS[0]}"
- args=(${COMP_WORDS[@]:1})
-
- # The __autocomplete__ command will return two lines of text (the first
- # being the completion mode (default, nospace, etc.) and the second being a
- # space-separated list of completion words). To handle this, we temporarily
- # change the shell separator to '\n' instead of ' ' in order to interpret
- # the results as exactly two values.
- OIFS=${IFS}
- IFS=$'\n'
- rets=($(${cmd} __autocomplete__ "${cur}" ${args[*]}))
- IFS=${OIFS}
-
- option="${rets[0]}"
- words="${rets[1]}"
-
- # Reset the completion mode to be whatever value was returned by
- # the __autocomplete__ command.
- complete -o ${option} -F _mesos mesos
-
- # Build the array of completion words.
- COMPREPLY=( $(compgen -W "${words}" -- ${cur}) )
-
- # If there are no completion words, then reset the completion to "nospace"
- # mode so that hitting tab will not produce a space after the current word.
- # This step is necessary since the mode might have been changed above.
- if [ "${#COMPREPLY[@]}" = "0" ]; then
- complete -o nospace -F _mesos mesos
- COMPREPLY=()
- fi
-
- return 0
-}
-complete -F _mesos mesos
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/pip-requirements.txt
----------------------------------------------------------------------
diff --git a/src/cli_new/pip-requirements.txt b/src/cli_new/pip-requirements.txt
deleted file mode 100644
index 7aeac34..0000000
--- a/src/cli_new/pip-requirements.txt
+++ /dev/null
@@ -1,16 +0,0 @@
-astroid==1.4.8
-backports.functools-lru-cache==1.2.1
-configparser==3.5.0
-docopt==0.6.2
-isort==4.2.5
-lazy-object-proxy==1.2.2
-mccabe==0.5.2
-parse==1.8.0
-Pygments==2.1.3
-PyInstaller==3.1.1
-pylint==1.6.4
-six==1.10.0
-termcolor==1.1.0
-toml==0.9.2
-tox==2.7.0
-wrapt==1.10.8
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/pylint.config
----------------------------------------------------------------------
diff --git a/src/cli_new/pylint.config b/src/cli_new/pylint.config
deleted file mode 100644
index 63fbb94..0000000
--- a/src/cli_new/pylint.config
+++ /dev/null
@@ -1,26 +0,0 @@
-[MASTER]
-ignore=.git
-
-[MESSAGES CONTROL]
-disable=I0011,no-self-use,fixme
-
-[REPORTS]
-reports=no
-
-[BASIC]
-bad-functions=input,file
-good-names=i,j,k,f,ip,_
-min-public-methods=0
-
-[FORMAT]
-max-line-length=80
-indent-string=' '
-
-[DESIGN]
-max-returns=100
-
-[EXCEPTIONS]
-overgeneral-exceptions=
-
-[TYPECHECK]
-ignored-modules = netifaces
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/cli_new/tests/main.py
----------------------------------------------------------------------
diff --git a/src/cli_new/tests/main.py b/src/cli_new/tests/main.py
deleted file mode 100644
index 3e4d2e4..0000000
--- a/src/cli_new/tests/main.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-This is the main executable of the mesos-cli unit tests.
-"""
-
-import unittest
-
-from termcolor import colored
-
-from cli.tests import CLITestCase
-
-# pylint: disable=unused-import
-# We import the tests that we want to run.
-from cli.tests import TestInfrastructure
-
-if __name__ == '__main__':
- CLITestCase.MESOS_BUILD_DIR = CLITestCase.default_mesos_build_dir()
-
- print colored("Running the Mesos CLI unit tests", "yellow")
- unittest.main(verbosity=2, testRunner=unittest.TextTestRunner)
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/README.md
----------------------------------------------------------------------
diff --git a/src/python/cli_new/README.md b/src/python/cli_new/README.md
new file mode 100644
index 0000000..c5475c7
--- /dev/null
+++ b/src/python/cli_new/README.md
@@ -0,0 +1,83 @@
+# Mesos CLI
+
+## Prerequisites
+
+Make sure you have the following prerequisites
+installed on your system before you begin.
+
+```
+python 2.6 or 2.7
+virtualenv
+```
+
+## Getting Started
+
+Once you you have the prerequisites installed, simply
+run the `bootstrap` script from this directory to set
+up a python virtual environment and start running the tool.
+
+```
+$ ./bootstrap
+
+...
+
+Setup complete!
+
+To begin working, simply activate your virtual environment,
+run the CLI, and then deactivate the virtual environment
+when you are done.
+
+ $ source activate
+ $ mesos <command> [<args>...]
+ $ source deactivate
+```
+
+**NOTE:** The virtual environment will also setup bash
+autocomplete for all `mesos` commands.
+
+
+## Running tests
+
+To run the unit tests developed for the Mesos CLI, use
+`mesos-cli-tests`:
+
+```
+$ ./bootstrap
+
+...
+
+Setup complete!
+
+To begin working, simply activate your virtual environment,
+run the CLI, and then deactivate the virtual environment
+when you are done.
+
+ $ source activate
+ $ mesos-cli-tests
+
+Running the Mesos CLI unit tests
+
+...
+
+OK
+```
+
+
+## Setting up your configuration
+
+In order to use this tool, you will need to create a
+configuration file in your home directory under
+`~/.mesos/config.toml`. A template for this config can be
+seen below:
+
+```
+# The `plugins` is an array listing the absolute paths of the
+# plugins you want to add to the CLI.
+plugins = [
+ "</absolute/path/to/plugin-1/directory>",
+ "</absolute/path/to/plugin-2/directory>"
+]
+```
+
+You can override the location of this configuration file using
+the environment variable `MESOS_CLI_CONFIG`.
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/activate
----------------------------------------------------------------------
diff --git a/src/python/cli_new/activate b/src/python/cli_new/activate
new file mode 100644
index 0000000..65df76f
--- /dev/null
+++ b/src/python/cli_new/activate
@@ -0,0 +1,4 @@
+DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+source ${DIR}/.virtualenv/bin/activate
+source ${DIR}/.virtualenv/bin/postactivate
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/bin/main.py
----------------------------------------------------------------------
diff --git a/src/python/cli_new/bin/main.py b/src/python/cli_new/bin/main.py
new file mode 100644
index 0000000..5313038
--- /dev/null
+++ b/src/python/cli_new/bin/main.py
@@ -0,0 +1,155 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+This is the main executable of the mesos-cli.
+"""
+
+import sys
+
+import settings
+
+import cli
+
+from cli.docopt import docopt
+from cli.exceptions import CLIException
+
+
+VERSION = "Mesos " + settings.VERSION + " CLI"
+
+SHORT_HELP = "Perform operations on a running Mesos cluster."
+
+USAGE = \
+"""Mesos CLI
+
+Usage:
+ mesos (-h | --help)
+ mesos --version
+ mesos <command> [<args>...]
+
+Options:
+ -h --help Show this screen.
+ --version Show version info.
+
+Commands:
+{commands}
+See 'mesos help <command>' for more information on a specific command.
+"""
+
+
+def autocomplete(cmds, plugins, config, argv):
+ """
+ Perform autocomplete for the given input arguments. If not
+ completing a top level command (or "help"), this function passes
+ the arguments down to the appropriate plugins for per-plugin
+ autocompletion.
+ """
+
+ option = "default"
+ current_word = argv[0]
+ argv = argv[1:]
+
+ if len(argv) > 0 and argv[0] == "help":
+ argv = argv[1:]
+
+ comp_words = list(cmds.keys()) + ["help"]
+ comp_words = cli.util.completions(comp_words, current_word, argv)
+ if comp_words != None:
+ return (option, comp_words)
+
+ plugin = cli.util.get_module(plugins, argv[0])
+ plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
+
+ return plugin_class(settings, config).__autocomplete_base__(
+ current_word,
+ argv[1:])
+
+
+def main(argv):
+ """
+ This is the main function for the Mesos CLI.
+ """
+
+ # Load the CLI config.
+ config = cli.config.Config(settings)
+
+ plugins = cli.util.import_modules(
+ cli.util.join_plugin_paths(settings, config),
+ "plugins")
+
+ cmds = {
+ cli.util.get_module(plugins, plugin).PLUGIN_NAME:
+ cli.util.get_module(plugins, plugin).SHORT_HELP
+ for plugin in plugins.keys()
+ }
+
+ # Parse all incoming arguments using docopt.
+ command_strings = ""
+ if cmds != {}:
+ command_strings = cli.util.format_commands_help(cmds)
+ usage = USAGE.format(commands=command_strings)
+
+ arguments = docopt(usage, argv=argv, version=VERSION, options_first=True)
+
+ cmd = arguments["<command>"]
+ argv = arguments["<args>"]
+
+ # Use the meta-command `__autocomplete__` to perform
+ # autocompletion on the remaining arguments.
+ if cmd == "__autocomplete__":
+ option = "default"
+ comp_words = []
+
+ # If there is an error performing the autocomplete, treat it
+ # as if we were just unable to complete any words. This avoids
+ # passing the erroring stack trace back as the list of words
+ # to complete on.
+ try:
+ option, comp_words = autocomplete(cmds, plugins, config, argv)
+ except Exception:
+ pass
+
+ print option
+ print " ".join(comp_words)
+
+ # Use the meta-command "help" to print help information for the
+ # supplied command and its subcommands.
+ elif cmd == "help":
+ if len(argv) > 0 and argv[0] in cmds:
+ plugin = cli.util.get_module(plugins, argv[0])
+ plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
+ plugin_class(settings, config).main(argv[1:] + ["--help"])
+ else:
+ main(["--help"])
+
+ # Run the command through its plugin.
+ elif cmd in cmds.keys():
+ plugin = cli.util.get_module(plugins, cmd)
+ plugin_class = getattr(plugin, plugin.PLUGIN_CLASS)
+ plugin_class(settings, config).main(argv)
+
+ # Print help information if no commands match.
+ else:
+ main(["--help"])
+
+
+if __name__ == "__main__":
+ try:
+ main(sys.argv[1:])
+ except CLIException as exception:
+ sys.exit("Error: {error}.".format(error=str(exception)))
+ except KeyboardInterrupt:
+ pass
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/bin/mesos
----------------------------------------------------------------------
diff --git a/src/python/cli_new/bin/mesos b/src/python/cli_new/bin/mesos
new file mode 100755
index 0000000..c5152a2
--- /dev/null
+++ b/src/python/cli_new/bin/mesos
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+CURRDIR="$(cd "$(dirname "$0")" && pwd)"
+
+source ${CURRDIR}/../activate
+python ${CURRDIR}/main.py "$@"
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/bin/mesos-cli-tests
----------------------------------------------------------------------
diff --git a/src/python/cli_new/bin/mesos-cli-tests b/src/python/cli_new/bin/mesos-cli-tests
new file mode 100755
index 0000000..07659e0
--- /dev/null
+++ b/src/python/cli_new/bin/mesos-cli-tests
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+
+CURRDIR="$(cd "$(dirname "$0")" && pwd)"
+
+source ${CURRDIR}/../activate
+python ${CURRDIR}/../tests/main.py "$@"
http://git-wip-us.apache.org/repos/asf/mesos/blob/09fa758b/src/python/cli_new/bin/settings.py
----------------------------------------------------------------------
diff --git a/src/python/cli_new/bin/settings.py b/src/python/cli_new/bin/settings.py
new file mode 100644
index 0000000..d42df04
--- /dev/null
+++ b/src/python/cli_new/bin/settings.py
@@ -0,0 +1,47 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""
+This file defines the default settings of the mesos-cli. It also takes care
+of updating the default configuration from reading environment variables or
+parsing a configuration file.
+"""
+
+import os
+
+
+# There is no version module included in this package. However,
+# when creating an executable using pyinstaller, a version.py
+# file will be autogenerated and inserted into the PYTHONPATH.
+# When this happens we import it to set the VERSION.
+try:
+ # pylint: disable=F0401,W0611
+ from version import VERSION
+except Exception:
+ VERSION = "Development"
+
+# The top-level directory of this project.
+PROJECT_DIR = os.path.join(os.path.dirname(__file__), os.pardir)
+
+# The builtin plugins.
+PLUGINS = [
+ os.path.join(PROJECT_DIR, "lib", "mesos", "plugins", "config")
+]
+
+DEFAULT_MESOS_CLI_CONFIG = os.path.join(
+ os.path.expanduser("~"),
+ ".mesos",
+ "config.toml")