Skip to content

Commit 56de27b

Browse files
committed
Synchronize Alire invocations
1 parent 84714a0 commit 56de27b

File tree

1 file changed

+102
-17
lines changed

1 file changed

+102
-17
lines changed

source/ada/lsp-alire.adb

Lines changed: 102 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
-- of the license. --
1616
------------------------------------------------------------------------------
1717

18+
with Ada.Exceptions;
1819
with Ada.Streams;
20+
with GNAT.Lock_Files;
1921
with GNAT.OS_Lib;
2022
with GNATCOLL.Traces;
2123
with GNATCOLL.VFS;
@@ -42,7 +44,8 @@ package body LSP.Alire is
4244
GNATCOLL_Tracers.Create ("ALS.ALIRE", GNATCOLL.Traces.On);
4345

4446
Alire_Verbose : constant GNATCOLL_Tracers.Tracer :=
45-
GNATCOLL_Tracers.Create ("ALS.ALIRE.VERBOSE", GNATCOLL.Traces.From_Config);
47+
GNATCOLL_Tracers.Create
48+
("ALS.ALIRE.VERBOSE", GNATCOLL.Traces.From_Config);
4649

4750
type Process_Listener is limited
4851
new Spawn.Process_Listeners.Process_Listener
@@ -63,11 +66,31 @@ package body LSP.Alire is
6366
overriding
6467
procedure Error_Occurred (Self : in out Process_Listener; Error : Integer);
6568

66-
procedure Start_Alire
69+
procedure Start_Alire_Sync
6770
(Options : VSS.String_Vectors.Virtual_String_Vector;
6871
Root : String;
6972
Error : out VSS.Strings.Virtual_String;
7073
Lines : out VSS.String_Vectors.Virtual_String_Vector);
74+
-- This procedure uses a cross-process lock based on the current directory
75+
-- before starting Alire. This ensures that all ALS processes spawned in
76+
-- the same directory make Alire invocations in sequence and not in
77+
-- parallel, since concurrent Alire invocations on the same workspace can
78+
-- clash with each other on shared temporary files.
79+
--
80+
-- The actual invocation of Alire is delegated to Start_Alire_Unsynced.
81+
--
82+
-- This is necessary in contexts where two ALS processes are spawned in the
83+
-- same workspace, one acting as an Ada language server and the other
84+
-- acting as a GPR language server. Both make Alire invocations to set up
85+
-- the environment, hence the need for synchronization.
86+
87+
procedure Start_Alire_Unsynced
88+
(Options : VSS.String_Vectors.Virtual_String_Vector;
89+
Root : String;
90+
Error : out VSS.Strings.Virtual_String;
91+
Lines : out VSS.String_Vectors.Virtual_String_Vector);
92+
-- This procedure starts Alire immediately with no synchronization
93+
-- mechanism.
7194

