Compare commits

2 Commits
main ... 1

7 changed files with 326 additions and 0 deletions

12
.gitignore vendored
View File

@@ -4,6 +4,11 @@ config.yaml
# ISO output files # ISO output files
*.iso *.iso
# Vendored/runtime assets fetched outside git
dcmtk-bin/
legacy/raw/
.local/
# Temp directories # Temp directories
/tmp/dicomdir_* /tmp/dicomdir_*
@@ -20,3 +25,10 @@ Thumbs.db
# Local-only docs tell @VArtzy<farrelnikoson@gmail.com> for request # Local-only docs tell @VArtzy<farrelnikoson@gmail.com> for request
docs/phases docs/phases
# Keep placeholder docs for ignored asset directories
!dcmtk-bin/
!dcmtk-bin/README.md
!legacy/
!legacy/raw/
!legacy/raw/README.md

View File

@@ -25,6 +25,9 @@ The service needs:
- MicroDicom files - MicroDicom files
- writable temp storage - writable temp storage
Large runtime assets are intentionally not stored in git.
Use the setup scripts in `scripts/` to stage local copies in ignored directories.
## Setup ## Setup
Before running the service, make sure the VM has: Before running the service, make sure the VM has:
- Go installed, if you are building on that machine - Go installed, if you are building on that machine
@@ -33,6 +36,20 @@ Before running the service, make sure the VM has:
- network access to PACS, the patient API, and the CD publisher - network access to PACS, the patient API, and the CD publisher
- a writable temp directory - a writable temp directory
Stage local runtime assets if needed:
```bash
scripts/setup-dcmtk.sh --source-dir /path/to/dcmtk/bin
scripts/setup-microdicom.sh --source-dir /path/to/microdicom
```
Or download your hosted release assets directly:
```bash
scripts/setup-dcmtk.sh --archive-url https://github.com/<owner>/<repo>/releases/download/<tag>/dcmtk-bin.tar.gz
scripts/setup-microdicom.sh --archive-url https://github.com/<owner>/<repo>/releases/download/<tag>/microdicom.zip
```
Create a local config file from the template: Create a local config file from the template:
```bash ```bash
@@ -40,6 +57,7 @@ cp config.example.yaml config.yaml
``` ```
Then adjust the paths, hosts, ports, and tokens for your environment. Then adjust the paths, hosts, ports, and tokens for your environment.
For local staging via the setup scripts, point config at `.local/dcmtk-bin/` and `.local/microdicom/`.
## Build ## Build
A normal Go build is enough in a friendly environment: A normal Go build is enough in a friendly environment:

View File

@@ -29,6 +29,13 @@ The service needs:
- a writable temp directory - a writable temp directory
- a free port range for `storescp` - a free port range for `storescp`
If you do not manage these assets globally on the VM, you can stage them locally first:
```bash
scripts/setup-dcmtk.sh --source-dir /path/to/dcmtk/bin --install-dir /opt/dicom-iso/dcmtk-bin
scripts/setup-microdicom.sh --source-dir /path/to/microdicom --install-dir /opt/dicom-iso/microdicom
```
## Build note ## Build note
The build environment cannot depend on public internet access. The build environment cannot depend on public internet access.
That means the binary must be built through an approved offline-friendly path. That means the binary must be built through an approved offline-friendly path.

18
docs/repo-size-cleanup.md Normal file
View File

@@ -0,0 +1,18 @@
# Repo size cleanup
Implemented in the working tree:
- removed tracked binaries from `dcmtk-bin/`
- removed tracked raw assets from `legacy/raw/`
- added `.gitignore` protections
- added setup scripts for DCMTK and MicroDicom
## Finish the cleanup in git history
Rewriting history is still required to shrink the remote repository size.
```bash
git filter-repo --path dcmtk-bin --path legacy/raw --invert-paths
git push --force --all
git push --force --tags
```
Coordinate this with any collaborators first.

14
scripts/purge-git-history.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
cat <<'EOF'
This rewrites git history to remove large vendored assets.
Run only after committing the current tree cleanup and coordinating with collaborators.
Commands:
git filter-repo --path dcmtk-bin --path legacy/raw --invert-paths
git push --force --all
git push --force --tags
Afterward, collaborators should reclone or hard-reset to the rewritten history.
EOF

