Skip to content

Commit 508dc54

Browse files
libre-manolmokramer
authored andcommitted
Add api layer and special files (#4)
* Make it possible to save new files in a temporary file * Handle request errors in separate function * Remove checks for O_CREAT and O_EXCL flags in open function As explained here [0] these flags will never be passed so they don't need any special consideration. [0] https://sourceforge.net/p/fuse/mailman/message/29515577/ * Add first api layer * Add help file class * Add special file for filesystem mode * Add `is-file` command to the api * Change default behaviour to only show latest submissions * Add grade and feedback special file
1 parent 7efd9dc commit 508dc54

12 files changed

Lines changed: 2708 additions & 233 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
/env/
22
/__pycache__/
3+
mount/
4+
/.dir-locals.el
5+
/.run_tests.sh
6+
.cov2emacs.log
7+
/.coverage

.travis.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ notifications:
55

66
services:
77
- postgresql
8+
- redis-server
89

910
branches:
1011
only:
@@ -35,13 +36,15 @@ install:
3536
- pip install coveralls pytest-cov
3637
- pip install codecov
3738
- pip install -r requirements.txt
39+
- pip install celery[redis]
3840
- git clone https://github.com/CodeGra-de/CodeGra.de.git backend
3941
- pip install -r backend/requirements.txt
4042

4143
before_script:
4244
- pwd
4345
- ls
4446
- echo -e '[Back-end]\nsqlalchemy_database_uri = postgresql:///travis_ci_test\nDEBUG = true' > backend/config.ini
47+
- echo -e '\n[Celery]\nbroker_url = redis://localhost:6379/0\n' >> backend/config.ini
4548
- mkdir -p backend/uploads
4649
- mkdir -p backend/mirror_uploads
4750
- python --version

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export PYTHONPATH=$(CURDIR)
2+
TEST_FLAGS?=
23
PYTEST?=pytest
34

45
.PHONY: install_deps
@@ -12,5 +13,5 @@ format:
1213
.PHONY: test
1314
test:
1415
coverage erase
15-
$(PYTEST) test/ -vvvvvvvvv
16+
$(PYTEST) test/ -vvvvvvvvv $(TEST_FLAGS)
1617
coverage report -m cgfs.py

api_consumer.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
#!/usr/bin/env python3
2+
import os
3+
import sys
4+
import json
5+
import socket
6+
7+
8+
def print_usage():
9+
print(
10+
(
11+
'Usage:\n'
12+
'{0} set-comment FILE LINE_NUMBER MESSAGE\n'
13+
'OR\n'
14+
'{0} delete-comment FILE LINE_NUMBER\n'
15+
'OR\n'
16+
'{0} get-comment FILE\n'
17+
).format(sys.argv[0]),
18+
file=sys.stderr,
19+
end='\n',
20+
)
21+
22+
23+
def recv(s):
24+
message = b''
25+
26+
while True:
27+
m = s.recv(1024)
28+
message += m
29+
if len(m) < 1024:
30+
break
31+
return message
32+
33+
34+
def is_file(s, file):
35+
s.send(
36+
bytes(
37+
json.dumps({
38+
'op': 'is_file',
39+
'file': os.path.abspath(file),
40+
}).encode('utf8')
41+
)
42+
)
43+
if json.loads(recv(s))['ok']:
44+
return 0
45+
else:
46+
return 2
47+
48+
49+
def get_comments(s, file):
50+
s.send(
51+
bytes(
52+
json.
53+
dumps({
54+
'op': 'get_feedback',
55+
'file': os.path.abspath(file),
56+
}).encode('utf8')
57+
)
58+
)
59+
message = recv(s)
60+
61+
out = json.loads(message)
62+
if out['ok']:
63+
res = []
64+
for key, val in out['data'].items():
65+
res.append({'col': 0, 'line': int(key) + 1, 'content': val['msg']})
66+
67+
res.sort(key=lambda i: i['line'])
68+
print(json.dumps(res))
69+
return 0
70+
else:
71+
return 2
72+
73+
74+
def delete_comment(s, file, line):
75+
s.send(
76+
bytes(
77+
json.dumps(
78+
{
79+
'op': 'delete_feedback',
80+
'file': os.path.abspath(file),
81+
'line': line - 1,
82+
}
83+
).encode('utf8')
84+
)
85+
)
86+
if json.loads(recv(s))['ok']:
87+
return 0
88+
else:
89+
return 2
90+
91+
92+
def set_comment(s, file, line, message):
93+
s.send(
94+
bytes(
95+
json.dumps(
96+
{
97+
'op': 'set_feedback',
98+
'file': os.path.abspath(sys.argv[2]),
99+
'line': line - 1,
100+
'message': message
101+
}
102+
).encode('utf8')
103+
)
104+
)
105+
if json.loads(recv(s))['ok']:
106+
return 0
107+
else:
108+
return 2
109+
110+
111+
def main():
112+
path = '/'
113+
if len(sys.argv) < 3:
114+
print_usage()
115+
sys.exit(1)
116+
117+
for p in os.path.abspath(sys.argv[2]).split('/'):
118+
if not p:
119+
continue
120+
path = os.path.join(path, p)
121+
if os.path.isfile(os.path.join(path, '.api.socket')):
122+
break
123+
else:
124+
print('Socket not found', file=sys.stderr)
125+
sys.exit(3)
126+
127+
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
128+
s.connect(open(os.path.join(path, '.api.socket'), 'r').read())
129+
130+
try:
131+
if sys.argv[1] == 'set-comment':
132+
if len(sys.argv) != 5:
133+
print_usage()
134+
sys.exit(1)
135+
136+
try:
137+
line = int(sys.argv[3])
138+
except ValueError:
139+
print_usage()
140+
sys.exit(3)
141+
142+
message = sys.argv[4]
143+
144+
sys.exit(set_comment(s, sys.argv[2], line, message))
145+
146+
elif sys.argv[1] == 'delete-comment':
147+
if len(sys.argv) != 4:
148+
print_usage()
149+
sys.exit(1)
150+
151+
try:
152+
line = int(sys.argv[3])
153+
except ValueError:
154+
print_usage()
155+
sys.exit(3)
156+
157+
sys.exit(delete_comment(s, sys.argv[2], line))
158+
159+
elif sys.argv[1] == 'is-file':
160+
if len(sys.argv) != 3:
161+
print_usage()
162+
sys.exit(1)
163+
164+
sys.exit(is_file(s, sys.argv[2]))
165+
166+
elif sys.argv[1] == 'get-comment':
167+
if len(sys.argv) != 3:
168+
print_usage()
169+
sys.exit(1)
170+
171+
sys.exit(get_comments(s, sys.argv[2]))
172+
else:
173+
print_usage()
174+
sys.exit(1)
175+
finally:
176+
s.close()
177+
178+
179+
if __name__ == '__main__':
180+
main()

0 commit comments

Comments
 (0)