# Replace genisoimage with go-diskfs (pure Go ISO creation) ## Why `genisoimage` is the only remaining external binary dependency after the dcmtk migration. Replacing it with `github.com/diskfs/go-diskfs` (pure Go, MIT, 644⭐, v1.9.3) makes the mkiso-server binary fully self-contained — zero external binaries beyond dcmtk storescp/movescu/storescu. ## What Replace `pkg/dicom/command.go`'s `RunGenISOImage()` (which shells out to genisoimage) with pure Go ISO creation using go-diskfs. This affects: | Current | New | |---------|-----| | `service/iso.go` calls `dicom.RunGenISOImage()` | Calls `isobuilder.BuildFromDirectory()` | | `pkg/dicom/command.go` has `RunGenISOImage()` | Remove it | | `config.go` has `Tools.Genisoimage` + validation | Remove field + validation | | `config.example.yaml` has `tools.genisoimage` | Remove | | `handler/health.go` checks genisoimage binary | Remove check | ## go-diskfs API reference ```go import ( diskfs "github.com/diskfs/go-diskfs" "github.com/diskfs/go-diskfs/disk" "github.com/diskfs/go-diskfs/filesystem" "github.com/diskfs/go-diskfs/filesystem/iso9660" ) type FinalizeOptions struct { RockRidge bool // Rock Ridge extensions (long names, perms) Joliet bool // Joliet (UCS-2 names for Windows) DeepDirectories bool // Allow dirs deeper than 8 levels ElTorito *ElTorito VolumeIdentifier string // Volume label, default "ISOIMAGE" PublisherIdentifier string } ``` ### ISO creation pattern (from go-diskfs examples/create-iso-from-folder/) ```go // 1. Calculate total size of directory folderSize := dirSize(srcDir) // 2. Create disk image file mydisk, err := diskfs.Create(isoPath, folderSize, 2048) mydisk.LogicalBlocksize = 2048 // 3. Create ISO9660 filesystem fs, err := mydisk.CreateFilesystem(disk.FilesystemSpec{ Partition: 0, FSType: filesystem.TypeISO9660, VolumeLabel: "DICOM", }) // 4. Walk source dir, copy files filepath.Walk(srcDir, func(path string, info os.FileInfo, err error) error { relPath, _ := filepath.Rel(srcDir, path) if info.IsDir() { fs.Mkdir(relPath) } else { rw, _ := fs.OpenFile(relPath, os.O_CREATE|os.O_RDWR) io.Copy(rw, file) rw.Close() } }) // 5. Finalize with Rock Ridge + Joliet iso := fs.(*iso9660.FileSystem) iso.Finalize(iso9660.FinalizeOptions{ RockRidge: true, Joliet: true, DeepDirectories: true, VolumeIdentifier: "DICOM", }) fs.Close() ``` ### Equivalent genisoimage flags to go-diskfs options | genisoimage flag | go-diskfs FinalizeOptions | |-----------------|--------------------------| | `-iso-level 4` | `DeepDirectories: true` | | `-r` (Rock Ridge) | `RockRidge: true` | | `-V DICOM` | `VolumeIdentifier: "DICOM"` | | `-allow-multidot` | Implicit via Rock Ridge | | `-allow-lowercase` | Implicit via Rock Ridge | | `-allow-leading-dots` | Implicit via Rock Ridge | | `-J` (Joliet) | `Joliet: true` | ## Implementation order - [ ] **1. Add go-diskfs dependency** — `go get github.com/diskfs/go-diskfs@v1.9.3` - [ ] **2. Create `internal/isobuilder/builder.go`** — `BuildFromDirectory(srcDir, isoPath, volumeLabel string) error` - `dirSize()` helper (walk dir, sum file sizes + 10% overhead margin) - Walk again to create dirs + copy files - Finalize with RockRidge + Joliet + DeepDirectories + VolumeIdentifier - [ ] **3. Update `internal/config/config.go`** - Remove `ToolsConfig.Genisoimage` field - Remove validation `c.Tools.Genisoimage == ""` - Remove `Tools` from Config struct entirely if empty (keep struct, remove field) - [ ] **4. Update `config.example.yaml`** — remove `tools.genisoimage` section - [ ] **5. Update `internal/service/iso.go`** - Replace both `dicom.RunGenISOImage(...)` calls with `isobuilder.BuildFromDirectory(tempDir, isoPath, "DICOM")` - Remove unused `dicom` import alias (if no longer needed in scope — it's still used for `countFiles` elsewhere) - [ ] **6. Update `internal/handler/health.go`** - Remove genisoimage from the dependency check array - [ ] **7. Remove `RunGenISOImage` from `pkg/dicom/command.go`** - Delete the entire function - [ ] **8. Build and test** - `go build ./...` must pass - `go vet ./...` must pass - Start server, verify `/api/health` no longer shows genisoimage - Verify ISO endpoint still returns proper errors (PACS unreachable)