@@ -671,8 +671,8 @@ def build(self) -> None:
671671 "SPHINXERRORHANDLING=" ,
672672 maketarget ,
673673 ])
674- run ([ "mkdir" , "-p" , self .log_directory ] )
675- run ([ " chgrp" , "-R" , self .group , self . log_directory ] )
674+ self .log_directory . mkdir ( parents = True , exist_ok = True )
675+ chgrp ( self . log_directory , group = self .group , recursive = True )
676676 if self .includes_html :
677677 setup_switchers (
678678 self .switchers_content , self .checkout / "Doc" / "build" / "html"
@@ -723,10 +723,7 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
723723 else :
724724 language_dir = self .www_root / self .language .tag
725725 language_dir .mkdir (parents = True , exist_ok = True )
726- try :
727- run (["chgrp" , "-R" , self .group , language_dir ])
728- except subprocess .CalledProcessError as err :
729- logging .warning ("Can't change group of %s: %s" , language_dir , str (err ))
726+ chgrp (language_dir , group = self .group , recursive = True )
730727 language_dir .chmod (0o775 )
731728 target = language_dir / self .version .name
732729
@@ -735,22 +732,18 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
735732 target .chmod (0o775 )
736733 except PermissionError as err :
737734 logging .warning ("Can't change mod of %s: %s" , target , str (err ))
738- try :
739- run (["chgrp" , "-R" , self .group , target ])
740- except subprocess .CalledProcessError as err :
741- logging .warning ("Can't change group of %s: %s" , target , str (err ))
735+ chgrp (target , group = self .group , recursive = True )
742736
743737 changed = []
744738 if self .includes_html :
745739 # Copy built HTML files to webroot (default /srv/docs.python.org)
746740 changed = changed_files (self .checkout / "Doc" / "build" / "html" , target )
747741 logging .info ("Copying HTML files to %s" , target )
748- run ([
749- "chown" ,
750- "-R" ,
751- ":" + self .group ,
742+ chgrp (
752743 self .checkout / "Doc" / "build" / "html/" ,
753- ])
744+ group = self .group ,
745+ recursive = True ,
746+ )
754747 run (["chmod" , "-R" , "o+r" , self .checkout / "Doc" / "build" / "html" ])
755748 run ([
756749 "find" ,
@@ -776,20 +769,15 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
776769 if not self .quick and (self .checkout / "Doc" / "dist" ).is_dir ():
777770 # Copy archive files to /archives/
778771 logging .debug ("Copying dist files." )
779- run ([
780- "chown" ,
781- "-R" ,
782- ":" + self .group ,
783- self .checkout / "Doc" / "dist" ,
784- ])
772+ chgrp (self .checkout / "Doc" / "dist" , group = self .group , recursive = True )
785773 run ([
786774 "chmod" ,
787775 "-R" ,
788776 "o+r" ,
789777 self .checkout / "Doc" / "dist" ,
790778 ])
791779 run (["mkdir" , "-m" , "o+rx" , "-p" , target / "archives" ])
792- run ([ "chown" , ":" + self . group , target / "archives" ] )
780+ chgrp ( target / "archives" , group = self . group )
793781 run ([
794782 "cp" ,
795783 "-a" ,
@@ -889,6 +877,36 @@ def save_state(
889877 logging .info ("Saved new rebuild state for %s: %s" , key , table .as_string ())
890878
891879
880+ def chgrp (
881+ path : Path ,
882+ / ,
883+ group : int | str | None ,
884+ * ,
885+ recursive : bool = False ,
886+ follow_symlinks : bool = True ,
887+ ) -> None :
888+ if sys .platform == "win32" :
889+ return
890+
891+ from grp import getgrnam
892+
893+ try :
894+ try :
895+ group_id = int (group )
896+ except ValueError :
897+ group_id = getgrnam (group )[2 ]
898+ except (LookupError , TypeError , ValueError ):
899+ return
900+
901+ try :
902+ os .chown (path , - 1 , group_id , follow_symlinks = follow_symlinks )
903+ if recursive :
904+ for p in path .rglob ("*" ):
905+ os .chown (p , - 1 , group_id , follow_symlinks = follow_symlinks )
906+ except OSError as err :
907+ logging .warning ("Can't change group of %s: %s" , path , str (err ))
908+
909+
892910def format_seconds (seconds : float ) -> str :
893911 hours , remainder = divmod (seconds , 3600 )
894912 minutes , seconds = divmod (remainder , 60 )
@@ -1213,7 +1231,7 @@ def build_sitemap(
12131231 sitemap_path = www_root / "sitemap.xml"
12141232 sitemap_path .write_text (rendered_template + "\n " , encoding = "UTF-8" )
12151233 sitemap_path .chmod (0o664 )
1216- run ([ " chgrp" , group , sitemap_path ] )
1234+ chgrp ( sitemap_path , group = group )
12171235
12181236
12191237def build_404 (www_root : Path , group : str ) -> None :
@@ -1225,7 +1243,7 @@ def build_404(www_root: Path, group: str) -> None:
12251243 not_found_file = www_root / "404.html"
12261244 shutil .copyfile (HERE / "templates" / "404.html" , not_found_file )
12271245 not_found_file .chmod (0o664 )
1228- run ([ " chgrp" , group , not_found_file ] )
1246+ chgrp ( not_found_file , group = group )
12291247
12301248
12311249def copy_robots_txt (
@@ -1243,7 +1261,7 @@ def copy_robots_txt(
12431261 robots_path = www_root / "robots.txt"
12441262 shutil .copyfile (template_path , robots_path )
12451263 robots_path .chmod (0o775 )
1246- run ([ " chgrp" , group , robots_path ] )
1264+ chgrp ( robots_path , group = group )
12471265 if not skip_cache_invalidation :
12481266 purge (http , "robots.txt" )
12491267
@@ -1311,7 +1329,7 @@ def symlink(
13111329 # Link does not exist or points to the wrong target.
13121330 link .unlink (missing_ok = True )
13131331 link .symlink_to (directory )
1314- run ([ "chown" , "-h" , f": { group } " , str ( link )] )
1332+ chgrp ( link , group = group , follow_symlinks = False )
13151333 if not skip_cache_invalidation :
13161334 surrogate_key = f"{ language_tag } /{ name } "
13171335 purge_surrogate_key (http , surrogate_key )
0 commit comments