@@ -671,8 +671,8 @@ def build(self) -> None:
671
671
"SPHINXERRORHANDLING=" ,
672
672
maketarget ,
673
673
])
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 )
676
676
if self .includes_html :
677
677
setup_switchers (
678
678
self .switchers_content , self .checkout / "Doc" / "build" / "html"
@@ -723,10 +723,7 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
723
723
else :
724
724
language_dir = self .www_root / self .language .tag
725
725
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 )
730
727
language_dir .chmod (0o775 )
731
728
target = language_dir / self .version .name
732
729
@@ -735,22 +732,18 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
735
732
target .chmod (0o775 )
736
733
except PermissionError as err :
737
734
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 )
742
736
743
737
changed = []
744
738
if self .includes_html :
745
739
# Copy built HTML files to webroot (default /srv/docs.python.org)
746
740
changed = changed_files (self .checkout / "Doc" / "build" / "html" , target )
747
741
logging .info ("Copying HTML files to %s" , target )
748
- run ([
749
- "chown" ,
750
- "-R" ,
751
- ":" + self .group ,
742
+ chgrp (
752
743
self .checkout / "Doc" / "build" / "html/" ,
753
- ])
744
+ group = self .group ,
745
+ recursive = True ,
746
+ )
754
747
run (["chmod" , "-R" , "o+r" , self .checkout / "Doc" / "build" / "html" ])
755
748
run ([
756
749
"find" ,
@@ -776,20 +769,15 @@ def copy_build_to_webroot(self, http: urllib3.PoolManager) -> None:
776
769
if not self .quick and (self .checkout / "Doc" / "dist" ).is_dir ():
777
770
# Copy archive files to /archives/
778
771
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 )
785
773
run ([
786
774
"chmod" ,
787
775
"-R" ,
788
776
"o+r" ,
789
777
self .checkout / "Doc" / "dist" ,
790
778
])
791
779
run (["mkdir" , "-m" , "o+rx" , "-p" , target / "archives" ])
792
- run ([ "chown" , ":" + self . group , target / "archives" ] )
780
+ chgrp ( target / "archives" , group = self . group )
793
781
run ([
794
782
"cp" ,
795
783
"-a" ,
@@ -889,6 +877,36 @@ def save_state(
889
877
logging .info ("Saved new rebuild state for %s: %s" , key , table .as_string ())
890
878
891
879
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
+
892
910
def format_seconds (seconds : float ) -> str :
893
911
hours , remainder = divmod (seconds , 3600 )
894
912
minutes , seconds = divmod (remainder , 60 )
@@ -1213,7 +1231,7 @@ def build_sitemap(
1213
1231
sitemap_path = www_root / "sitemap.xml"
1214
1232
sitemap_path .write_text (rendered_template + "\n " , encoding = "UTF-8" )
1215
1233
sitemap_path .chmod (0o664 )
1216
- run ([ " chgrp" , group , sitemap_path ] )
1234
+ chgrp ( sitemap_path , group = group )
1217
1235
1218
1236
1219
1237
def build_404 (www_root : Path , group : str ) -> None :
@@ -1225,7 +1243,7 @@ def build_404(www_root: Path, group: str) -> None:
1225
1243
not_found_file = www_root / "404.html"
1226
1244
shutil .copyfile (HERE / "templates" / "404.html" , not_found_file )
1227
1245
not_found_file .chmod (0o664 )
1228
- run ([ " chgrp" , group , not_found_file ] )
1246
+ chgrp ( not_found_file , group = group )
1229
1247
1230
1248
1231
1249
def copy_robots_txt (
@@ -1243,7 +1261,7 @@ def copy_robots_txt(
1243
1261
robots_path = www_root / "robots.txt"
1244
1262
shutil .copyfile (template_path , robots_path )
1245
1263
robots_path .chmod (0o775 )
1246
- run ([ " chgrp" , group , robots_path ] )
1264
+ chgrp ( robots_path , group = group )
1247
1265
if not skip_cache_invalidation :
1248
1266
purge (http , "robots.txt" )
1249
1267
@@ -1311,7 +1329,7 @@ def symlink(
1311
1329
# Link does not exist or points to the wrong target.
1312
1330
link .unlink (missing_ok = True )
1313
1331
link .symlink_to (directory )
1314
- run ([ "chown" , "-h" , f": { group } " , str ( link )] )
1332
+ chgrp ( link , group = group , follow_symlinks = False )
1315
1333
if not skip_cache_invalidation :
1316
1334
surrogate_key = f"{ language_tag } /{ name } "
1317
1335
purge_surrogate_key (http , surrogate_key )
0 commit comments