Skip to content
5 changes: 5 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SPDX-FileCopyrightText: 2025 STRATO GmbH
# SPDX-License-Identifier: AGPL-3.0-or-later

# List files: simple line-based configuration files
*.list text eol=lf linguist-language=Shell
108 changes: 108 additions & 0 deletions .list-format-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<!--
- SPDX-FileCopyrightText: 2025 STRATO GmbH
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

# List File Format Specification

## Overview

Files with the `.list` extension in this project contain simple, line-based lists of items. This format is used for configuration purposes, particularly for managing app inclusion/exclusion lists.

## Syntax Rules

### Basic Format
- **One item per line**: Each line contains a single item (app name, identifier, etc.)
- **Case sensitive**: Item names are processed as-is
- **No quotes needed**: Items are plain text without quotes or delimiters

### Comments
- **Shell-style comments**: Lines starting with `#` are treated as comments
- **Full-line comments only**: Inline comments (after an item) are NOT supported
- **Whitespace before `#`**: Leading whitespace before `#` is allowed

### Empty Lines
- **Ignored**: Blank lines and lines with only whitespace are ignored
- **Used for readability**: Can be used to group related items visually

### Example

```list
# Core apps that should be disabled
dashboard
weather_status

# Communication apps
mail
calendar

# Optional: These are disabled for performance reasons
# circles
# federation
```

## Files Using This Format

- **`disabled-apps.list`**: Nextcloud apps to disable during build
- **`enabled-core-apps.list`**: Nextcloud apps to check/re-enable if presently disabled
- **`always-enabled-apps.list`**: Nextcloud apps added to the `alwaysEnabled` array in `core/shipped.json`, so they cannot be disabled by administrators
- **`removed-apps.txt`**: Nextcloud apps to completely remove from package

## Processing

Scripts process these files using standard shell commands:
```bash
# Example: Read and filter
grep -v '^#' file.list | grep -v '^[[:space:]]*$'
```

This approach:
1. Removes comment lines (`^#`)
2. Removes empty lines (`^[[:space:]]*$`)
3. Preserves item names exactly as written

Comment on lines +53 to +63
## IDE Support

### EditorConfig
The `.editorconfig` file in this directory configures basic formatting for `.list` files:
- Character encoding: UTF-8
- Line endings: LF (Unix-style)
- Indentation: 2 spaces
- Final newline: Required

### Syntax Highlighting

For JetBrains IDEs (IntelliJ IDEA, WebStorm, PyCharm, etc.):
1. Go to **Settings** → **Editor** → **File Types**
2. Find or create **"Shell Script"** file type
3. Add `*.list` to the file name patterns
4. This enables shell-style comment highlighting

For VS Code:
1. Add to `.vscode/settings.json`:
```json
{
"files.associations": {
"*.list": "shellscript"
}
}
```

## Best Practices

1. **Add comments**: Explain why items are included, especially for non-obvious choices
2. **Group logically**: Use empty lines to separate related groups of items
3. **Keep sorted**: Consider alphabetically sorting items within groups for easier maintenance
4. **Document changes**: When adding/removing items, document the reason in comments or commit messages
5. **Avoid duplicates**: Each item should appear only once in the file

## Validation

To validate a `.list` file:
```bash
# Check for duplicates
sort file.list | uniq -d

# Preview processed output (what scripts will see)
grep -v '^#' file.list | grep -v '^[[:space:]]*$'
```
20 changes: 20 additions & 0 deletions always-enabled-apps.list
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# SPDX-FileCopyrightText: 2025 STRATO GmbH
# SPDX-License-Identifier: AGPL-3.0-or-later

################################################################################
# Always Enabled Apps List
################################################################################
#
# This file contains a list of Nextcloud apps that should be added to the
# 'alwaysEnabled' array in core/shipped.json, ensuring they cannot be
# disabled by administrators.
#
# Format:
# - One app name per line
# - Lines starting with # are comments
# - Empty lines are ignored
# - Whitespace is trimmed
Comment on lines +12 to +16
#
# This list is currently empty: no HiDrive Next apps have been decided as
# always-enabled yet. Add entries here deliberately, on a case-by-case basis.
################################################################################
122 changes: 103 additions & 19 deletions apps-disable.sh
Original file line number Diff line number Diff line change
@@ -1,22 +1,53 @@
#!/bin/sh
set -e

# SPDX-FileCopyrightText: 2025 STRATO GmbH
#
# SPDX-License-Identifier: AGPL-3.0-or-later

# This script assumes to be located in /IONOS as submodule within the Nextcloud server
# repository.

