Files
dicom-iso/todo/02-genisoimage-to-godiskfs.md
2026-06-05 08:11:44 +07:00

118 lines
4.3 KiB
Markdown

# 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)