7295
Anchored : constant VSS.Regular_Expressions.Match_Options :=
7396
(VSS.Regular_Expressions.Anchored_Match => True);
@@ -103,7 +126,7 @@ package body LSP.Alire is
103126
is
104127
Lines : VSS.String_Vectors.Virtual_String_Vector;
105128
begin
106-
Start_Alire
129+
Start_Alire_Sync
107130
(Options => ["--non-interactive", "build", "--stop-after=generation"],
108131
Root => Root,
109132
Error => Error,
@@ -123,7 +146,7 @@ package body LSP.Alire is
123146
begin
124147
Project.Clear;
125148

126-
Start_Alire
149+
Start_Alire_Sync
127150
(Options => ["--non-interactive", "show"],
128151
Root => Root,
129152
Error => Error,
@@ -201,7 +224,7 @@ package body LSP.Alire is
201224
Lines : VSS.String_Vectors.Virtual_String_Vector;
202225
begin
203226

204-
Start_Alire (["--non-interactive", "printenv"], Root, Error, Lines);
227+
Start_Alire_Sync (["--non-interactive", "printenv"], Root, Error, Lines);
205228

206229
if not Error.Is_Empty then
207230
return;
@@ -224,11 +247,73 @@ package body LSP.Alire is
224247
end loop;
225248
end Setup_Alire_Env;
226249

227-
-----------------
228-
-- Start_Alire --
229-
-----------------
250+
----------------------
251+
-- Start_Alire_Sync --
252+
----------------------
230253

231-
procedure Start_Alire
254+
procedure Start_Alire_Sync
255+
(Options : VSS.String_Vectors.Virtual_String_Vector;
256+
Root : String;
257+
Error : out VSS.Strings.Virtual_String;
258+
Lines : out VSS.String_Vectors.Virtual_String_Vector)
259+
is
260+
use VSS.Strings;
261+
use VSS.Strings.Conversions;
262+
263+
Lock_File : constant GNAT.Lock_Files.Path_Name :=
264+
GNATCOLL.VFS.Get_Current_Dir.Create_From_Dir (".als-alire")
265+
.Display_Full_Name;
266+
Lock_File_VS : constant Virtual_String := To_Virtual_String (Lock_File);
267+
begin
268+
269+
begin
270+
Trace.Trace_Text ("Acquiring Alire lock file: " & Lock_File_VS);
271+
GNAT.Lock_Files.Lock_File (Lock_File_Name => Lock_File, Wait => 0.2);
272+
exception
273+
when E : GNAT.Lock_Files.Lock_Error =>
274+
Trace.Trace_Exception (E);
275+
Error :=
276+
"Could not acquire Alire lock file. Try deleting the lock file manually: ";
277+
Error.Append (Lock_File_VS);
278+
return;
279+
end;
280+
281+
begin
282+
begin
283+
Start_Alire_Unsynced
284+
(Options => Options,
285+
Root => Root,
286+
Error => Error,
287+
Lines => Lines);
288+
exception
289+
when E : others =>
290+
Trace.Trace_Exception (E);
291+
Error := "Error running Alire: ";
292+
Error.Append
293+
(To_Virtual_String
294+
(Ada.Exceptions.Exception_Information (E)));
295+
Trace.Trace_Text ("Releasing Alire lock file: " & Lock_File_VS);
296+
GNAT.Lock_Files.Unlock_File (Lock_File);
297+
return;
298+
end;
299+
300+
Trace.Trace_Text ("Releasing Alire lock file: " & Lock_File_VS);
301+
GNAT.Lock_Files.Unlock_File (Lock_File);
302+
exception
303+
when E : others =>
304+
Trace.Trace_Exception (E);
305+
Error.Append
306+
(VSS.Characters.Latin.Line_Feed
307+
& "Could not release Alire lock file. Try deleting the lock files manually: ");
308+
Error.Append
309+
(Lock_File_VS
310+
& VSS.Characters.Latin.Line_Feed
311+
& To_Virtual_String (Ada.Exceptions.Exception_Information (E)));
312+
return;
313+
end;
314+
end Start_Alire_Sync;
315+
316+
procedure Start_Alire_Unsynced
232317
(Options : VSS.String_Vectors.Virtual_String_Vector;
233318
Root : String;
234319
Error : out VSS.Strings.Virtual_String;
@@ -241,14 +326,13 @@ package body LSP.Alire is
241326
use VSS.Strings.Formatters.Strings;
242327
use VSS.Strings.Conversions;
243328

244-
Item : aliased Process_Listener;
245-
Process : Spawn.Processes.Process renames Item.Process;
329+
Item : aliased Process_Listener;
330+
Process : Spawn.Processes.Process renames Item.Process;
246331
Full_Options : VSS.String_Vectors.Virtual_String_Vector := Options;
247-
Sp_Options : Spawn.String_Vectors.UTF_8_String_Vector;
248-
Decoder : VSS.Strings.Converters.Decoders.Virtual_String_Decoder;
249-
Text : VSS.Strings.Virtual_String;
332+
Sp_Options : Spawn.String_Vectors.UTF_8_String_Vector;
333+
Decoder : VSS.Strings.Converters.Decoders.Virtual_String_Decoder;
334+
Text : VSS.Strings.Virtual_String;
250335
begin
251-
252336
declare
253337
use type GNAT.OS_Lib.String_Access;
254338
ALR : GNAT.OS_Lib.String_Access :=
@@ -358,7 +442,7 @@ package body LSP.Alire is
358442
end if;
359443
end if;
360444

361-
end Start_Alire;
445+
end Start_Alire_Unsynced;
362446

363447
------------------------------
364448
-- Standard_Error_Available --
@@ -412,7 +496,8 @@ package body LSP.Alire is
412496
(Client : LSP.Ada_Client_Capabilities.Client_Capability) return Boolean
413497
is
414498
Alire_TOML : constant GNATCOLL.VFS.Virtual_File :=
415-
(if Client.Root.Is_Empty then GNATCOLL.VFS.No_File
499+
(if Client.Root.Is_Empty
500+
then GNATCOLL.VFS.No_File
416501
else Client.Root_Directory.Create_From_Dir ("alire.toml"));
417502
begin
418503
return Alire_TOML.Is_Regular_File;

0 commit comments

Comments
 (0)