Skip to content

Commit cae663e

Browse files
committed
cEP 23: Breaking down coala
Closes #138
1 parent 93c7cce commit cae663e

File tree

1 file changed

+277
-0
lines changed

1 file changed

+277
-0
lines changed

cEP-0023.md

+277
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
# Breaking down coala
2+
3+
| Metadata | |
4+
|----------|-----------------------------------------------|
5+
| cEP | 0023 |
6+
| Version | 1.0 |
7+
| Title | Breaking down the coala |
8+
| Authors | Muhammad Kaisar Arkhan <mailto:[email protected]> |
9+
| Status | Proposed |
10+
| Type | Feature |
11+
12+
## Abstract
13+
14+
This cEP proposes a new architecture evolution for coala.
15+
16+
## How coala works
17+
18+
coala is a Python program that also provides API for bears and interacting with
19+
them.
20+
21+
Bears are Python classes filled with metadata needed to execute linter programs
22+
and may contain helper code to generate configuration files. Since bears are
23+
Python code, some bears have the actual linter inside of them and some just
24+
execute the Python API of a linter.
25+
26+
Bears are written with the API provided by the coala core and they're running
27+
under the same process as coala.
28+
29+
On startup, coala reads and intepret the configuration file. Configuration files
30+
are separated by sections which contains what bear is required and the
31+
configuration for the bear.
32+
33+
After it's intepreted, it is passed over to an executor which will executes it
34+
per section. The executor will find and import the bear class which usually
35+
resides in the Python packages path. It then pass the Section data to the bear
36+
and set it's require configuration. The bear first prepare the whole command
37+
along with it's parameters or generate a configuration file. After that's done,
38+
the linter program will be executed by the bear as a separate process and the
39+
bear will intepret it's standard output by matching a regex. The bear will yield
40+
the output of the program to the executor which will end up to the generator
41+
where the user see the warning/error and determine an action.
42+
43+
## The Architectural Issue
44+
45+
There is no clear distinction between the coala core which job is to intepret
46+
and run bears and the one that shows the command line interface to the user. In
47+
addition, bears in essence can do anything it wants to since it is just a Python
48+
class that is loaded into the coala process.
49+
50+
This caused numerous unwanted regressions between bears and coala and costed a
51+
lot in maintenance. This is also the reason why bears are not released
52+
separately as a "collection" rather it is shipped with coala core along with
53+
every linter in the collection.
54+
55+
Instead of leaving the project at this state, we should define borders and setup
56+
a more proper architecture and standards.
57+
58+
## The new architecture
59+
60+
Bears are now just simple formatted plain-text file containing the metadata
61+
needed. It can also contain a simple program as helpers or sole linters.
62+
63+
coala will separated into two parts: The coala Engine and The coala CLI.
64+
65+
The coala CLI's sole job is to present an interactive command line interface for
66+
the coala Engine. The CLI will present the output of the Engine and present them
67+
with possible actions that the user can do.
68+
69+
Meanwhile, the coala Engine's sole job is to intepret the bear files and
70+
execute/supervise the linter/helper programs along with committing the action
71+
that is requsted by the user.
72+
73+
If a helper program is needed, They'll act as the linter program and do stuff
74+
before the program (e.g generating the configuration file) and do stuff
75+
after it (e.g cleaning).
76+
77+
The frontend and backend programs will communicate to each other via json-rpc.
78+
json-rpc is chosen for it's simplicity.
79+
80+
## The new bear file
81+
82+
Bears will be ini files which is already a part of the Python standard library.
83+
Ini files are readable and simple to write. Making it a lot easier for projects
84+
making their own internal bears.
85+
86+
### GoVet.bear
87+
88+
```ini
89+
[bear]
90+
name = GoVetBear
91+
description = Analyze Go code and raise suspicious constructs, such as printf
92+
calls whose arguments do not correctly match the format string,
93+
useless assignments, common mistakes about boolean operations, unreachable code,
94+
etc.
95+
languages = Go
96+
authors = The coala developers
97+
authors_email = [email protected]
98+
license = AGPL-3.0
99+
can_detect = Unused code, Smell, Unreachable Code
100+
101+
[requirement]
102+
type = go
103+
package = golang.org/cmd/vet
104+
105+
[run]
106+
executable = go
107+
arguments = vet
108+
use_stdout = false
109+
use_stderr = true
110+
output_regex = .+:(?P<line>\d+): (?P<message>.*)
111+
```
112+
113+
The coala Engine will intepret the following file, check the requirement, and
114+
execute the linter program while intepreting the output with the regex.
115+
116+
### SpaceConsistency.bear
117+
118+
```ini
119+
[bear]
120+
name = SpaceConsistencyBear
121+
description = Check and correct spacing for all textual data. This includes usage of
122+
tabs vs. spaces, trailing whitespace and (missing) newlines before
123+
the end of the file.
124+
languages = All
125+
authors = The coala developers
126+
authors_email = [email protected]
127+
license = AGPL-3.0
128+
can_detect = Formatting
129+
130+
[param.use_spaces]
131+
description = True if spaces are to be used instead of tabs
132+
type = boolean
133+
134+
[param.allow_trailing_whitespace]
135+
description = Whether to allow trailing whitespace or not.
136+
type = boolean
137+
default = false
138+
139+
[params.indent_size]
140+
description = Number of spaces per indentation level
141+
type = int
142+
default = 8
143+
144+
[params.enforce_newline_at_EOF]
145+
description = Whether to enforce a newline at the end of file
146+
type = boolean
147+
default = true
148+
config_key = enforce_newline
149+
150+
[run]
151+
local = true
152+
executable = space_consistency_bear.py
153+
output_regex = .+:(?P<line>\d+): (?P<message>.*)
154+
155+
```
156+
157+
The coala Engine will intepret the following file, setup the command arguments,
158+
and run the Python file. Note that it does not load it as a library rather
159+
running it as a program.
160+
161+
This also means it is possible to run it without the engine.
162+
163+
```
164+
/usr/local/share/coala/bears/SpaceConsistency/space_consistency_bear.py \
165+
--use_spaces=false \
166+
--allow_trailing_whitespace=false \
167+
--indent_size=8 \
168+
--enforce_newline_at_EOF=8 \
169+
```
170+
171+
## The RPC
172+
173+
The RPC will follow the JSON-RPC specification
174+
(https://www.jsonrpc.org/specification).
175+
176+
The methods will be the following:
177+
* `start`
178+
* `commit`
179+
180+
The following examples will use the syntax below:
181+
```
182+
--> data sent to the Engine
183+
<-- data sent to the Frontend
184+
```
185+
186+
### `start_session`
187+
188+
`start_session` will start a new coala session. It will pass the whole
189+
configuration.
190+
191+
```json
192+
--> {
193+
"jsonrpc": "2.0",
194+
"method": "start_session",
195+
"params": {
196+
"sections": [
197+
"all": {
198+
"bears": ["SpaceConsistencyBear"],
199+
"use_spaces": true,
200+
"files": "**/**.py"
201+
}
202+
]
203+
}
204+
}
205+
<-- {
206+
"jsonrpc": "2.0",
207+
"result": {
208+
"file": "/home/asuka/src/myproject/main.py",
209+
"bear": "SpaceConsistencyBear",
210+
"message": "Tabs used instead of spaces.",
211+
"line": 47,
212+
"patch": "<patch goes here>",
213+
"has_next": true,
214+
"actions": [
215+
{
216+
"action": "patch",
217+
"name": "Apply Patch",
218+
"description": "Applies the proposed patch to the file"
219+
},
220+
{
221+
"action": "ignore",
222+
"name": "Ignore",
223+
"description": "Ignore the warning"
224+
}
225+
]
226+
}
227+
}
228+
```
229+
230+
### `commit`
231+
232+
`commit` will commit an action proposed by the Engine and pass onto the next warning.
233+
234+
```json
235+
--> {
236+
"jsonrpc": "2.0",
237+
"method": "commit",
238+
"params": {
239+
"action": "ignore"
240+
}
241+
}
242+
<-- {
243+
"jsonrpc": "2.0",
244+
"result": {
245+
"file": "/home/asuka/src/myproject/handler.py",
246+
"bear": "SpaceConsistencyBear",
247+
"message": "Tabs used instead of spaces.",
248+
"line": 20,
249+
"patch": "<patch goes here>",
250+
"section": "all",
251+
"has_next": false,
252+
"actions": [
253+
{
254+
"action": "patch",
255+
"name": "Apply Patch",
256+
"description": "Applies the proposed patch to the file"
257+
},
258+
{
259+
"action": "ignore",
260+
"name": "Ignore",
261+
"description": "Ignore the warning"
262+
}
263+
]
264+
}
265+
}
266+
--> {
267+
"jsonrpc": "2.0",
268+
"method": "commit",
269+
"params": {
270+
"action": "ignore"
271+
}
272+
}
273+
<-- {
274+
"jsonrpc": "2.0",
275+
"result": {}
276+
}
277+
```

0 commit comments

Comments
 (0)