File: projects.adb

package info (click to toggle)
gnat-gps 18-5
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 45,716 kB
  • sloc: ada: 362,679; python: 31,031; xml: 9,597; makefile: 1,030; ansic: 917; sh: 264; java: 17
file content (350 lines) | stat: -rw-r--r-- 10,471 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
------------------------------------------------------------------------------
--                                  G P S                                   --
--                                                                          --
--                     Copyright (C) 2002-2018, AdaCore                     --
--                                                                          --
-- This is free software;  you can redistribute it  and/or modify it  under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  This software is distributed in the hope  that it will be useful, --
-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public --
-- License for  more details.  You should have  received  a copy of the GNU --
-- General  Public  License  distributed  with  this  software;   see  file --
-- COPYING3.  If not, go to http://www.gnu.org/licenses for a complete copy --
-- of the license.                                                          --
------------------------------------------------------------------------------

with Ada.Strings.Hash_Case_Insensitive;
with Ada.Unchecked_Deallocation;
with GPR.Opt;                    use GPR.Opt;
with GPR.Names;                  use GPR.Names;
with GPR.Snames;                 use GPR.Snames;
with GNAT.Strings;               use GNAT.Strings;

pragma Warnings (Off);
with GNAT.Expect.TTY;           use GNAT.Expect, GNAT.Expect.TTY;
with GNAT.Expect.TTY.Remote;    use GNAT.Expect.TTY.Remote;
pragma Warnings (On);

with GNATCOLL.Traces;           use GNATCOLL.Traces;

