Modified 2020-07-17 by Andrea Censi
Modified 2020-07-17 by Andrea Censi
You can download the source code of the commands by forking the duckietown-shell-commands
repository and pulling your fork locally. The repository can be found
here.
Modified 2019-09-22 by Andrea Censi
Move to the directory where you pulled the commands repository. Run
$ tree ./
You should be able to see a hierarchy of Python files that looks like the following,
./
├── README.md
├── __init__.py
├── lib
│ └── ...
│ ...
├── install
│ ├── __init__.py
│ ├── command.py
│ └── installed.flag
├── uninstall
│ ├── __init__.py
│ ├── command.py
│ └── installed.flag
...
├── exit
│ ├── __init__.py
│ ├── command.py
│ └── installed.flag
└── version
├── __init__.py
├── command.py
└── installed.flag
Let us focus on the directories first. The directory lib
is reserved to third-party libraries needed by the
commands. Each directory (except for lib
) defines a command. You will recognize some of the core commands
(e.g., install, uninstall, version). The name of the directory defines the name of the command.
A valid command name can contain only alphanumeric characters plus _
and -
.
Let us focus on files now.
dts
determines whether a command mycommand
is installed by looking for the file
./mycommand/installed.flag
.
All the command directories contain a default __init__.py
file. Such file is the same for all the commands.
A standard template file __init__.py.template
that you can copy if you wish to implement your own command
is available in the main level of the repository.
All the magic happens in the file command.py
, where the logic of the command is implemented.
If you want to learn more about how to create your own command, read the section Subsection 2.0.3 - Create a new command.
This is all you need to know about the structure of the repository.
Modified 2019-09-22 by Andrea Censi
Before you can create a new command, you have to pull the source code locally as described in Subsection 2.0.1 - Downloading the commands. It is also important that you are familiar with the structure of the repository (described in Subsection 2.0.2 - Understanding the structure of the repository).
You can create a command mycommand
by creating a directory in the main level of the repository with
the following structure
./
...
└── mycommand
├── __init__.py
└── command.py
You can copy the files __init__.py.template
and command.py.template
that you find on the main level of
the repo into your new command directory renaming them as __init__.py
and command.py
respectively.
This is enough to get your new command in dt-shell
. Launch dt-shell
and run
$ dt> mycommand
You should be able to see something like the following
dts> mycommand
You called the "mycommand" command, level 0, with arguments []
You can pass arguments to your command. For example, by running
$ dt> mycommand --arg1 value1
the shell will return
dts> mycommand
You called the "mycommand" command, level 0, with arguments ['--arg1', 'value1']
When the user types in the command mycommand
and presses Enter, the file ./mycommand/command.py
will be used to serve the request.
A valid file command.py
will have the following structure
from dt_shell import DTCommandAbs
class DTCommand(DTCommandAbs):
help = 'Brief description of the command' # please redefine this help message
# name = <read-only> a string with the name of the command
# level = <read-only> an integer indicating the level of this command. Follows the directory hierarchy
# commands = <read-only> a dictionary of subcommands
@staticmethod
def command(shell, args):
# this function will be invoked when the user presses the [Return] key and submits the command
#
# shell is the instance of DTShell hosting this command
# args is a list of arguments passed to the command
#
# PUT YOUR CODE HERE
print(
'You called the "%s" command, level %d, with arguments %r' % (
DTCommand.name,
DTCommand.level,
args
)
)
@staticmethod
def complete(shell, word, line):
# this function will be invoked when the user presses the [Tab] key for auto completion.
#
# shell is the instance of DTShell hosting this command
# word is the right-most word typed in the terminal (usually the string the user is trying to auto-complete)
# line is the entire command
#
# return a list of strings. Each string is a suggestion for the user
#
# PUT YOUR CODE HERE
return ['suggestion_1', 'suggestion_2']
You can find the same template in the file command.py.template
in the main level of the repository.
You can recognize the default message printed above by the method command(shell, args)
of the command mycommand
.
The method command(shell, args)
is invoked by the object shell
when the user presses Enter
and submits the argument args
to the command. The argument shell
is the instance of DTShell hosting this
command, while args
is the list of arguments passed to the command.
The method complete(shell, word, line)
is invoked by the object shell
when the user presses Tab
and requests auto-complete. This method should return a list of strings, with each string being a suggestion
for completing the command.
Modified 2019-09-22 by Andrea Censi
Before you can create a new command, you have to pull the source code locally as described in Subsection 2.0.1 - Downloading the commands. It is also important that you are familiar with the structure of the repository (described in Subsection 2.0.2 - Understanding the structure of the repository).
You can follow the instructions in the section Subsection 2.0.3 - Create a new command to learn how the shell reacts to the input of the user and update your commands accordingly.
Modified 2020-07-17 by Andrea Censi
You can add third-party libraries to the ./lib/
directory using git submodule
if you have access to a
public git
repository that you can pull. Alternatively (but not suggested) you can simply copy your library
in the ./lib/
directory and push it together with the commands.
dt-shell
prepends the ./lib/
path to the $PYTHON_PATH
environment variable before calling your command function.
If you have your library in ./lib/my_lib/foo.py
, you can add the line
from my_lib import foo
at the very top
of your command.py
file.
dt-shell
will take care of updating your library when the user runs dt> update
if you use git submodule
.