Skip to content

Commit 173565c

Browse files
committed
contributing: Added copilot agent instructions
1 parent 9173ace commit 173565c

File tree

7 files changed

+1382
-0
lines changed

7 files changed

+1382
-0
lines changed

.github/copilot-instructions.md

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
# Copilot Instructions (GRASS GIS)
2+
3+
GRASS GIS is a geospatial processing engine with 500+ tools (modules) for
4+
raster, vector, imagery, temporal, and 3D analysis. Each tool is self-contained
5+
with source, docs, Makefile, and tests in one directory.
6+
7+
## Repository Layout
8+
9+
| Path | Contents |
10+
| ---- | -------- |
11+
| `raster/r.*/` | Raster tools (C, e.g. `raster/r.slope.aspect/`) |
12+
| `vector/v.*/` | Vector tools (C/Python) |
13+
| `temporal/t.*/` | Temporal framework tools (Python) |
14+
| `display/d.*/` | Display/rendering tools (C) |
15+
| `general/g.*/` | General management tools |
16+
| `db/db.*/` | Database tools |
17+
| `imagery/i.*/` | Imagery processing tools |
18+
| `scripts/` | Python script tools (e.g. `scripts/r.grow/r.grow.py`) |
19+
| `lib/` | Shared C libraries (`lib/gis/`, `lib/raster/`, `lib/vector/`, etc.) |
20+
| `python/grass/` | Python packages (`script/`, `pygrass/`, `gunittest/`, `temporal/`, `tools/`) |
21+
| `gui/wxpython/` | wxPython GUI |
22+
23+
## Module Directory Structure
24+
25+
Each module directory contains:
26+
27+
- `Makefile` — links to `include/Make/Module.make` (C)
28+
or `include/Make/Script.make` (Python)
29+
- `main.c` or `<tool>.py` — source code
30+
- `<tool>.md` — documentation (Markdown, **no header/footer**)
31+
- `tests/` — pytest tests (preferred for new tests)
32+
- `testsuite/` — legacy gunittest tests
33+
34+
## Build System
35+
36+
GRASS has two build systems. **CMake + Ninja** is recommended for development:
37+
38+
```bash
39+
cmake -S . -B build -G Ninja -DCMAKE_INSTALL_PREFIX="$HOME/install"
40+
cmake --build build -j$(nproc)
41+
cmake --install build
42+
```
43+
44+
Autotools is also supported:
45+
`./configure --prefix=$PREFIX && make -j$(nproc) && make install`
46+
47+
## Testing
48+
49+
Two test frameworks coexist:
50+
51+
**pytest** (preferred for new tests) — files in `<module>/tests/`:
52+
53+
```python
54+
# tests/conftest.py — typical fixture pattern
55+
import grass.script as gs
56+
from grass.tools import Tools
57+
58+
@pytest.fixture
59+
def xy_dataset_session(tmp_path):
60+
project = tmp_path / "xy_test"
61+
gs.create_project(project)
62+
with gs.setup.init(project, env=os.environ.copy()) as session, \
63+
Tools(session=session) as tools:
64+
tools.g_region(s=0, n=5, w=0, e=6, res=1)
65+
tools.r_mapcalc(expression="rows_raster = row()")
66+
yield session
67+
68+
# tests/my_tool_test.py
69+
def test_output(xy_dataset_session):
70+
tools = Tools(session=xy_dataset_session, consistent_return_value=True)
71+
tools.r_slope_aspect(elevation="rows_raster", slope="slope_out")
72+
stats = tools.r_univar(map="slope_out", format="json")
73+
assert stats["min"] == 45
74+
```
75+
76+
**gunittest** (legacy) — files in `<module>/testsuite/`, based on
77+
`grass.gunittest.case.TestCase` with assertions like `assertModule()`,
78+
`assertRasterMinMax()`.
79+
80+
Run tests:
81+
82+
```bash
83+
# pytest (from build directory or with GRASS in PATH)
84+
pytest raster/r.slope.aspect/tests/
85+
# gunittest (requires NC sample dataset)
86+
grass --tmp-project XY --exec python3 -m grass.gunittest.main \
87+
--grassdata $HOME --location nc_spm_full_v2beta1 --min-success 100
88+
```
89+
90+
## Critical Coding Conventions
91+
92+
These are GRASS-specific rules that differ from general practice. See
93+
`.github/instructions/` for full details.
94+
95+
### Python Tools
96+
97+
- **Import**: always `import grass.script as gs`
98+
- **Translatable messages**: use `_()` with `str.format()`, never f-strings:
99+
`gs.warning(_("Raster map <{}> not found.").format(name))`
100+
- **Non-translatable strings**: f-strings are fine:
101+
`expression = f"{output} = {input} * 3"`
102+
- **Parser interface**: defined via special comments, not argparse:
103+
104+
```python
105+
# %Module
106+
# % description: Short tool description
107+
# % keyword: raster
108+
# %end
109+
# %option G_OPT_R_INPUT
110+
# %end
111+
# %option G_OPT_R_OUTPUT
112+
# %end
113+
```
114+
115+
- **Computational region**: never change globally. Use context manager:
116+
`with gs.RegionManager(raster=input_map): ...`
117+
- **Raster mask**: never set/remove globally. Use:
118+
`with gs.MaskManager(): gs.run_command("r.mask", raster=mask)`
119+
- **Temporary maps**: use `gs.append_node_pid("tmp_name")` + `atexit` cleanup
120+
- **Record history**: call `gs.raster_history(output)` or `gs.vector_history(output)`
121+
- **Overwrite**: never overwrite outputs unless the user passes `--overwrite`
122+
- **Mapsets**: outputs go to the current mapset; inputs may come from any mapset.
123+
Do not hard-code file paths for geodata; use GRASS map names.
124+
- **Messages**: map names in `<angle brackets>`, file paths in `'single quotes'`,
125+
capitalize, no contractions, use `gs.message()` / `gs.fatal()` / `gs.warning()`
126+
(never `print()` for messages)
127+
128+
### C Tools
129+
130+
- Use GRASS APIs: `G_malloc()`, `G_fatal_error()`, `G_warning()`, `Rast_open_old()`
131+
- Header include order: system → non-core libs → `grass/*.h` → local headers
132+
- Format with `clang-format` (v18+); snake_case for function names
133+
- Exit with `EXIT_SUCCESS` / `EXIT_FAILURE`
134+
135+
### Documentation (`<tool>.md`)
136+
137+
Required sections: DESCRIPTION, SEE ALSO, AUTHORS.
138+
Suggested: NOTES, EXAMPLES. Tool names in italics (`*r.slope.aspect*`),
139+
flags/params bold (`**-n**`, `**input**`), shell values in backticks.
140+
See `.github/instructions/docs.instructions.md` for full markup guide.
141+
142+
## Formatting & Linting
143+
144+
Pre-commit runs all checks. Install once, then it runs on every commit:
145+
146+
```bash
147+
python -m pip install pre-commit && pre-commit install
148+
# Manual run:
149+
pre-commit run --all-files
150+
# Target specific files:
151+
pre-commit run --files raster/r.slope.aspect/*
152+
```
153+
154+
Key tools: `ruff format` + `ruff check` (Python), `clang-format` (C/C++),
155+
`markdownlint` (docs). Config in `pyproject.toml`, `.clang-format`,
156+
`.pre-commit-config.yaml`.
157+
158+
## Key Reference Files
159+
160+
- Python conventions: `.github/instructions/python.instructions.md`
161+
- C conventions: `.github/instructions/c.instructions.md`
162+
- Doc markup guide: `.github/instructions/docs.instructions.md`
163+
- General rules: `.github/instructions/general.instructions.md`
164+
- [GRASS Python API docs](https://grass.osgeo.org/grass-devel/manuals/libpython/)
165+
- [GRASS C Programmer's Manual](https://grass.osgeo.org/programming8/)
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
---
2+
description: "GRASS Programming Style Guide for C and C++ Instructions"
3+
applyTo: "**/*.c, **/*.h"
4+
---
5+
# GRASS Programming Style Guide for C and C++
6+
7+
- C and C++ code is formatted with ClangFormat
8+
- Contributions are expected to be formatted
9+
with `clang-format` (currently with version 18+).
10+
- The most convenient method to install clang-format and format files is using pre-commit.
11+
12+
Alternatively, using separately installed clang-format on modified files:
13+
14+
```bash
15+
clang-format -i <new_or_modified_file.c>
16+
```
17+
18+
The ClangFormat settings for the repo are defined in
19+
[.clang-format](../../.clang-format).
20+
21+
If using pre-commit is not an option, for whatever reason, there is a helper
22+
script [grass_clang_format.sh](./utils/grass_clang_format.sh), which simplifies
23+
bulk reformatting.
24+
25+
## Order of include headers
26+
27+
In general, headers should be included in the order:
28+
29+
1. Core system headers (stdio.h, ctype.h, ...)
30+
2. Headers for non-core system components (X11, libraries).
31+
3. GRASS headers (grass/gis.h, grass/glocale.h, ...)
32+
4. Headers for the specific library/program (geodesic.h, ...)
33+
34+
Each class of headers has an obligation to be compatible with those above it in
35+
the list, but not those below it. The header groups should be alphabetically
36+
sorted and separated by a newline.
37+
38+
```c
39+
#include <stdlib.h>
40+
#include <string.h>
41+
#include <unistd.h>
42+
43+
#include <grass/gis.h>
44+
#include <grass/glocale.h>
45+
#include <grass/raster.h>
46+
47+
#include "local_proto.h"
48+
#include "mask.h"
49+
```
50+
51+
## Naming conventions
52+
53+
Use function names which fulfill the official [GNU naming
54+
convention](https://www.gnu.org/prep/standards/html_node/Names.html). Instead of
55+
naming a function like: `MyNewFunction()` use snake case: `my_new_function()`.
56+
57+
## C API documentation
58+
59+
We
60+
[use doxygen and document the functions](https://grass.osgeo.org/programming8/)
61+
directly in the source code. See `lib/gis/open.c` and `lib/gis/gislib.dox` for
62+
examples.
63+
64+
### Developing C tools
65+
66+
Refer to the [online GRASS Programmer's
67+
Manual](https://grass.osgeo.org/programming8/) or generate it with `make
68+
htmldocs` or `make pdfdocs`.
69+
70+
#### Use GRASS library functions
71+
72+
Use the GRASS library functions, when available, instead of the standard C
73+
functions. The reason for this is that the following functions ensure good
74+
programming practice (e.g. always checking if memory was allocated) and/or
75+
improves portability.
76+
77+
- Memory management: `G_malloc()`, `G_calloc()`, `G_realloc()`, `G_free()`
78+
- Environmental variables: `G_getenv()`, `G_setenv()`, `G_unsetenv()`
79+
- File seek: `G_fseek()`, `G_ftell()`
80+
- Printing: `G_asprintf()`, `G_vsaprintf()`, `G_vfaprintf()`, ...
81+
82+
Please refer to the [programmers manual](https://grass.osgeo.org/programming8/)
83+
for the proper use (e.g., determining if any casts are needed for arguments or
84+
return values) of these library functions. They may perform a task slightly
85+
different from their corresponding C library function, and thus, their use may
86+
not be the same.
87+
88+
#### Returning value of main function
89+
90+
Tool exit status is defined as `EXIT_SUCCESS` or `EXIT_FAILURE` (declared in
91+
`stdlib.h`), e.g.
92+
93+
```c
94+
{
95+
...
96+
if (G_parser (argc, argv))
97+
exit (EXIT_FAILURE);
98+
99+
...
100+
exit (EXIT_SUCCESS);
101+
}
102+
```
103+
104+
#### Messages and data output
105+
106+
See rules for [messages in Python scripts](python.instructions.md#messages)
107+
for proper usage of `G_fatal_error()`, `G_warning()`, etc. Message
108+
output is not expected to be sent to pipe or file.
109+
110+
For data output redirected to pipe or file, please use `fprintf()` and specify
111+
the stdout stream as follows:
112+
113+
```c
114+
fprintf(stdout, ...);
115+
fflush(stdout);
116+
117+
fflush(stdout) /* always required when using fprintf(stdout, ...). */
118+
```
119+
120+
#### Header section
121+
122+
- Add a header section to file main.c of your tool and make sure you include the
123+
copyright.
124+
- If you are modifying an existing file you may under no circumstances
125+
remove prior copyright or licensing text that is not your own, even for a major
126+
rewrite.
127+
- If any original code or code that is in part derived from another's
128+
original work remains, it must be properly cited.
129+
130+
```c
131+
/****************************************************************************
132+
*
133+
* MODULE: g.foo
134+
* AUTHOR(S): John Doe <jdoe at somewhere org>
135+
* PURPOSE: Provide short description of module here...
136+
* COPYRIGHT: (C) 2010 by John Doe, and the GRASS Development Team
137+
*
138+
* SPDX-License-Identifier: GPL-2.0-or-later
139+
*
140+
*****************************************************************************/
141+
```

0 commit comments

Comments
 (0)