package body Projects is
   Me : constant Trace_Handle := Create ("GPS.KERNEL.PROJECTS");

   -----------------------
   -- Project_Name_Hash --
   -----------------------

   function Project_Name_Hash
     (Project : Project_Type) return Ada.Containers.Hash_Type is
   begin
      return Ada.Strings.Hash_Case_Insensitive (Project.Name);
   end Project_Name_Hash;

   -----------------------
   -- Project_Directory --
   -----------------------

   function Project_Directory
     (Project : Project_Type;
      Host    : String := Local_Host) return GNATCOLL.VFS.Virtual_File is
   begin
      return Dir (Project_Path (Project, Host));
   end Project_Directory;

   --------------------
   -- Set_Paths_Type --
   --------------------

   procedure Set_Paths_Type
     (Project : Project_Type; Paths : Paths_Type_Information) is
   begin
      GPS_Project_Data_Access (Project.Data).Paths_Type := Paths;
   end Set_Paths_Type;

   --------------------
   -- Get_Paths_Type --
   --------------------

   function Get_Paths_Type
     (Project : Project_Type) return Paths_Type_Information is
   begin
      return GPS_Project_Data_Access (Project.Data).Paths_Type;
   end Get_Paths_Type;

   --------------------------
   -- Source_Dirs_With_VCS --
   --------------------------

   function Source_Dirs_With_VCS
     (Project   : Project_Type;
      Recursive : Boolean) return GNATCOLL.VFS.File_Array
   is
   begin
      --  ??? We could optimize and only take into account projects with a
      --  VCS attribute. This used to be the case before we moved the projects
      --  API into GNATCOLL

      return Project.Source_Dirs (Recursive => Recursive);
   end Source_Dirs_With_VCS;

   ---------------------------
   -- Is_Valid_Project_Name --
   ---------------------------

   function Is_Valid_Project_Name (Name : String) return Boolean is
      Start  : Natural;
      Finish : Natural;

      function Is_Ada_Identifier (S : String) return Boolean;
      --  Returns True iff S has the syntax of an Ada identifier and is not an
      --  Ada95 reserved word.

      -----------------------
      -- Is_Ada_Identifier --
      -----------------------

      function Is_Ada_Identifier (S : String) return Boolean is
         Underscore : Boolean := False;
      begin
         --  An Ada identifier cannot be empty and must start with a letter

         if S'Length = 0 or else
            (S (S'First) not in 'a' .. 'z' and then
             S (S'First) not in 'A' .. 'Z')
         then
            return False;
         end if;

         for J in S'First + 1 .. S'Last loop
            if S (J) = '_' then
               --  An Ada identifier cannot have two consecutive underscores

               if Underscore then
                  return False;
               end if;

               Underscore := True;

            else
               Underscore := False;

               --  An Ada identifier is made only of letters, digits and
               --  underscores (already treated).

               if S (J) not in 'a' .. 'z' and then
                  S (J) not in 'A' .. 'Z' and then
                  S (J) not in '0' .. '9'
               then
                  return False;
               end if;
            end if;
         end loop;

         --  An Ada identifier cannot ends with an underscore

         if Underscore then
            return False;
         end if;

         Name_Len := S'Length;
         Name_Buffer (1 .. Name_Len) := S;

         --  A project name cannot be an Ada95 reserved word

         if Name_Find in Reserved_Ada_Project then
            return False;
         end if;

         --  All checks have succeeded

         return True;
      end Is_Ada_Identifier;

   begin
      --  A project name cannot be empty of ends with a dot

      if Name'Length = 0 or else Name (Name'Last) = '.' then
         return False;
      end if;

      Start := Name'First;

      loop
         Finish := Start - 1;
         while Finish < Name'Last and then
               Name (Finish + 1) /= '.'
         loop
            Finish := Finish + 1;
         end loop;

         declare
            OK : constant Boolean :=
                    Is_Ada_Identifier (Name (Start .. Finish));
         begin
            --  A project name needs to be an Ada identifier and cannot be an
            --  Ada95 reserved word.

            if not OK then
               return False;
            end if;
         end;

         Start := Finish + 2;
         exit when Start > Name'Last;
      end loop;

      --  All checks have succeeded

      return True;
   end Is_Valid_Project_Name;

   -----------------
   -- Environment --
   -----------------

   function Environment
     (Self : Project_Registry) return Project_Environment_Access
   is
   begin
      return Self.Env;
   end Environment;

   ----------
   -- Tree --
   ----------

   function Tree (Self : Project_Registry) return Project_Tree_Access is
   begin
      return Self.Tree;
   end Tree;

   -------------
   -- Destroy --
   -------------

   procedure Destroy (Registry : in out Project_Registry_Access) is
      procedure Unchecked_Free is new Ada.Unchecked_Deallocation
        (Project_Registry'Class, Project_Registry_Access);
   begin
      Cleanup_Subdirs (Registry.Tree.all);

      Registry.Tree.Unload;
      Free (Registry.Tree);
      Free (Registry.Env);
      Unchecked_Free (Registry);

      GNATCOLL.Projects.Finalize;
   end Destroy;

   ------------
   -- Create --
   ------------

   function Create
     (Tree : not null access GNATCOLL.Projects.Project_Tree'Class;
      Env  : GNATCOLL.Projects.Project_Environment_Access := null)
      return Project_Registry_Access
   is
      Reg : constant Project_Registry_Access := new Project_Registry;
   begin
      Reg.Tree := Project_Tree_Access (Tree);
      Reg.Env  := Env;
      Initialize (Reg.Env, IDE_Mode => True);
      return Reg;
   end Create;

   ----------
   -- Free --
   ----------

   procedure Free (Self : in out Project_Type_Array_Access) is
      procedure Unchecked_Free is new Ada.Unchecked_Deallocation
        (Project_Type_Array, Project_Type_Array_Access);
   begin
      Unchecked_Free (Self);
   end Free;

   --------------------------------
   -- Source_Files_Non_Recursive --
   --------------------------------

   function Source_Files_Non_Recursive
     (Projects : Project_Type_Array) return GNATCOLL.VFS.File_Array_Access
   is
      Result : File_Array_Access;
      Tmp    : File_Array_Access;
   begin
      for P in Projects'Range loop
         Tmp := Projects (P).Source_Files (Recursive => False);
         if Tmp /= null then
            Append (Result, Tmp.all);
            Unchecked_Free (Tmp);
         end if;
      end loop;
      return Result;
   end Source_Files_Non_Recursive;

   ---------------------
   -- Cleanup_Subdirs --
   ---------------------

   procedure Cleanup_Subdirs (Tree : GNATCOLL.Projects.Project_Tree'Class) is
      F : Virtual_File;
      Success : Boolean;
   begin
      --  Remove temporary files if needed

      if Tree.Root_Project.Object_Dir /= No_File then
         F := Create_From_Dir
            (Tree.Root_Project.Object_Dir, Saved_Config_File);
         if F.Is_Regular_File then
            Trace (Me, "Deleting " & F.Display_Full_Name);
            F.Delete (Success);
         end if;
      end if;

      F := Create_From_Dir
         (Tree.Root_Project.Project_Path.Dir, Saved_Config_File);
      if F.Is_Regular_File then
         Trace (Me, "Deleting " & F.Display_Full_Name);
         F.Delete (Success);
      end if;

      --  Nothing to do if Prj.Subdirs is not set
      if GPR.Subdirs = null then
         return;
      end if;

      declare
         Objs    : constant File_Array :=
           Root_Project (Tree).Object_Path (Recursive => True);
         Success : Boolean;
      begin
         for J in Objs'Range loop
            declare
               Dir : Virtual_File renames Objs (J);
            begin
               if Dir.Is_Directory then
                  --  Remove emtpy directories (this call won't remove the dir
                  --  if files or subdirectories are in it.
                  Dir.Remove_Dir (Success => Success);
               end if;
            end;
         end loop;
      end;

   exception
      when Constraint_Error =>
         --  Object_Path can raise Constraint_Error when project view was not
         --  computed and aggreate project is loaded. Just ignore it, see
         --  NA08-021.

         null;
   end Cleanup_Subdirs;

begin
   --  Use full path name so that the messages are sent to Locations view
   GPR.Opt.Full_Path_Name_For_Brief_Errors := True;
end Projects;