@@ -865,64 +865,57 @@ def _meson_version(self) -> str:
865865
866866 def sdist (self , directory : Path ) -> pathlib .Path :
867867 """Generates a sdist (source distribution) in the specified directory."""
868- # generate meson dist file
868+ # Generate meson dist file.
869869 self ._run (self ._meson + ['dist' , '--allow-dirty' , '--no-tests' , '--formats' , 'gztar' , * self ._meson_args ['dist' ]])
870870
871- # move meson dist file to output path
872871 dist_name = f'{ self ._metadata .distribution_name } -{ self ._metadata .version } '
873872 meson_dist_name = f'{ self ._meson_name } -{ self ._meson_version } '
874873 meson_dist_path = pathlib .Path (self ._build_dir , 'meson-dist' , f'{ meson_dist_name } .tar.gz' )
875- sdist = pathlib .Path (directory , f'{ dist_name } .tar.gz' )
874+ sdist_path = pathlib .Path (directory , f'{ dist_name } .tar.gz' )
876875
877- with tarfile .open (meson_dist_path , 'r:gz' ) as meson_dist , mesonpy ._util .create_targz (sdist ) as tar :
876+ with tarfile .open (meson_dist_path , 'r:gz' ) as meson_dist , mesonpy ._util .create_targz (sdist_path ) as sdist :
878877 for member in meson_dist .getmembers ():
879- # calculate the file path in the source directory
880- assert member .name , member .name
881- member_parts = member .name .split ('/' )
882- if len (member_parts ) <= 1 :
883- continue
884- path = self ._source_dir .joinpath (* member_parts [1 :])
885-
886- if not path .exists () and member .isfile ():
887- # File doesn't exists on the source directory but exists on
888- # the Meson dist, so it is generated file, which we need to
889- # include.
890- # See https://mesonbuild.com/Reference-manual_builtin_meson.html#mesonadd_dist_script
891-
892- # MESON_DIST_ROOT could have a different base name
893- # than the actual sdist basename, so we need to rename here
878+ if member .isfile ():
894879 file = meson_dist .extractfile (member .name )
895- member .name = str (pathlib .Path (dist_name , * member_parts [1 :]).as_posix ())
896- tar .addfile (member , file )
897- continue
898-
899- if not path .is_file ():
900- continue
901880
902- info = tarfile .TarInfo (member .name )
903- file_stat = os .stat (path )
904- info .mtime = member .mtime
905- info .size = file_stat .st_size
906- info .mode = int (oct (file_stat .st_mode )[- 3 :], 8 )
907-
908- # rewrite the path if necessary, to match the sdist distribution name
909- if dist_name != meson_dist_name :
910- info .name = pathlib .Path (
911- dist_name ,
912- path .relative_to (self ._source_dir )
913- ).as_posix ()
914-
915- with path .open ('rb' ) as f :
916- tar .addfile (info , fileobj = f )
917-
918- # add PKG-INFO to dist file to make it a sdist
919- pkginfo_info = tarfile .TarInfo (f'{ dist_name } /PKG-INFO' )
920- pkginfo_info .mtime = time .time () # type: ignore[assignment]
881+ # Reset pax extended header. The tar archive member may be
882+ # using pax headers to store some file metadata. The pax
883+ # headers are not reset when the metadata is modified and
884+ # they take precedence when the member is deserialized.
885+ # This is relevant because when rewriting the member name,
886+ # the length of the path may shrink from being more than
887+ # 100 characters (requiring the path to be stored in the
888+ # pax headers) to being less than 100 characters. When this
889+ # happens, the tar archive member is serialized with the
890+ # shorter name in the regular header and the longer one in
891+ # the extended pax header. The archives handled here are
892+ # not expected to use extended pax headers other than for
893+ # the ones required to encode file metadata. The easiest
894+ # solution is to reset the pax extended headers.
895+ member .pax_headers = {}
896+
897+ # Rewrite the path to match the sdist distribution name.
898+ stem = member .name .split ('/' , 1 )[1 ]
899+ member .name = '/' .join ((dist_name , stem ))
900+
901+ # Reset owner and group to root:root. This mimics what
902+ # 'git archive' does and makes the sdist reproducible upon
903+ # being built by different users.
904+ member .uname = member .gname = 'root'
905+ member .uid = member .gid = 0
906+
907+ sdist .addfile (member , file )
908+
909+ # Add 'PKG-INFO'.
910+ member = tarfile .TarInfo (f'{ dist_name } /PKG-INFO' )
911+ member .uid = member .gid = 0
912+ member .uname = member .gname = 'root'
913+ member .mtime = time .time ()
921914 metadata = bytes (self ._metadata .as_rfc822 ())
922- pkginfo_info .size = len (metadata )
923- tar .addfile (pkginfo_info , fileobj = io .BytesIO (metadata ))
915+ member .size = len (metadata )
916+ sdist .addfile (member , io .BytesIO (metadata ))
924917
925- return sdist
918+ return sdist_path
926919
927920 def wheel (self , directory : Path ) -> pathlib .Path :
928921 """Generates a wheel in the specified directory."""
0 commit comments