118 lines
4.3 KiB
Markdown
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)
|