Skip to content

GNATCOLL.Projects.Rename_And_Move fails to preserve trailing directory separator #32

@LordAro

Description

@LordAro

When calling GNATCOLL.Projects.Rename_And_Move, if you pass in a directory that is missing the trailing slash (such as a path generated by Ada.Directories.Containing_Directory), the resulting renamed gpr file is missing path separators in attributes such as Object_Dir, which can lead to invalid directory/pathnames

Minimal test case

bug6486.adb

with GNATCOLL.Projects; use GNATCOLL.Projects;
with GNATCOLL.VFS;      use GNATCOLL.VFS;
with Ada.Directories;

procedure bug6486 is
   tree : Project_Tree;
   proj_file : String := "bug6486.gpr";
   proj : Project_Type;
   dummy : Boolean;
begin
   tree.Load (Create (Filesystem_String (proj_file)));

   proj := tree.Root_Project;
   proj.Rename_And_Move
      ("foobar_" & proj.Name, Create (Filesystem_String 
         (Ada.Directories.Containing_Directory (+proj.Project_Path.Full_Name))));

   tree.Recompute_View;
   dummy := proj.Save;
end bug6486;

bug6486.gpr

with "gnatcoll_full";

project bug6486 is

   for Exec_Dir use ".";
   for Source_Dirs use (".");
   for Main use ("bug6486.adb");
   type Kind_Type is
      ("dev", "release");
   Kind : Kind_Type := external ("Kind");

   case Kind is

      when "dev" =>
         for Object_Dir use "obj/" & Kind;

      when "release" =>
         for Object_Dir use "obj/" & Kind;
   end case;

end bug6486;

Results

With the above code, run:

gprbuild -p -XKind=dev -Pbug6486 && ./bug6486 && diff -wu bug6486.gpr foobar_bug6486.gpr

which should result in:

--- bug6486.gpr 2018-06-12 15:14:59.566694628 +0100
+++ foobar_bug6486.gpr  2018-06-12 15:15:01.086683191 +0100
@@ -1,6 +1,6 @@
 with "gnatcoll_full";

-project bug6486 is
+project Foobar_Bug6486 is

    for Exec_Dir use ".";
    for Source_Dirs use (".");
@@ -12,11 +12,11 @@
    case Kind is

       when "dev" =>
-         for Object_Dir use "obj/" & Kind;
+         for Object_Dir use "obj" & Kind;

       when "release" =>
-         for Object_Dir use "obj/" & Kind;
+         for Object_Dir use "obj" & Kind;
    end case;

-end bug6486;
+end Foobar_Bug6486;

Hacky fix

The following hack is being used internally. I've not pull requested it, because it's a hack, and I'm not convinced it's the correct fix anyway.

From my own investigations, the issue is that the Relative_Path (File, New_Path) call inside GNATCOLL.Projects.Normalize is stripping the trailing path separator (when New_Path is missing a trailing '/'), compared to the original 'D' string, but I've not got as far as working out quite why that's happening

(even the diff is hacked together, probably won't even apply automatically)

Index: gnatcoll-projects-normalize.adb
===================================================================
--- gnatcoll-projects-normalize.adb     (revision 55361)
+++ gnatcoll-projects-normalize.adb     (revision 55362)
@@ -2875,11 +2875,28 @@
                               Get_Host (New_Path));
                begin
                   if not Is_Absolute_Path (D) then
+                     -- fix here for bug6486
+                     declare
+                        dir_string : constant String := String(D);
+                        -- get whether string ends in directory seperator
+                        end_with_slash : constant Boolean := (dir_string(dir_string'Last) = '/'
+                                                              or else dir_string(dir_string'Last) = '\');
+                        -- if it does make sure that this is not lost
+                        function get_possible_end_dir_sep return String is
+                        begin
+                           if end_with_slash then
+                              return "" & dir_string(dir_string'Last);
+                           else
+                              return "";
+                           end if;
+                        end get_possible_end_dir_sep;
+                        suffix : constant String := get_possible_end_dir_sep;
+                     begin
+
                      Set_String_Value_Of
                        (Node, Tree_Node,
-                        Get_String
-                          (+Relative_Path
-                             (File, New_Path)));
+                           Get_String (+(Relative_Path (File, New_Path)) & suffix));
+                     end;
                   end if;
                end;

(Copy of R612-025)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions