@@ -670,8 +670,8 @@ def build(self) -> None:
670
670
"SPHINXERRORHANDLING=" ,
671
671
maketarget ,
672
672
])
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 )
675
675
if self .includes_html :
676
676
setup_switchers (
677
677
self .switchers_content , self .checkout / "Doc" / "build" / "html"
@@ -722,10 +722,7 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
722
722
else :
723
723
language_dir = self .www_root / self .language .tag
724
724
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 )
729
726
language_dir .chmod (0o775 )
730
727
target = language_dir / self .version .name
731
728
@@ -734,22 +731,18 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
734
731
target .chmod (0o775 )
735
732
except PermissionError as err :
736
733
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 )
741
735
742
736
changed = []
743
737
if self .includes_html :
744
738
# Copy built HTML files to webroot (default /srv/docs.python.org)
745
739
changed = changed_files (self .checkout / "Doc" / "build" / "html" , target )
746
740
logging .info ("Copying HTML files to %s" , target )
747
- run ([
748
- "chown" ,
749
- "-R" ,
750
- ":" + self .group ,
741
+ chgrp (
751
742
self .checkout / "Doc" / "build" / "html/" ,
752
- ])
743
+ group = self .group ,
744
+ recursive = True ,
745
+ )
753
746
run (["chmod" , "-R" , "o+r" , self .checkout / "Doc" / "build" / "html" ])
754
747
run ([
755
748
"find" ,
@@ -775,20 +768,17 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
775
768
if not self .quick and (self .checkout / "Doc" / "dist" ).is_dir ():
776
769
# Copy archive files to /archives/
777
770
logging .debug ("Copying dist files." )
778
- run ([
779
- "chown" ,
780
- "-R" ,
781
- ":" + self .group ,
782
- self .checkout / "Doc" / "dist" ,
783
- ])
771
+ chgrp (
772
+ self .checkout / "Doc" / "dist" , group = self .group , recursive = True
773
+ )
784
774
run ([
785
775
"chmod" ,
786
776
"-R" ,
787
777
"o+r" ,
788
778
self .checkout / "Doc" / "dist" ,
789
779
])
790
780
run (["mkdir" , "-m" , "o+rx" , "-p" , target / "archives" ])
791
- run ([ "chown" , ":" + self . group , target / "archives" ] )
781
+ chgrp ( target / "archives" , group = self . group )
792
782
run ([
793
783
"cp" ,
794
784
"-a" ,
@@ -888,6 +878,29 @@ def save_state(
888
878
logging .info ("Saved new rebuild state for %s: %s" , key , table .as_string ())
889
879
890
880
881
+ def chgrp (path : Path , / , group : int | str | None , * , recursive : bool = False ) -> None :
882
+ if sys .platform == "win32" :
883
+ return
884
+
885
+ from grp import getgrnam
886
+
887
+ try :
888
+ try :
889
+ group_id = int (group )
890
+ except ValueError :
891
+ group_id = getgrnam (group )[2 ]
892
+ except (LookupError , TypeError , ValueError ):
893
+ return
894
+
895
+ try :
896
+ os .chown (path , - 1 , group_id )
897
+ if recursive :
898
+ for p in path .rglob ("*" ):
899
+ os .chown (p , - 1 , group_id )
900
+ except OSError as err :
901
+ logging .warning ("Can't change group of %s: %s" , path , str (err ))
902
+
903
+
891
904
def format_seconds (seconds : float ) -> str :
892
905
hours , remainder = divmod (seconds , 3600 )
893
906
minutes , seconds = divmod (remainder , 60 )
@@ -1212,7 +1225,7 @@ def build_sitemap(
1212
1225
sitemap_path = www_root / "sitemap.xml"
1213
1226
sitemap_path .write_text (rendered_template + "\n " , encoding = "UTF-8" )
1214
1227
sitemap_path .chmod (0o664 )
1215
- run ([ " chgrp" , group , sitemap_path ] )
1228
+ chgrp ( sitemap_path , group = group )
1216
1229
1217
1230
1218
1231
def build_404 (www_root : Path , group : str ) -> None :
@@ -1224,7 +1237,7 @@ def build_404(www_root: Path, group: str) -> None:
1224
1237
not_found_file = www_root / "404.html"
1225
1238
shutil .copyfile (HERE / "templates" / "404.html" , not_found_file )
1226
1239
not_found_file .chmod (0o664 )
1227
- run ([ " chgrp" , group , not_found_file ] )
1240
+ chgrp ( not_found_file , group = group )
1228
1241
1229
1242
1230
1243
def copy_robots_txt (
@@ -1242,7 +1255,7 @@ def copy_robots_txt(
1242
1255
robots_path = www_root / "robots.txt"
1243
1256
shutil .copyfile (template_path , robots_path )
1244
1257
robots_path .chmod (0o775 )
1245
- run ([ " chgrp" , group , robots_path ] )
1258
+ chgrp ( robots_path , group = group )
1246
1259
if not skip_cache_invalidation :
1247
1260
purge (http , "robots.txt" )
1248
1261
@@ -1310,7 +1323,7 @@ def symlink(
1310
1323
# Link does not exist or points to the wrong target.
1311
1324
link .unlink (missing_ok = True )
1312
1325
link .symlink_to (directory )
1313
- run ([ "chown" , "-h" , f": { group } " , str ( link )])
1326
+ chgrp ( link , group = group ) # --no-dereference
1314
1327
if not skip_cache_invalidation :
1315
1328
surrogate_key = f"{ language_tag } /{ name } "
1316
1329
purge_surrogate_key (http , surrogate_key )
0 commit comments