139
scripts/setup-dcmtk.sh Executable file
View File

@@ -0,0 +1,139 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INSTALL_DIR="${INSTALL_DIR:-$ROOT_DIR/.local/dcmtk-bin}"
REQUIRED_BINS=(storescp movescu storescu findscu dcmdump dcmodify getscu echoscu dcmj2pnm)
SOURCE_DIR=""
ARCHIVE_URL=""
TMP_DIR=""
usage() {
cat <<'EOF'
Usage:
scripts/setup-dcmtk.sh [--source-dir DIR | --archive-url URL] [--install-dir DIR]
Behavior:
- Copies required DCMTK binaries into a local ignored directory.
- If --source-dir is omitted, binaries are resolved from PATH.
- If --archive-url is given, the script downloads and extracts an archive,
then searches for the required binaries inside it.
Examples:
scripts/setup-dcmtk.sh --source-dir /opt/dcmtk/bin
scripts/setup-dcmtk.sh --archive-url https://github.com/<owner>/<repo>/releases/download/<tag>/dcmtk-bin.tar.gz
scripts/setup-dcmtk.sh --install-dir /data/dcmtk-bin
EOF
}
download() {
local url="$1"
local out="$2"
if command -v curl >/dev/null 2>&1; then
curl -fL "$url" -o "$out"
elif command -v wget >/dev/null 2>&1; then
wget -O "$out" "$url"
else
echo "need curl or wget to download $url" >&2
exit 1
fi
}
extract_archive() {
local archive="$1"
local dest="$2"
case "$archive" in
*.tar.gz|*.tgz) tar -xzf "$archive" -C "$dest" ;;
*.tar.xz) tar -xJf "$archive" -C "$dest" ;;
*.tar) tar -xf "$archive" -C "$dest" ;;
*.zip)
command -v unzip >/dev/null 2>&1 || { echo "unzip is required for $archive" >&2; exit 1; }
unzip -q "$archive" -d "$dest"
;;
*)
echo "unsupported archive format: $archive" >&2
exit 1
;;
esac
}
while [[ $# -gt 0 ]]; do
case "$1" in
--source-dir)
SOURCE_DIR="${2:?missing value for --source-dir}"
shift 2
;;
--archive-url)
ARCHIVE_URL="${2:?missing value for --archive-url}"
shift 2
;;
--install-dir)
INSTALL_DIR="${2:?missing value for --install-dir}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -n "$SOURCE_DIR" && -n "$ARCHIVE_URL" ]]; then
echo "use only one of --source-dir or --archive-url" >&2
exit 1
fi
cleanup() {
[[ -n "$TMP_DIR" && -d "$TMP_DIR" ]] && rm -rf "$TMP_DIR"
}
trap cleanup EXIT
if [[ -n "$ARCHIVE_URL" ]]; then
TMP_DIR="$(mktemp -d)"
archive="$TMP_DIR/archive"
download "$ARCHIVE_URL" "$archive"
mkdir -p "$TMP_DIR/extracted"
mv "$archive" "$TMP_DIR/archive$(basename "$ARCHIVE_URL" | sed 's/.*\(\.[^.][^.]*\)$/\1/')" 2>/dev/null || true
archive_path="$(find "$TMP_DIR" -maxdepth 1 -type f | head -n 1)"
extract_archive "$archive_path" "$TMP_DIR/extracted"
SOURCE_DIR="$TMP_DIR/extracted"
fi
mkdir -p "$INSTALL_DIR"
resolve_bin() {
local name="$1"
if [[ -n "$SOURCE_DIR" ]]; then
local candidate
candidate="$(find "$SOURCE_DIR" -type f -name "$name" -perm -u+x | head -n 1 || true)"
[[ -n "$candidate" ]] || candidate="$(find "$SOURCE_DIR" -type f -name "$name" | head -n 1 || true)"
[[ -n "$candidate" ]] || { echo "missing binary in source: $name" >&2; return 1; }
printf '%s\n' "$candidate"
return 0
fi
command -v "$name" >/dev/null 2>&1 || { echo "binary not found in PATH: $name" >&2; return 1; }
command -v "$name"
}
for bin in "${REQUIRED_BINS[@]}"; do
src="$(resolve_bin "$bin")"
install -m 0755 "$src" "$INSTALL_DIR/$bin"
echo "installed $bin -> $INSTALL_DIR/$bin"
done
cat <<EOF
Done.
Set these config values:
dcmtk:
storescp: "$INSTALL_DIR/storescp"
movescu: "$INSTALL_DIR/movescu"
storescu: "$INSTALL_DIR/storescu"
EOF

