Added methods to read and write files with a given encoding to the eric-ide server file system interface and adapted the code accordingly.
10341
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
1
|
# -*- coding: utf-8 -*- |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
2
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
3
|
# Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de> |
10439
|
4
|
# Copyright (c) 2023 - 2024 Detlev Offenbach <detlev@die-offenbachs.de> |
10341
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
5
|
# |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
6
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
7
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
8
|
Module implementing the syntax check for JavaScript. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
9
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
10
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
11
|
import multiprocessing |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
12
|
import queue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
13
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
14
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
15
|
def initService(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
16
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
17
|
Initialize the service and return the entry point. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
18
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
19
|
@return the entry point for the background client |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
20
|
@rtype function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
21
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
22
|
return jsSyntaxCheck |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
23
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
24
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
25
|
def initBatchService(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
26
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
27
|
Initialize the batch service and return the entry point. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
28
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
29
|
@return the entry point for the background client |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
30
|
@rtype function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
31
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
32
|
return jsSyntaxBatchCheck |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
33
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
34
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
35
|
def jsSyntaxCheck(file, codestring): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
36
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
37
|
Function to check a Javascript source file for syntax errors. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
38
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
39
|
@param file source filename |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
40
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
41
|
@param codestring string containing the code to check |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
42
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
43
|
@return list of dictionaries with the key 'error' which contain a tuple with |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
44
|
details about the syntax error. Each tuple contains the file name, line |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
45
|
number, column, code string and the error message. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
46
|
@rtype list of dict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
47
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
48
|
return __jsSyntaxCheck(file, codestring) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
49
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
50
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
51
|
def jsSyntaxBatchCheck(argumentsList, send, fx, cancelled, maxProcesses=0): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
52
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
53
|
Module function to check syntax for a batch of files. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
54
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
55
|
@param argumentsList list of arguments tuples as given for jsSyntaxCheck |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
56
|
@type list |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
57
|
@param send reference to send function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
58
|
@type function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
59
|
@param fx registered service name |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
60
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
61
|
@param cancelled reference to function checking for a cancellation |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
62
|
@type function |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
63
|
@param maxProcesses number of processes to be used |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
64
|
@type int |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
65
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
66
|
if maxProcesses == 0: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
67
|
# determine based on CPU count |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
68
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
69
|
NumberOfProcesses = multiprocessing.cpu_count() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
70
|
if NumberOfProcesses >= 1: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
71
|
NumberOfProcesses -= 1 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
72
|
except NotImplementedError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
73
|
NumberOfProcesses = 1 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
74
|
else: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
75
|
NumberOfProcesses = maxProcesses |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
76
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
77
|
# Create queues |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
78
|
taskQueue = multiprocessing.Queue() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
79
|
doneQueue = multiprocessing.Queue() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
80
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
81
|
# Submit tasks (initially two time number of processes |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
82
|
tasks = len(argumentsList) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
83
|
initialTasks = 2 * NumberOfProcesses |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
84
|
for _ in range(initialTasks): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
85
|
taskQueue.put(argumentsList.pop(0)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
86
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
87
|
# Start worker processes |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
88
|
workers = [ |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
89
|
multiprocessing.Process(target=workerTask, args=(taskQueue, doneQueue)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
90
|
for _ in range(NumberOfProcesses) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
91
|
] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
92
|
for worker in workers: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
93
|
worker.start() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
94
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
95
|
# Get and send results |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
96
|
for _ in range(tasks): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
97
|
resultSent = False |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
98
|
wasCancelled = False |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
99
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
100
|
while not resultSent: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
101
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
102
|
# get result (waiting max. 3 seconds and send it to frontend |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
103
|
filename, result = doneQueue.get() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
104
|
send(fx, filename, result) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
105
|
resultSent = True |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
106
|
except queue.Empty: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
107
|
# ignore empty queue, just carry on |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
108
|
if cancelled(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
109
|
wasCancelled = True |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
110
|
break |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
111
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
112
|
if wasCancelled or cancelled(): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
113
|
# just exit the loop ignoring the results of queued tasks |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
114
|
break |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
115
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
116
|
if argumentsList: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
117
|
taskQueue.put(argumentsList.pop(0)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
118
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
119
|
# Tell child processes to stop |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
120
|
for _ in range(NumberOfProcesses): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
121
|
taskQueue.put("STOP") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
122
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
123
|
for worker in workers: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
124
|
worker.join() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
125
|
worker.close() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
126
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
127
|
taskQueue.close() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
128
|
doneQueue.close() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
129
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
130
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
131
|
def workerTask(inputQueue, outputQueue): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
132
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
133
|
Module function acting as the parallel worker for the syntax check. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
134
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
135
|
@param inputQueue input queue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
136
|
@type multiprocessing.Queue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
137
|
@param outputQueue output queue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
138
|
@type multiprocessing.Queue |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
139
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
140
|
for filename, args in iter(inputQueue.get, "STOP"): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
141
|
source = args[0] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
142
|
result = __jsSyntaxCheck(filename, source) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
143
|
outputQueue.put((filename, result)) |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
144
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
145
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
146
|
def __jsSyntaxCheck(file, codestring): |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
147
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
148
|
Function to check a JavaScript source file for syntax errors. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
149
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
150
|
@param file source filename |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
151
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
152
|
@param codestring string containing the code to check |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
153
|
@type str |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
154
|
@return list of dictionaries with the key 'error' which contain a tuple with |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
155
|
details about the syntax error. Each tuple contains the file name, line |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
156
|
number, column, code string and the error message. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
157
|
@rtype list of dict |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
158
|
""" |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
159
|
if codestring: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
160
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
161
|
import esprima # noqa: I101, I102 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
162
|
except ImportError: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
163
|
error = "esprima not available. Install it via the PyPI interface." |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
164
|
return [{"error": (file, 0, 0, "", error)}] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
165
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
166
|
try: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
167
|
esprima.parse(codestring, esnext=True, sourceType="module") |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
168
|
# Parsing is just done to get syntax errors. |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
169
|
except esprima.Error as exc: |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
170
|
line = exc.lineNumber |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
171
|
column = exc.column |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
172
|
error = exc.message.split(":", 1)[-1].strip() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
173
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
174
|
codelines = codestring.splitlines() |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
175
|
cline = min(len(codelines), line) - 1 |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
176
|
code = codelines[cline] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
177
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
178
|
return [{"error": (file, line, column, code, error)}] |
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
179
|
|
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff
changeset
|
180
|
return [{}] |