This is an automated email from the ASF dual-hosted git repository.
sbp pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git
The following commit(s) were added to refs/heads/main by this push:
new 552e2d3 Add a function to change file permissions recursively
552e2d3 is described below
commit 552e2d322f863e4c81c398a729e876d2663ab5a8
Author: Sean B. Palmer <[email protected]>
AuthorDate: Tue Jan 20 16:41:40 2026 +0000
Add a function to change file permissions recursively
---
atr/util.py | 7 ++++
tests/unit/test_util.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 111 insertions(+)
diff --git a/atr/util.py b/atr/util.py
index aa40a5c..4b83f96 100644
--- a/atr/util.py
+++ b/atr/util.py
@@ -208,6 +208,13 @@ def chmod_directories(path: pathlib.Path, permissions: int
= 0o755) -> None:
os.chmod(dir_path, permissions)
+def chmod_files(path: pathlib.Path, permissions: int) -> None:
+ """Set permissions on all files in a directory tree."""
+ for file_path in path.rglob("*"):
+ if file_path.is_file():
+ os.chmod(file_path, permissions)
+
+
def committee_is_standing(committee_name: str) -> bool:
return committee_name in registry.STANDING_COMMITTEES
diff --git a/tests/unit/test_util.py b/tests/unit/test_util.py
new file mode 100644
index 0000000..0a8c814
--- /dev/null
+++ b/tests/unit/test_util.py
@@ -0,0 +1,104 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+import os
+import pathlib
+import stat
+import tempfile
+
+import atr.util as util
+
+
+def test_chmod_files_does_not_change_directory_permissions():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ subdir = tmp_path / "subdir"
+ subdir.mkdir()
+ os.chmod(subdir, 0o700)
+ test_file = subdir / "test.txt"
+ test_file.write_text("content")
+
+ util.chmod_files(tmp_path, 0o444)
+
+ dir_mode = stat.S_IMODE(subdir.stat().st_mode)
+ assert dir_mode == 0o700
+
+
+def test_chmod_files_handles_empty_directory():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ util.chmod_files(tmp_path, 0o444)
+
+
+def test_chmod_files_handles_multiple_files():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ files = [tmp_path / f"file{i}.txt" for i in range(5)]
+ for f in files:
+ f.write_text("content")
+ os.chmod(f, 0o644)
+
+ util.chmod_files(tmp_path, 0o400)
+
+ for f in files:
+ file_mode = stat.S_IMODE(f.stat().st_mode)
+ assert file_mode == 0o400
+
+
+def test_chmod_files_handles_nested_directories():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ nested_dir = tmp_path / "subdir" / "nested"
+ nested_dir.mkdir(parents=True)
+ file1 = tmp_path / "root.txt"
+ file2 = tmp_path / "subdir" / "mid.txt"
+ file3 = nested_dir / "deep.txt"
+ for f in [file1, file2, file3]:
+ f.write_text("content")
+ os.chmod(f, 0o644)
+
+ util.chmod_files(tmp_path, 0o444)
+
+ for f in [file1, file2, file3]:
+ file_mode = stat.S_IMODE(f.stat().st_mode)
+ assert file_mode == 0o444
+
+
+def test_chmod_files_sets_custom_permissions():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ test_file = tmp_path / "test.txt"
+ test_file.write_text("content")
+ os.chmod(test_file, 0o644)
+
+ util.chmod_files(tmp_path, 0o400)
+
+ file_mode = stat.S_IMODE(test_file.stat().st_mode)
+ assert file_mode == 0o400
+
+
+def test_chmod_files_sets_default_permissions():
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ tmp_path = pathlib.Path(tmp_dir)
+ test_file = tmp_path / "test.txt"
+ test_file.write_text("content")
+ os.chmod(test_file, 0o644)
+
+ util.chmod_files(tmp_path, 0o444)
+
+ file_mode = stat.S_IMODE(test_file.stat().st_mode)
+ assert file_mode == 0o444
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]