File 2051-Do-not-consider-dotfiles-to-be-an-extension.patch of Package erlang

From ef32118513ca11a4edb9b4456ef4ba6df5fc3ff0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@dashbit.co>
Date: Thu, 6 Aug 2020 20:47:43 +0200
Subject: [PATCH] Do not consider dotfiles to be an extension

Previously, filename:extension(".gitignore") would
return ".gitignore" as an extension while ".gitignore"
is actually part of the filename. Similarly,
filename:rootname("foo/.gitignore") would return "foo/".

One argument for .gitignore to be treated as filename
is that we should expect this property to hold:

    length(filename:split(Path)) =:=
        length(filename:split(filename:rootname(Path)))

But that was violated for dotfiles prior to this commit.

Another point of discussion is filenames such as "..ext".
This commit takes the approch that the rootname is "."
and the extension is ".ext".
---
 lib/stdlib/src/filename.erl        | 43 +++++++++++++++++++-----------
 lib/stdlib/test/filename_SUITE.erl | 20 ++++++++++++++
 2 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index b6df99621f..9f706e9970 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -398,22 +398,31 @@ extension(Name) when is_binary(Name) ->
 	[] ->
 	    <<>>;
 	List ->
-	    {Pos,_} = lists:last(List),
-	    <<_:Pos/binary,Part/binary>> = Name,
-	    case binary:match(Part,[<<"/">>|SList]) of
-		nomatch ->
-		    Part;
-		_ ->
-		    <<>>
+	    case lists:last(List) of
+		{0,_} ->
+		    <<>>;
+		{Pos, _} ->
+		    <<_:(Pos-1)/binary,Part/binary>> = Name,
+		    case binary:match(Part,[<<"/">>|SList]) of
+			nomatch ->
+			    <<_:Pos/binary,Result/binary>> = Name,
+			    Result;
+			_ ->
+			    <<>>
+		    end
 	    end
     end;
 
 extension(Name0) ->
     Name = flatten(Name0),
-    extension(Name, [], major_os_type()).
+    extension([$/ | Name], [], major_os_type()).
 
 extension([$.|Rest]=Result, _Result, OsType) ->
     extension(Rest, Result, OsType);
+extension([$/,$.|Rest], _Result, OsType) ->
+    extension(Rest, [], OsType);
+extension([$\\,$.|Rest], _Result, win32) ->
+    extension(Rest, [], win32);
 extension([Char|Rest], [], OsType) when is_integer(Char) ->
     extension(Rest, [], OsType);
 extension([$/|Rest], _Result, OsType) ->
@@ -634,8 +643,8 @@ rootname([$/|Rest], Root, Ext, OsType) ->
     rootname(Rest, [$/]++Ext++Root, [], OsType);
 rootname([$\\|Rest], Root, Ext, win32) ->
     rootname(Rest, [$/]++Ext++Root, [], win32);
-rootname([$.|Rest], Root, [], OsType) ->
-    rootname(Rest, Root, ".", OsType);
+rootname([$.|Rest], [$/|_]=Root, [], OsType) ->
+    rootname(Rest, [$.|Root], [], OsType);
 rootname([$.|Rest], Root, Ext, OsType) ->
     rootname(Rest, Ext++Root, ".", OsType);
 rootname([Char|Rest], Root, [], OsType) when is_integer(Char) ->
@@ -664,14 +673,18 @@ rootname(Name, Ext) when is_binary(Ext) ->
 rootname(Name0, Ext0) ->
     Name = flatten(Name0),
     Ext = flatten(Ext0),
-    rootname2(Name, Ext, []).
+    rootname2(Name, Ext, [], major_os_type()).
 
-rootname2(Ext, Ext, Result) ->
+rootname2(Ext, Ext, [$/|_]=Result, _OsType) ->
+    lists:reverse(Result, Ext);
+rootname2(Ext, Ext, [$\\|_]=Result, win32) ->
+    lists:reverse(Result, Ext);
+rootname2(Ext, Ext, Result, _OsType) ->
     lists:reverse(Result);
-rootname2([], _Ext, Result) ->
+rootname2([], _Ext, Result, _OsType) ->
     lists:reverse(Result);
