diff pipcl.py @ 18:dd663470c57c

Make building an sdist work on FreeBSD and with Mercurial as SCM. Because of the inclusion of MuPDF symbolic links in tar-files must be handled also.
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 18 Sep 2025 22:02:17 +0200
parents 59f1bd90b2a0
children dcabf2733f0f
line wrap: on
line diff
--- a/pipcl.py	Thu Sep 18 17:40:40 2025 +0200
+++ b/pipcl.py	Thu Sep 18 22:02:17 2025 +0200
@@ -687,7 +687,7 @@
             # Add the files returned by fn_build().
             #
             for item in items:
-                from_, (to_abs, to_rel) = self._fromto(item)
+                from_, (to_abs, to_rel, _) = self._fromto(item)
                 add(from_, to_rel)
 
             # Add <name>-<version>.dist-info/WHEEL.
@@ -785,10 +785,24 @@
                 textb = text.encode('utf8')
                 return add(textb, name)
 
+            def add_symlink(from_, name, linkname=None):
+                check_name(name)
+                assert isinstance(from_, str)
+                assert isinstance(name, str)
+                assert name
+                assert os.path.islink(from_)
+                if linkname is None:
+                    linkname = os.readlink(from_)
+                log2(f'Adding symlink: {os.path.relpath(from_)} => {name} --> {linkname}')
+                ti = tar.gettarinfo(from_, name)
+                tar.addfile(ti)
+
             found_pyproject_toml = False
             for item in items:
-                from_, (to_abs, to_rel) = self._fromto(item)
-                if isinstance(from_, bytes):
+                from_, (to_abs, to_rel, to_symlink) = self._fromto(item, resolve_symlinks=False)
+                if to_symlink:
+                    add_symlink(from_, to_rel, to_symlink)
+                elif isinstance(from_, bytes):
                     add(from_, to_rel)
                 else:
                     if from_.startswith(f'{os.path.abspath(sdist_directory)}/'):
@@ -1020,7 +1034,7 @@
             record.add_content(content, to_rel)
 
         for item in items:
-            from_, (to_abs, to_rel) = self._fromto(item)
+            from_, (to_abs, to_rel, _) = self._fromto(item)
             log0(f'{from_=} {to_abs=} {to_rel=}')
             to_abs2 = f'{root2}/{to_rel}'
             add_file( from_, to_abs2, to_rel)
@@ -1415,7 +1429,7 @@
             ret += '\n'
         return ret
 
-    def _path_relative_to_root(self, path, assert_within_root=True):
+    def _path_relative_to_root(self, path, assert_within_root=True, resolve_symlinks=True):
         '''
         Returns `(path_abs, path_rel)`, where `path_abs` is absolute path and
         `path_rel` is relative to `self.root`.
@@ -1431,14 +1445,21 @@
             p = path
         else:
             p = os.path.join(self.root, path)
+        path_abs = p
+        # always resolve symlinks at first
         p = os.path.realpath(os.path.abspath(p))
         if assert_within_root:
             assert p.startswith(self.root+os.sep) or p == self.root, \
                     f'Path not within root={self.root+os.sep!r}: {path=} {p=}'
         p_rel = os.path.relpath(p, self.root)
-        return p, p_rel
-
-    def _fromto(self, p):
+        if resolve_symlinks or not os.path.islink(path_abs):
+            return p, p_rel, None
+        else:
+            assert os.path.islink(path_abs)
+            p_rel = os.path.relpath(path_abs, self.root)
+            return path_abs, p_rel, os.readlink(path_abs)
+
+    def _fromto(self, p, resolve_symlinks=True):
         '''
         Returns `(from_, (to_abs, to_rel))`.
 
@@ -1476,8 +1497,8 @@
         if to_.startswith( prefix):
             to_ = f'{self.name}-{self.version}.data/{to_[ len(prefix):]}'
         if isinstance(from_, str):
-            from_, _ = self._path_relative_to_root( from_, assert_within_root=False)
-        to_ = self._path_relative_to_root(to_)
+            from_, _, _ = self._path_relative_to_root( from_, assert_within_root=False, resolve_symlinks=resolve_symlinks)
+        to_ = self._path_relative_to_root(to_, resolve_symlinks=resolve_symlinks)
         assert isinstance(from_, (str, bytes))
         log2(f'returning {from_=} {to_=}')
         return from_, to_
@@ -2006,9 +2027,14 @@
 
     This function can be useful for the `fn_sdist()` callback.
     '''
-    command = 'cd ' + directory + ' && git ls-files'
-    if submodules:
-        command += ' --recurse-submodules'
+    if os.path.isdir(os.path.join(directory, ".hg")):
+        command = 'cd ' + directory + ' && hg files'
+        if submodules:
+            command += ' --subrepos'
+    else:
+        command = 'cd ' + directory + ' && git ls-files'
+        if submodules:
+            command += ' --recurse-submodules'
     log1(f'Running {command=}')
     text = subprocess.check_output( command, shell=True)
     ret = []