118
scripts/setup-microdicom.sh Executable file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
INSTALL_DIR="${INSTALL_DIR:-$ROOT_DIR/.local/microdicom}"
SOURCE_DIR=""
ARCHIVE_URL=""
TMP_DIR=""
usage() {
cat <<'EOF'
Usage:
scripts/setup-microdicom.sh [--source-dir DIR | --archive-url URL] [--install-dir DIR]
Behavior:
- Copies a prepared MicroDicom directory into a local ignored directory.
- With --archive-url, downloads and extracts an archive, then searches for
a directory containing AUTORUN.INF and MICROD/.
Example:
scripts/setup-microdicom.sh --archive-url https://github.com/<owner>/<repo>/releases/download/<tag>/microdicom.zip
EOF
}
download() {
local url="$1"
local out="$2"
if command -v curl >/dev/null 2>&1; then
curl -fL "$url" -o "$out"
elif command -v wget >/dev/null 2>&1; then
wget -O "$out" "$url"
else
echo "need curl or wget to download $url" >&2
exit 1
fi
}
extract_archive() {
local archive="$1"
local dest="$2"
case "$archive" in
*.tar.gz|*.tgz) tar -xzf "$archive" -C "$dest" ;;
*.tar.xz) tar -xJf "$archive" -C "$dest" ;;
*.tar) tar -xf "$archive" -C "$dest" ;;
*.zip)
command -v unzip >/dev/null 2>&1 || { echo "unzip is required for $archive" >&2; exit 1; }
unzip -q "$archive" -d "$dest"
;;
*)
echo "unsupported archive format: $archive" >&2
exit 1
;;
esac
}
while [[ $# -gt 0 ]]; do
case "$1" in
--source-dir)
SOURCE_DIR="${2:?missing value for --source-dir}"
shift 2
;;
--archive-url)
ARCHIVE_URL="${2:?missing value for --archive-url}"
shift 2
;;
--install-dir)
INSTALL_DIR="${2:?missing value for --install-dir}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -n "$SOURCE_DIR" && -n "$ARCHIVE_URL" ]]; then
echo "use only one of --source-dir or --archive-url" >&2
exit 1
fi
cleanup() {
[[ -n "$TMP_DIR" && -d "$TMP_DIR" ]] && rm -rf "$TMP_DIR"
}
trap cleanup EXIT
if [[ -n "$ARCHIVE_URL" ]]; then
TMP_DIR="$(mktemp -d)"
archive="$TMP_DIR/$(basename "$ARCHIVE_URL")"
download "$ARCHIVE_URL" "$archive"
mkdir -p "$TMP_DIR/extracted"
extract_archive "$archive" "$TMP_DIR/extracted"
SOURCE_DIR="$(find "$TMP_DIR/extracted" -type f -name AUTORUN.INF -printf '%h\n' | head -n 1 || true)"
fi
[[ -n "$SOURCE_DIR" ]] || { echo "one of --source-dir or --archive-url is required" >&2; exit 1; }
[[ -d "$SOURCE_DIR" ]] || { echo "source directory does not exist: $SOURCE_DIR" >&2; exit 1; }
[[ -f "$SOURCE_DIR/AUTORUN.INF" ]] || { echo "missing AUTORUN.INF in source directory" >&2; exit 1; }
[[ -d "$SOURCE_DIR/MICROD" ]] || { echo "missing MICROD/ in source directory" >&2; exit 1; }
rm -rf "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
cp -a "$SOURCE_DIR"/. "$INSTALL_DIR"/
echo "installed MicroDicom assets -> $INSTALL_DIR"
cat <<EOF
Done.
Set this config value:
iso:
microdicom_path: "$INSTALL_DIR"
EOF