8
8
from types import MappingProxyType
9
9
import subprocess
10
10
import logging
11
+ import shutil
11
12
12
13
import pytest
13
14
16
17
17
18
PATH_PROJECTS = Path ("projects" ).absolute ()
18
19
PATH_LANGUAGES = Path ('languages' ).absolute ()
19
- LOOKUP_LANGUAGE_FOLDER = MappingProxyType ({
20
+ LANGUAGE_TO_FOLDER_MAPPING = MappingProxyType ({
20
21
'py' : 'python' ,
21
22
'cs' : 'csharp' ,
22
23
})
23
24
25
+ # `tempdir` creates 'secure' temp folders.
26
+ # These are not available to other users.
27
+ # docker on mac runs as a different user.
28
+ # None of the temp folders from env work because again - owned by the user
29
+ # environ.get('TMPDIR') or environ.get('TEMP') or environ.get('TMP') or
30
+ tempdir = Path ('.' ).joinpath ('_language_runner' )
31
+ tempdir .mkdir (exist_ok = True )
32
+ def clear (path : Path ):
33
+ # https://docs.python.org/3/library/pathlib.html#pathlib.Path.walk
34
+ for root , dirs , files in path .walk (top_down = False ):
35
+ for name in files :
36
+ (root / name ).unlink ()
37
+ for name in dirs :
38
+ (root / name ).rmdir ()
39
+
40
+
41
+ # Docker -----------------------------------------------------------------------
24
42
25
43
def get_built_docker_language_runners () -> set [str ]:
26
44
result = subprocess .run (
@@ -32,41 +50,30 @@ def get_built_docker_language_runners() -> set[str]:
32
50
)
33
51
return {container ['Tag' ] for container in map (json .loads , filter (None , result .stdout .split ('\n ' )))}
34
52
35
- BUILT_LANGUAGES = get_built_docker_language_runners ()
53
+ BUILT_LANGUAGES_RUNNERS = get_built_docker_language_runners ()
54
+
55
+ def get_docker_folder_for_language (language : str ) -> Path :
56
+ return PATH_LANGUAGES .joinpath (LANGUAGE_TO_FOLDER_MAPPING .get (language , language ))
36
57
37
58
def build_docker_language_runner (language ) -> subprocess .CompletedProcess :
38
59
return subprocess .run (
39
- ("docker" , "build" , PATH_LANGUAGES . joinpath ( LOOKUP_LANGUAGE_FOLDER . get ( language , language ) ), "--tag" , f"language_runner:{ language } " ),
60
+ ("docker" , "build" , get_docker_folder_for_language ( language ), "--tag" , f"language_runner:{ language } " ),
40
61
capture_output = True ,
41
62
timeout = 120 ,
42
63
text = True ,
43
64
check = True ,
44
65
)
45
66
46
67
47
- # `tempdir` creates 'secure' temp folders.
48
- # These are not available to other users.
49
- # docker on mac runs as a different user.
50
- # None of the temp folders from env work because again - owned by the user
51
- # environ.get('TMPDIR') or environ.get('TEMP') or environ.get('TMP') or
52
- tempdir = Path ('.' ).joinpath ('_language_runner' )
53
- tempdir .mkdir (exist_ok = True )
54
- def clear (path : Path ):
55
- # https://docs.python.org/3/library/pathlib.html#pathlib.Path.walk
56
- for root , dirs , files in path .walk (top_down = False ):
57
- for name in files :
58
- (root / name ).unlink ()
59
- for name in dirs :
60
- (root / name ).rmdir ()
61
-
68
+ # Project Compile --------------------------------------------------------------
62
69
63
70
class ProjectItemSpec (NamedTuple ):
64
71
name : str
65
72
language : str
66
73
version : str
67
74
code : str
68
75
69
- def exec_language (self , language_args : tuple [str ]):
76
+ def exec_language (self , language_args : tuple [str ]= () ):
70
77
workdir = f"/{ self .language } "
71
78
docker_args = (
72
79
"docker" , "run" , "--rm" ,
@@ -103,15 +110,21 @@ def get_java_main_classname(code: str) -> str:
103
110
if match := re .search (r'class (\w+?) .*public static void main' , code , re .DOTALL ):
104
111
return match .group (1 )
105
112
raise Exception ('unable to find top level classname for filename' , code )
106
-
107
113
def compile_test_java (spec : ProjectItemSpec ):
108
114
path_code_file = tempdir .joinpath (get_java_main_classname (spec .code ) + ".java" )
109
115
path_code_file .write_text (spec .code )
110
116
spec .exec_language (("javac" , path_code_file .name ))
111
117
118
+
119
+ def copy_cs_file_to_workdir (filename : str ):
120
+ shutil .copyfile (get_docker_folder_for_language ('cs' ).joinpath (filename ), tempdir .joinpath (filename ))
112
121
def compile_test_csharp (spec : ProjectItemSpec ):
113
- # csharp create manifest?
114
- raise NotImplementedError ('' )
122
+ copy_cs_file_to_workdir ('main.csproj' )
123
+ copy_cs_file_to_workdir ('packages.log.json' )
124
+ path_code_file = tempdir .joinpath (spec .name )
125
+ path_code_file .write_text (spec .code )
126
+ # TODO: edit `main.csproj` to point to top level cs class
127
+ spec .exec_language () # The containers base command is already `dotnet run`
115
128
116
129
117
130
LANGUAGES : MappingProxyType [str , Callable ] = MappingProxyType (
@@ -159,11 +172,11 @@ def pytest_collection_finish(session: pytest.Session):
159
172
for item in session .items
160
173
if hasattr (item , 'spec' )
161
174
}
162
- language_runners_to_build = (languages_in_items - BUILT_LANGUAGES ) & LANGUAGES .keys ()
175
+ language_runners_to_build = (languages_in_items - BUILT_LANGUAGES_RUNNERS ) & LANGUAGES .keys ()
163
176
for language in language_runners_to_build :
164
177
print (f"docker build --tag language_runner:{ language } " ) #log.info
165
178
build_docker_language_runner (language )
166
- BUILT_LANGUAGES .add (language )
179
+ BUILT_LANGUAGES_RUNNERS .add (language )
167
180
168
181
169
182
def pytest_sessionfinish (session : pytest .Session , exitstatus : int ):
0 commit comments