-rootname2([Char|Rest], Ext, Result) when is_integer(Char) ->
-    rootname2(Rest, Ext, [Char|Result]).
+rootname2([Char|Rest], Ext, Result, OsType) when is_integer(Char) ->
+    rootname2(Rest, Ext, [Char|Result], OsType).
 
 %% Returns a list whose elements are the path components in the filename.
 %%
diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl
index 846394d366..bc5eb7e14c 100644
--- a/lib/stdlib/test/filename_SUITE.erl
+++ b/lib/stdlib/test/filename_SUITE.erl
@@ -313,11 +313,18 @@ extension(Config) when is_list(Config) ->
     ".erl" = filename:extension("A:/usr.bar/foo.nisse.erl"),
     "" = filename:extension("A:/usr.bar/foo"),
     "" = filename:extension("A:/usr/foo"),
+    "" = filename:extension(".gitignore"),
+    "" = filename:extension("A:/usr/.gitignore"),
+    ".ignore" = filename:extension("A:/usr/..ignore"),
+    ".ignore" = filename:extension("A:/usr/.git.ignore"),
     case os:type() of
         {win32, _} ->
             "" = filename:extension("A:\\usr\\foo"),
             ".erl" = filename:extension("A:/usr.bar/foo.nisse.erl"),
             "" = filename:extension("A:/usr.bar/foo"),
+            "" = filename:extension("A:\\usr\\.gitignore"),
+            ".ignore" = filename:extension("A:\\usr\\..ignore"),
+            ".ignore" = filename:extension("A:\\usr\\.git.ignore"),
             ok;
         _ -> ok
     end.
@@ -441,8 +448,14 @@ pathtype(Config) when is_list(Config) ->
 rootname(Config) when is_list(Config) ->
     "/jam.src/kalle" = filename:rootname("/jam.src/kalle"),
     "/jam.src/foo" = filename:rootname("/jam.src/foo.erl"),
+    "/jam.src/.gitignore" = filename:rootname("/jam.src/.gitignore"),
+    "/jam.src/.git" = filename:rootname("/jam.src/.git.ignore"),
+    "/jam.src/." = filename:rootname("/jam.src/..gitignore"),
     "/jam.src/foo" = filename:rootname(["/ja",'m.sr',"c/foo.erl"]),
     "/jam.src/foo" = filename:rootname("/jam.src/foo.erl", ".erl"),
+    "/jam.src/.gitignore" = filename:rootname("/jam.src/.gitignore", ".gitignore"),
+    "/jam.src/.git" = filename:rootname("/jam.src/.git.ignore", ".ignore"),
+    "/jam.src/." = filename:rootname("/jam.src/..gitignore", ".gitignore"),
     "/jam.src/foo.jam" = filename:rootname("/jam.src/foo.jam", ".erl"),
     "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j',"am"],".erl"),
     "/jam.src/foo.jam" = filename:rootname(["/jam.sr",'c/foo.j'|am],".erl"),
@@ -693,11 +706,18 @@ extension_bin(Config) when is_list(Config) ->
     <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>),
     <<"">> = filename:extension(<<"A:/usr.bar/foo">>),
     <<"">> = filename:extension(<<"A:/usr/foo">>),
+    <<"">> = filename:extension(<<".gitignore">>),
+    <<"">> = filename:extension(<<"A:/usr/.gitignore">>),
+    <<".ignore">> = filename:extension(<<"A:/usr/..ignore">>),
+    <<".ignore">> = filename:extension(<<"A:/usr/.git.ignore">>),
     case os:type() of
         {win32, _} ->
             <<"">> = filename:extension(<<"A:\\usr\\foo">>),
             <<".erl">> = filename:extension(<<"A:/usr.bar/foo.nisse.erl">>),
             <<"">> = filename:extension(<<"A:/usr.bar/foo">>),
+            <<"">> = filename:extension(<<"A:/usr/.gitignore">>),
+            <<".ignore">> = filename:extension(<<"A:/usr/..ignore">>),
+            <<".ignore">> = filename:extension(<<"A:/usr/.git.ignore">>),
             ok;
         _ -> ok
     end.
-- 
2.26.2

openSUSE Build Service is sponsored by