# Since this script modifies the shipped.json file, it should not be executed for every
# nextcloud pod in K8s. Also, since we do not use any pvc it would need to be applied for
# each nc-pod individually. Therefore this script should be executed during the image
# build.

BDIR="$( dirname ${0} )"
################################################################################
# HiDrive Next Apps Configuration Script
################################################################################
#
# DESCRIPTION:
# This script manages Nextcloud app configurations by:
# 1. Removing specified apps from the shipped.json file (disabling them)
# 2. Adding specified apps to the alwaysEnabled array (forcing them enabled)
#
# It modifies the 'defaultEnabled' and 'alwaysEnabled' arrays in core/shipped.json
# to control which apps are shipped with the installation and which cannot be
# disabled by administrators.
#
# LOCATION:
# This script is located in /IONOS as a submodule within the Nextcloud
# server repository.
#
# EXECUTION CONTEXT:
# This script modifies the shipped.json file, so it should not be executed
# for every Nextcloud pod in K8s. Since we do not use any PVCs, it would
# need to be applied for each pod individually. Therefore this script should
# be executed during the image build.
#
# USAGE:
# ./apps-disable.sh
#
# The script reads app names from:
# - disabled-apps.list: Apps to remove from shipped.json (one per line)
# - always-enabled-apps.list: Apps to add to alwaysEnabled array (one per line)
#
# PREREQUISITES:
# - jq (JSON processor) must be installed
# - disabled-apps.list must exist in the same directory
# - always-enabled-apps.list is optional but will be processed if present
# - ../core/shipped.json must exist and be valid JSON
#
################################################################################

# Configuration: Base directory and file paths
BDIR="$(dirname "${0}")"
SHIPPED_JSON="${BDIR}/../core/shipped.json"

. ${BDIR}/disabled-apps.inc.sh
DISABLED_APPS_FILE="${BDIR}/disabled-apps.list"
ALWAYS_ENABLED_APPS_FILE="${BDIR}/always-enabled-apps.list"

# Log fatal error message and exit with failure code
# Usage: log_fatal <message>
Expand All @@ -25,24 +56,77 @@ log_fatal() {
exit 1
}

# Read app list from file, ignoring comments and empty lines
# Usage: read_app_list <file_path>
read_app_list() {
_list_file="${1}"
if [ ! -f "${_list_file}" ]; then
echo ""
return
fi
grep -v '^[[:space:]]*#' "${_list_file}" | grep -v '^[[:space:]]*$' | tr '\n' ' '
}

# Remove an app from both defaultEnabled and alwaysEnabled arrays in shipped.json
# Usage: unship_app <app_name>
unship_app() {
app="${1}"
temp_file="${SHIPPED_JSON}.tmp"

if ! jq --arg app "${app}" \
'del(.defaultEnabled[] | select(. == $app)) | del(.alwaysEnabled[] | select(. == $app))' \
"${SHIPPED_JSON}" > "${temp_file}"; then
log_fatal "Failed to process ${app} with jq"
fi

mv "${temp_file}" "${SHIPPED_JSON}"
echo "Unshipped app '${app}'"
}

# Add an app to the alwaysEnabled array in shipped.json if not already present
# Usage: ship_app <app_name>
ship_app() {
app="${1}"
temp_file="${SHIPPED_JSON}.tmp"

if ! jq --arg app "${app}" \
'if (.alwaysEnabled | index($app)) then . else .alwaysEnabled += [$app] end' \
"${SHIPPED_JSON}" > "${temp_file}"; then
log_fatal "Failed to process ${app} with jq"
fi

mv "${temp_file}" "${SHIPPED_JSON}"
echo "Shipped app '${app}' as always enabled"
}

main() {
if ! which jq 2>&1 >/dev/null; then
log_fatal "jq is required"
fi
Comment on lines 102 to 105

# alwaysEnabled should be the only attribute in this json file which really matters,
# since it is the only attribute, which is checked for which app can be disabled or not.
if [ ! -f "${SHIPPED_JSON}" ]; then
log_fatal "Shipped JSON file not found: ${SHIPPED_JSON}"
fi

# NOTE: alwaysEnabled should be the only attribute in this json file which
# really matters, since it is the only attribute, which is checked for
# which app can be disabled or not.
# defaultEnabled is only used during installation, but not for updates.

echo "Remove apps from 'shipped' list ..."
DISABLED_APPS=$(read_app_list "${DISABLED_APPS_FILE}")
ALWAYS_ENABLED_APPS=$(read_app_list "${ALWAYS_ENABLED_APPS_FILE}")

echo "Remove apps from 'shipped' list ..."
for app in ${DISABLED_APPS}; do
echo "Unship app '${app}' ..."
cat ${SHIPPED_JSON} \
| jq --arg toUnforce "${app}" 'del(.defaultEnabled[] | select(. == $toUnforce))' \
| jq --arg toUnforce "${app}" 'del(.alwaysEnabled[] | select(. == $toUnforce))' > ${SHIPPED_JSON}.tmp \
&& mv ${SHIPPED_JSON}.tmp ${SHIPPED_JSON}
unship_app "${app}"
done

if [ -n "${ALWAYS_ENABLED_APPS}" ]; then
echo "Add apps to 'alwaysEnabled' list ..."
for app in ${ALWAYS_ENABLED_APPS}; do
ship_app "${app}"
done
fi
}

