parent = os.path.dirname(dst_abs)
os.makedirs(parent, exist_ok=True)
+ # helper: check parent-dir writability
+ def _is_writable_dir(p):
+ return os.access(p, os.W_OK)
+
+ # determine if we must flip u+w on parent
+ flip_needed = not _is_writable_dir(parent)
+ restore_mode = None
+ parent_show = _display_dst(parent)
+
if dry:
+ if flip_needed:
+ print(f"(dry) chmod u+w '{parent_show}'")
if os.path.exists(dst_abs):
print(f"(dry) unlink '{dst_show}'")
print(f"(dry) install -m {oct(mode)[2:]} -D '{src_show}' '{dst_show}'")
+ if flip_needed:
+ print(f"(dry) chmod u-w '{parent_show}'")
return
- # Replace even if dst exists and is read-only: write temp then atomic replace.
- fd, tmp_path = tempfile.mkstemp(prefix=".tmp.", dir=parent)
+ # real path: flip write bit if needed
try:
- with os.fdopen(fd, "wb") as tmpf, open(src_abs, "rb") as sf:
- shutil.copyfileobj(sf, tmpf)
- tmpf.flush()
- os.chmod(tmp_path, mode)
- os.replace(tmp_path, dst_abs)
- finally:
+ if flip_needed:
+ try:
+ st_parent = os.stat(parent)
+ restore_mode = stat.S_IMODE(st_parent.st_mode)
+ os.chmod(parent, restore_mode | stat.S_IWUSR)
+ except PermissionError:
+ exit_with_status(f"cannot write: parent dir not writable and chmod failed on {parent_show}")
+
+ # Replace even if dst exists and is read-only: temp then atomic replace.
+ fd, tmp_path = tempfile.mkstemp(prefix='.tmp.', dir=parent)
try:
- if os.path.exists(tmp_path):
- os.unlink(tmp_path)
- except Exception:
- pass
+ with os.fdopen(fd, "wb") as tmpf, open(src_abs, "rb") as sf:
+ shutil.copyfileobj(sf, tmpf)
+ tmpf.flush()
+ os.chmod(tmp_path, mode)
+ os.replace(tmp_path, dst_abs)
+ finally:
+ try:
+ if os.path.exists(tmp_path):
+ os.unlink(tmp_path)
+ except Exception:
+ pass
+ finally:
+ # restore parent dir mode if we flipped it
+ if restore_mode is not None:
+ try:
+ os.chmod(parent, restore_mode)
+ except Exception:
+ pass
print(f"+ install -m {oct(mode)[2:]} '{src_show}' '{dst_show}'")
#!/usr/bin/env bash
+# env_toolsmith — enter the project toolsmith environment
+# (must be sourced)
+
script_afp=$(realpath "${BASH_SOURCE[0]}")
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
echo "$script_afp:: This script must be sourced, not executed."
exit 1
fi
-export ROLE=toolsmith
-source tool_shared/bespoke/env
-export ENV=$ROLE
+# enter project environment
+#
+ source tool_shared/bespoke/env
+
+# setup tools
+# initially these will not exist, as the toolsmith installs them
+#
+ export PYTHON_HOME="$REPO_HOME/tool_shared/third_party/python"
+ if [[ ":$PATH:" != *":$PYTHON_HOME/bin:"* ]]; then
+ export PATH="$PYTHON_HOME/bin:$PATH"
+ fi
+
+ RT_gcc="$REPO_HOME/tool_shared/third_party/RT_gcc/release"
+ if [[ ":$PATH:" != *":$RT_gcc:"* ]]; then
+ export PATH="$RT_gcc:$PATH"
+ fi
+
+# enter the role environment
+#
+ export ROLE=toolsmith
+
+ TOOL_DIR="$REPO_HOME/tool"
+ if [[ ":$PATH:" != *":$TOOL_DIR:"* ]]; then
+ export PATH="$TOOL_DIR:$PATH"
+ fi
+
+ export ENV="tool/env"
+ cd "$REPO_HOME"
+ if [[ -f "tool/env" ]]; then
+ source "tool/env"
+ echo "in environment: $ENV"
+ else
+ echo "not found: $ENV"
+ fi