Skip to content

Commit

Permalink
Fix handling of symbolic links on Windows
Browse files Browse the repository at this point in the history
When cloning a Git repository on Windows Git puts the link file path as
the content of an ordinary file. When downloading tarball the symbolic
link files cannot be properly established and Tar writes empty files
instead. This leads to different packages checksums compared to the case
when the package is downloaded via Git or downloaded on Linux either
via Git or via tarball.

To fix the problem we parsed the content of the tarball and extract the
link paths from there. After that, we write a link file with the link
path in it overriding the empty file extracted by Tar.

Additionally, the `getPackageFileListWithoutVcs` procedure is fixed to
return relative paths to files with `/` character as directory separator
even on Windows, because they are used in the package checksum
calculation and we must have the same checksum for the same package
regardless of the operating system or download method.

Related to nim-lang#127
  • Loading branch information
bobeff authored and CyberTailor committed Dec 12, 2021
1 parent 928fe89 commit fbf6db0
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 2 deletions.
20 changes: 20 additions & 0 deletions src/nimblepkg/download.nim
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,26 @@ proc doDownloadTarball(url, downloadDir, version: string, queryRevision: bool):
raise nimbleError(tryDoCmdExErrorMessage(cmd, output, exitCode))
display("Completed", "unpacking " & filePath)

when defined(windows):
# On Windows symbolic link files are not being extracted properly by the
# `tar` command. They are extracted as empty files, but when cloning the
# repository with Git they are extracted as ordinary files with the link
# path in them. For that reason here we parse the tar file content to
# extract the symbolic links and add their paths manually to the content of
# their files.
let listCmd = &"{getTarExePath()} -ztvf {filePath} --force-local"
let (cmdOutput, cmdExitCode) = doCmdEx(listCmd)
if cmdExitCode != QuitSuccess:
raise nimbleError(tryDoCmdExErrorMessage(listCmd, cmdOutput, cmdExitCode))
let lines = cmdOutput.splitLines()
for line in lines:
if line.contains(" -> "):
let parts = line.split
let linkPath = parts[^1]
let linkNameParts = parts[^3].split('/')
let linkName = linkNameParts[1 .. ^1].foldl(a / b)
writeFile(downloadDir / linkName, linkPath)

filePath.removeFile
return if queryRevision: getRevision(url, version) else: notSetSha1Hash

Expand Down
7 changes: 5 additions & 2 deletions src/nimblepkg/vcstools.nim
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ proc getPackageFileListWithoutVcs(dir: Path): seq[string] =
## its subdirectories.
for file in walkDirRec($dir, yieldFilter = {pcFile, pcLinkToFile},
relative = true):
when defined(windows):
# On windows relative paths to files which are included in the calculation
# of the package checksum must be the same as on POSIX systems.
let file = file.replace('\\', '/')
result.add file

proc getPackageFileList*(dir: Path): seq[string] =
Expand Down Expand Up @@ -1061,7 +1065,6 @@ username = John Doe <[email protected]>
check not isValidSha1Hash($getVcsRevision(testNoVcsDir))

test "getPackageFileList":
check getPackageFileList(testNoVcsDir) ==
@[testFile, testSubDirFile.normalizedPath]
check getPackageFileList(testNoVcsDir) == @[testFile, testSubDirFile]

tearDownSuite(testNoVcsDir)

0 comments on commit fbf6db0

Please sign in to comment.