main
15 changes: 13 additions & 2 deletions apps-enable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,19 @@ BDIR="$( dirname "${0}" )"

NEXTCLOUD_DIR="${BDIR}/.."

. ${BDIR}/enabled-core-apps.inc.sh
. ${BDIR}/disabled-apps.inc.sh
# Read app list from file, ignoring comments and empty lines
# Usage: read_app_list <file_path>
read_app_list() {
_list_file="${1}"
if [ ! -f "${_list_file}" ]; then
echo ""
return
fi
grep -v '^[[:space:]]*#' "${_list_file}" | grep -v '^[[:space:]]*$' | tr '\n' ' '
}

ENABLED_CORE_APPS=$( read_app_list "${BDIR}/enabled-core-apps.list" )
DISABLED_APPS=$( read_app_list "${BDIR}/disabled-apps.list" )

execute_occ_command() {
php "${NEXTCLOUD_DIR}/occ" \
Expand Down
56 changes: 34 additions & 22 deletions configure-object-store.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,32 @@ log_fatal() {
exit 1
}

# Log warning message
# Usage: log_warning <message>
log_warning() {
echo "\033[1;33m[w] Warning: ${*}\033[0m" >/dev/stderr
}

# Validate required environment variables
# Usage: validate_env_vars <var1> <var2> ...
# Returns: 0 if all variables are set, 1 otherwise
validate_env_vars() {
_validation_failed=false

for _var in "${@}"; do
eval "_value=\${${_var}}"
if [ -z "${_value}" ]; then
log_warning "${_var} environment variable is not set"
_validation_failed=true
fi
done

if [ "${_validation_failed}" = "true" ]; then
return 1
fi
return 0
}

write_config_file() {
config="${NEXTCLOUD_ROOT_DIR}/config/object-store.config.php"

Expand Down Expand Up @@ -63,28 +89,14 @@ main() {
log_fatal "occ command not found, are you in Nextcloud's root dir?"
fi

if [ -z "${ENC_OBJECT_STORAGE_BUCKET_NAME}" ]; then
log_fatal "ENC_OBJECT_STORAGE_BUCKET_NAME not set"
fi

if [ -z "${ENC_OBJECT_STORAGE_ACCESS_KEY}" ]; then
log_fatal "ENC_OBJECT_STORAGE_ACCESS_KEY not set"
fi

if [ -z "${ENC_OBJECT_STORAGE_SECRET}" ]; then
log_fatal "ENC_OBJECT_STORAGE_SECRET not set"
fi

if [ -z "${ENC_OBJECT_STORAGE_REGION}" ]; then
log_fatal "ENC_OBJECT_STORAGE_REGION not set"
fi

if [ -z "${ENC_OBJECT_STORAGE_HOSTNAME}" ]; then
log_fatal "ENC_OBJECT_STORAGE_HOSTNAME not set"
fi

if [ -z "${ENC_OBJECT_STORAGE_PORT}" ]; then
log_fatal "ENC_OBJECT_STORAGE_PORT not set"
if ! validate_env_vars \
ENC_OBJECT_STORAGE_BUCKET_NAME \
ENC_OBJECT_STORAGE_ACCESS_KEY \
ENC_OBJECT_STORAGE_SECRET \
ENC_OBJECT_STORAGE_REGION \
ENC_OBJECT_STORAGE_HOSTNAME \
ENC_OBJECT_STORAGE_PORT; then
log_fatal "required object store environment variables are not set"
fi

if [ -n "${ENC_OBJECT_STORAGE_USE_SSL}" ] && [ "${ENC_OBJECT_STORAGE_USE_SSL}" != "true" ] && [ "${ENC_OBJECT_STORAGE_USE_SSL}" != "false" ]; then
Expand Down
Loading
Loading