@@ -85,8 +85,9 @@ public function synchronize(string $targetDir, string $packagePath, string $dire
8585 $ entryName = $ packagedEntry ->getFilename ();
8686 $ targetLink = Path::makeAbsolute ($ entryName , $ targetDir );
8787 $ sourcePath = $ packagedEntry ->getRealPath ();
88+ $ isDirectory = $ packagedEntry ->isDir ();
8889
89- $ this ->processLink ($ entryName , $ targetLink , $ sourcePath , $ result );
90+ $ this ->processLink ($ entryName , $ targetLink , $ sourcePath , $ isDirectory , $ result );
9091 }
9192
9293 return $ result ;
@@ -104,10 +105,11 @@ private function processLink(
104105 string $ entryName ,
105106 string $ targetLink ,
106107 string $ sourcePath ,
108+ bool $ isDirectory ,
107109 SynchronizeResult $ result ,
108110 ): void {
109111 if (! $ this ->filesystem ->exists ($ targetLink )) {
110- $ this ->createNewLink ($ entryName , $ targetLink , $ sourcePath , $ result );
112+ $ this ->createNewLink ($ entryName , $ targetLink , $ sourcePath , $ isDirectory , $ result );
111113
112114 return ;
113115 }
@@ -118,7 +120,7 @@ private function processLink(
118120 return ;
119121 }
120122
121- $ this ->processExistingSymlink ($ entryName , $ targetLink , $ sourcePath , $ result );
123+ $ this ->processExistingSymlink ($ entryName , $ targetLink , $ sourcePath , $ isDirectory , $ result );
122124 }
123125
124126 /**
@@ -133,9 +135,13 @@ private function createNewLink(
133135 string $ entryName ,
134136 string $ targetLink ,
135137 string $ sourcePath ,
138+ bool $ isDirectory ,
136139 SynchronizeResult $ result ,
137140 ): void {
138- $ relativeSourcePath = $ this ->filesystem ->makePathRelative ($ sourcePath , $ this ->filesystem ->dirname ($ targetLink ));
141+ $ relativeSourcePath = $ this ->normalizeRelativeSourcePath (
142+ $ this ->filesystem ->makePathRelative ($ sourcePath , $ this ->filesystem ->dirname ($ targetLink )),
143+ $ isDirectory ,
144+ );
139145
140146 $ this ->filesystem ->symlink ($ relativeSourcePath , $ targetLink );
141147 $ this ->logger ->info ('Created link: ' . $ entryName . ' -> ' . $ relativeSourcePath );
@@ -168,12 +174,13 @@ private function processExistingSymlink(
168174 string $ entryName ,
169175 string $ targetLink ,
170176 string $ sourcePath ,
177+ bool $ isDirectory ,
171178 SynchronizeResult $ result ,
172179 ): void {
173180 $ linkPath = $ this ->filesystem ->readlink ($ targetLink , true );
174181
175182 if (! $ linkPath || ! $ this ->filesystem ->exists ($ linkPath )) {
176- $ this ->repairBrokenLink ($ entryName , $ targetLink , $ sourcePath , $ result );
183+ $ this ->repairBrokenLink ($ entryName , $ targetLink , $ sourcePath , $ isDirectory , $ result );
177184
178185 return ;
179186 }
@@ -194,13 +201,34 @@ private function repairBrokenLink(
194201 string $ entryName ,
195202 string $ targetLink ,
196203 string $ sourcePath ,
204+ bool $ isDirectory ,
197205 SynchronizeResult $ result ,
198206 ): void {
199207 $ this ->filesystem ->remove ($ targetLink );
200208 $ this ->logger ->notice ('Existing link is broken: ' . $ entryName . ' (removing and recreating) ' );
201209 $ result ->addRemovedBrokenLink ($ entryName );
202210
203- $ this ->createNewLink ($ entryName , $ targetLink , $ sourcePath , $ result );
211+ $ this ->createNewLink ($ entryName , $ targetLink , $ sourcePath , $ isDirectory , $ result );
212+ }
213+
214+ /**
215+ * Normalizes a relative symlink target emitted by Symfony path helpers.
216+ *
217+ * Files MUST NOT keep the trailing slash that directory-oriented path helpers
218+ * may append, otherwise link creation treats them as non-existent directories.
219+ *
220+ * @param string $relativeSourcePath Relative path from the consumer target directory to the packaged source
221+ * @param bool $isDirectory Whether the packaged source is a directory
222+ *
223+ * @return string Normalized relative symlink target
224+ */
225+ private function normalizeRelativeSourcePath (string $ relativeSourcePath , bool $ isDirectory ): string
226+ {
227+ if ($ isDirectory ) {
228+ return $ relativeSourcePath ;
229+ }
230+
231+ return rtrim ($ relativeSourcePath , '/ ' );
204232 }
205233
206234 /**
0 commit comments