@@ -670,8 +670,8 @@ def build(self) -> None:
670670 "SPHINXERRORHANDLING=" ,
671671 maketarget ,
672672 ])
673- run ([ "mkdir" , "-p" , self .log_directory ] )
674- run ([ " chgrp" , "-R" , self .group , self . log_directory ] )
673+ self .log_directory . mkdir ( parents = True , exist_ok = True )
674+ chgrp ( self . log_directory , group = self .group , recursive = True )
675675 if self .includes_html :
676676 setup_switchers (
677677 self .switchers_content , self .checkout / "Doc" / "build" / "html"
@@ -722,10 +722,7 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
722722 else :
723723 language_dir = self .www_root / self .language .tag
724724 language_dir .mkdir (parents = True , exist_ok = True )
725- try :
726- run (["chgrp" , "-R" , self .group , language_dir ])
727- except subprocess .CalledProcessError as err :
728- logging .warning ("Can't change group of %s: %s" , language_dir , str (err ))
725+ chgrp (language_dir , group = self .group , recursive = True )
729726 language_dir .chmod (0o775 )
730727 target = language_dir / self .version .name
731728
@@ -734,22 +731,18 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
734731 target .chmod (0o775 )
735732 except PermissionError as err :
736733 logging .warning ("Can't change mod of %s: %s" , target , str (err ))
737- try :
738- run (["chgrp" , "-R" , self .group , target ])
739- except subprocess .CalledProcessError as err :
740- logging .warning ("Can't change group of %s: %s" , target , str (err ))
734+ chgrp (target , group = self .group , recursive = True )
741735
742736 changed = []
743737 if self .includes_html :
744738 # Copy built HTML files to webroot (default /srv/docs.python.org)
745739 changed = changed_files (self .checkout / "Doc" / "build" / "html" , target )
746740 logging .info ("Copying HTML files to %s" , target )
747- run ([
748- "chown" ,
749- "-R" ,
750- ":" + self .group ,
741+ chgrp (
751742 self .checkout / "Doc" / "build" / "html/" ,
752- ])
743+ group = self .group ,
744+ recursive = True ,
745+ )
753746 run (["chmod" , "-R" , "o+r" , self .checkout / "Doc" / "build" / "html" ])
754747 run ([
755748 "find" ,
@@ -775,20 +768,15 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
775768 if not self .quick and (self .checkout / "Doc" / "dist" ).is_dir ():
776769 # Copy archive files to /archives/
777770 logging .debug ("Copying dist files." )
778- run ([
779- "chown" ,
780- "-R" ,
781- ":" + self .group ,
782- self .checkout / "Doc" / "dist" ,
783- ])
771+ chgrp (self .checkout / "Doc" / "dist" , group = self .group , recursive = True )
784772 run ([
785773 "chmod" ,
786774 "-R" ,
787775 "o+r" ,
788776 self .checkout / "Doc" / "dist" ,
789777 ])
790778 run (["mkdir" , "-m" , "o+rx" , "-p" , target / "archives" ])
791- run ([ "chown" , ":" + self . group , target / "archives" ] )
779+ chgrp ( target / "archives" , group = self . group )
792780 run ([
793781 "cp" ,
794782 "-a" ,
@@ -888,6 +876,36 @@ def save_state(
888876 logging .info ("Saved new rebuild state for %s: %s" , key , table .as_string ())
889877
890878
879+ def chgrp (
880+ path : Path ,
881+ / ,
882+ group : int | str | None ,
883+ * ,
884+ recursive : bool = False ,
885+ follow_symlinks : bool = True ,
886+ ) -> None :
887+ if sys .platform == "win32" :
888+ return
889+
890+ from grp import getgrnam
891+
892+ try :
893+ try :
894+ group_id = int (group )
895+ except ValueError :
896+ group_id = getgrnam (group )[2 ]
897+ except (LookupError , TypeError , ValueError ):
898+ return
899+
900+ try :
901+ os .chown (path , - 1 , group_id , follow_symlinks = follow_symlinks )
902+ if recursive :
903+ for p in path .rglob ("*" ):
904+ os .chown (p , - 1 , group_id , follow_symlinks = follow_symlinks )
905+ except OSError as err :
906+ logging .warning ("Can't change group of %s: %s" , path , str (err ))
907+
908+
891909def format_seconds (seconds : float ) -> str :
892910 hours , remainder = divmod (seconds , 3600 )
893911 minutes , seconds = divmod (remainder , 60 )
@@ -1212,7 +1230,7 @@ def build_sitemap(
12121230 sitemap_path = www_root / "sitemap.xml"
12131231 sitemap_path .write_text (rendered_template + "\n " , encoding = "UTF-8" )
12141232 sitemap_path .chmod (0o664 )
1215- run ([ " chgrp" , group , sitemap_path ] )
1233+ chgrp ( sitemap_path , group = group )
12161234
12171235
12181236def build_404 (www_root : Path , group : str ) -> None :
@@ -1224,7 +1242,7 @@ def build_404(www_root: Path, group: str) -> None:
12241242 not_found_file = www_root / "404.html"
12251243 shutil .copyfile (HERE / "templates" / "404.html" , not_found_file )
12261244 not_found_file .chmod (0o664 )
1227- run ([ " chgrp" , group , not_found_file ] )
1245+ chgrp ( not_found_file , group = group )
12281246
12291247
12301248def copy_robots_txt (
@@ -1242,7 +1260,7 @@ def copy_robots_txt(
12421260 robots_path = www_root / "robots.txt"
12431261 shutil .copyfile (template_path , robots_path )
12441262 robots_path .chmod (0o775 )
1245- run ([ " chgrp" , group , robots_path ] )
1263+ chgrp ( robots_path , group = group )
12461264 if not skip_cache_invalidation :
12471265 purge (http , "robots.txt" )
12481266
@@ -1310,7 +1328,7 @@ def symlink(
13101328 # Link does not exist or points to the wrong target.
13111329 link .unlink (missing_ok = True )
13121330 link .symlink_to (directory )
1313- run ([ "chown" , "-h" , f": { group } " , str ( link )] )
1331+ chgrp ( link , group = group , follow_symlinks = False )
13141332 if not skip_cache_invalidation :
13151333 surrogate_key = f"{ language_tag } /{ name } "
13161334 purge_surrogate_key (http , surrogate_key )
0 commit comments