Commit d6c76320 authored by Simon Praetorius's avatar Simon Praetorius
Browse files

Extend the setup-env script by an install and remove command

parent 617b7cd9
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -69,6 +69,9 @@ Useful setup script options:
./setup-env.sh --help
./setup-env.sh --env-dir /path/to/env
./setup-env.sh --force
./setup-env.sh --install dune-functions
./setup-env.sh --install dune-functions --with-suggestions
./setup-env.sh --remove dune-functions
```

## 4. General source-based setup
+264 −33
Original line number Diff line number Diff line
@@ -4,12 +4,53 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_DIR="${SCRIPT_DIR}/_env"
FORCE=0
MODE="setup"
MODULE=""
WITH_SUGGESTIONS=0
declare -a INSTALLED_MODULES=()

declare -A MODULE_REPOS=(
  ["dune-common"]="https://gitlab.dune-project.org/core/dune-common.git"
  ["dune-geometry"]="https://gitlab.dune-project.org/core/dune-geometry.git"
  ["dune-grid"]="https://gitlab.dune-project.org/core/dune-grid.git"
  ["dune-istl"]="https://gitlab.dune-project.org/core/dune-istl.git"
  ["dune-localfunctions"]="https://gitlab.dune-project.org/core/dune-localfunctions.git"
  ["dune-typetree"]="https://gitlab.dune-project.org/staging/dune-typetree.git"
  ["dune-functions"]="https://gitlab.dune-project.org/staging/dune-functions.git"
  ["dune-assembler"]="https://gitlab.dune-project.org/staging/dune-assembler.git"
  ["dune-uggrid"]="https://gitlab.dune-project.org/staging/dune-uggrid.git"
  ["dune-alugrid"]="https://gitlab.dune-project.org/extensions/dune-alugrid.git"
  ["dune-foamgrid"]="https://gitlab.dune-project.org/extensions/dune-foamgrid.git"
  ["dune-polygongrid"]="https://gitlab.dune-project.org/extensions/dune-polygongrid.git"
  ["dune-spgrid"]="https://gitlab.dune-project.org/extensions/dune-spgrid.git"
  ["dune-subgrid"]="https://gitlab.dune-project.org/extensions/dune-subgrid.git"
  ["dune-grid-glue"]="https://gitlab.dune-project.org/extensions/dune-grid-glue.git"
  ["dune-iga"]="https://gitlab.dune-project.org/extensions/dune-iga.git"
  ["dune-p4estgrid"]="https://gitlab.dune-project.org/extensions/dune-p4estgrid.git"
  ["dune-periodic"]="https://gitlab.dune-project.org/extensions/dune-periodic.git"
  ["dune-vtk"]="https://gitlab.dune-project.org/extensions/dune-vtk.git"
  ["dune-curvedgrid"]="https://gitlab.dune-project.org/extensions/dune-curvedgrid.git"
  ["dune-curvedgeometry"]="https://gitlab.dune-project.org/extensions/dune-curvedgeometry.git"
  ["dune-gmsh4"]="https://gitlab.dune-project.org/extensions/dune-gmsh4.git"
  ["dune-mmesh"]="https://gitlab.dune-project.org/extensions/dune-mmesh.git"
  ["dune-fem"]="https://gitlab.dune-project.org/dune-fem/dune-fem.git"
  ["dune-fufem"]="https://gitlab.dune-project.org/fufem/dune-fufem.git"
  ["dune-matrix-vector"]="https://gitlab.dune-project.org/fufem/dune-matrix-vector.git"
)

usage() {
  cat <<'EOF'
Usage: ./setup-env.sh [--env-dir PATH] [--force]
Usage:
  ./setup-env.sh [--env-dir PATH] [--force]
  ./setup-env.sh [-i|--install] [--with-suggestions] [--env-dir PATH] <module>
  ./setup-env.sh [-r|--remove] [--env-dir PATH] <module>

Commands:
  (default)       Set up tutorial base environment (core modules + scripts)
  -i, --install   Install one module and its dependencies
  -r, --remove    Remove one installed module directory

Set up a local DUNE tutorial environment:
Setup command:
1. Create _env (or custom --env-dir)
2. Clone DUNE core modules (if missing)
3. Create debug/release opts files
@@ -18,6 +59,7 @@ Set up a local DUNE tutorial environment:
Options:
  --env-dir PATH         Target environment directory (default: ./_env)
  --force                Overwrite generated files (opts + activation scripts)
  --with-suggestions     Also install modules listed in Suggests:
  -h, --help             Show this help

References:
@@ -26,6 +68,126 @@ References:
EOF
}

normalize_module_name() {
  local name="$1"
  if [[ "${name}" != dune-* ]]; then
    name="dune-${name}"
  fi
  if [[ ! "${name}" =~ ^dune-[a-zA-Z0-9-]+$ ]]; then
    echo "Invalid module name: ${1}" >&2
    exit 1
  fi
  printf '%s\n' "${name}"
}

lookup_repo_url() {
  local module="$1"
  if [[ -n "${MODULE_REPOS[${module}]+x}" ]]; then
    printf '%s\n' "${MODULE_REPOS[${module}]}"
    return 0
  fi
  echo "No repository configured for ${module}" >&2
  echo "Add it to MODULE_REPOS in setup-env.sh." >&2
  exit 1
}

extract_dune_modules_from_field() {
  local dune_module_file="$1"
  local field="$2"
  awk -v field="${field}" '
    BEGIN { in_field = 0 }
    $0 ~ ("^" field ":[[:space:]]*") {
      in_field = 1
      sub("^" field ":[[:space:]]*", "", $0)
      print
      next
    }
    in_field && $0 ~ "^[[:space:]]+" {
      sub("^[[:space:]]+", "", $0)
      print
      next
    }
    in_field {
      in_field = 0
    }
  ' "${dune_module_file}" | grep -Eo 'dune-[a-zA-Z0-9-]+' || true
}

clone_module_if_needed() {
  local module="$1"
  local target="${ENV_DIR}/${module}"

  if [[ -d "${target}/.git" ]]; then
    echo "Skipping ${module} (already cloned)"
    return 0
  fi
  if [[ -e "${target}" ]]; then
    echo "Path exists but is not a git clone: ${target}" >&2
    exit 1
  fi

  local repo_url
  repo_url="$(lookup_repo_url "${module}")"
  echo "Cloning ${module} ..."
  git clone "${repo_url}" "${target}"
  INSTALLED_MODULES+=("${module}")
}

install_module_recursive() {
  local requested_module
  requested_module="$(normalize_module_name "$1")"
  local -a queue=("${requested_module}")
  local -A seen=()
  local idx=0

  while [[ ${idx} -lt ${#queue[@]} ]]; do
    local module="${queue[${idx}]}"
    idx=$((idx + 1))

    if [[ -n "${seen[${module}]+x}" ]]; then
      continue
    fi
    seen["${module}"]=1

    clone_module_if_needed "${module}"

    local dune_module_file="${ENV_DIR}/${module}/dune.module"
    if [[ ! -f "${dune_module_file}" ]]; then
      echo "Warning: ${module} has no dune.module, skipping dependency scan." >&2
      continue
    fi

    mapfile -t deps < <(extract_dune_modules_from_field "${dune_module_file}" "Depends")
    for dep in "${deps[@]}"; do
      queue+=("${dep}")
    done

    if [[ "${WITH_SUGGESTIONS}" -eq 1 ]]; then
      mapfile -t suggests < <(extract_dune_modules_from_field "${dune_module_file}" "Suggests")
      for suggestion in "${suggests[@]}"; do
        queue+=("${suggestion}")
      done
    fi
  done
}

remove_module() {
  local module
  module="$(normalize_module_name "$1")"
  local target="${ENV_DIR}/${module}"

  if [[ ! -e "${target}" ]]; then
    echo "Skipping ${module} (not present in ${ENV_DIR})"
    return 0
  fi
  if [[ "${target}" == "${ENV_DIR}" || "${target}" == "/" ]]; then
    echo "Refusing to remove unsafe target: ${target}" >&2
    exit 1
  fi
  rm -rf "${target}"
  echo "Removed ${module}"
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --env-dir)
@@ -35,39 +197,98 @@ while [[ $# -gt 0 ]]; do
    --force)
      FORCE=1
      ;;
    --with-suggestions)
      WITH_SUGGESTIONS=1
      ;;
    -i|--install)
      if [[ "${MODE}" != "setup" ]]; then
        echo "Only one command can be specified." >&2
        usage
        exit 1
      fi
      MODE="install"
      shift
      MODULE="${1:-}"
      if [[ -z "${MODULE}" ]]; then
        echo "Missing module for ${MODE} command" >&2
        usage
        exit 1
      fi
      ;;
    -r|--remove)
      if [[ "${MODE}" != "setup" ]]; then
        echo "Only one command can be specified." >&2
        usage
        exit 1
      fi
      MODE="remove"
      shift
      MODULE="${1:-}"
      if [[ -z "${MODULE}" ]]; then
        echo "Missing module for ${MODE} command" >&2
        usage
        exit 1
      fi
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      if [[ -n "${MODULE}" ]]; then
        echo "Unknown argument: $1" >&2
        usage
        exit 1
      fi
      MODULE="$1"
      ;;
  esac
  shift
done

if [[ "${MODE}" == "setup" && -n "${MODULE}" ]]; then
  echo "Unexpected positional argument for setup: ${MODULE}" >&2
  usage
  exit 1
fi

if [[ "${MODE}" != "install" && "${WITH_SUGGESTIONS}" -eq 1 ]]; then
  echo "--with-suggestions is only supported with --install" >&2
  usage
  exit 1
fi

mkdir -p "${ENV_DIR}"
ENV_DIR="$(cd "${ENV_DIR}" && pwd)"

core_modules=(common geometry grid istl localfunctions)
core_modules=(dune-common dune-geometry dune-grid dune-istl dune-localfunctions)

echo "Environment directory: ${ENV_DIR}"

if [[ "${MODE}" == "setup" ]]; then
  for mod in "${core_modules[@]}"; do
  target="${ENV_DIR}/dune-${mod}"
  if [[ -d "${target}/.git" ]]; then
    echo "Skipping dune-${mod} (already cloned)"
    continue
  fi
  if [[ -e "${target}" ]]; then
    echo "Path exists but is not a git clone: ${target}" >&2
    clone_module_if_needed "${mod}"
  done
elif [[ "${MODE}" == "install" ]]; then
  install_module_recursive "${MODULE}"
elif [[ "${MODE}" == "remove" ]]; then
  remove_module "${MODULE}"
  echo
  echo "Remove complete."
  exit 0
else
  echo "Unknown mode: ${MODE}" >&2
  exit 1
fi
  echo "Cloning dune-${mod} ..."
  git clone "https://gitlab.dune-project.org/core/dune-${mod}.git" "${target}"
done

print_install_summary() {
  echo
  if [[ "${#INSTALLED_MODULES[@]}" -gt 0 ]]; then
    echo "Installed modules (${#INSTALLED_MODULES[@]}): ${INSTALLED_MODULES[*]}"
  else
    echo "Installed modules (0): none (all requested modules already present)"
  fi
}

write_file() {
  local path="$1"
@@ -89,6 +310,7 @@ DEBUG_OPTS='CMAKE_FLAGS="\
  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
  -DCMAKE_CXX_STANDARD=20 \
  -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=1 \
  -DDUNE_GRID_GRIDTYPE_SELECTOR:BOOL=1 \
  -DCMAKE_CXX_FLAGS=\"-Wall -DDUNE_CHECK_BOUNDS=1 -DDUNE_ISTL_WITH_CHECKING=1 -DDUNE_FMatrix_WITH_CHECKING=1 -DCHECK_RESERVEDVECTOR\""
BUILDDIR="build/debug"
'
@@ -97,6 +319,7 @@ RELEASE_OPTS='CMAKE_FLAGS="\
  -G Ninja \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_CXX_STANDARD=20 \
  -DDUNE_GRID_GRIDTYPE_SELECTOR:BOOL=1 \
  -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=1"
BUILDDIR="build/release"
'
@@ -170,15 +393,23 @@ echo "Deactivated DUNE tutorial environment"
echo "  dunecontrol=$(command -v dunecontrol 2>/dev/null || echo '\''not in PATH'\'')"
'

if [[ "${MODE}" == "setup" ]]; then
  write_file "${ENV_DIR}/debug.opts" 0644 "${DEBUG_OPTS}"
  write_file "${ENV_DIR}/release.opts" 0644 "${RELEASE_OPTS}"
  write_file "${ENV_DIR}/activate.sh" 0755 "${ACTIVATE_SH}"
  write_file "${ENV_DIR}/deactivate.sh" 0755 "${DEACTIVATE_SH}"

echo
  print_install_summary
  echo "Setup complete."
  echo "Next steps:"
  echo "  source ${ENV_DIR}/activate.sh"
  echo "  dunecontrol all"
  echo "  # optional release mode:"
  echo "  export DUNE_OPTS_FILE=\"${ENV_DIR}/release.opts\""
elif [[ "${MODE}" == "install" ]]; then
  print_install_summary
  echo "Install complete."
  echo "After installing new modules:"
  echo "  source ${ENV_DIR}/activate.sh"
  echo "  dunecontrol all"
fi