├── mbed ├── __init__.py ├── __main__.py └── mbed_terminal.py ├── requirements.txt ├── tools └── bash_completion │ ├── templates │ ├── scm.tmplt │ ├── protocol.tmplt │ ├── README.md │ ├── ide.tmplt │ ├── target.tmplt │ ├── .README.md.swp │ ├── toolchain.tmplt │ ├── command.tmplt │ ├── boilerplate.tmplt │ └── mbed.tmplt │ ├── install.md │ ├── generator.py │ └── mbed ├── MANIFEST.in ├── mkdocs.yml ├── docs └── index.md ├── test ├── ls_test.py ├── import_test.py ├── remove_test.py ├── README.md ├── add_test.py ├── sync_update_test.py └── util.py ├── README.rst ├── .gitignore ├── .github └── workflows │ └── main.yml ├── circle_tests.py ├── setup.py └── LICENSE /mbed/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /mbed/__main__.py: -------------------------------------------------------------------------------- 1 | from .mbed import main 2 | main() 3 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyserial>=3.0,<4.0 2 | mbed-os-tools>=0.0.9 3 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/scm.tmplt: -------------------------------------------------------------------------------- 1 | __mbedcomp "bld git hg" 2 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/protocol.tmplt: -------------------------------------------------------------------------------- 1 | __mbedcomp "https http ssh git" 2 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/README.md: -------------------------------------------------------------------------------- 1 | # Templates 2 | 3 | Note these templates are inspired by the mustache syntax. 4 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/ide.tmplt: -------------------------------------------------------------------------------- 1 | declare IDES=$(mbed export --supported ides) 2 | __mbedcomp "${IDES}" 3 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/target.tmplt: -------------------------------------------------------------------------------- 1 | declare TARGETS=$(mbed compile --supported targets) 2 | __mbedcomp "${TARGETS}" 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | global-exclude *.py[cod] __pycache__ *.so 2 | graft test 3 | include README.rst 4 | include LICENSE 5 | include requirements.txt 6 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/.README.md.swp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARMmbed/mbed-cli/HEAD/tools/bash_completion/templates/.README.md.swp -------------------------------------------------------------------------------- /tools/bash_completion/templates/toolchain.tmplt: -------------------------------------------------------------------------------- 1 | declare TOOLCHAINS=$(mbed compile --supported toolchains) 2 | __mbedcomp "${TOOLCHAINS}" 3 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: mbed 2 | 3 | docs_dir: docs 4 | 5 | pages: 6 | - ['index.md','Introduction to mbed'] 7 | - ['user_guide.md','mbed User Guide'] 8 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Arm Mbed command-line interface 2 | 3 | *Mbed CLI* is the name of the Arm Mbed command-line tool, packaged as `mbed-cli`, which enables the full Mbed workflow: repositories version control, maintaining dependencies, publishing code, updating from remotely hosted repositories (GitHub, GitLab and mbed.org) and invoking Arm Mbed's own build system and export functions, among other operations. 4 | -------------------------------------------------------------------------------- /tools/bash_completion/install.md: -------------------------------------------------------------------------------- 1 | # Install Guide 2 | 3 | ## System-wide Installation (root) 4 | 5 | - Copy or link the bash completion script, `mbed`, into your `/etc/bash_completion.d` or `/usr/local/etc/bash_completion.d` directory. 6 | - Reopen terminal 7 | 8 | ## Local Installation 9 | 10 | - `mkdir ~/.bash_completion.d && cp mbed ~/.bash_completion.d/` 11 | - `echo "source ~/.bash_completion.d/mbed" >> ~/.bash_profile` 12 | - logout and login 13 | 14 | -------------------------------------------------------------------------------- /test/ls_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from util import * 14 | 15 | # Tests 'mbed ls' and provides sanity check of test framework 16 | def test_ls(mbed, testrepos): 17 | assertls(mbed, 'test1', [ 18 | "[mbed]", 19 | "test1", 20 | "`- test2", 21 | " `- test3", 22 | " `- test4", 23 | ]) 24 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/command.tmplt: -------------------------------------------------------------------------------- 1 | __mbed_complete_{{COMMAND}}() { 2 | 3 | local cur="${COMP_WORDS[COMP_CWORD]}" 4 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 5 | case "$cur" in 6 | --*) 7 | __mbedcomp " 8 | {{#DDASH_COMMANDS}} 9 | {{name}} 10 | {{/DDASH_COMMANDS}} 11 | " 12 | 13 | return 14 | ;; 15 | -*) 16 | __mbedcomp " 17 | {{#DASH_COMMANDS}} 18 | {{name}} 19 | {{/DASH_COMMANDS}} 20 | " 21 | return 22 | ;; 23 | esac 24 | 25 | # Handle the dependent commands 26 | {{#HAVE_PREV}} 27 | case "$prev" in 28 | {{#PREV_CASE}} 29 | {{case}}) 30 | {{code}} 31 | return 32 | ;; 33 | {{/PREV_CASE}} 34 | esac 35 | {{/HAVE_PREV}} 36 | 37 | } 38 | -------------------------------------------------------------------------------- /test/import_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from util import * 14 | 15 | # Tests 'mbed import' 16 | def test_import(mbed, testrepos): 17 | test1 = testrepos[0] 18 | popen(['python', mbed, 'import', test1, 'testimport']) 19 | 20 | assertls(mbed, 'testimport', [ 21 | "[mbed]", 22 | "testimport", 23 | "`- test2", 24 | " `- test3", 25 | " `- test4", 26 | ]) 27 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Arm Mbed CLI 2 | ============ 3 | 4 | Mbed CLI is the name of the `Arm Mbed `_ command line tool, packaged as mbed-cli, which enables the full mbed workflow: repositories version control, maintaining dependencies, publishing code, updating from remotely hosted repositories (GitHub, GitLab and mbed.com), and invoking Arm Mbed's own build system and export functions, among other operations. 5 | 6 | 7 | Installation 8 | ============ 9 | Mbed CLI is a Python script, so you'll need Python installed in order to use it. mbed CLI was tested with Python 2.7 and Python 3.6. 10 | 11 | Mbed CLI supports both Git and Mercurial repositories, so you'll also need to install Mercurial and Git. 12 | 13 | Get Started 14 | =========== 15 | The best way to get started is to `read the documentation on os.mbed.com `_. 16 | 17 | License 18 | ======= 19 | Mbed CLI is licensed under Apache-2.0 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # mbed-ls related files 6 | .mbedls-mock 7 | mbedls.json 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | .eggs/ 26 | *.egg-info/ 27 | .installed.cfg 28 | *.egg 29 | .tests 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | # Mac stuff 63 | .DS_Store 64 | 65 | # Doxygen 66 | html/ 67 | latex/ 68 | 69 | # PyCharm 70 | .idea 71 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/boilerplate.tmplt: -------------------------------------------------------------------------------- 1 | # Note this file is generated 2 | # Based on mbed auto complete scripts 3 | 4 | __mbedcomp_words_include() { 5 | local i=1 6 | while [[ "$i" -lt "$COMP_CWORD" ]] 7 | do 8 | if [[ "${COMP_WORDS[i]}" = "$1" ]] 9 | then 10 | return 0 11 | fi 12 | i="$((++i))" 13 | done 14 | return 1 15 | } 16 | 17 | # Find the previous non-switch word 18 | __mbedcomp_prev() { 19 | local idx="$((COMP_CWORD - 1))" 20 | local prv="${COMP_WORDS[idx]}" 21 | while [[ "$prv" = -* ]] 22 | do 23 | idx="$((--idx))" 24 | prv="${COMP_WORDS[idx]}" 25 | done 26 | echo "$prv" 27 | } 28 | 29 | __mbedcomp() { 30 | # break $1 on space, tab, and newline characters, 31 | # and turn it into a newline separated list of words 32 | local list s sep=$'\n' IFS=$' '$'\t'$'\n' 33 | local cur="${COMP_WORDS[COMP_CWORD]}" 34 | 35 | for s in $1 36 | do 37 | __mbedcomp_words_include "$s" && continue 38 | list="$list$s$sep" 39 | done 40 | 41 | IFS="$sep" 42 | COMPREPLY=($(compgen -W "$list" -- "$cur")) 43 | } 44 | -------------------------------------------------------------------------------- /tools/bash_completion/templates/mbed.tmplt: -------------------------------------------------------------------------------- 1 | 2 | _mbed () { 3 | local i=1 cmd prev 4 | 5 | prev="${COMP_WORDS[COMP_CWORD-1]}" 6 | 7 | # find the subcommand 8 | while [[ "$i" -lt "$COMP_CWORD" ]] 9 | do 10 | local s="${COMP_WORDS[i]}" 11 | case "$s" in 12 | --*) 13 | cmd="$s" 14 | break 15 | ;; 16 | -*) 17 | ;; 18 | *) 19 | cmd="$s" 20 | break 21 | ;; 22 | esac 23 | 24 | i="$((++i))" 25 | done 26 | 27 | # Handle the main command completions 28 | if [[ "$i" -eq "$COMP_CWORD" ]] 29 | then 30 | local cmds=" 31 | {{#COMMAND}} 32 | {{name}} 33 | {{/COMMAND}} 34 | " 35 | 36 | __mbedcomp "${cmds}" 37 | fi 38 | 39 | # Each subcommand has a completion function based on the parent 40 | case "$cmd" in 41 | {{#COMMAND}} 42 | {{name}}) __mbed_complete_{{name}} ;; 43 | {{/COMMAND}} 44 | *) ;; 45 | esac 46 | 47 | } 48 | 49 | complete -o bashdefault -o default -F _mbed mbed 50 | complete -o bashdefault -o default -F _mbed mbed-cli 51 | 52 | -------------------------------------------------------------------------------- /test/remove_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from util import * 14 | 15 | # Tests the result of 'mbed remove' 16 | def test_remove(mbed, testrepos): 17 | with cd('test1'): 18 | popen(['python', mbed, 'remove', 'test2']) 19 | 20 | assertls(mbed, 'test1', [ 21 | "[mbed]", 22 | "test1", 23 | ]) 24 | 25 | # Tests if a repo can be imported correctly after 'mbed remove' 26 | def test_import_after_remove(mbed, testrepos): 27 | test_remove(mbed, testrepos) 28 | mkcommit('test1') 29 | 30 | test1 = testrepos[0] 31 | popen(['python', mbed, 'import', test1, 'testimport']) 32 | 33 | assertls(mbed, 'testimport', [ 34 | "[mbed]", 35 | "testimport", 36 | ]) 37 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Tests for *neo* are based on the [pytest framework](http://pytest.org/latest/). 4 | To run the available tests, invoke py.test on the test directory: 5 | 6 | ``` bash 7 | py.test test 8 | ``` 9 | 10 | The easiest way to debug failing tests is to run them individually. The names for specific 11 | tests can be found with the `-v` option. 12 | 13 | ``` bash 14 | py.test test/ls_test.py::test_ls[git1] 15 | ``` 16 | 17 | ## Test structure 18 | 19 | Each function that begins with `test_` indicates a test to run. `util.py` provides useful 20 | testing utilities for testing *neo*. 21 | 22 | - The `neo` [fixture](http://pytest.org/latest/fixture.html#fixture) provides the path to 23 | the current `neo` python script. 24 | 25 | - The `testrepos` [fixture](http://pytest.org/latest/fixture.html#fixture) provides a set 26 | of repositories to test against of varying git/hg combinations. Each repository has a local 27 | "server" specified by absolute path and the server address can be accesses through the 28 | `testrepos` variable. Currently the repostories are laid out in the following: 29 | 30 | ``` 31 | test1 32 | `- test2 33 | `- test3 34 | `- test4 35 | ``` 36 | 37 | - The `assertls` takes a neo path, directory to test, and a structure of repositories to compare 38 | against the result of `neo ls`. 39 | 40 | `ls_test.py` provides the simpliest test to demonstrate the framework. 41 | -------------------------------------------------------------------------------- /test/add_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from util import * 14 | 15 | # Tests the result of 'mbed add' 16 | def test_add(mbed, testrepos): 17 | test3 = testrepos[2] 18 | 19 | with cd('test1'): 20 | popen(['python', mbed, 'add', test3, "-vv"]) 21 | 22 | assertls(mbed, 'test1', [ 23 | "[mbed]", 24 | "test1", 25 | "|- test2", 26 | "| `- test3", 27 | "| `- test4", 28 | "`- test3", 29 | " `- test4", 30 | ]) 31 | 32 | # Tests if a repo can be imported correctly after 'mbed add' 33 | def test_import_after_add(mbed, testrepos): 34 | test_add(mbed, testrepos) 35 | mkcommit('test1') 36 | 37 | test1 = testrepos[0] 38 | popen(['python', mbed, 'import', test1, 'testimport', "-vv"]) 39 | 40 | assertls(mbed, 'testimport', [ 41 | "[mbed]", 42 | "testimport", 43 | "|- test2", 44 | "| `- test3", 45 | "| `- test4", 46 | "`- test3", 47 | " `- test4", 48 | ]) 49 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | 5 | jobs: 6 | build: 7 | strategy: 8 | fail-fast: false 9 | matrix: 10 | python-version: [ 'pypy-2.7', 'pypy-3.6', 'pypy-3.7' ] 11 | 12 | container: 13 | image: ghcr.io/armmbed/mbed-os-env:master-latest 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - 19 | name: Checkout 20 | uses: actions/checkout@v2 21 | 22 | 23 | - name: Setup python 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: ${{ matrix.python-version }} 27 | 28 | - name: Display Python version 29 | run: python -c "import sys; print(sys.version)" 30 | 31 | - 32 | name: Configure Git and Mercurial 33 | shell: bash 34 | run: | 35 | git config --global user.email "test@mbed.org" 36 | git config --global user.name "mbed Test" 37 | echo -e "[ui]\nusername = mbed Test \n" > ~/.hgrc 38 | 39 | - 40 | name: Run unit tests 41 | run: | 42 | python -m pip install pytest setuptools 43 | python -m pytest test 44 | 45 | - 46 | name: install mbed-cli 47 | run: | 48 | python -m pip install -e . 49 | python -m mbed --version 50 | 51 | - 52 | name: Configure Mbed CLI for integration tests 53 | run: | 54 | python -m mbed toolchain -G GCC_ARM 55 | python -m mbed target -G K64F 56 | python -m mbed config -G protocol https 57 | 58 | - 59 | name: Create a new project 60 | run: | 61 | mkdir integration_tests 62 | cd integration_tests 63 | python -m mbed new new-test 64 | 65 | - 66 | name: Test project inspection 67 | working-directory: integration_tests/new-test 68 | run: | 69 | python -m mbed ls 70 | python -m mbed releases -r 71 | 72 | - 73 | name: Build through "compile" and "test" 74 | working-directory: integration_tests/new-test 75 | run: | 76 | python -m mbed compile --source=. --source=mbed-os/drivers/tests/TESTS/mbed_drivers/generic_tests -j 0 77 | python -m mbed test --compile -n mbed-os-tests-mbed_drivers-generic_tests -j 0 78 | -------------------------------------------------------------------------------- /circle_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | 9 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 14 | # either express or implied. 15 | 16 | from __future__ import print_function 17 | 18 | import os 19 | import sys 20 | import subprocess 21 | import shutil 22 | import yaml 23 | 24 | def rmtree_readonly(directory): 25 | def remove_readonly(func, path, _): 26 | os.chmod(path, stat.S_IWRITE) 27 | func(path) 28 | 29 | shutil.rmtree(directory, onerror=remove_readonly) 30 | 31 | # Source tests from yaml config 32 | tests = None 33 | with open('.circleci/config.yml', 'r') as f: 34 | data = yaml.safe_load(f) 35 | 36 | # Read yaml tree 37 | if sys.version_info[0] == 3: 38 | tests = data['jobs']['py3']['steps'] 39 | else: 40 | tests = data['jobs']['py2']['steps'] 41 | 42 | # Filter command list to only contain commands 43 | tests = [item['run'] for item in list(filter(lambda x : type(x) is dict, tests))] 44 | 45 | # ... and replace new lines with ampersands 46 | tests = [item.replace('\n', ' && ') for item in tests] 47 | 48 | # Exit if no tests are found 49 | if tests == None: 50 | sys.exit(1) 51 | 52 | # Ignore all tests found before `pip install -e` 53 | startIndex = -1 54 | for cmd in tests: 55 | if 'pip install -e' in cmd: 56 | startIndex = tests.index(cmd) + 1 57 | break 58 | 59 | if startIndex == -1: 60 | sys.exit(1) 61 | 62 | # Delete `.test` directory if it exists 63 | cwd = os.path.abspath(os.path.dirname(__file__)) 64 | 65 | if os.path.exists(os.path.join(cwd, '.tests')): 66 | rmtree_readonly(os.path.join(cwd, '.tests')) 67 | os.mkdir(os.path.join(cwd, '.tests')) 68 | 69 | # Run tests 70 | for cmd in tests[startIndex:]: 71 | os.chdir(cwd) 72 | print("\n----------\nEXEC: \"%s\" " % cmd) 73 | proc = subprocess.Popen(cmd, shell=True) 74 | proc.communicate() 75 | 76 | if proc.returncode != 0: 77 | print("\n------------\nERROR: \"%s\"" % cmd) 78 | sys.exit(1) 79 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016-2019 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | import os 14 | from setuptools import setup 15 | from setuptools import find_packages 16 | 17 | NAME = 'mbed-cli' 18 | __version__ = '1.10.5' 19 | 20 | repository_dir = os.path.dirname(__file__) 21 | 22 | # .rst readme needed for pypi 23 | with open(os.path.join(repository_dir, 'README.rst')) as fh: 24 | long_description = fh.read() 25 | 26 | with open(os.path.join(repository_dir, 'requirements.txt')) as fh: 27 | requirements = fh.readlines() 28 | 29 | with open("README.rst", "r") as fh: 30 | long_description = fh.read() 31 | 32 | setup( 33 | author='Arm mbed', 34 | author_email='support@mbed.org', 35 | classifiers=( 36 | 'Development Status :: 5 - Production/Stable', 37 | 'Intended Audience :: Developers', 38 | 'License :: OSI Approved :: Apache Software License', 39 | 'Programming Language :: Python :: 2', 40 | 'Programming Language :: Python :: 2.7', 41 | 'Programming Language :: Python :: 3', 42 | 'Programming Language :: Python :: 3.5', 43 | 'Programming Language :: Python :: 3.6', 44 | 'Programming Language :: Python :: 3.7', 45 | 'Programming Language :: Python', 46 | 'Topic :: Software Development :: Build Tools', 47 | 'Topic :: Software Development :: Embedded Systems', 48 | ), 49 | description="Command line tool for interacting with Mbed OS projects", 50 | keywords="Mbed OS CLI", 51 | include_package_data=True, 52 | install_requires=requirements, 53 | license='Apache 2.0', 54 | long_description=long_description, 55 | name=NAME, 56 | packages=find_packages(), 57 | python_requires='>=2.7.10, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4', 58 | url="http://github.com/ARMmbed/mbed-cli", 59 | version=__version__, 60 | entry_points={ 61 | 'console_scripts': [ 62 | 'mbed=mbed.mbed:main', 63 | 'mbed-cli=mbed.mbed:main', 64 | ] 65 | } 66 | ) 67 | -------------------------------------------------------------------------------- /test/sync_update_test.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from util import * 14 | 15 | # Tests if a 'mbed sync', commit, and 'mbed update' works on a simple file change 16 | def test_sync_update(mbed, testrepos): 17 | test1 = testrepos[0] 18 | popen(['python', mbed, 'import', test1, 'testimport', '-vv']) 19 | 20 | with cd('test1/test2'): 21 | with open('hello', 'w') as f: 22 | f.write('hello\n') 23 | popen([scm(), 'add', 'hello']) 24 | popen(['python', mbed, 'sync', '-vv']) 25 | mkcommit() 26 | 27 | with cd('test1'): 28 | popen(['python', mbed, 'sync', '-vv']) 29 | mkcommit() 30 | 31 | with cd('testimport'): 32 | popen(['python', mbed, 'update', '-vv']) 33 | 34 | assert os.path.isfile('testimport/test2/hello') 35 | 36 | # Tests if removing a library is carried over sync/update 37 | def test_sync_update_remove(mbed, testrepos): 38 | test1 = testrepos[0] 39 | popen(['python', mbed, 'import', test1, 'testimport', '-vv']) 40 | 41 | with cd('test1/test2'): 42 | remove('test3') 43 | popen(['python', mbed, 'sync', '-vv']) 44 | mkcommit() 45 | 46 | with cd('test1'): 47 | popen(['python', mbed, 'sync', '-vv']) 48 | mkcommit() 49 | 50 | with cd('testimport'): 51 | popen(['python', mbed, 'update', '-vv']) 52 | 53 | assertls(mbed, 'testimport', [ 54 | "[mbed]", 55 | "testimport", 56 | "`- test2", 57 | ]) 58 | 59 | # Tests if adding a library is carried over sync/update 60 | def test_sync_update_add(mbed, testrepos): 61 | test1 = testrepos[0] 62 | popen(['python', mbed, 'import', test1, 'testimport', '-vv']) 63 | 64 | with cd('test1/test2'): 65 | copy('test3', 'testcopy') 66 | popen(['python', mbed, 'sync', '-vv']) 67 | mkcommit() 68 | 69 | with cd('test1'): 70 | popen(['python', mbed, 'sync', '-vv']) 71 | mkcommit() 72 | 73 | with cd('testimport'): 74 | popen(['python', mbed, 'update', '-vv']) 75 | 76 | assertls(mbed, 'testimport', [ 77 | "[mbed]", 78 | "testimport", 79 | "`- test2", 80 | " |- test3", 81 | " | `- test4", 82 | " `- testcopy", 83 | " `- test4", 84 | ]) 85 | 86 | # Tests if moving a library is carried over sync/update 87 | def test_sync_update_move(mbed, testrepos): 88 | test1 = testrepos[0] 89 | popen(['python', mbed, 'import', test1, 'testimport', '-vv']) 90 | 91 | with cd('test1/test2'): 92 | move('test3', 'testmove') 93 | popen(['python', mbed, 'sync', '-vv']) 94 | mkcommit() 95 | 96 | with cd('test1'): 97 | popen(['python', mbed, 'sync', '-vv']) 98 | mkcommit() 99 | 100 | with cd('testimport'): 101 | popen(['python', mbed, 'update', '-vv']) 102 | 103 | assertls(mbed, 'testimport', [ 104 | "[mbed]", 105 | "testimport", 106 | "`- test2", 107 | " `- testmove", 108 | " `- test4", 109 | ]) 110 | 111 | -------------------------------------------------------------------------------- /mbed/mbed_terminal.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | 9 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 14 | # either express or implied. 15 | 16 | 17 | # pylint: disable=too-many-arguments, too-many-locals, too-many-branches, too-many-lines, line-too-long, 18 | # pylint: disable=too-many-nested-blocks, too-many-public-methods, too-many-instance-attributes, too-many-statements 19 | # pylint: disable=invalid-name, missing-docstring, bad-continuation 20 | 21 | 22 | # Global class used for global config 23 | class MbedTerminal(object): 24 | serial = None # Serial() object 25 | port = None 26 | baudrate = None 27 | echo = None 28 | 29 | def __init__(self, port, baudrate=9600, echo=True, timeout=10): 30 | self.port = port 31 | self.baudrate = int(baudrate) 32 | self.timeout = int(timeout) 33 | self.echo = False if str(echo).lower() == 'off' else True 34 | 35 | try: 36 | from serial import Serial, SerialException 37 | self.serial = Serial(self.port, baudrate=self.baudrate, timeout=self.timeout) 38 | self.serial.flush() 39 | self.serial.reset_input_buffer() 40 | except (IOError, ImportError, OSError, Exception): 41 | self.serial = None 42 | return 43 | 44 | def terminal(self, print_header=True): 45 | try: 46 | import serial.tools.miniterm as miniterm 47 | except (IOError, ImportError, OSError): 48 | return False 49 | 50 | term = miniterm.Miniterm(self.serial, echo=self.echo) 51 | term.exit_character = '\x03' 52 | term.menu_character = '\x14' 53 | term.set_rx_encoding('UTF-8') 54 | term.set_tx_encoding('UTF-8') 55 | 56 | def console_print(text): 57 | term.console.write('--- %s ---\n' % text) 58 | 59 | def get_print_help(): 60 | return """ 61 | --- Mbed Serial Terminal (0.3a) 62 | --- Based on miniterm from pySerial 63 | --- 64 | --- Ctrl+b Send Break (reset target) 65 | --- Ctrl+c Exit terminal 66 | --- Ctrl+e Toggle local echo 67 | --- Ctrl+h Help 68 | --- Ctrl+t Menu escape key, followed by: 69 | --- p Change COM port 70 | --- b Change baudrate 71 | --- Tab Show detailed terminal info 72 | --- Ctrl+a Change encoding (default UTF-8) 73 | --- Ctrl+f Edit filters 74 | --- Ctrl+l Toggle EOL 75 | --- Ctrl+r Toggle RTS 76 | --- Ctrl+d Toggle DTR 77 | --- Ctrl+c Send control character to remote 78 | --- Ctrl+t Send control character to remote 79 | """ 80 | 81 | def print_help(): 82 | term.console.write(get_print_help()) 83 | 84 | 85 | def input_handler(): 86 | menu_active = False 87 | while term.alive: 88 | try: 89 | c = term.console.getkey() 90 | except KeyboardInterrupt: 91 | c = '\x03' 92 | if not term.alive: 93 | break 94 | if menu_active and c in ['p', 'b', '\t', '\x01', '\x03', '\x04', '\x05', '\x06', '\x0c', '\x14']: 95 | term.handle_menu_key(c) 96 | menu_active = False 97 | elif c == term.menu_character: 98 | console_print('[MENU]') 99 | menu_active = True # next char will be for menu 100 | elif c == '\x02': # ctrl+b sendbreak 101 | console_print('[RESET]') 102 | self.reset() 103 | elif c == '\x03': # ctrl+c 104 | console_print('[QUIT]') 105 | term.stop() 106 | term.alive = False 107 | break 108 | elif c == '\x05': # ctrl+e 109 | console_print('[ECHO %s]' % ('OFF' if term.echo else 'ON')) 110 | term.echo = not term.echo 111 | elif c == '\x08': # ctrl+h 112 | print_help() 113 | # elif c == '\t': # tab/ctrl+i 114 | # term.dump_port_settings() 115 | else: 116 | text = c 117 | for transformation in term.tx_transformations: 118 | text = transformation.tx(text) 119 | term.serial.write(term.tx_encoder.encode(text)) 120 | if term.echo: 121 | echo_text = c 122 | for transformation in term.tx_transformations: 123 | echo_text = transformation.echo(echo_text) 124 | term.console.write(echo_text) 125 | term.writer = input_handler 126 | 127 | if print_header: 128 | console_print("Terminal on {p.name} - {p.baudrate},{p.bytesize},{p.parity},{p.stopbits}".format(p=term.serial)) 129 | 130 | term.start() 131 | 132 | try: 133 | term.join(True) 134 | except KeyboardInterrupt: 135 | pass 136 | term.join() 137 | term.close() 138 | 139 | return True 140 | 141 | def reset(self): 142 | try: 143 | self.serial.sendBreak() 144 | except: 145 | try: 146 | self.serial.setBreak(False) # For Linux the following setBreak() is needed to release the reset signal on the target mcu. 147 | except: 148 | return False 149 | return True 150 | -------------------------------------------------------------------------------- /test/util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2016 ARM Limited, All Rights Reserved 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | 7 | # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 11 | # either express or implied. 12 | 13 | from __future__ import print_function 14 | 15 | import contextlib 16 | import subprocess 17 | import pytest 18 | import os 19 | import re 20 | import shutil 21 | import stat 22 | 23 | MBED_PATH = os.path.abspath(os.path.join('mbed', 'mbed.py')) 24 | 25 | # Process execution 26 | class ProcessException(Exception): 27 | pass 28 | 29 | def popen(command, stdin=None, **kwargs): 30 | print(' '.join(command)) 31 | proc = subprocess.Popen(command, **kwargs) 32 | 33 | if proc.wait() != 0: 34 | raise ProcessException(proc.returncode) 35 | 36 | def pquery(command, stdin=None, **kwargs): 37 | print(' '.join(command)) 38 | proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) 39 | stdout, _ = proc.communicate(stdin) 40 | 41 | if proc.returncode != 0: 42 | raise ProcessException(proc.returncode) 43 | 44 | return stdout.decode("utf-8") 45 | 46 | # Directory navigation 47 | @contextlib.contextmanager 48 | def cd(newdir): 49 | prevdir = os.getcwd() 50 | os.chdir(newdir) 51 | try: 52 | yield 53 | finally: 54 | os.chdir(prevdir) 55 | 56 | # Handling test environment 57 | @pytest.fixture 58 | def mbed(tmpdir): 59 | tmpdir.chdir() 60 | 61 | return MBED_PATH 62 | 63 | # Higher level functions 64 | def remove(path): 65 | def remove_readonly(func, path, _): 66 | os.chmod(path, stat.S_IWRITE) 67 | func(path) 68 | 69 | shutil.rmtree(path, onerror=remove_readonly) 70 | 71 | def move(src, dst): 72 | shutil.move(src, dst) 73 | 74 | def copy(src, dst): 75 | shutil.copytree(src, dst) 76 | 77 | # Test specific utils 78 | def mkgit(name): 79 | os.mkdir(name) 80 | with cd(name): 81 | popen(['git', 'init']) 82 | with open('test', 'w') as f: 83 | f.write('hello') 84 | popen(['git', 'add', 'test']) 85 | popen(['git', 'commit', '-m', '"commit 1"']) 86 | 87 | bare = os.path.abspath(name + '.git') 88 | popen(['git', 'clone', '--bare', name, bare]) 89 | remove(name) 90 | return os.path.abspath(bare).replace('\\', '/') 91 | 92 | def mkhg(name): 93 | os.mkdir(name+'.hg') 94 | with cd(name+'.hg'): 95 | popen(['hg', 'init']) 96 | with open('test', 'w') as f: 97 | f.write('hello') 98 | popen(['hg', 'add', 'test']) 99 | popen(['hg', 'commit', '-m', '"commit 1"']) 100 | 101 | return os.path.abspath(name+'.hg').replace('\\', '/') 102 | 103 | def assertls(mbed, dir, tree): 104 | tree = ''.join(re.escape(l)+r'.*\n' for l in tree) 105 | 106 | with cd(dir): 107 | result = pquery(['python', mbed, 'ls']) 108 | 109 | print(result) 110 | assert re.match(tree, result, re.MULTILINE) 111 | 112 | def scm(dir=None): 113 | if not dir: 114 | dir = os.getcwd() 115 | 116 | if os.path.isdir(os.path.join(dir, '.git')): 117 | return 'git' 118 | elif os.path.isdir(os.path.join(dir, '.hg')): 119 | return 'hg' 120 | 121 | def mkcommit(dir=None, files=[]): 122 | with cd(dir or os.getcwd()): 123 | if scm() == 'git': 124 | if files: 125 | popen(['git', 'add'] + files) 126 | popen(['git', 'commit', '-a', '-m', 'test commit']) 127 | popen(['git', 'push', 'origin', 'master']) 128 | elif scm() == 'hg': 129 | if files: 130 | popen(['hg', 'add'] + files) 131 | popen(['hg', 'commit', '-m', 'test commit']) 132 | popen(['hg', 'push']) 133 | 134 | # Different repository structures 135 | @pytest.fixture(params=['git1', 'hg1', 'alt1', 'alt2']) 136 | def testrepos(mbed, request): 137 | if request.param in ['git1', 'alt1']: 138 | test1 = mkgit('test1') 139 | popen(['git', 'clone', test1, 'test1']) 140 | else: 141 | test1 = mkhg('test1') 142 | popen(['hg', 'clone', test1, 'test1']) 143 | 144 | if request.param in ['git1', 'alt2']: 145 | test2 = mkgit('test2') 146 | popen(['git', 'clone', test2, 'test1/test2']) 147 | else: 148 | test2 = mkhg('test2') 149 | popen(['hg', 'clone', test2, 'test1/test2']) 150 | 151 | if request.param in ['git1', 'alt1']: 152 | test3 = mkgit('test3') 153 | popen(['git', 'clone', test3, 'test1/test2/test3']) 154 | else: 155 | test3 = mkhg('test3') 156 | popen(['hg', 'clone', test3, 'test1/test2/test3']) 157 | 158 | if request.param in ['git1', 'alt2']: 159 | test4 = mkgit('test4') 160 | popen(['git', 'clone', test4, 'test1/test2/test3/test4']) 161 | else: 162 | test4 = mkhg('test4') 163 | popen(['hg', 'clone', test4, 'test1/test2/test3/test4']) 164 | 165 | with cd('test1/test2/test3'): 166 | with open('test4.lib', 'w') as f: 167 | hash = 'none' 168 | with cd('test4'): 169 | if scm() == 'git': 170 | hash = pquery(['git', 'rev-parse', 'HEAD']) 171 | elif scm() == 'hg': 172 | hash = pquery(['hg', 'id', '-i']) 173 | f.write(test4 + '/#' + hash + '\n') 174 | 175 | if scm() == 'git': 176 | popen(['git', 'add', 'test4.lib']) 177 | popen(['git', 'commit', '-m', 'test commit']) 178 | popen(['git', 'push', 'origin', 'master']) 179 | elif scm() == 'hg': 180 | popen(['hg', 'add', 'test4.lib']) 181 | popen(['hg', 'commit', '-m', 'test commit']) 182 | popen(['hg', 'push']) 183 | 184 | with cd('test1/test2'): 185 | with open('test3.lib', 'w') as f: 186 | with cd('test3'): 187 | if scm() == 'git': 188 | hash = pquery(['git', 'rev-parse', 'HEAD']) 189 | elif scm() == 'hg': 190 | hash = pquery(['hg', 'id', '-i']) 191 | f.write(test3 + '/#' + hash + '\n') 192 | 193 | if scm() == 'git': 194 | popen(['git', 'add', 'test3.lib']) 195 | popen(['git', 'commit', '-m', 'test commit']) 196 | popen(['git', 'push', 'origin', 'master']) 197 | elif scm() == 'hg': 198 | popen(['hg', 'add', 'test3.lib']) 199 | popen(['hg', 'commit', '-m', 'test commit']) 200 | popen(['hg', 'push']) 201 | 202 | with cd('test1'): 203 | with open('test2.lib', 'w') as f: 204 | with cd('test2'): 205 | if scm() == 'git': 206 | hash = pquery(['git', 'rev-parse', 'HEAD']) 207 | elif scm() == 'hg': 208 | hash = pquery(['hg', 'id', '-i']) 209 | f.write(test2 + '/#' + hash + '\n') 210 | 211 | if scm() == 'git': 212 | popen(['git', 'add', 'test2.lib']) 213 | popen(['git', 'commit', '-m', 'test commit']) 214 | popen(['git', 'push', 'origin', 'master']) 215 | elif scm() == 'hg': 216 | popen(['hg', 'add', 'test2.lib']) 217 | popen(['hg', 'commit', '-m', 'test commit']) 218 | popen(['hg', 'push']) 219 | 220 | return test1, test2, test3, test4 221 | 222 | -------------------------------------------------------------------------------- /tools/bash_completion/generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Michael Bartling (michael.bartling@arm.com) 3 | 4 | from collections import defaultdict 5 | import pystache 6 | import re 7 | import subprocess 8 | 9 | # Top level --version is a pain to deal with so ignoring for now 10 | # This one extracts single commands and the help txt 11 | commandRegex = r"^\s+(?P\w+)\s+(?P[a-zA-Z ]*)$" 12 | 13 | # Why the hell do spaces get regexed in command1 ? 14 | subcommandRegex = r"^\s+(?P-+[a-zA-Z_\-]+(?P\s+[A-Z_\-]+)?)"\ 15 | r"(?P,\s+-+[a-zA-Z_-]+(?P\s+[A-Z_-]+)?)?"\ 16 | r"\s+(?P.*)$" 17 | 18 | 19 | def getHelpTxt(command=None): 20 | if command: 21 | p = subprocess.Popen(["mbed", command, "-h"], stdout=subprocess.PIPE) 22 | else: 23 | p = subprocess.Popen(["mbed", "-h"], stdout=subprocess.PIPE) 24 | out, err = p.communicate() 25 | return out 26 | 27 | def getTargetCode(): 28 | with open("templates/target.tmplt") as fp: 29 | txt = fp.read() 30 | return txt 31 | 32 | def getToolchainCode(): 33 | with open("templates/toolchain.tmplt") as fp: 34 | txt = fp.read() 35 | return txt 36 | 37 | def getSCMCode(): 38 | with open("templates/scm.tmplt") as fp: 39 | txt = fp.read() 40 | return txt 41 | 42 | def getIDECode(): 43 | with open("templates/ide.tmplt") as fp: 44 | txt = fp.read() 45 | return txt 46 | 47 | def getProtocolCode(): 48 | with open("templates/protocol.tmplt") as fp: 49 | txt = fp.read() 50 | return txt 51 | 52 | def parseCommands(): 53 | commands = defaultdict(defaultdict) 54 | commands["COMMAND"] = [] 55 | helpTxt = getHelpTxt() 56 | # print helpTxt 57 | for line in helpTxt.split('\n'): 58 | match = re.search(commandRegex, line) 59 | if match: 60 | g = match.groupdict() 61 | commands[g["command"]]["helptxt"] = g["helptxt"] 62 | commands[g["command"]]["subcommands"] = [] 63 | 64 | # Subcommand mustache generation 65 | commands[g["command"]]["DDASH_COMMANDS"] = [] 66 | commands[g["command"]]["DASH_COMMANDS"] = [] 67 | commands[g["command"]]["COMMAND"] = g["command"] 68 | 69 | commands[g["command"]]["HAVE_PREV"] = {"PREV_CASE": []} 70 | 71 | # Main function generation 72 | commands["COMMAND"].append({"name": g["command"]}) 73 | 74 | for commandKey in commands: 75 | # Skip 76 | if commandKey == "COMMAND": 77 | continue 78 | 79 | helpTxt = getHelpTxt(commandKey) 80 | for line in helpTxt.split('\n'): 81 | match = re.search(subcommandRegex, line) 82 | if match: 83 | commandMatch = match.groupdict() 84 | 85 | # Clean up the subcommands 86 | command1 = commandMatch["command1"] 87 | command2 = commandMatch["command2"] 88 | 89 | if command1: 90 | command1 = re.sub(",", "", command1) 91 | command1.strip() 92 | command1 = command1.split()[0] 93 | if command2: 94 | command2 = re.sub(",", "", command2) 95 | command2.strip() 96 | command2 = command2.split()[0] 97 | 98 | # Not sure why the cleaning is even necessary, 99 | # the regex looks correct 100 | commandMatch["command1"] = command1 101 | commandMatch["command2"] = command2 102 | 103 | commands[commandKey]["subcommands"].append(commandMatch) 104 | 105 | # Push format for mustache 106 | if command1 and '--' in command1: 107 | commands[commandKey]["DDASH_COMMANDS"].append( 108 | {"name": command1}) 109 | if command2 and '--' in command2: 110 | commands[commandKey]["DDASH_COMMANDS"].append( 111 | {"name": command2}) 112 | 113 | if command1: 114 | m = re.match("^-[a-zA-Z]{1,2}", command1) 115 | if m: 116 | commands[commandKey]["DASH_COMMANDS"].append( 117 | {"name": command1}) 118 | else: 119 | command1 = "" 120 | 121 | if command2: 122 | m = re.match("^-[a-zA-Z]{1,2}", command2) 123 | if m: 124 | commands[commandKey]["DASH_COMMANDS"].append( 125 | {"name": command2}) 126 | else: 127 | command2 = "" 128 | 129 | # Adding the dependent command handlers 130 | if "target" in command1 or "target" in command2: 131 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": "|".join(filter(None, [command1, command2])), "code": getTargetCode()}) 132 | 133 | if "toolchain" in command1 or "toolchain" in command2: 134 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": "|".join(filter(None, [command1, command2])), "code": getToolchainCode()}) 135 | 136 | 137 | if "--ide" in command1 or "--ide" in command2: 138 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": "|".join(filter(None, [command1, command2])), "code": getIDECode()}) 139 | 140 | if "scm" in command1 or "scm" in command2: 141 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": "|".join(filter(None, [command1, command2])), "code": getSCMCode()}) 142 | 143 | if "protocol" in command1 or "protocol" in command2: 144 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": "|".join(filter(None, [command1, command2])), "code": getProtocolCode()}) 145 | 146 | # Adding the dependent command handlers for target and toolchain 147 | if "target" in commandKey: 148 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": commandKey, "code": getTargetCode()}) 149 | 150 | if "toolchain" in commandKey: 151 | commands[commandKey]["HAVE_PREV"]["PREV_CASE"].append({"case": commandKey, "code": getToolchainCode()}) 152 | 153 | return commands 154 | 155 | 156 | def generateMain(commands): 157 | txt = [] 158 | 159 | with open("templates/mbed.tmplt") as fp: 160 | tmplt = fp.read() 161 | 162 | txt.append(pystache.render(tmplt, commands)) 163 | 164 | return txt 165 | 166 | 167 | def generateCompleters(commands): 168 | txt = [] 169 | 170 | renderer = pystache.Renderer(escape=lambda u: u) 171 | 172 | with open("templates/command.tmplt") as fp: 173 | tmplt = fp.read() 174 | 175 | for commandKey in commands: 176 | txt.append(renderer.render(tmplt, commands[commandKey])) 177 | 178 | # if need to add hacks add them here 179 | 180 | return txt 181 | 182 | 183 | def generateBoilerPlate(_): 184 | txt = [] 185 | 186 | with open("templates/boilerplate.tmplt") as fp: 187 | txt.append(fp.read()) 188 | 189 | return txt 190 | 191 | 192 | def generateScript(commands): 193 | txt = [] 194 | 195 | txt.extend(generateBoilerPlate(commands)) 196 | txt.extend(generateCompleters(commands)) 197 | txt.extend(generateMain(commands)) 198 | 199 | with open("mbed-completion", "w") as fp: 200 | for x in txt: 201 | fp.write("%s\n" % x) 202 | 203 | 204 | if __name__ == '__main__': 205 | commands = parseCommands() 206 | 207 | # At this point we have a list of all the commands and sub commands 208 | # for each command create a Bash function 209 | # register each subcommand 210 | generateScript(commands) 211 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | -------------------------------------------------------------------------------- /tools/bash_completion/mbed: -------------------------------------------------------------------------------- 1 | # Based on mbed auto complete scripts 2 | 3 | __mbedcomp_words_include() { 4 | local i=1 5 | while [[ "$i" -lt "$COMP_CWORD" ]] 6 | do 7 | if [[ "${COMP_WORDS[i]}" = "$1" ]] 8 | then 9 | return 0 10 | fi 11 | i="$((++i))" 12 | done 13 | return 1 14 | } 15 | 16 | # Find the previous non-switch word 17 | __mbedcomp_prev() { 18 | local idx="$((COMP_CWORD - 1))" 19 | local prv="${COMP_WORDS[idx]}" 20 | while [[ "$prv" = -* ]] 21 | do 22 | idx="$((--idx))" 23 | prv="${COMP_WORDS[idx]}" 24 | done 25 | echo "$prv" 26 | } 27 | 28 | __mbedcomp() { 29 | # break $1 on space, tab, and newline characters, 30 | # and turn it into a newline separated list of words 31 | local list s sep=$'\n' IFS=$' '$'\t'$'\n' 32 | local cur="${COMP_WORDS[COMP_CWORD]}" 33 | 34 | for s in $1 35 | do 36 | __mbedcomp_words_include "$s" && continue 37 | list="$list$s$sep" 38 | done 39 | 40 | IFS="$sep" 41 | COMPREPLY=($(compgen -W "$list" -- "$cur")) 42 | } 43 | 44 | __mbed_complete_new() { 45 | 46 | local cur="${COMP_WORDS[COMP_CWORD]}" 47 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 48 | case "$cur" in 49 | --*) 50 | __mbedcomp " 51 | --help 52 | --scm 53 | --program 54 | --library 55 | --mbedlib 56 | --create-only 57 | --depth 58 | --protocol 59 | --verbose 60 | --very_verbose 61 | " 62 | 63 | return 64 | ;; 65 | -*) 66 | __mbedcomp " 67 | -h 68 | -v 69 | -vv 70 | " 71 | return 72 | ;; 73 | esac 74 | case "$prev" in 75 | --scm) 76 | __mbedcomp "bld git hg" 77 | return 78 | ;; 79 | --protocol) 80 | __mbedcomp "https http ssh git" 81 | return 82 | ;; 83 | esac 84 | } 85 | 86 | __mbed_complete_import() { 87 | 88 | local cur="${COMP_WORDS[COMP_CWORD]}" 89 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 90 | case "$cur" in 91 | --*) 92 | __mbedcomp " 93 | --help 94 | --ignore 95 | --depth 96 | --protocol 97 | --verbose 98 | --very_verbose 99 | " 100 | 101 | return 102 | ;; 103 | -*) 104 | __mbedcomp " 105 | -h 106 | -I 107 | -v 108 | -vv 109 | " 110 | return 111 | ;; 112 | esac 113 | case "$prev" in 114 | --protocol) 115 | __mbedcomp "https http ssh git" 116 | return 117 | ;; 118 | esac 119 | } 120 | 121 | __mbed_complete_add() { 122 | 123 | local cur="${COMP_WORDS[COMP_CWORD]}" 124 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 125 | case "$cur" in 126 | --*) 127 | __mbedcomp " 128 | --help 129 | --ignore 130 | --depth 131 | --protocol 132 | --verbose 133 | --very_verbose 134 | " 135 | 136 | return 137 | ;; 138 | -*) 139 | __mbedcomp " 140 | -h 141 | -I 142 | -v 143 | -vv 144 | " 145 | return 146 | ;; 147 | esac 148 | case "$prev" in 149 | --protocol) 150 | __mbedcomp "https http ssh git" 151 | return 152 | ;; 153 | esac 154 | } 155 | 156 | __mbed_complete_remove() { 157 | 158 | local cur="${COMP_WORDS[COMP_CWORD]}" 159 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 160 | case "$cur" in 161 | --*) 162 | __mbedcomp " 163 | --help 164 | --verbose 165 | --very_verbose 166 | " 167 | 168 | return 169 | ;; 170 | -*) 171 | __mbedcomp " 172 | -h 173 | -v 174 | -vv 175 | " 176 | return 177 | ;; 178 | esac 179 | } 180 | 181 | __mbed_complete_deploy() { 182 | 183 | local cur="${COMP_WORDS[COMP_CWORD]}" 184 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 185 | case "$cur" in 186 | --*) 187 | __mbedcomp " 188 | --help 189 | --ignore 190 | --depth 191 | --protocol 192 | --verbose 193 | --very_verbose 194 | " 195 | 196 | return 197 | ;; 198 | -*) 199 | __mbedcomp " 200 | -h 201 | -I 202 | -v 203 | -vv 204 | " 205 | return 206 | ;; 207 | esac 208 | case "$prev" in 209 | --protocol) 210 | __mbedcomp "https http ssh git" 211 | return 212 | ;; 213 | esac 214 | } 215 | 216 | __mbed_complete_publish() { 217 | 218 | local cur="${COMP_WORDS[COMP_CWORD]}" 219 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 220 | case "$cur" in 221 | --*) 222 | __mbedcomp " 223 | --help 224 | --all 225 | --message 226 | --verbose 227 | --very_verbose 228 | " 229 | 230 | return 231 | ;; 232 | -*) 233 | __mbedcomp " 234 | -h 235 | -A 236 | -M 237 | -v 238 | -vv 239 | " 240 | return 241 | ;; 242 | esac 243 | } 244 | 245 | __mbed_complete_update() { 246 | 247 | local cur="${COMP_WORDS[COMP_CWORD]}" 248 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 249 | case "$cur" in 250 | --*) 251 | __mbedcomp " 252 | --help 253 | --clean 254 | --clean-files 255 | --clean-deps 256 | --ignore 257 | --depth 258 | --protocol 259 | --verbose 260 | --very_verbose 261 | " 262 | 263 | return 264 | ;; 265 | -*) 266 | __mbedcomp " 267 | -h 268 | -C 269 | -I 270 | -v 271 | -vv 272 | " 273 | return 274 | ;; 275 | esac 276 | case "$prev" in 277 | --protocol) 278 | __mbedcomp "https http ssh git" 279 | return 280 | ;; 281 | esac 282 | } 283 | 284 | __mbed_complete_sync() { 285 | 286 | local cur="${COMP_WORDS[COMP_CWORD]}" 287 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 288 | case "$cur" in 289 | --*) 290 | __mbedcomp " 291 | --help 292 | --verbose 293 | --very_verbose 294 | " 295 | 296 | return 297 | ;; 298 | -*) 299 | __mbedcomp " 300 | -h 301 | -v 302 | -vv 303 | " 304 | return 305 | ;; 306 | esac 307 | } 308 | 309 | __mbed_complete_ls() { 310 | 311 | local cur="${COMP_WORDS[COMP_CWORD]}" 312 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 313 | case "$cur" in 314 | --*) 315 | __mbedcomp " 316 | --help 317 | --all 318 | --ignore 319 | --verbose 320 | --very_verbose 321 | " 322 | 323 | return 324 | ;; 325 | -*) 326 | __mbedcomp " 327 | -h 328 | -a 329 | -I 330 | -v 331 | -vv 332 | " 333 | return 334 | ;; 335 | esac 336 | } 337 | 338 | __mbed_complete_status() { 339 | 340 | local cur="${COMP_WORDS[COMP_CWORD]}" 341 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 342 | case "$cur" in 343 | --*) 344 | __mbedcomp " 345 | --help 346 | --ignore 347 | --verbose 348 | --very_verbose 349 | " 350 | 351 | return 352 | ;; 353 | -*) 354 | __mbedcomp " 355 | -h 356 | -I 357 | -v 358 | -vv 359 | " 360 | return 361 | ;; 362 | esac 363 | } 364 | 365 | __mbed_complete_compile () { 366 | 367 | local cur="${COMP_WORDS[COMP_CWORD]}" 368 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 369 | case "$cur" in 370 | --*) 371 | __mbedcomp " 372 | --help 373 | --toolchain 374 | --target 375 | --profile 376 | --library 377 | --config 378 | --prefix 379 | --source 380 | --build 381 | --clean 382 | --artifact-name 383 | --supported 384 | --app-config 385 | --verbose 386 | --very_verbose 387 | " 388 | 389 | return 390 | ;; 391 | -*) 392 | __mbedcomp " 393 | -h 394 | -t 395 | -m 396 | -c 397 | -N 398 | -S 399 | -v 400 | -vv 401 | " 402 | return 403 | ;; 404 | esac 405 | case "$prev" in 406 | --target|-m) 407 | declare TARGETS=$(mbed target --supported | cut -d '|' -f 2 | sed -n '/^+/!p' | sed -n '/^Supported/!p' | sed -n '/^ [A-Z][A-Z]/p') 408 | __mbedcomp "${TARGETS}" 409 | return 410 | ;; 411 | --toolchain|-t) 412 | declare TOOLCHAINS=$(mbed target --supported | head -n 2 | tail -n 1 | tr '|' '\n' | sed -n '/^ Target/!p' | sed -n '/^ mbed/!p') 413 | __mbedcomp "${TOOLCHAINS}" 414 | return 415 | ;; 416 | esac 417 | } 418 | 419 | __mbed_complete_test() { 420 | 421 | local cur="${COMP_WORDS[COMP_CWORD]}" 422 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 423 | case "$cur" in 424 | --*) 425 | __mbedcomp " 426 | --help 427 | --toolchain 428 | --target 429 | --compile-list 430 | --run-list 431 | --compile 432 | --run 433 | --tests-by-name 434 | --source 435 | --build 436 | --profile 437 | --clean 438 | --test-spec 439 | --app-config 440 | --verbose 441 | --very_verbose 442 | " 443 | 444 | return 445 | ;; 446 | -*) 447 | __mbedcomp " 448 | -h 449 | -t 450 | -m 451 | -n 452 | -c 453 | -v 454 | -vv 455 | " 456 | return 457 | ;; 458 | esac 459 | case "$prev" in 460 | --target|-m) 461 | declare TARGETS=$(mbed target --supported | cut -d '|' -f 2 | sed -n '/^+/!p' | sed -n '/^Supported/!p' | sed -n '/^ [A-Z][A-Z]/p') 462 | __mbedcomp "${TARGETS}" 463 | return 464 | ;; 465 | --toolchain|-t) 466 | declare TOOLCHAINS=$(mbed target --supported | head -n 2 | tail -n 1 | tr '|' '\n' | sed -n '/^ Target/!p' | sed -n '/^ mbed/!p') 467 | __mbedcomp "${TOOLCHAINS}" 468 | return 469 | ;; 470 | esac 471 | } 472 | 473 | __mbed_complete_export() { 474 | 475 | local cur="${COMP_WORDS[COMP_CWORD]}" 476 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 477 | case "$cur" in 478 | --*) 479 | __mbedcomp " 480 | --help 481 | --ide 482 | --target 483 | --source 484 | --clean 485 | --supported 486 | --verbose 487 | --very_verbose 488 | " 489 | 490 | return 491 | ;; 492 | -*) 493 | __mbedcomp " 494 | -h 495 | -i 496 | -m 497 | -c 498 | -S 499 | -v 500 | -vv 501 | " 502 | return 503 | ;; 504 | esac 505 | case "$prev" in 506 | --target|-m) 507 | declare TARGETS=$(mbed export --supported | cut -d '|' -f 2 | sed -n '/^+/!p' | sed -n '/^Platform/!p' | sed -n '/^Total/!p') 508 | __mbedcomp "${TARGETS}" 509 | return 510 | ;; 511 | --ide|-i) 512 | declare IDES=$(mbed export --supported | tail -n +1 | head -n 2 | tr '|' '\n' | sed -n '/^+/!p' | sed -n '/^ Platform/!p') 513 | __mbedcomp "${IDES}" 514 | return 515 | ;; 516 | esac 517 | } 518 | 519 | __mbed_complete_detect() { 520 | 521 | local cur="${COMP_WORDS[COMP_CWORD]}" 522 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 523 | case "$cur" in 524 | --*) 525 | __mbedcomp " 526 | --help 527 | --verbose 528 | --very_verbose 529 | " 530 | 531 | return 532 | ;; 533 | -*) 534 | __mbedcomp " 535 | -h 536 | -v 537 | -vv 538 | " 539 | return 540 | ;; 541 | esac 542 | } 543 | 544 | __mbed_complete_config() { 545 | 546 | local cur="${COMP_WORDS[COMP_CWORD]}" 547 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 548 | case "$cur" in 549 | --*) 550 | __mbedcomp " 551 | --help 552 | --global 553 | --unset 554 | --list 555 | --verbose 556 | --very_verbose 557 | " 558 | 559 | return 560 | ;; 561 | -*) 562 | __mbedcomp " 563 | -h 564 | -G 565 | -U 566 | -L 567 | -v 568 | -vv 569 | " 570 | return 571 | ;; 572 | esac 573 | } 574 | 575 | __mbed_complete_target() { 576 | 577 | local cur="${COMP_WORDS[COMP_CWORD]}" 578 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 579 | case "$cur" in 580 | --*) 581 | __mbedcomp " 582 | --help 583 | --global 584 | --supported 585 | --verbose 586 | --very_verbose 587 | " 588 | 589 | return 590 | ;; 591 | -*) 592 | __mbedcomp " 593 | -h 594 | -G 595 | -S 596 | -v 597 | -vv 598 | " 599 | return 600 | ;; 601 | esac 602 | case "$prev" in 603 | target|-G|--global|-v|--verbose|-vv|--very_verbose) 604 | declare TARGETS=$(mbed target --supported | cut -d '|' -f 2 | sed -n '/^+/!p' | sed -n '/^Supported/!p' | sed -n '/^ [A-Z][A-Z]/p') 605 | __mbedcomp "${TARGETS}" 606 | return 607 | ;; 608 | esac 609 | } 610 | __mbed_complete_toolchain() { 611 | 612 | local cur="${COMP_WORDS[COMP_CWORD]}" 613 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 614 | case "$cur" in 615 | --*) 616 | __mbedcomp " 617 | --help 618 | --global 619 | --supported 620 | --verbose 621 | --very_verbose 622 | " 623 | 624 | return 625 | ;; 626 | -*) 627 | __mbedcomp " 628 | -h 629 | -G 630 | -S 631 | -v 632 | -vv 633 | " 634 | return 635 | ;; 636 | esac 637 | case "$prev" in 638 | toolchain|-G|--global|-v|--verbose|-vv|--very_verbose) 639 | declare TOOLCHAINS=$(mbed target --supported | head -n 2 | tail -n 1 | tr '|' '\n' | sed -n '/^ Target/!p' | sed -n '/^ mbed/!p') 640 | __mbedcomp "${TOOLCHAINS}" 641 | return 642 | ;; 643 | esac 644 | } 645 | 646 | __mbed_complete_help() { 647 | 648 | local cur="${COMP_WORDS[COMP_CWORD]}" 649 | local prev="${COMP_WORDS[COMP_CWORD-1]}" 650 | case "$cur" in 651 | --*) 652 | __mbedcomp " 653 | --help 654 | --verbose 655 | --very_verbose 656 | " 657 | 658 | return 659 | ;; 660 | -*) 661 | __mbedcomp " 662 | -h 663 | -v 664 | -vv 665 | " 666 | return 667 | ;; 668 | esac 669 | } 670 | 671 | _mbed () { 672 | local i=1 cmd prev 673 | 674 | prev="${COMP_WORDS[COMP_CWORD-1]}" 675 | 676 | # find the subcommand 677 | while [[ "$i" -lt "$COMP_CWORD" ]] 678 | do 679 | local s="${COMP_WORDS[i]}" 680 | case "$s" in 681 | --*) 682 | cmd="$s" 683 | break 684 | ;; 685 | -*) 686 | ;; 687 | *) 688 | cmd="$s" 689 | break 690 | ;; 691 | esac 692 | 693 | i="$((++i))" 694 | done 695 | 696 | # Handle the main command completions 697 | if [[ "$i" -eq "$COMP_CWORD" ]] 698 | then 699 | local cmds=" 700 | --version 701 | new 702 | import 703 | add 704 | remove 705 | deploy 706 | publish 707 | update 708 | sync 709 | ls 710 | status 711 | compile 712 | test 713 | export 714 | detect 715 | config 716 | target 717 | toolchain 718 | help 719 | " 720 | 721 | __mbedcomp "${cmds}" 722 | fi 723 | 724 | # Each subcommand has a completion function based on the parent 725 | case "$cmd" in 726 | new) __mbed_complete_new ;; 727 | import) __mbed_complete_import ;; 728 | add) __mbed_complete_add ;; 729 | remove) __mbed_complete_remove ;; 730 | deploy) __mbed_complete_deploy ;; 731 | publish) __mbed_complete_publish ;; 732 | update) __mbed_complete_update ;; 733 | sync) __mbed_complete_sync ;; 734 | ls) __mbed_complete_ls ;; 735 | status) __mbed_complete_status ;; 736 | compile) __mbed_complete_compile ;; 737 | test) __mbed_complete_test ;; 738 | export) __mbed_complete_export;; 739 | detect) __mbed_complete_detect ;; 740 | config) __mbed_complete_config ;; 741 | target) __mbed_complete_target ;; 742 | toolchain) __mbed_complete_toolchain ;; 743 | *) ;; 744 | esac 745 | 746 | } 747 | 748 | complete -o bashdefault -o default -F _mbed mbed 749 | complete -o bashdefault -o default -F _mbed mbed-cli 750 | 751 | --------------------------------------------------------------------------------