mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 05:16:31 +01:00
Reorganize docs into flat folder layout
This commit is contained in:
parent
106558cec0
commit
892d8efb93
135 changed files with 34 additions and 1180 deletions
222
docs/source/Coding/Continuous-Integration.md
Normal file
222
docs/source/Coding/Continuous-Integration.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
# Continuous Integration
|
||||
|
||||
One of the advantages of Evennia over traditional MUSH development systems is that Evennia is
|
||||
capable of integrating into enterprise level integration environments and source control. Because of
|
||||
this, it can also be the subject of automation for additional convenience, allowing a more
|
||||
streamlined development environment.
|
||||
|
||||
## What is Continuous Integration?
|
||||
|
||||
[Continuous Integration (CI)](https://www.thoughtworks.com/continuous-integration) is a development
|
||||
practice that requires developers to integrate code into a shared repository several times a day.
|
||||
Each check-in is then verified by an automated build, allowing teams to detect problems early.
|
||||
|
||||
For Evennia, continuous integration allows an automated build process to:
|
||||
* Pull down a latest build from Source Control.
|
||||
* Run migrations on the backing SQL database.
|
||||
* Automate additional unique tasks for that project.
|
||||
* Run unit tests.
|
||||
* Publish those files to the server directory
|
||||
* Reload the game.
|
||||
|
||||
## Preparation
|
||||
To prepare a CI environment for your `MU*`, it will be necessary to set up some prerequisite
|
||||
software for your server.
|
||||
|
||||
Among those you will need:
|
||||
* A Continuous Integration Environment.
|
||||
* I recommend [TeamCity](https://www.jetbrains.com/teamcity/) which has an in-depth [Setup
|
||||
Guide](https://confluence.jetbrains.com/display/TCD8/Installing+and+Configuring+the+TeamCity+Server)
|
||||
* [Source Control](Version-Control)
|
||||
* This could be Git or SVN or any other available SC.
|
||||
|
||||
## Linux TeamCity Setup
|
||||
For this part of the guide, an example setup will be provided for administrators running a TeamCity
|
||||
build integration environment on Linux.
|
||||
|
||||
After meeting the preparation steps for your specific environment, log on to your teamcity interface
|
||||
at `http://<your server>:8111/`.
|
||||
|
||||
Create a new project named "Evennia" and in it construct a new template called continuous-
|
||||
integration.
|
||||
|
||||
### A Quick Overview
|
||||
Templates are fancy objects in TeamCity that allow an administrator to define build steps that are
|
||||
shared between one or more build projects. Assigning a VCS Root (Source Control) is unnecessary at
|
||||
this stage, primarily you'll be worrying about the build steps and your default parameters (both
|
||||
visible on the tabs to the left.)
|
||||
|
||||
### Template Setup
|
||||
|
||||
In this template, you'll be outlining the steps necessary to build your specific game. (A number of
|
||||
sample scripts are provided under this section below!) Click Build Steps and prepare your general
|
||||
flow. For this example, we will be doing a few basic example steps:
|
||||
|
||||
* Transforming the Settings.py file
|
||||
* We do this to update ports or other information that make your production environment unique
|
||||
from your development environment.
|
||||
* Making migrations and migrating the game database.
|
||||
* Publishing the game files.
|
||||
* Reloading the server.
|
||||
|
||||
For each step we'll being use the "Command Line Runner" (a fancy name for a shell script executor).
|
||||
|
||||
* Create a build step with the name: Transform Configuration
|
||||
* For the script add:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Replaces the game configuration with one
|
||||
# appropriate for this deployment.
|
||||
|
||||
CONFIG="%system.teamcity.build.checkoutDir%/server/conf/settings.py"
|
||||
MYCONF="%system.teamcity.build.checkoutDir%/server/conf/my.cnf"
|
||||
|
||||
sed -e 's/TELNET_PORTS = [4000]/TELNET_PORTS = [%game.ports%]/g' "$CONFIG" > "$CONFIG".tmp && mv
|
||||
"$CONFIG".tmp "$CONFIG"
|
||||
sed -e 's/WEBSERVER_PORTS = [(4001, 4002)]/WEBSERVER_PORTS = [%game.webports%]/g' "$CONFIG" >
|
||||
"$CONFIG".tmp && mv "$CONFIG".tmp "$CONFIG"
|
||||
|
||||
# settings.py MySQL DB configuration
|
||||
echo Configuring Game Database...
|
||||
echo "" >> "$CONFIG"
|
||||
echo "######################################################################" >> "$CONFIG"
|
||||
echo "# MySQL Database Configuration" >> "$CONFIG"
|
||||
echo "######################################################################" >> "$CONFIG"
|
||||
|
||||
echo "DATABASES = {" >> "$CONFIG"
|
||||
echo " 'default': {" >> "$CONFIG"
|
||||
echo " 'ENGINE': 'django.db.backends.mysql'," >> "$CONFIG"
|
||||
echo " 'OPTIONS': {" >> "$CONFIG"
|
||||
echo " 'read_default_file': 'server/conf/my.cnf'," >> "$CONFIG"
|
||||
echo " }," >> "$CONFIG"
|
||||
echo " }" >> "$CONFIG"
|
||||
echo "}" >> "$CONFIG"
|
||||
|
||||
# Create the My.CNF file.
|
||||
echo "[client]" >> "$MYCONF"
|
||||
echo "database = %mysql.db%" >> "$MYCONF"
|
||||
echo "user = %mysql.user%" >> "$MYCONF"
|
||||
echo "password = %mysql.pass%" >> "$MYCONF"
|
||||
echo "default-character-set = utf8" >> "$MYCONF"
|
||||
```
|
||||
|
||||
If you look at the parameters side of the page after saving this script, you'll notice that some new
|
||||
parameters have been populated for you. This is because we've included new teamcity configuration
|
||||
parameters that are populated when the build itself is ran. When creating projects that inherit this
|
||||
template, we'll be able to fill in or override those parameters for project-specific configuration.
|
||||
|
||||
* Go ahead and create another build step called "Make Database Migration"
|
||||
* If you're using SQLLite on your game, it will be prudent to change working directory on this
|
||||
step to: %game.dir%
|
||||
* In this script include:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Update the DB migration
|
||||
|
||||
LOGDIR="server/logs"
|
||||
|
||||
. %evenv.dir%/bin/activate
|
||||
|
||||
# Check that the logs directory exists.
|
||||
if [ ! -d "$LOGDIR" ]; then
|
||||
# Control will enter here if $LOGDIR doesn't exist.
|
||||
mkdir "$LOGDIR"
|
||||
fi
|
||||
|
||||
evennia makemigrations
|
||||
```
|
||||
|
||||
* Create yet another build step, this time named: "Execute Database Migration":
|
||||
* If you're using SQLLite on your game, it will be prudent to change working directory on this
|
||||
step to: %game.dir%
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Apply the database migration.
|
||||
|
||||
LOGDIR="server/logs"
|
||||
|
||||
. %evenv.dir%/bin/activate
|
||||
|
||||
# Check that the logs directory exists.
|
||||
if [ ! -d "$LOGDIR" ]; then
|
||||
# Control will enter here if $LOGDIR doesn't exist.
|
||||
mkdir "$LOGDIR"
|
||||
fi
|
||||
|
||||
evennia migrate
|
||||
|
||||
```
|
||||
|
||||
Our next build step is where we actually publish our build. Up until now, all work on game has been
|
||||
done in a 'work' directory on TeamCity's build agent. From that directory we will now copy our files
|
||||
to where our game actually exists on the local server.
|
||||
|
||||
* Create a new build step called "Publish Build":
|
||||
* If you're using SQLLite on your game, be sure to order this step ABOVE the Database Migration
|
||||
steps. The build order will matter!
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Publishes the build to the proper build directory.
|
||||
|
||||
DIRECTORY="%game.dir%"
|
||||
|
||||
if [ ! -d "$DIRECTORY" ]; then
|
||||
# Control will enter here if $DIRECTORY doesn't exist.
|
||||
mkdir "$DIRECTORY"
|
||||
fi
|
||||
|
||||
# Copy all the files.
|
||||
cp -ruv %teamcity.build.checkoutDir%/* "$DIRECTORY"
|
||||
chmod -R 775 "$DIRECTORY"
|
||||
|
||||
```
|
||||
|
||||
Finally the last script will reload our game for us.
|
||||
|
||||
* Create a new script called "Reload Game":
|
||||
* The working directory on this build step will be: %game.dir%
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Apply the database migration.
|
||||
|
||||
LOGDIR="server/logs"
|
||||
PIDDIR="server/server.pid"
|
||||
|
||||
. %evenv.dir%/bin/activate
|
||||
|
||||
# Check that the logs directory exists.
|
||||
if [ ! -d "$LOGDIR" ]; then
|
||||
# Control will enter here if $LOGDIR doesn't exist.
|
||||
mkdir "$LOGDIR"
|
||||
fi
|
||||
|
||||
# Check that the server is running.
|
||||
if [ -d "$PIDDIR" ]; then
|
||||
# Control will enter here if the game is running.
|
||||
evennia reload
|
||||
fi
|
||||
```
|
||||
|
||||
Now the template is ready for use! It would be useful this time to revisit the parameters page and
|
||||
set the evenv parameter to the directory where your virtualenv exists: IE "/srv/mush/evenv".
|
||||
|
||||
### Creating the Project
|
||||
|
||||
Now it's time for the last few steps to set up a CI environment.
|
||||
|
||||
* Return to the Evennia Project overview/administration page.
|
||||
* Create a new Sub-Project called "Production"
|
||||
* This will be the category that holds our actual game.
|
||||
* Create a new Build Configuration in Production with the name of your MUSH.
|
||||
* Base this configuration off of the continuous-integration template we made earlier.
|
||||
* In the build configuration, enter VCS roots and create a new VCS root that points to the
|
||||
branch/version control that you are using.
|
||||
* Go to the parameters page and fill in the undefined parameters for your specific configuration.
|
||||
* If you wish for the CI to run every time a commit is made, go to the VCS triggers and add one for
|
||||
"On Every Commit".
|
||||
|
||||
And you're done! At this point, you can return to the project overview page and queue a new build
|
||||
for your game. If everything was set up correctly, the build will complete successfully. Additional
|
||||
build steps could be added or removed at this point, adding some features like Unit Testing or more!
|
||||
296
docs/source/Coding/Debugging.md
Normal file
296
docs/source/Coding/Debugging.md
Normal file
|
|
@ -0,0 +1,296 @@
|
|||
# Debugging
|
||||
|
||||
|
||||
Sometimes, an error is not trivial to resolve. A few simple `print` statements is not enough to find
|
||||
the cause of the issue. Running a *debugger* can then be very helpful and save a lot of time.
|
||||
Debugging
|
||||
means running Evennia under control of a special *debugger* program. This allows you to stop the
|
||||
action at a given point, view the current state and step forward through the program to see how its
|
||||
logic works.
|
||||
|
||||
Evennia natively supports these debuggers:
|
||||
|
||||
- [Pdb](https://docs.python.org/2/library/pdb.html) is a part of the Python distribution and
|
||||
available out-of-the-box.
|
||||
- [PuDB](https://pypi.org/project/pudb/) is a third-party debugger that has a slightly more
|
||||
'graphical', curses-based user interface than pdb. It is installed with `pip install pudb`.
|
||||
|
||||
## Debugging Evennia
|
||||
|
||||
To run Evennia with the debugger, follow these steps:
|
||||
|
||||
1. Find the point in the code where you want to have more insight. Add the following line at that
|
||||
point.
|
||||
```python
|
||||
from evennia import set_trace;set_trace()
|
||||
```
|
||||
2. (Re-)start Evennia in interactive (foreground) mode with `evennia istart`. This is important -
|
||||
without this step the debugger will not start correctly - it will start in this interactive
|
||||
terminal.
|
||||
3. Perform the steps that will trigger the line where you added the `set_trace()` call. The debugger
|
||||
will start in the terminal from which Evennia was interactively started.
|
||||
|
||||
The `evennia.set_trace` function takes the following arguments:
|
||||
|
||||
|
||||
```python
|
||||
evennia.set_trace(debugger='auto', term_size=(140, 40))
|
||||
```
|
||||
|
||||
Here, `debugger` is one of `pdb`, `pudb` or `auto`. If `auto`, use `pudb` if available, otherwise
|
||||
use `pdb`. The `term_size` tuple sets the viewport size for `pudb` only (it's ignored by `pdb`).
|
||||
|
||||
|
||||
## A simple example using pdb
|
||||
|
||||
The debugger is useful in different cases, but to begin with, let's see it working in a command.
|
||||
Add the following test command (which has a range of deliberate errors) and also add it to your
|
||||
default cmdset. Then restart Evennia in interactive mode with `evennia istart`.
|
||||
|
||||
|
||||
```python
|
||||
# In file commands/command.py
|
||||
|
||||
|
||||
class CmdTest(Command):
|
||||
|
||||
"""
|
||||
A test command just to test pdb.
|
||||
|
||||
Usage:
|
||||
test
|
||||
|
||||
"""
|
||||
|
||||
key = "test"
|
||||
|
||||
def func(self):
|
||||
from evennia import set_trace; set_trace() # <--- start of debugger
|
||||
obj = self.search(self.args)
|
||||
self.msg("You've found {}.".format(obj.get_display_name()))
|
||||
|
||||
```
|
||||
|
||||
If you type `test` in your game, everything will freeze. You won't get any feedback from the game,
|
||||
and you won't be able to enter any command (nor anyone else). It's because the debugger has started
|
||||
in your console, and you will find it here. Below is an example with `pdb`.
|
||||
|
||||
```
|
||||
...
|
||||
> .../mygame/commands/command.py(79)func()
|
||||
-> obj = self.search(self.args)
|
||||
(Pdb)
|
||||
|
||||
```
|
||||
|
||||
`pdb` notes where it has stopped execution and, what line is about to be executed (in our case, `obj
|
||||
= self.search(self.args)`), and ask what you would like to do.
|
||||
|
||||
### Listing surrounding lines of code
|
||||
|
||||
When you have the `pdb` prompt `(Pdb)`, you can type in different commands to explore the code. The
|
||||
first one you should know is `list` (you can type `l` for short):
|
||||
|
||||
```
|
||||
(Pdb) l
|
||||
43
|
||||
44 key = "test"
|
||||
45
|
||||
46 def func(self):
|
||||
47 from evennia import set_trace; set_trace() # <--- start of debugger
|
||||
48 -> obj = self.search(self.args)
|
||||
49 self.msg("You've found {}.".format(obj.get_display_name()))
|
||||
50
|
||||
51 # -------------------------------------------------------------
|
||||
52 #
|
||||
53 # The default commands inherit from
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
Okay, this didn't do anything spectacular, but when you become more confident with `pdb` and find
|
||||
yourself in lots of different files, you sometimes need to see what's around in code. Notice that
|
||||
there is a little arrow (`->`) before the line that is about to be executed.
|
||||
|
||||
This is important: **about to be**, not **has just been**. You need to tell `pdb` to go on (we'll
|
||||
soon see how).
|
||||
|
||||
### Examining variables
|
||||
|
||||
`pdb` allows you to examine variables (or really, to run any Python instruction). It is very useful
|
||||
to know the values of variables at a specific line. To see a variable, just type its name (as if
|
||||
you were in the Python interpreter:
|
||||
|
||||
```
|
||||
(Pdb) self
|
||||
<commands.command.CmdTest object at 0x045A0990>
|
||||
(Pdb) self.args
|
||||
u''
|
||||
(Pdb) self.caller
|
||||
<Character: XXX>
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
If you try to see the variable `obj`, you'll get an error:
|
||||
|
||||
```
|
||||
(Pdb) obj
|
||||
*** NameError: name 'obj' is not defined
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
That figures, since at this point, we haven't created the variable yet.
|
||||
|
||||
> Examining variable in this way is quite powerful. You can even run Python code and keep on
|
||||
> executing, which can help to check that your fix is actually working when you have identified an
|
||||
> error. If you have variable names that will conflict with `pdb` commands (like a `list`
|
||||
> variable), you can prefix your variable with `!`, to tell `pdb` that what follows is Python code.
|
||||
|
||||
### Executing the current line
|
||||
|
||||
It's time we asked `pdb` to execute the current line. To do so, use the `next` command. You can
|
||||
shorten it by just typing `n`:
|
||||
|
||||
```
|
||||
(Pdb) n
|
||||
AttributeError: "'CmdTest' object has no attribute 'search'"
|
||||
> .../mygame/commands/command.py(79)func()
|
||||
-> obj = self.search(self.args)
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
`Pdb` is complaining that you try to call the `search` method on a command... whereas there's no
|
||||
`search` method on commands. The character executing the command is in `self.caller`, so we might
|
||||
change our line:
|
||||
|
||||
```python
|
||||
obj = self.caller.search(self.args)
|
||||
```
|
||||
|
||||
### Letting the program run
|
||||
|
||||
`pdb` is waiting to execute the same instruction... it provoked an error but it's ready to try
|
||||
again, just in case. We have fixed it in theory, but we need to reload, so we need to enter a
|
||||
command. To tell `pdb` to terminate and keep on running the program, use the `continue` (or `c`)
|
||||
command:
|
||||
|
||||
```
|
||||
(Pdb) c
|
||||
...
|
||||
```
|
||||
|
||||
You see an error being caught, that's the error we have fixed... or hope to have. Let's reload the
|
||||
game and try again. You need to run `evennia istart` again and then run `test` to get into the
|
||||
command again.
|
||||
|
||||
```
|
||||
> .../mygame/commands/command.py(79)func()
|
||||
-> obj = self.caller.search(self.args)
|
||||
(Pdb)
|
||||
|
||||
```
|
||||
|
||||
`pdb` is about to run the line again.
|
||||
|
||||
```
|
||||
(Pdb) n
|
||||
> .../mygame/commands/command.py(80)func()
|
||||
-> self.msg("You've found {}.".format(obj.get_display_name()))
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
This time the line ran without error. Let's see what is in the `obj` variable:
|
||||
|
||||
```
|
||||
(Pdb) obj
|
||||
(Pdb) print obj
|
||||
None
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
We have entered the `test` command without parameter, so no object could be found in the search
|
||||
(`self.args` is an empty string).
|
||||
|
||||
Let's allow the command to continue and try to use an object name as parameter (although, we should
|
||||
fix that bug too, it would be better):
|
||||
|
||||
```
|
||||
(Pdb) c
|
||||
...
|
||||
```
|
||||
|
||||
Notice that you'll have an error in the game this time. Let's try with a valid parameter. I have
|
||||
another character, `barkeep`, in this room:
|
||||
|
||||
```test barkeep```
|
||||
|
||||
And again, the command freezes, and we have the debugger opened in the console.
|
||||
|
||||
Let's execute this line right away:
|
||||
|
||||
```
|
||||
> .../mygame/commands/command.py(79)func()
|
||||
-> obj = self.caller.search(self.args)
|
||||
(Pdb) n
|
||||
> .../mygame/commands/command.py(80)func()
|
||||
-> self.msg("You've found {}.".format(obj.get_display_name()))
|
||||
(Pdb) obj
|
||||
<Character: barkeep>
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
At least this time we have found the object. Let's process...
|
||||
|
||||
```
|
||||
(Pdb) n
|
||||
TypeError: 'get_display_name() takes exactly 2 arguments (1 given)'
|
||||
> .../mygame/commands/command.py(80)func()
|
||||
-> self.msg("You've found {}.".format(obj.get_display_name()))
|
||||
(Pdb)
|
||||
```
|
||||
|
||||
As an exercise, fix this error, reload and run the debugger again. Nothing better than some
|
||||
experimenting!
|
||||
|
||||
Your debugging will often follow the same strategy:
|
||||
|
||||
1. Receive an error you don't understand.
|
||||
2. Put a breaking point **BEFORE** the error occurs.
|
||||
3. Run the code again and see the debugger open.
|
||||
4. Run the program line by line,examining variables, checking the logic of instructions.
|
||||
5. Continue and try again, each step a bit further toward the truth and the working feature.
|
||||
|
||||
### Stepping through a function
|
||||
|
||||
`n` is useful, but it will avoid stepping inside of functions if it can. But most of the time, when
|
||||
we have an error we don't understand, it's because we use functions or methods in a way that wasn't
|
||||
intended by the developer of the API. Perhaps using wrong arguments, or calling the function in a
|
||||
situation that would cause a bug. When we have a line in the debugger that calls a function or
|
||||
method, we can "step" to examine it further. For instance, in the previous example, when `pdb` was
|
||||
about to execute `obj = self.caller.search(self.args)`, we may want to see what happens inside of
|
||||
the `search` method.
|
||||
|
||||
To do so, use the `step` (or `s`) command. This command will show you the definition of the
|
||||
function/method and you can then use `n` as before to see it line-by-line. In our little example,
|
||||
stepping through a function or method isn't that useful, but when you have an impressive set of
|
||||
commands, functions and so on, it might really be handy to examine some feature and make sure they
|
||||
operate as planned.
|
||||
|
||||
## Cheat-sheet of pdb/pudb commands
|
||||
|
||||
PuDB and Pdb share the same commands. The only real difference is how it's presented. The `look`
|
||||
command is not needed much in `pudb` since it displays the code directly in its user interface.
|
||||
|
||||
| Pdb/PuDB command | To do what |
|
||||
| ----------- | ---------- |
|
||||
| list (or l) | List the lines around the point of execution (not needed for `pudb`, it will show
|
||||
this directly). |
|
||||
| print (or p) | Display one or several variables. |
|
||||
| `!` | Run Python code (using a `!` is often optional). |
|
||||
| continue (or c) | Continue execution and terminate the debugger for this time. |
|
||||
| next (or n) | Execute the current line and goes to the next one. |
|
||||
| step (or s) | Step inside of a function or method to examine it. |
|
||||
| `<RETURN>` | Repeat the last command (don't type `n` repeatedly, just type it once and then press
|
||||
`<RETURN>` to repeat it). |
|
||||
|
||||
If you want to learn more about debugging with Pdb, you will find an [interesting tutorial on that
|
||||
topic here](https://pymotw.com/3/pdb/).
|
||||
68
docs/source/Coding/Directory-Overview.md
Normal file
68
docs/source/Coding/Directory-Overview.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# Directory Overview
|
||||
|
||||
|
||||
This is an overview of the directories relevant to Evennia coding.
|
||||
|
||||
## The Game directory
|
||||
|
||||
The game directory is created with `evennia --init <name>`. In the Evennia documentation we always
|
||||
assume it's called `mygame`. Apart from the `server/` subfolder within, you could reorganize this
|
||||
folder if you preferred a different code structure for your game.
|
||||
|
||||
- `mygame/`
|
||||
- `commands/` - Overload default [Commands](Commands) or add your own Commands/[Command
|
||||
sets](Command-Sets) here.
|
||||
- `server`/ - The structure of this folder should not change since Evennia expects it.
|
||||
- [`conf/`](https://github.com/evennia/evennia/tree/master/evennia/game_template/server) - All
|
||||
server configuration files sits here. The most important file is `settings.py`.
|
||||
- `logs/` - Portal log files are stored here (Server is logging to the terminal by default)
|
||||
- `typeclasses/` - this folder contains empty templates for overloading default game entities of
|
||||
Evennia. Evennia will automatically use the changes in those templates for the game entities it
|
||||
creates.
|
||||
- `web/` - This holds the [Web features](Web-Features) of your game.
|
||||
- `world/` - this is a "miscellaneous" folder holding everything related to the world you are
|
||||
building, such as build scripts and rules modules that don't fit with one of the other folders.
|
||||
|
||||
## Evennia library layout:
|
||||
|
||||
If you cloned the GIT repo following the instructions, you will have a folder named `evennia`. The
|
||||
top level of it contains Python package specific stuff such as a readme file, `setup.py` etc. It
|
||||
also has two subfolders`bin/` and `evennia/` (again).
|
||||
|
||||
The `bin/` directory holds OS-specific binaries that will be used when installing Evennia with `pip`
|
||||
as per the [Getting started](Getting-Started) instructions. The library itself is in the `evennia`
|
||||
subfolder. From your code you will access this subfolder simply by `import evennia`.
|
||||
|
||||
- evennia
|
||||
- [`__init__.py`](Evennia-API) - The "flat API" of Evennia resides here.
|
||||
- [`commands/`](Commands) - The command parser and handler.
|
||||
- `default/` - The [default commands](Default-Command-Help) and cmdsets.
|
||||
- [`comms/`](Communications) - Systems for communicating in-game.
|
||||
- `contrib/` - Optional plugins too game-specific for core Evennia.
|
||||
- `game_template/` - Copied to become the "game directory" when using `evennia --init`.
|
||||
- [`help/`](Help-System) - Handles the storage and creation of help entries.
|
||||
- `locale/` - Language files ([i18n](Internationalization)).
|
||||
- [`locks/`](Locks) - Lock system for restricting access to in-game entities.
|
||||
- [`objects/`](Objects) - In-game entities (all types of items and Characters).
|
||||
- [`prototypes/`](Spawner-and-Prototypes) - Object Prototype/spawning system and OLC menu
|
||||
- [`accounts/`](Accounts) - Out-of-game Session-controlled entities (accounts, bots etc)
|
||||
- [`scripts/`](Scripts) - Out-of-game entities equivalence to Objects, also with timer support.
|
||||
- [`server/`](Portal-And-Server) - Core server code and Session handling.
|
||||
- `portal/` - Portal proxy and connection protocols.
|
||||
- [`settings_default.py`](Server-Conf#Settings-file) - Root settings of Evennia. Copy settings
|
||||
from here to `mygame/server/settings.py` file.
|
||||
- [`typeclasses/`](Typeclasses) - Abstract classes for the typeclass storage and database system.
|
||||
- [`utils/`](Coding-Utils) - Various miscellaneous useful coding resources.
|
||||
- [`web/`](Web-Features) - Web resources and webserver. Partly copied into game directory on
|
||||
initialization.
|
||||
|
||||
All directories contain files ending in `.py`. These are Python *modules* and are the basic units of
|
||||
Python code. The roots of directories also have (usually empty) files named `__init__.py`. These are
|
||||
required by Python so as to be able to find and import modules in other directories. When you have
|
||||
run Evennia at least once you will find that there will also be `.pyc` files appearing, these are
|
||||
pre-compiled binary versions of the `.py` files to speed up execution.
|
||||
|
||||
The root of the `evennia` folder has an `__init__.py` file containing the "[flat API](Evennia-API)".
|
||||
This holds shortcuts to various subfolders in the evennia library. It is provided to make it easier
|
||||
to find things; it allows you to just import `evennia` and access things from that rather than
|
||||
having to import from their actual locations inside the source tree.
|
||||
77
docs/source/Coding/Evennia-API.md
Normal file
77
docs/source/Coding/Evennia-API.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Evennia API
|
||||
|
||||
|
||||
Evennia makes much of its programming tools available directly from the top-level `evennia` package.
|
||||
This is often referred to as Evennia's "flat" [Application Programming
|
||||
Interface](https://en.wikipedia.org/wiki/Application_programming_interface) (API). The flat API
|
||||
tries to collect and bring the most commonly used resources to the front in a way where everything
|
||||
is available at a glance (in a flat display), making it a good place to start to learn Evennia.
|
||||
|
||||
> Evennia's flat (and full) API can be perused through the auto-generated [API Library
|
||||
refence](github:evennia).
|
||||
|
||||
A good, interactive way to explore the flat API is to use [IPython](http://ipython.org/), a more
|
||||
flexible version of the default Python shell. Inside your virtual environment you can install
|
||||
IPython simply by
|
||||
|
||||
pip install ipython
|
||||
|
||||
Windows users should also install [PyReadline](http://ipython.org/pyreadline.html):
|
||||
|
||||
pip install pyreadline
|
||||
|
||||
With IPython installed, go to your game directory and run
|
||||
|
||||
evennia shell
|
||||
|
||||
This should give you the IPython shell automatically. Inside IPython
|
||||
you then do
|
||||
|
||||
import evennia
|
||||
|
||||
Followed by
|
||||
|
||||
evennia.<TAB>
|
||||
|
||||
That is, write `evennia.` and press the TAB key. What pops up is the contents of the `evennia` top-
|
||||
level package - in other words [the "flat" API](github:evennia#the-flat-api).
|
||||
|
||||
evennia.DefaultObject?
|
||||
|
||||
Starting to write the name of an API entity and pressing `<TAB>` will auto-complete the name. Adding
|
||||
a question mark (`?`) to its name will show you its documentation. Append `??` to get the actual
|
||||
source code. This way you can quickly explore Evennia and see what is available.
|
||||
|
||||
|
||||
## To remember when importing from `evennia`
|
||||
|
||||
Properties on the root of the `evennia` package are *not* modules in their own right. They are just
|
||||
shortcut properties stored in the `evennia/__init__.py` module. That means that you cannot use dot-
|
||||
notation to `import` nested module-names over `evennia`. The rule of thumb is that you cannot use
|
||||
`import` for more than one level down. Hence you can do
|
||||
|
||||
```python
|
||||
import evennia
|
||||
print(evennia.default_cmds.CmdLook)
|
||||
```
|
||||
|
||||
or import one level down
|
||||
|
||||
```python
|
||||
from evennia import default_cmds
|
||||
print(default_cmds.CmdLook)
|
||||
```
|
||||
|
||||
but you *cannot* import two levels down
|
||||
|
||||
```python
|
||||
from evennia.default_cmds import CmdLook # error!
|
||||
```
|
||||
|
||||
This will give you an `ImportError` telling you that the module `default_cmds` cannot be found -
|
||||
this is becasue `default_cmds` is just a *variable* stored in `evennia.__init__.py`; this cannot be
|
||||
imported from. If you really want full control over which level of package you import you can always
|
||||
bypass the root package and import directly from from the real location. For example
|
||||
`evennia.DefaultObject` is a shortcut to `evennia.objects.objects.DefaultObject`. Using this full
|
||||
path will have the import mechanism work normally. See `evennia/__init__.py` to see where the
|
||||
package imports from.
|
||||
125
docs/source/Coding/Profiling.md
Normal file
125
docs/source/Coding/Profiling.md
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
# Profiling
|
||||
|
||||
*This is considered an advanced topic mainly of interest to server developers.*
|
||||
|
||||
## Introduction
|
||||
|
||||
Sometimes it can be useful to try to determine just how efficient a particular piece of code is, or
|
||||
to figure out if one could speed up things more than they are. There are many ways to test the
|
||||
performance of Python and the running server.
|
||||
|
||||
Before digging into this section, remember Donald Knuth's [words of
|
||||
wisdom](https://en.wikipedia.org/wiki/Program_optimization#When_to_optimize):
|
||||
|
||||
> *[...]about 97% of the time: Premature optimization is the root of all evil*.
|
||||
|
||||
That is, don't start to try to optimize your code until you have actually identified a need to do
|
||||
so. This means your code must actually be working before you start to consider optimization.
|
||||
Optimization will also often make your code more complex and harder to read. Consider readability
|
||||
and maintainability and you may find that a small gain in speed is just not worth it.
|
||||
|
||||
## Simple timer tests
|
||||
|
||||
Python's `timeit` module is very good for testing small things. For example, in order to test if it
|
||||
is faster to use a `for` loop or a list comprehension you could use the following code:
|
||||
|
||||
```python
|
||||
import timeit
|
||||
# Time to do 1000000 for loops
|
||||
timeit.timeit("for i in range(100):\n a.append(i)", setup="a = []")
|
||||
<<< 10.70982813835144
|
||||
# Time to do 1000000 list comprehensions
|
||||
timeit.timeit("a = [i for i in range(100)]")
|
||||
<<< 5.358283996582031
|
||||
```
|
||||
|
||||
The `setup` keyword is used to set up things that should not be included in the time measurement,
|
||||
like `a = []` in the first call.
|
||||
|
||||
By default the `timeit` function will re-run the given test 1000000 times and returns the *total
|
||||
time* to do so (so *not* the average per test). A hint is to not use this default for testing
|
||||
something that includes database writes - for that you may want to use a lower number of repeats
|
||||
(say 100 or 1000) using the `number=100` keyword.
|
||||
|
||||
## Using cProfile
|
||||
|
||||
Python comes with its own profiler, named cProfile (this is for cPython, no tests have been done
|
||||
with `pypy` at this point). Due to the way Evennia's processes are handled, there is no point in
|
||||
using the normal way to start the profiler (`python -m cProfile evennia.py`). Instead you start the
|
||||
profiler through the launcher:
|
||||
|
||||
evennia --profiler start
|
||||
|
||||
This will start Evennia with the Server component running (in daemon mode) under cProfile. You could
|
||||
instead try `--profile` with the `portal` argument to profile the Portal (you would then need to
|
||||
[start the Server separately](Start-Stop-Reload)).
|
||||
|
||||
Please note that while the profiler is running, your process will use a lot more memory than usual.
|
||||
Memory usage is even likely to climb over time. So don't leave it running perpetually but monitor it
|
||||
carefully (for example using the `top` command on Linux or the Task Manager's memory display on
|
||||
Windows).
|
||||
|
||||
Once you have run the server for a while, you need to stop it so the profiler can give its report.
|
||||
Do *not* kill the program from your task manager or by sending it a kill signal - this will most
|
||||
likely also mess with the profiler. Instead either use `evennia.py stop` or (which may be even
|
||||
better), use `@shutdown` from inside the game.
|
||||
|
||||
Once the server has fully shut down (this may be a lot slower than usual) you will find that
|
||||
profiler has created a new file `mygame/server/logs/server.prof`.
|
||||
|
||||
## Analyzing the profile
|
||||
|
||||
The `server.prof` file is a binary file. There are many ways to analyze and display its contents,
|
||||
all of which has only been tested in Linux (If you are a Windows/Mac user, let us know what works).
|
||||
|
||||
We recommend the
|
||||
[Runsnake](http://www.vrplumber.com/programming/runsnakerun/) visualizer to see the processor usage
|
||||
of different processes in a graphical form. For more detailed listing of usage time, you can use
|
||||
[KCachegrind](http://kcachegrind.sourceforge.net/html/Home.html). To make KCachegrind work with
|
||||
Python profiles you also need the wrapper script
|
||||
[pyprof2calltree](https://pypi.python.org/pypi/pyprof2calltree/). You can get pyprof2calltree via
|
||||
`pip` whereas KCacheGrind is something you need to get via your package manager or their homepage.
|
||||
|
||||
How to analyze and interpret profiling data is not a trivial issue and depends on what you are
|
||||
profiling for. Evennia being an asynchronous server can also confuse profiling. Ask on the mailing
|
||||
list if you need help and be ready to be able to supply your `server.prof` file for comparison,
|
||||
along with the exact conditions under which it was obtained.
|
||||
|
||||
## The Dummyrunner
|
||||
|
||||
It is difficult to test "actual" game performance without having players in your game. For this
|
||||
reason Evennia comes with the *Dummyrunner* system. The Dummyrunner is a stress-testing system: a
|
||||
separate program that logs into your game with simulated players (aka "bots" or "dummies"). Once
|
||||
connected these dummies will semi-randomly perform various tasks from a list of possible actions.
|
||||
Use `Ctrl-C` to stop the Dummyrunner.
|
||||
|
||||
> Warning: You should not run the Dummyrunner on a production database. It will spawn many objects
|
||||
and also needs to run with general permissions.
|
||||
|
||||
To launch the Dummyrunner, first start your server normally (with or without profiling, as above).
|
||||
Then start a new terminal/console window and active your virtualenv there too. In the new terminal,
|
||||
try to connect 10 dummy players:
|
||||
|
||||
evennia --dummyrunner 10
|
||||
|
||||
The first time you do this you will most likely get a warning from Dummyrunner. It will tell you to
|
||||
copy an import string to the end of your settings file. Quit the Dummyrunner (`Ctrl-C`) and follow
|
||||
the instructions. Restart Evennia and try `evennia --dummyrunner 10` again. Make sure to remove that
|
||||
extra settings line when running a public server.
|
||||
|
||||
The actions perform by the dummies is controlled by a settings file. The default Dummyrunner
|
||||
settings file is `evennia/server/server/profiling/dummyrunner_settings.py` but you shouldn't modify
|
||||
this directly. Rather create/copy the default file to `mygame/server/conf/` and modify it there. To
|
||||
make sure to use your file over the default, add the following line to your settings file:
|
||||
|
||||
```python
|
||||
DUMMYRUNNER_SETTINGS_MODULE = "server/conf/dummyrunner_settings.py"
|
||||
```
|
||||
|
||||
> Hint: Don't start with too many dummies. The Dummyrunner defaults to taxing the server much more
|
||||
intensely than an equal number of human players. A good dummy number to start with is 10-100.
|
||||
|
||||
Once you have the dummyrunner running, stop it with `Ctrl-C`.
|
||||
|
||||
Generally, the dummyrunner system makes for a decent test of general performance; but it is of
|
||||
course hard to actually mimic human user behavior. For this, actual real-game testing is required.
|
||||
120
docs/source/Coding/Quirks.md
Normal file
120
docs/source/Coding/Quirks.md
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
# Quirks
|
||||
|
||||
|
||||
This is a list of various quirks or common stumbling blocks that people often ask about or report
|
||||
when using (or trying to use) Evennia. They are not bugs.
|
||||
|
||||
### Forgetting to use @reload to see changes to your typeclasses
|
||||
|
||||
Firstly: Reloading the server is a safe and usually quick operation which will *not* disconnect any
|
||||
accounts.
|
||||
|
||||
New users tend to forget this step. When editing source code (such as when tweaking typeclasses and
|
||||
commands or adding new commands to command sets) you need to either use the in-game `@reload`
|
||||
command or, from the command line do `python evennia.py reload` before you see your changes.
|
||||
|
||||
### Web admin to create new Account
|
||||
|
||||
If you use the default login system and are trying to use the Web admin to create a new Player
|
||||
account, you need to consider which `MULTIACCOUNT_MODE` you are in. If you are in
|
||||
`MULTIACCOUNT_MODE` `0` or `1`, the login system expects each Account to also have a Character
|
||||
object named the same as the Account - there is no character creation screen by default. If using
|
||||
the normal mud login screen, a Character with the same name is automatically created and connected
|
||||
to your Account. From the web interface you must do this manually.
|
||||
|
||||
So, when creating the Account, make sure to also create the Character *from the same form* as you
|
||||
create the Account from. This should set everything up for you. Otherwise you need to manually set
|
||||
the "account" property on the Character and the "character" property on the Account to point to each
|
||||
other. You must also set the lockstring of the Character to allow the Account to "puppet" this
|
||||
particular character.
|
||||
|
||||
### Mutable attributes and their connection to the database
|
||||
|
||||
When storing a mutable object (usually a list or a dictionary) in an Attribute
|
||||
|
||||
```python
|
||||
object.db.mylist = [1,2,3]
|
||||
```
|
||||
|
||||
you should know that the connection to the database is retained also if you later extract that
|
||||
Attribute into another variable (what is stored and retrieved is actually a `PackedList` or a
|
||||
`PackedDict` that works just like their namesakes except they save themselves to the database when
|
||||
changed). So if you do
|
||||
|
||||
```python
|
||||
alist = object.db.mylist
|
||||
alist.append(4)
|
||||
```
|
||||
|
||||
this updates the database behind the scenes, so both `alist` and `object.db.mylist` are now
|
||||
`[1,2,3,4]`
|
||||
|
||||
If you don't want this, Evennia provides a way to stably disconnect the mutable from the database by
|
||||
use of `evennia.utils.dbserialize.deserialize`:
|
||||
|
||||
```python
|
||||
from evennia.utils.dbserialize import deserialize
|
||||
|
||||
blist = deserialize(object.db.mylist)
|
||||
blist.append(4)
|
||||
```
|
||||
|
||||
The property `blist` is now `[1,2,3,4]` whereas `object.db.mylist` remains unchanged. If you want to
|
||||
update the database you'd need to explicitly re-assign the updated data to the `mylist` Attribute.
|
||||
|
||||
### Commands are matched by name *or* alias
|
||||
|
||||
When merging [command sets](Commands) it's important to remember that command objects are identified
|
||||
*both* by key *or* alias. So if you have a command with a key `look` and an alias `ls`, introducing
|
||||
another command with a key `ls` will be assumed by the system to be *identical* to the first one.
|
||||
This usually means merging cmdsets will overload one of them depending on priority. Whereas this is
|
||||
logical once you know how command objects are handled, it may be confusing if you are just looking
|
||||
at the command strings thinking they are parsed as-is.
|
||||
|
||||
### Objects turning to `DefaultObject`
|
||||
|
||||
A common confusing error for new developers is finding that one or more objects in-game are suddenly
|
||||
of the type `DefaultObject` rather than the typeclass you wanted it to be. This happens when you
|
||||
introduce a critical Syntax error to the module holding your custom class. Since such a module is
|
||||
not valid Python, Evennia can't load it at all to get to the typeclasses within. To keep on running,
|
||||
Evennia will solve this by printing the full traceback to the terminal/console and temporarily fall
|
||||
back to the safe `DefaultObject` until you fix the problem and reload. Most errors of this kind will
|
||||
be caught by any good text editors. Keep an eye on the terminal/console during a reload to catch
|
||||
such errors - you may have to scroll up if your window is small.
|
||||
|
||||
### Overriding of magic methods
|
||||
|
||||
Python implements a system of [magic
|
||||
methods](https://docs.python.org/3/reference/datamodel.html#emulating-container-types), usually
|
||||
prefixed and suffixed by double-underscores (`__example__`) that allow object instances to have
|
||||
certain operations performed on them without needing to do things like turn them into strings or
|
||||
numbers first-- for example, is `obj1` greater than or equal to `obj2`?
|
||||
|
||||
Neither object is a number, but given `obj1.size == "small"` and `obj2.size == "large"`, how might
|
||||
one compare these two arbitrary English adjective strings to figure out which is greater than the
|
||||
other? By defining the `__ge__` (greater than or equal to) magic method on the object class in which
|
||||
you figure out which word has greater significance, perhaps through use of a mapping table
|
||||
(`{'small':0, 'large':10}`) or other lookup and comparing the numeric values of each.
|
||||
|
||||
Evennia extensively makes use of magic methods on typeclasses to do things like initialize objects,
|
||||
check object existence or iterate over objects in an inventory or container. If you override or
|
||||
interfere with the return values from the methods Evennia expects to be both present and working, it
|
||||
can result in very inconsistent and hard-to-diagnose errors.
|
||||
|
||||
The moral of the story-- it can be dangerous to tinker with magic methods on typeclassed objects.
|
||||
Try to avoid doing so.
|
||||
|
||||
### Known upstream bugs
|
||||
|
||||
- There is currently (Autumn 2017) a bug in the `zope.interface` installer on some Linux Ubuntu
|
||||
distributions (notably Ubuntu 16.04 LTS). Zope is a dependency of Twisted. The error manifests in
|
||||
the server not starting with an error that `zope.interface` is not found even though `pip list`
|
||||
shows it's installed. The reason is a missing empty `__init__.py` file at the root of the zope
|
||||
package. If the virtualenv is named "evenv" as suggested in the [Getting Started](Getting-Started)
|
||||
instructions, use the following command to fix it:
|
||||
|
||||
```shell
|
||||
touch evenv/local/lib/python2.7/site-packages/zope/__init__.py
|
||||
```
|
||||
|
||||
This will create the missing file and things should henceforth work correctly.
|
||||
116
docs/source/Coding/Setting-up-PyCharm.md
Normal file
116
docs/source/Coding/Setting-up-PyCharm.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# Setting up PyCharm
|
||||
|
||||
# Directions for setting up PyCharm with Evennia
|
||||
|
||||
[PyCharm](https://www.jetbrains.com/pycharm/) is a Python developer's IDE from Jetbrains available
|
||||
for Windows, Mac and Linux. It is a commercial product but offer free trials, a scaled-down
|
||||
community edition and also generous licenses for OSS projects like Evennia.
|
||||
|
||||
> This page was originally tested on Windows (so use Windows-style path examples), but should work
|
||||
the same for all platforms.
|
||||
|
||||
First, install Evennia on your local machine with [[Getting Started]]. If you're new to PyCharm,
|
||||
loading your project is as easy as selecting the `Open` option when PyCharm starts, and browsing to
|
||||
your game folder (the one created with `evennia --init`). We refer to it as `mygame` here.
|
||||
|
||||
If you want to be able to examine evennia's core code or the scripts inside your virtualenv, you'll
|
||||
need to add them to your project too:
|
||||
1. Go to `File > Open...`
|
||||
1. Select the folder (i.e. the `evennia` root)
|
||||
1. Select "Open in current window" and "Add to currently opened projects"
|
||||
|
||||
## Setting up the project interpreter
|
||||
|
||||
It's a good idea to do this before attempting anything further. The rest of this page assumes your
|
||||
project is already configured in PyCharm.
|
||||
|
||||
1. Go to `File > Settings... > Project: \<mygame\> > Project Interpreter`
|
||||
1. Click the Gear symbol `> Add local`
|
||||
1. Navigate to your `evenv/scripts directory`, and select Python.exe
|
||||
|
||||
Enjoy seeing all your imports checked properly, setting breakpoints, and live variable watching!
|
||||
|
||||
## Attaching PyCharm debugger to Evennia
|
||||
|
||||
1. Launch Evennia in your preferred way (usually from a console/terminal)
|
||||
1. Open your project in PyCharm
|
||||
1. In the PyCharm menu, select `Run > Attach to Local Process...`
|
||||
1. From the list, pick the `twistd` process with the `server.py` parameter (Example: `twistd.exe
|
||||
--nodaemon --logfile=\<mygame\>\server\logs\server.log --python=\<evennia
|
||||
repo\>\evennia\server\server.py`)
|
||||
|
||||
Of course you can attach to the `portal` process as well. If you want to debug the Evennia launcher
|
||||
or runner for some reason (or just learn how they work!), see Run Configuration below.
|
||||
|
||||
> NOTE: Whenever you reload Evennia, the old Server process will die and a new one start. So when
|
||||
you restart you have to detach from the old and then reattach to the new process that was created.
|
||||
|
||||
> To make the process less tedious you can apply a filter in settings to show only the server.py
|
||||
process in the list. To do that navigate to: `Settings/Preferences | Build, Execution, Deployment |
|
||||
Python Debugger` and then in `Attach to process` field put in: `twistd.exe" --nodaemon`. This is an
|
||||
example for windows, I don't have a working mac/linux box.
|
||||

|
||||
|
||||
## Setting up an Evennia run configuration
|
||||
|
||||
This configuration allows you to launch Evennia from inside PyCharm. Besides convenience, it also
|
||||
allows suspending and debugging the evennia_launcher or evennia_runner at points earlier than you
|
||||
could by running them externally and attaching. In fact by the time the server and/or portal are
|
||||
running the launcher will have exited already.
|
||||
|
||||
1. Go to `Run > Edit Configutations...`
|
||||
1. Click the plus-symbol to add a new configuration and choose Python
|
||||
1. Add the script: `\<yourrepo\>\evenv\Scripts\evennia_launcher.py` (substitute your virtualenv if
|
||||
it's not named `evenv`)
|
||||
1. Set script parameters to: `start -l` (-l enables console logging)
|
||||
1. Ensure the chosen interpreter is from your virtualenv
|
||||
1. Set Working directory to your `mygame` folder (not evenv nor evennia)
|
||||
1. You can refer to the PyCharm documentation for general info, but you'll want to set at least a
|
||||
config name (like "MyMUD start" or similar).
|
||||
|
||||
Now set up a "stop" configuration by following the same steps as above, but set your Script
|
||||
parameters to: stop (and name the configuration appropriately).
|
||||
|
||||
A dropdown box holding your new configurations should appear next to your PyCharm run button.
|
||||
Select MyMUD start and press the debug icon to begin debugging. Depending on how far you let the
|
||||
program run, you may need to run your "MyMUD stop" config to actually stop the server, before you'll
|
||||
be able start it again.
|
||||
|
||||
## Alternative run configuration - utilizing logfiles as source of data
|
||||
|
||||
This configuration takes a bit different approach as instead of focusing on getting the data back
|
||||
through logfiles. Reason for that is this way you can easily separate data streams, for example you
|
||||
rarely want to follow both server and portal at the same time, and this will allow it. This will
|
||||
also make sure to stop the evennia before starting it, essentially working as reload command (it
|
||||
will also include instructions how to disable that part of functionality). We will start by defining
|
||||
a configuration that will stop evennia. This assumes that `upfire` is your pycharm project name, and
|
||||
also the game name, hence the `upfire/upfire` path.
|
||||
|
||||
1. Go to `Run > Edit Configutations...`\
|
||||
1. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should
|
||||
be project default)
|
||||
1. Name the configuration as "stop evennia" and fill rest of the fields accordingly to the image:
|
||||

|
||||
1. Press `Apply`
|
||||
|
||||
Now we will define the start/reload command that will make sure that evennia is not running already,
|
||||
and then start the server in one go.
|
||||
1. Go to `Run > Edit Configutations...`\
|
||||
1. Click the plus-symbol to add a new configuration and choose the python interpreter to use (should
|
||||
be project default)
|
||||
1. Name the configuration as "start evennia" and fill rest of the fields accordingly to the image:
|
||||

|
||||
1. Navigate to the `Logs` tab and add the log files you would like to follow. The picture shows
|
||||
adding `portal.log` which will show itself in `portal` tab when running:
|
||||

|
||||
1. Skip the following steps if you don't want the launcher to stop evennia before starting.
|
||||
1. Head back to `Configuration` tab and press the `+` sign at the bottom, under `Before launch....`
|
||||
and select `Run another configuration` from the submenu that will pop up.
|
||||
1. Click `stop evennia` and make sure that it's added to the list like on the image above.
|
||||
1. Click `Apply` and close the run configuration window.
|
||||
|
||||
You are now ready to go, and if you will fire up `start evennia` configuration you should see
|
||||
following in the bottom panel:
|
||||

|
||||
and you can click through the tabs to check appropriate logs, or even the console output as it is
|
||||
still running in interactive mode.
|
||||
398
docs/source/Coding/Unit-Testing.md
Normal file
398
docs/source/Coding/Unit-Testing.md
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
# Unit Testing
|
||||
|
||||
|
||||
*Unit testing* means testing components of a program in isolation from each other to make sure every
|
||||
part works on its own before using it with others. Extensive testing helps avoid new updates causing
|
||||
unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia
|
||||
article on unit testing can be found [here](http://en.wikipedia.org/wiki/Unit_test)).
|
||||
|
||||
A typical unit test set calls some function or method with a given input, looks at the result and
|
||||
makes sure that this result looks as expected. Rather than having lots of stand-alone test programs,
|
||||
Evennia makes use of a central *test runner*. This is a program that gathers all available tests all
|
||||
over the Evennia source code (called *test suites*) and runs them all in one go. Errors and
|
||||
tracebacks are reported.
|
||||
|
||||
By default Evennia only tests itself. But you can also add your own tests to your game code and have
|
||||
Evennia run those for you.
|
||||
|
||||
## Running the Evennia test suite
|
||||
|
||||
To run the full Evennia test suite, go to your game folder and issue the command
|
||||
|
||||
evennia test evennia
|
||||
|
||||
This will run all the evennia tests using the default settings. You could also run only a subset of
|
||||
all tests by specifying a subpackage of the library:
|
||||
|
||||
evennia test evennia.commands.default
|
||||
|
||||
A temporary database will be instantiated to manage the tests. If everything works out you will see
|
||||
how many tests were run and how long it took. If something went wrong you will get error messages.
|
||||
If you contribute to Evennia, this is a useful sanity check to see you haven't introduced an
|
||||
unexpected bug.
|
||||
|
||||
## Running tests with custom settings file
|
||||
|
||||
If you have implemented your own tests for your game (see below) you can run them from your game dir
|
||||
with
|
||||
|
||||
evennia test .
|
||||
|
||||
The period (`.`) means to run all tests found in the current directory and all subdirectories. You
|
||||
could also specify, say, `typeclasses` or `world` if you wanted to just run tests in those subdirs.
|
||||
|
||||
Those tests will all be run using the default settings. To run the tests with your own settings file
|
||||
you must use the `--settings` option:
|
||||
|
||||
evennia test --settings settings.py .
|
||||
|
||||
The `--settings` option of Evennia takes a file name in the `mygame/server/conf` folder. It is
|
||||
normally used to swap settings files for testing and development. In combination with `test`, it
|
||||
forces Evennia to use this settings file over the default one.
|
||||
|
||||
## Writing new tests
|
||||
|
||||
Evennia's test suite makes use of Django unit test system, which in turn relies on Python's
|
||||
*unittest* module.
|
||||
|
||||
> If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io
|
||||
page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of
|
||||
test coverage and which does not.
|
||||
|
||||
To make the test runner find the tests, they must be put in a module named `test*.py` (so `test.py`,
|
||||
`tests.py` etc). Such a test module will be found wherever it is in the package. It can be a good
|
||||
idea to look at some of Evennia's `tests.py` modules to see how they look.
|
||||
|
||||
Inside a testing file, a `unittest.TestCase` class is used to test a single aspect or component in
|
||||
various ways. Each test case contains one or more *test methods* - these define the actual tests to
|
||||
run. You can name the test methods anything you want as long as the name starts with "`test_`".
|
||||
Your `TestCase` class can also have a method `setUp()`. This is run before each test, setting up and
|
||||
storing whatever preparations the test methods need. Conversely, a `tearDown()` method can
|
||||
optionally do cleanup after each test.
|
||||
|
||||
To test the results, you use special methods of the `TestCase` class. Many of those start with
|
||||
"`assert`", such as `assertEqual` or `assertTrue`.
|
||||
|
||||
Example of a `TestCase` class:
|
||||
|
||||
```python
|
||||
import unittest
|
||||
|
||||
# the function we want to test
|
||||
from mypath import myfunc
|
||||
|
||||
class TestObj(unittest.TestCase):
|
||||
"This tests a function myfunc."
|
||||
|
||||
def test_return_value(self):
|
||||
"test method. Makes sure return value is as expected."
|
||||
expected_return = "This is me being nice."
|
||||
actual_return = myfunc()
|
||||
# test
|
||||
self.assertEqual(expected_return, actual_return)
|
||||
def test_alternative_call(self):
|
||||
"test method. Calls with a keyword argument."
|
||||
expected_return = "This is me being baaaad."
|
||||
actual_return = myfunc(bad=True)
|
||||
# test
|
||||
self.assertEqual(expected_return, actual_return)
|
||||
```
|
||||
|
||||
You might also want to read the [documentation for the unittest
|
||||
module](http://docs.python.org/library/unittest.html).
|
||||
|
||||
### Using the EvenniaTest class
|
||||
|
||||
Evennia offers a custom TestCase, the `evennia.utils.test_resources.EvenniaTest` class. This class
|
||||
initiates a range of useful properties on themselves for testing Evennia systems. Examples are
|
||||
`.account` and `.session` representing a mock connected Account and its Session and `.char1` and
|
||||
`char2` representing Characters complete with a location in the test database. These are all useful
|
||||
when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full
|
||||
definition of the `EvenniaTest` class in
|
||||
[evennia/utils/test_resources.py](https://github.com/evennia/evennia/blob/master/evennia/utils/test_resources.py).
|
||||
|
||||
```python
|
||||
# in a test module
|
||||
|
||||
from evennia.utils.test_resources import EvenniaTest
|
||||
|
||||
class TestObject(EvenniaTest):
|
||||
def test_object_search(self):
|
||||
# char1 and char2 are both created in room1
|
||||
self.assertEqual(self.char1.search(self.char2.key), self.char2)
|
||||
self.assertEqual(self.char1.search(self.char1.location.key), self.char1.location)
|
||||
# ...
|
||||
```
|
||||
|
||||
### Testing in-game Commands
|
||||
|
||||
In-game Commands are a special case. Tests for the default commands are put in
|
||||
`evennia/commands/default/tests.py`. This uses a custom `CommandTest` class that inherits from
|
||||
`evennia.utils.test_resources.EvenniaTest` described above. `CommandTest` supplies extra convenience
|
||||
functions for executing commands and check that their return values (calls of `msg()` returns
|
||||
expected values. It uses Characters and Sessions generated on the `EvenniaTest` class to call each
|
||||
class).
|
||||
|
||||
Each command tested should have its own `TestCase` class. Inherit this class from the `CommandTest`
|
||||
class in the same module to get access to the command-specific utilities mentioned.
|
||||
|
||||
```python
|
||||
from evennia.commands.default.tests import CommandTest
|
||||
from evennia.commands.default import general
|
||||
class TestSet(CommandTest):
|
||||
"tests the look command by simple call, using Char2 as a target"
|
||||
def test_mycmd_char(self):
|
||||
self.call(general.CmdLook(), "Char2", "Char2(#7)")
|
||||
"tests the look command by simple call, with target as room"
|
||||
def test_mycmd_room(self):
|
||||
self.call(general.CmdLook(), "Room",
|
||||
"Room(#1)\nroom_desc\nExits: out(#3)\n"
|
||||
"You see: Obj(#4), Obj2(#5), Char2(#7)")
|
||||
```
|
||||
|
||||
### Unit testing contribs with custom models
|
||||
|
||||
A special case is if you were to create a contribution to go to the `evennia/contrib` folder that
|
||||
uses its [own database models](New-Models). The problem with this is that Evennia (and Django) will
|
||||
only recognize models in `settings.INSTALLED_APPS`. If a user wants to use your contrib, they will
|
||||
be required to add your models to their settings file. But since contribs are optional you cannot
|
||||
add the model to Evennia's central `settings_default.py` file - this would always create your
|
||||
optional models regardless of if the user wants them. But at the same time a contribution is a part
|
||||
of the Evennia distribution and its unit tests should be run with all other Evennia tests using
|
||||
`evennia test evennia`.
|
||||
|
||||
The way to do this is to only temporarily add your models to the `INSTALLED_APPS` directory when the
|
||||
test runs. here is an example of how to do it.
|
||||
|
||||
> Note that this solution, derived from this [stackexchange
|
||||
answer](http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-
|
||||
testing#503435) is currently untested! Please report your findings.
|
||||
|
||||
```python
|
||||
# a file contrib/mycontrib/tests.py
|
||||
|
||||
from django.conf import settings
|
||||
import django
|
||||
from evennia.utils.test_resources import EvenniaTest
|
||||
|
||||
OLD_DEFAULT_SETTINGS = settings.INSTALLED_APPS
|
||||
DEFAULT_SETTINGS = dict(
|
||||
INSTALLED_APPS=(
|
||||
'contrib.mycontrib.tests',
|
||||
),
|
||||
DATABASES={
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3"
|
||||
}
|
||||
},
|
||||
SILENCED_SYSTEM_CHECKS=["1_7.W001"],
|
||||
)
|
||||
|
||||
class TestMyModel(EvenniaTest):
|
||||
def setUp(self):
|
||||
|
||||
if not settings.configured:
|
||||
settings.configure(**DEFAULT_SETTINGS)
|
||||
django.setup()
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.db.models import loading
|
||||
loading.cache.loaded = False
|
||||
call_command('syncdb', verbosity=0)
|
||||
|
||||
def tearDown(self):
|
||||
settings.configure(**OLD_DEFAULT_SETTINGS)
|
||||
django.setup()
|
||||
|
||||
from django.core.management import call_command
|
||||
from django.db.models import loading
|
||||
loading.cache.loaded = False
|
||||
call_command('syncdb', verbosity=0)
|
||||
|
||||
# test cases below ...
|
||||
|
||||
def test_case(self):
|
||||
# test case here
|
||||
```
|
||||
|
||||
### A note on adding new tests
|
||||
|
||||
Having an extensive tests suite is very important for avoiding code degradation as Evennia is
|
||||
developed. Only a small fraction of the Evennia codebase is covered by test suites at this point.
|
||||
Writing new tests is not hard, it's more a matter of finding the time to do so. So adding new tests
|
||||
is really an area where everyone can contribute, also with only limited Python skills.
|
||||
|
||||
### A note on making the test runner faster
|
||||
|
||||
If you have custom models with a large number of migrations, creating the test database can take a
|
||||
very long time. If you don't require migrations to run for your tests, you can disable them with the
|
||||
django-test-without-migrations package. To install it, simply:
|
||||
|
||||
```
|
||||
$ pip install django-test-without-migrations
|
||||
```
|
||||
|
||||
Then add it to your `INSTALLED_APPS` in your `server.conf.settings.py`:
|
||||
|
||||
```python
|
||||
INSTALLED_APPS = (
|
||||
# ...
|
||||
'test_without_migrations',
|
||||
)
|
||||
```
|
||||
|
||||
After doing so, you can then run tests without migrations by adding the `--nomigrations` argument:
|
||||
|
||||
```
|
||||
evennia test --settings settings.py --nomigrations .
|
||||
```
|
||||
|
||||
## Testing for Game development (mini-tutorial)
|
||||
|
||||
Unit testing can be of paramount importance to game developers. When starting with a new game, it is
|
||||
recommended to look into unit testing as soon as possible; an already huge game is much harder to
|
||||
write tests for. The benefits of testing a game aren't different from the ones regarding library
|
||||
testing. For example it is easy to introduce bugs that affect previously working code. Testing is
|
||||
there to ensure your project behaves the way it should and continue to do so.
|
||||
|
||||
If you have never used unit testing (with Python or another language), you might want to check the
|
||||
[official Python documentation about unit testing](https://docs.python.org/2/library/unittest.html),
|
||||
particularly the first section dedicated to a basic example.
|
||||
|
||||
### Basic testing using Evennia
|
||||
|
||||
Evennia's test runner can be used to launch tests in your game directory (let's call it 'mygame').
|
||||
Evennia's test runner does a few useful things beyond the normal Python unittest module:
|
||||
|
||||
* It creates and sets up an empty database, with some useful objects (accounts, characters and
|
||||
rooms, among others).
|
||||
* It provides simple ways to test commands, which can be somewhat tricky at times, if not tested
|
||||
properly.
|
||||
|
||||
Therefore, you should use the command-line to execute the test runner, while specifying your own
|
||||
game directories (not the one containing evennia). Go to your game directory (referred as 'mygame'
|
||||
in this section) and execute the test runner:
|
||||
|
||||
evennia --settings settings.py test commands
|
||||
|
||||
This command will execute Evennia's test runner using your own settings file. It will set up a dummy
|
||||
database of your choice and look into the 'commands' package defined in your game directory
|
||||
(`mygame/commands` in this example) to find tests. The test module's name should begin with 'test'
|
||||
and contain one or more `TestCase`. A full example can be found below.
|
||||
|
||||
### A simple example
|
||||
|
||||
In your game directory, go to `commands` and create a new file `tests.py` inside (it could be named
|
||||
anything starting with `test`). We will start by making a test that has nothing to do with Commands,
|
||||
just to show how unit testing works:
|
||||
|
||||
```python
|
||||
# mygame/commands/tests.py
|
||||
|
||||
import unittest
|
||||
|
||||
class TestString(unittest.TestCase):
|
||||
|
||||
"""Unittest for strings (just a basic example)."""
|
||||
|
||||
def test_upper(self):
|
||||
"""Test the upper() str method."""
|
||||
self.assertEqual('foo'.upper(), 'FOO')
|
||||
```
|
||||
|
||||
This example, inspired from the Python documentation, is used to test the 'upper()' method of the
|
||||
'str' class. Not very useful, but it should give you a basic idea of how tests are used.
|
||||
|
||||
Let's execute that test to see if it works.
|
||||
|
||||
> evennia --settings settings.py test commands
|
||||
|
||||
TESTING: Using specified settings file 'server.conf.settings'.
|
||||
|
||||
(Obs: Evennia's full test suite may not pass if the settings are very
|
||||
different from the default. Use 'test .' as arguments to run only tests
|
||||
on the game dir.)
|
||||
|
||||
Creating test database for alias 'default'...
|
||||
.
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 test in 0.001s
|
||||
|
||||
OK
|
||||
Destroying test database for alias 'default'...
|
||||
|
||||
We specified the `commands` package to the evennia test command since that's where we put our test
|
||||
file. In this case we could just as well just said `.` to search all of `mygame` for testing files.
|
||||
If we have a lot of tests it may be useful to test only a single set at a time though. We get an
|
||||
information text telling us we are using our custom settings file (instead of Evennia's default
|
||||
file) and then the test runs. The test passes! Change the "FOO" string to something else in the test
|
||||
to see how it looks when it fails.
|
||||
|
||||
### Testing commands
|
||||
|
||||
This section will test the proper execution of the 'abilities' command, as described in the [First
|
||||
Steps Coding](First-Steps-Coding) page. Follow this tutorial to create the 'abilities' command, we
|
||||
will need it to test it.
|
||||
|
||||
Testing commands in Evennia is a bit more complex than the simple testing example we have seen.
|
||||
Luckily, Evennia supplies a special test class to do just that ... we just need to inherit from it
|
||||
and use it properly. This class is called 'CommandTest' and is defined in the
|
||||
'evennia.commands.default.tests' package. To create a test for our 'abilities' command, we just
|
||||
need to create a class that inherits from 'CommandTest' and add methods.
|
||||
|
||||
We could create a new test file for this but for now we just append to the `tests.py` file we
|
||||
already have in `commands` from before.
|
||||
|
||||
```python
|
||||
# bottom of mygame/commands/tests.py
|
||||
|
||||
from evennia.commands.default.tests import CommandTest
|
||||
|
||||
from commands.command import CmdAbilities
|
||||
from typeclasses.characters import Character
|
||||
|
||||
class TestAbilities(CommandTest):
|
||||
|
||||
character_typeclass = Character
|
||||
|
||||
def test_simple(self):
|
||||
self.call(CmdAbilities(), "", "STR: 5, AGI: 4, MAG: 2")
|
||||
```
|
||||
|
||||
* Line 1-4: we do some importing. 'CommandTest' is going to be our base class for our test, so we
|
||||
need it. We also import our command ('CmdAbilities' in this case). Finally we import the
|
||||
'Character' typeclass. We need it, since 'CommandTest' doesn't use 'Character', but
|
||||
'DefaultCharacter', which means the character calling the command won't have the abilities we have
|
||||
written in the 'Character' typeclass.
|
||||
* Line 6-8: that's the body of our test. Here, a single command is tested in an entire class.
|
||||
Default commands are usually grouped by category in a single class. There is no rule, as long as
|
||||
you know where you put your tests. Note that we set the 'character_typeclass' class attribute to
|
||||
Character. As explained above, if you didn't do that, the system would create a 'DefaultCharacter'
|
||||
object, not a 'Character'. You can try to remove line 4 and 8 to see what happens when running the
|
||||
test.
|
||||
* Line 10-11: our unique testing method. Note its name: it should begin by 'test_'. Apart from
|
||||
that, the method is quite simple: it's an instance method (so it takes the 'self' argument) but no
|
||||
other arguments are needed. Line 11 uses the 'call' method, which is defined in 'CommandTest'.
|
||||
It's a useful method that compares a command against an expected result. It would be like comparing
|
||||
two strings with 'assertEqual', but the 'call' method does more things, including testing the
|
||||
command in a realistic way (calling its hooks in the right order, so you don't have to worry about
|
||||
that).
|
||||
|
||||
Line 11 can be understood as: test the 'abilities' command (first parameter), with no argument
|
||||
(second parameter), and check that the character using it receives his/her abilities (third
|
||||
parameter).
|
||||
|
||||
Let's run our new test:
|
||||
|
||||
> evennia --settings settings.py test commands
|
||||
[...]
|
||||
Creating test database for alias 'default'...
|
||||
..
|
||||
----------------------------------------------------------------------
|
||||
Ran 2 tests in 0.156s
|
||||
|
||||
OK
|
||||
Destroying test database for alias 'default'...
|
||||
|
||||
Two tests were executed, since we have kept 'TestString' from last time. In case of failure, you
|
||||
will get much more information to help you fix the bug.
|
||||
133
docs/source/Coding/Updating-Your-Game.md
Normal file
133
docs/source/Coding/Updating-Your-Game.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# Updating Your Game
|
||||
|
||||
|
||||
Fortunately, it's extremely easy to keep your Evennia server up-to-date. If you haven't already, see
|
||||
the [Getting Started guide](Getting-Started) and get everything running.
|
||||
|
||||
### Updating with the latest Evennia code changes
|
||||
|
||||
Very commonly we make changes to the Evennia code to improve things. There are many ways to get told
|
||||
when to update: You can subscribe to the RSS feed or manually check up on the feeds from
|
||||
http://www.evennia.com. You can also simply fetch the latest regularly.
|
||||
|
||||
When you're wanting to apply updates, simply `cd` to your cloned `evennia` root directory and type:
|
||||
|
||||
git pull
|
||||
|
||||
assuming you've got the command line client. If you're using a graphical client, you will probably
|
||||
want to navigate to the `evennia` directory and either right click and find your client's pull
|
||||
function, or use one of the menus (if applicable).
|
||||
|
||||
You can review the latest changes with
|
||||
|
||||
git log
|
||||
|
||||
or the equivalent in the graphical client. You can also see the latest changes online
|
||||
[here](https://github.com/evennia/evennia/blob/master/CHANGELOG.md).
|
||||
|
||||
You will always need to do `evennia reload` (or `reload` from -in-game) from your game-dir to have
|
||||
the new code affect your game. If you want to be really sure you should run a full `evennia reboot`
|
||||
so that both Server and Portal can restart (this will disconnect everyone though, so if you know the
|
||||
Portal has had no updates you don't have to do that).
|
||||
|
||||
### Upgrading Evennia dependencies
|
||||
|
||||
On occasion we update the versions of third-party libraries Evennia depend on (or we may add a new
|
||||
dependency). This will be announced on the mailing list/forum. If you run into errors when starting
|
||||
Evennia, always make sure you have the latest versions of everything. In some cases, like for
|
||||
Django, starting the server may also give warning saying that you are using a working, but too-old
|
||||
version that should not be used in production.
|
||||
|
||||
Upgrading `evennia` will automatically fetch all the latest packages that it now need. First `cd` to
|
||||
your cloned `evennia` folder. Make sure your `virtualenv` is active and use
|
||||
|
||||
pip install --upgrade -e .
|
||||
|
||||
Remember the period (`.`) at the end - that applies the upgrade to the current location (your
|
||||
`evennia` dir).
|
||||
|
||||
> The `-e` means that we are _linking_ the evennia sources rather than copying them into the
|
||||
environment. This means we can most of the time just update the sources (with `git pull`) and see
|
||||
those changes directly applied to our installed `evennia` package. Without installing/upgrading the
|
||||
package with `-e`, we would have to remember to upgrade the package every time we downloaded any new
|
||||
source-code changes.
|
||||
|
||||
Follow the upgrade output to make sure it finishes without errors. To check what packages are
|
||||
currently available in your python environment after the upgrade, use
|
||||
|
||||
pip list
|
||||
|
||||
This will show you the version of all installed packages. The `evennia` package will also show the
|
||||
location of its source code.
|
||||
|
||||
## Migrating the Database Schema
|
||||
|
||||
Whenever we change the database layout of Evennia upstream (such as when we add new features) you
|
||||
will need to *migrate* your existing database. When this happens it will be clearly noted in the
|
||||
`git log` (it will say something to the effect of "Run migrations"). Database changes will also be
|
||||
announced on the Evennia [mailing list](https://groups.google.com/forum/#!forum/evennia).
|
||||
|
||||
When the database schema changes, you just go to your game folder and run
|
||||
|
||||
evennia migrate
|
||||
|
||||
> Hint: If the `evennia` command is not found, you most likely need to activate your
|
||||
[virtualenv](Glossary#virtualenv).
|
||||
|
||||
## Resetting your database
|
||||
|
||||
Should you ever want to start over completely from scratch, there is no need to re-download Evennia
|
||||
or anything like that. You just need to clear your database. Once you are done, you just rebuild it
|
||||
from scratch as described in [step 2](Getting-Started#step-2-setting-up-your-game) of the [Getting
|
||||
Started guide](Getting-Started).
|
||||
|
||||
First stop a running server with
|
||||
|
||||
evennia stop
|
||||
|
||||
If you run the default `SQlite3` database (to change this you need to edit your `settings.py` file),
|
||||
the database is actually just a normal file in `mygame/server/` called `evennia.db3`. *Simply delete
|
||||
that file* - that's it. Now run `evennia migrate` to recreate a new, fresh one.
|
||||
|
||||
If you run some other database system you can instead flush the database:
|
||||
|
||||
evennia flush
|
||||
|
||||
This will empty the database. However, it will not reset the internal counters of the database, so
|
||||
you will start with higher dbref values. If this is okay, this is all you need.
|
||||
|
||||
Django also offers an easy way to start the database's own management should we want more direct
|
||||
control:
|
||||
|
||||
evennia dbshell
|
||||
|
||||
In e.g. MySQL you can then do something like this (assuming your MySQL database is named "Evennia":
|
||||
|
||||
mysql> DROP DATABASE Evennia;
|
||||
mysql> exit
|
||||
|
||||
> NOTE: Under Windows OS, in order to access SQLite dbshell you need to [download the SQLite
|
||||
command-line shell program](https://www.sqlite.org/download.html). It's a single executable file
|
||||
(sqlite3.exe) that you should place in the root of either your MUD folder or Evennia's (it's the
|
||||
same, in both cases Django will find it).
|
||||
|
||||
## More about schema migrations
|
||||
|
||||
If and when an Evennia update modifies the database *schema* (that is, the under-the-hood details as
|
||||
to how data is stored in the database), you must update your existing database correspondingly to
|
||||
match the change. If you don't, the updated Evennia will complain that it cannot read the database
|
||||
properly. Whereas schema changes should become more and more rare as Evennia matures, it may still
|
||||
happen from time to time.
|
||||
|
||||
One way one could handle this is to apply the changes manually to your database using the database's
|
||||
command line. This often means adding/removing new tables or fields as well as possibly convert
|
||||
existing data to match what the new Evennia version expects. It should be quite obvious that this
|
||||
quickly becomes cumbersome and error-prone. If your database doesn't contain anything critical yet
|
||||
it's probably easiest to simply reset it and start over rather than to bother converting.
|
||||
|
||||
Enter *migrations*. Migrations keeps track of changes in the database schema and applies them
|
||||
automatically for you. Basically, whenever the schema changes we distribute small files called
|
||||
"migrations" with the source. Those tell the system exactly how to implement the change so you don't
|
||||
have to do so manually. When a migration has been added we will tell you so on Evennia's mailing
|
||||
lists and in commit messages -
|
||||
you then just run `evennia migrate` to be up-to-date again.
|
||||
37
docs/source/Coding/Using-Travis.md
Normal file
37
docs/source/Coding/Using-Travis.md
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# Using Travis
|
||||
|
||||
Evennia uses [Travis CI](http://travis-ci.org/) to check that it's building successfully after every
|
||||
commit to its Github repository (you can for example see the `build: passing` badge at the top of
|
||||
Evennia's [Readme file](https://github.com/evennia/evennia)). If your game is open source on Github
|
||||
you may also use Travis for free. See [the Travis docs](http://docs.travis-ci.com/user/getting-
|
||||
started/) for how to get started.
|
||||
|
||||
After logging in you will get to point Travis to your repository on github. One further thing you
|
||||
need to set up yourself is a Travis config file named `.travis.yml` (note the initial period `.`).
|
||||
This should be created in the root of your game directory. The idea with this file is that it
|
||||
describes what Travis needs to import and build in order to create an instance of Evennia from
|
||||
scratch and then run validation tests on it. Here is an example:
|
||||
|
||||
``` yaml
|
||||
language: python
|
||||
python:
|
||||
- "2.7"
|
||||
install:
|
||||
- git clone https://github.com/evennia/evennia.git
|
||||
- cd evennia
|
||||
- pip install -e .
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
script:
|
||||
- evennia migrate
|
||||
- evennia test evennia
|
||||
- evennia test
|
||||
```
|
||||
|
||||
This will tell travis how to download Evennia, install it, set up a database and then run the test
|
||||
suite.
|
||||
You need to add this file to git (`git add .travis.yml`) and then commit your changes before Travis
|
||||
will be able to see it.
|
||||
|
||||
For properly testing your game you of course also need to write unittests. [We have a page](Unit-
|
||||
Testing) on how we set those up for Evennia, you should be able to refer to that for making tests
|
||||
fitting your game.
|
||||
475
docs/source/Coding/Version-Control.md
Normal file
475
docs/source/Coding/Version-Control.md
Normal file
|
|
@ -0,0 +1,475 @@
|
|||
# Version Control
|
||||
|
||||
|
||||
Version control software allows you to track the changes you make to your code, as well as being
|
||||
able to easily backtrack these changes, share your development efforts and more. Even if you are not
|
||||
contributing to Evennia itself, and only wish to develop your own MU* using Evennia, having a
|
||||
version control system in place is a good idea (and standard coding practice). For an introduction
|
||||
to the concept, start with the Wikipedia article
|
||||
[here](http://en.wikipedia.org/wiki/Version_control). Evennia uses the version control system
|
||||
[Git](https://git-scm.com/) and this is what will be covered henceforth. Note that this page also
|
||||
deals with commands for Linux operating systems, and the steps below may vary for other systems,
|
||||
however where possible links will be provided for alternative instructions.
|
||||
|
||||
For more help on using Git, please refer to the [Official GitHub
|
||||
documentation](https://help.github.com/articles/set-up-git#platform-all).
|
||||
|
||||
## Setting up Git
|
||||
|
||||
If you have gotten Evennia installed, you will have Git already and can skip to **Step 2** below.
|
||||
Otherwise you will need to install Git on your platform. You can find expanded instructions for
|
||||
installation [here](http://git-scm.com/book/en/Getting-Started-Installing-Git).
|
||||
|
||||
### Step 1: Install Git
|
||||
|
||||
- **Fedora Linux**
|
||||
|
||||
yum install git-core
|
||||
|
||||
- **Debian Linux** _(Ubuntu, Linux Mint, etc.)_
|
||||
|
||||
apt-get install git
|
||||
|
||||
- **Windows**: It is recommended to use [Git for Windows](http://msysgit.github.io/).
|
||||
- **Mac**: Mac platforms offer two methods for installation, one via MacPorts, which you can find
|
||||
out about [here](http://git-scm.com/book/en/Getting-Started-Installing-Git#Installing-on-Mac), or
|
||||
you can use the [Git OSX Installer](https://sourceforge.net/projects/git-osx-installer/).
|
||||
|
||||
### Step 2: Define user/e-mail Settings for Git
|
||||
|
||||
To avoid a common issue later, you will need to set a couple of settings; first you will need to
|
||||
tell Git your username, followed by your e-mail address, so that when you commit code later you will
|
||||
be properly credited.
|
||||
|
||||
> Note that your commit information will be visible to everyone if you ever contribute to Evennia or
|
||||
use an online service like github to host your code. So if you are not comfortable with using your
|
||||
real, full name online, put a nickname here.
|
||||
|
||||
1. Set the default name for git to use when you commit:
|
||||
|
||||
git config --global user.name "Your Name Here"
|
||||
|
||||
2. Set the default email for git to use when you commit:
|
||||
|
||||
git config --global user.email "your_email@example.com"
|
||||
|
||||
|
||||
## Putting your game folder under version control
|
||||
|
||||
> Note: The game folder's version control is completely separate from Evennia's repository.
|
||||
|
||||
After you have set up your game you will have created a new folder to host your particular game
|
||||
(let's call this folder `mygame` for now).
|
||||
|
||||
This folder is *not* under version control at this point.
|
||||
|
||||
git init mygame
|
||||
|
||||
Your mygame folder is now ready for version control! Now add all the content and make a first
|
||||
commit:
|
||||
|
||||
cd mygame
|
||||
git add *
|
||||
git commit -m "Initial commit"
|
||||
|
||||
Read on for help on what these commands do.
|
||||
|
||||
|
||||
### Tracking files
|
||||
|
||||
When working on your code or fix bugs in your local branches you may end up creating new files. If
|
||||
you do you must tell Git to track them by using the add command:
|
||||
|
||||
```
|
||||
git add <filename>
|
||||
```
|
||||
|
||||
You can check the current status of version control with `git status`. This will show if you have
|
||||
any modified, added or otherwise changed files. Some files, like database files, logs and temporary
|
||||
PID files are usually *not* tracked in version control. These should either not show up or have a
|
||||
question mark in front of them.
|
||||
|
||||
### Controlling tracking
|
||||
|
||||
You will notice that some files are not covered by your git version control, notably your settings
|
||||
file (`mygame/server/conf/settings.py`) and your sqlite3 database file `mygame/server/evennia.db3`.
|
||||
This is controlled by the hidden file `mygame/.gitignore`. Evennia creates this file as part of the
|
||||
creation of your game directory. Everything matched in this file will be ignored by GIT. If you want
|
||||
to, for example, include your settings file for collaborators to access, remove that entry in
|
||||
`.gitignore`.
|
||||
|
||||
> Note: You should *never* put your sqlite3 database file into git by removing its entry in
|
||||
`.gitignore`. GIT is for backing up your code, not your database. That way lies madness and a good
|
||||
chance you'll confuse yourself so that after a few commits and reverts don't know what is in your
|
||||
database or not. If you want to backup your database, do so by simply copying the file on your hard
|
||||
drive to a backup-name.
|
||||
|
||||
### Committing your Code
|
||||
|
||||
> Committing means storing the current snapshot of your code within git. This creates a "save point"
|
||||
or "history" of your development process. You can later jump back and forth in your history, for
|
||||
example to figure out just when a bug was introduced or see what results the code used to produce
|
||||
compared to now.
|
||||
|
||||
It's usually a good idea to commit your changes often. Committing is fast and local only - you will
|
||||
never commit anything online at this point. To commit your changes, use
|
||||
|
||||
```
|
||||
git commit --all
|
||||
```
|
||||
|
||||
This will save all changes you made since last commit. The command will open a text editor where you
|
||||
can add a message detailing the changes you've made. Make it brief but informative. You can see the
|
||||
history of commits with `git log`. If you don't want to use the editor you can set the message
|
||||
directly by using the `-m` flag:
|
||||
|
||||
```
|
||||
git commit --all -m "This fixes a bug in the combat code."
|
||||
```
|
||||
|
||||
### Changing your mind
|
||||
|
||||
If you have non-committed changes that you realize you want to throw away, you can do the following:
|
||||
|
||||
```
|
||||
git checkout <file to revert>
|
||||
```
|
||||
|
||||
This will revert the file to the state it was in at your last `commit`, throwing away the changes
|
||||
you did to it since. It's a good way to make wild experiments without having to remember just what
|
||||
you changed. If you do ` git checkout .` you will throw away _all_ changes since the last commit.
|
||||
|
||||
### Pushing your code online
|
||||
|
||||
So far your code is only located on your private machine. A good idea is to back it up online. The
|
||||
easiest way to do this is to push it to your own remote repository on GitHub.
|
||||
|
||||
1. Make sure you have your game directory setup under git version control as described above. Make
|
||||
sure to commit any changes.
|
||||
2. Create a new, empty repository on Github. Github explains how
|
||||
[here](https://help.github.com/articles/create-a-repo/) (do *not* "Initialize the repository with a
|
||||
README" or else you'll create unrelated histories).
|
||||
3. From your local game dir, do `git remote add origin <github URL>` where `<github URL>` is the URL
|
||||
to your online repo. This tells your game dir that it should be pushing to the remote online dir.
|
||||
4. `git remote -v` to verify the online dir.
|
||||
5. `git push origin master` now pushes your game dir online so you can see it on github.com.
|
||||
|
||||
You can commit your work locally (`git commit --all -m "Make a change that ..."`) as many times as
|
||||
you want. When you want to push those changes to your online repo, you do `git push`. You can also
|
||||
`git clone <url_to_online_repo>` from your online repo to somewhere else (like your production
|
||||
server) and henceforth do `git pull` to update that to the latest thing you pushed.
|
||||
|
||||
Note that GitHub's repos are, by default publicly visible by all. Creating a publicly visible online
|
||||
clone might not be what you want for all parts of your development process - you may prefer a more
|
||||
private venue when sharing your revolutionary work with your team. If that's the case you can change
|
||||
your repository to "Private" in the github settings. Then your code will only be visible to those
|
||||
you specifically grant access.
|
||||
|
||||
|
||||
## Forking Evennia
|
||||
|
||||
This helps you set up an online *fork* of Evennia so you can easily commit fixes and help with
|
||||
upstream development.
|
||||
|
||||
### Step 1: Fork the evennia/master repository
|
||||
|
||||
> Before proceeding with the following step, make sure you have registered and created an account on
|
||||
[GitHub.com](https://github.com/). This is necessary in order to create a fork of Evennia's master
|
||||
repository, and to push your commits to your fork either for yourself or for contributing to
|
||||
Evennia.
|
||||
|
||||
A _fork_ is a clone of the master repository that you can make your own commits and changes to. At
|
||||
the top of [this page](https://github.com/evennia/evennia), click the "Fork" button, as it appears
|
||||
below. 
|
||||
|
||||
### Step 2: Clone your fork
|
||||
|
||||
The fork only exists online as of yet. In a terminal, change your directory to the folder you wish
|
||||
to develop in. From this directory run the following command:
|
||||
|
||||
```
|
||||
git clone https://github.com/yourusername/evennia.git
|
||||
```
|
||||
|
||||
This will download your fork to your computer. It creates a new folder `evennia/` at your current
|
||||
location.
|
||||
|
||||
### Step 3: Configure remotes
|
||||
|
||||
A _remote_ is a repository stored on another computer, in this case on GitHub's server. When a
|
||||
repository is cloned, it has a default remote called `origin`. This points to your fork on GitHub,
|
||||
not the original repository it was forked from. To easily keep track of the original repository
|
||||
(that is, Evennia's official repository), you need to add another remote. The standard name for this
|
||||
remote is "upstream".
|
||||
|
||||
Below we change the active directory to the newly cloned "evennia" directory and then assign the
|
||||
original Evennia repository to a remote called "upstream":
|
||||
|
||||
```
|
||||
cd evennia
|
||||
git remote add upstream https://github.com/evennia/evennia.git
|
||||
```
|
||||
|
||||
If you also want to access Evennia's `develop` branch (the bleeding edge development branch) do the
|
||||
following:
|
||||
|
||||
```
|
||||
git fetch upstream develop
|
||||
git checkout develop
|
||||
```
|
||||
|
||||
You should now have the upstream branch available locally. You can use this instead of `master`
|
||||
below if you are contributing new features rather than bug fixes.
|
||||
|
||||
|
||||
## Working with your fork
|
||||
|
||||
> A _branch_ is a separate instance of your code. Changes you do to code in a branch does not affect
|
||||
that in other branches (so if you for example add/commit a file to one branch and then switches to
|
||||
another branch, that file will be gone until you switch back to the first branch again). One can
|
||||
switch between branches at will and create as many branches as one needs for a given project. The
|
||||
content of branches can also be merged together or deleted without affecting other branches. This is
|
||||
not only a common way to organize development but also to test features without messing with
|
||||
existing code.
|
||||
|
||||
The default _branch_ of git is called the "master" branch. As a rule of thumb, you should *never*
|
||||
make modifications directly to your local copy of the master branch. Rather keep the master clean
|
||||
and only update it by pulling our latest changes to it. Any work you do should instead happen in a
|
||||
local, other branches.
|
||||
|
||||
### Making a work branch
|
||||
|
||||
```
|
||||
git checkout -b myfixes
|
||||
```
|
||||
|
||||
This command will checkout and automatically create the new branch `myfixes` on your machine. If you
|
||||
stared out in the master branch, *myfixes* will be a perfect copy of the master branch. You can see
|
||||
which branch you are on with `git branch` and change between different branches with `git checkout
|
||||
<branchname>`.
|
||||
|
||||
Branches are fast and cheap to create and manage. It is common practice to create a new branch for
|
||||
every bug you want to work on or feature you want to create, then create a *pull request* for that
|
||||
branch to be merged upstream (see below). Not only will this organize your work, it will also make
|
||||
sure that *your* master branch version of Evennia is always exactly in sync with the upstream
|
||||
version's master branch.
|
||||
|
||||
### Updating with upstream changes
|
||||
|
||||
When Evennia's official repository updates, first make sure to commit all your changes to your
|
||||
branch and then checkout the "clean" master branch:
|
||||
|
||||
```
|
||||
git commit --all
|
||||
git checkout master
|
||||
```
|
||||
|
||||
Pull the latest changes from upstream:
|
||||
|
||||
```
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
This should sync your local master branch with upstream Evennia's master branch. Now we go back to
|
||||
our own work-branch (let's say it's still called "myfixes") and _merge_ the updated master into our
|
||||
branch.
|
||||
|
||||
```
|
||||
git checkout myfixes
|
||||
git merge master
|
||||
```
|
||||
|
||||
If everything went well, your `myfixes` branch will now have the latest version of Evennia merged
|
||||
with whatever changes you have done. Use `git log` to see what has changed. You may need to restart
|
||||
the server or run `manage.py migrate` if the database schema changed (this will be seen in the
|
||||
commit log and on the mailing list). See the [Git manuals](http://git-scm.com/documentation) for
|
||||
learning more about useful day-to-day commands, and special situations such as dealing with merge
|
||||
collisions.
|
||||
|
||||
## Sharing your Code Publicly
|
||||
|
||||
Up to this point your `myfixes` branch only exists on your local computer. No one else can see it.
|
||||
If you want a copy of this branch to also appear in your online fork on GitHub, make sure to have
|
||||
checked out your "myfixes" branch and then run the following:
|
||||
|
||||
```
|
||||
git push -u origin myfixes
|
||||
```
|
||||
|
||||
This will create a new _remote branch_ named "myfixes" in your online repository (which is refered
|
||||
to as "origin" by default); the `-u` flag makes sure to set this to the default push location.
|
||||
Henceforth you can just use `git push` from your myfixes branch to push your changes online. This is
|
||||
a great way to keep your source backed-up and accessible. Remember though that by default your
|
||||
repository will be public so everyone will be able to browse and download your code (same way as you
|
||||
can with Evennia itself). If you want secrecy you can change your repository to "Private" in the
|
||||
Github settings. Note though that if you do, you might have trouble contributing to Evennia (since
|
||||
we can't see the code you want to share).
|
||||
|
||||
*Note: If you hadn't setup a public key on GitHub or aren't asked for a username/password, you might
|
||||
get an error `403: Forbidden Access` at this stage. In that case, some users have reported that the
|
||||
workaround is to create a file `.netrc` under your home directory and add your credentials there:*
|
||||
|
||||
```bash
|
||||
machine github.com
|
||||
login <my_github_username>
|
||||
password <my_github_password>
|
||||
```
|
||||
|
||||
## Committing fixes to Evennia
|
||||
|
||||
_Contributing_ can mean both bug-fixes or adding new features to Evennia. Please note that if your
|
||||
change is not already listed and accepted in the [Issue
|
||||
Tracker](https://github.com/evennia/evennia/issues), it is recommended that you first hit the
|
||||
developer mailing list or IRC chat to see beforehand if your feature is deemed suitable to include
|
||||
as a core feature in the engine. When it comes to bug-fixes, other developers may also have good
|
||||
input on how to go about resolving the issue.
|
||||
|
||||
To contribute you need to have [forked Evennia](Version-Control#forking-evennia) first. As described
|
||||
above you should do your modification in a separate local branch (not in the master branch). This
|
||||
branch is what you then present to us (as a *Pull request*, PR, see below). We can then merge your
|
||||
change into the upstream master and you then do `git pull` to update master usual. Now that the
|
||||
master is updated with your fixes, you can safely delete your local work branch. Below we describe
|
||||
this work flow.
|
||||
|
||||
First update the Evennia master branch to the latest Evennia version:
|
||||
|
||||
```
|
||||
git checkout master
|
||||
git pull upstream master
|
||||
```
|
||||
|
||||
Next, create a new branch to hold your contribution. Let's call it the "fixing_strange_bug" branch:
|
||||
|
||||
```
|
||||
git checkout -b fixing_strange_bug
|
||||
```
|
||||
|
||||
It is wise to make separate branches for every fix or series of fixes you want to contribute. You
|
||||
are now in your new `fixing_strange_bug` branch. You can list all branches with `git branch` and
|
||||
jump between branches with `git checkout <branchname>`. Code and test things in here, committing as
|
||||
you go:
|
||||
|
||||
```
|
||||
git commit --all -m "Fix strange bug in look command. Resolves #123."
|
||||
```
|
||||
|
||||
You can make multiple commits if you want, depending on your work flow and progress. Make sure to
|
||||
always make clear and descriptive commit messages so it's easy to see what you intended. To refer
|
||||
to, say, issue number 123, write `#123`, it will turn to a link on GitHub. If you include the text
|
||||
"Resolves #123", that issue will be auto-closed on GitHub if your commit gets merged into main
|
||||
Evennia.
|
||||
|
||||
>If you refer to in-game commands that start with `@`(such as `@examine`), please put them in
|
||||
backticks \`, for example \`@examine\`. The reason for this is that GitHub uses `@username` to refer
|
||||
to GitHub users, so if you forget the ticks, any user happening to be named `examine` will get a
|
||||
notification ....
|
||||
|
||||
If you implement multiple separate features/bug-fixes, split them into different branches if they
|
||||
are very different and should be handled as separate PRs. You can do any number of commits to your
|
||||
branch as you work. Once you are at a stage where you want to show the world what you did you might
|
||||
want to consider making it clean for merging into Evennia's master branch by using [git
|
||||
rebase](https://www.git-scm.com/book/en/v2/Git-Branching-Rebasing) (this is not always necessary,
|
||||
and if it sounds too hard, say so and we'll handle it on our end).
|
||||
|
||||
Once you are ready, push your work to your online Evennia fork on github, in a new remote branch:
|
||||
|
||||
```
|
||||
git push -u origin fixing_strange_bug
|
||||
```
|
||||
|
||||
The `-u` flag is only needed the first time - this tells GIT to create a remote branch. If you
|
||||
already created the remote branch earlier, just stand in your `fixing_strange_bug` branch and do
|
||||
`git push`.
|
||||
|
||||
Now you should tell the Evennia developers that they should consider merging your brilliant changes
|
||||
into Evennia proper. [Create a pull request](https://github.com/evennia/evennia/pulls) and follow
|
||||
the instructions. Make sure to specifically select your `fixing_strange_bug` branch to be the source
|
||||
of the merge. Evennia developers will then be able to examine your request and merge it if it's
|
||||
deemed suitable.
|
||||
|
||||
Once your changes have been merged into Evennia your local `fixing_strange_bug` can be deleted
|
||||
(since your changes are now available in the "clean" Evennia repository). Do
|
||||
|
||||
```
|
||||
git branch -D fixing_strange_bug
|
||||
```
|
||||
|
||||
to delete your work branch. Update your master branch (`checkout master` and then `git pull`) and
|
||||
you should get your fix back, now as a part of official Evennia!
|
||||
|
||||
|
||||
## GIT tips and tricks
|
||||
|
||||
Some of the GIT commands can feel a little long and clunky if you need to do them often. Luckily you
|
||||
can create aliases for those. Here are some useful commands to run:
|
||||
|
||||
|
||||
```
|
||||
# git st
|
||||
# - view brief status info
|
||||
git config --global alias.st 'status -s'
|
||||
```
|
||||
|
||||
Above, you only need to ever enter the `git config ...` command once - you have then added the new
|
||||
alias. Afterwards, just do `git st` to get status info. All the examples below follow the same
|
||||
template.
|
||||
|
||||
```
|
||||
# git cl
|
||||
# - clone a repository
|
||||
git config --global alias.cl clone
|
||||
```
|
||||
|
||||
```
|
||||
# git cma "commit message"
|
||||
# - commit all changes without opening editor for message
|
||||
git config --global alias.cma 'commit -a -m'
|
||||
```
|
||||
|
||||
```
|
||||
# git ca
|
||||
# - amend text to your latest commit message
|
||||
git config --global alias.ca 'commit --amend'
|
||||
```
|
||||
|
||||
```
|
||||
# git fl
|
||||
# - file log; shows diffs of files in latest commits
|
||||
git config --global alias.fl 'log -u'
|
||||
```
|
||||
|
||||
```
|
||||
# git co [branchname]
|
||||
# - checkout
|
||||
git config --global alias.co checkout
|
||||
```
|
||||
|
||||
```
|
||||
# git br <branchname>
|
||||
# - create branch
|
||||
git config --global alias.br branch
|
||||
```
|
||||
|
||||
```
|
||||
# git ls
|
||||
# - view log tree
|
||||
git config --global alias.ls 'log --pretty=format:"%C(green)%h\ %C(yellow)[%ad]%Cred%d\
|
||||
%Creset%s%Cblue\ [%cn]" --decorate --date=relative --graph'
|
||||
```
|
||||
|
||||
```
|
||||
# git diff
|
||||
# - show current uncommitted changes
|
||||
git config --global alias.diff 'diff --word-diff'
|
||||
```
|
||||
|
||||
```
|
||||
# git grep <query>
|
||||
# - search (grep) codebase for a search criterion
|
||||
git config --global alias.grep 'grep -Ii'
|
||||
```
|
||||
|
||||
To get a further feel for GIT there is also [a good YouTube talk about
|
||||
it](https://www.youtube.com/watch?v=1ffBJ4sVUb4#t=1m58s) - it's a bit long but it will help you
|
||||
understand the underlying ideas behind GIT
|
||||
(which in turn makes it a lot more intuitive to use).
|
||||
Loading…
Add table
Add a link
Reference in a new issue