Skip to content

Commit

Permalink
Working on writing untarred bags
Browse files Browse the repository at this point in the history
  • Loading branch information
diamondap committed Jan 12, 2024
1 parent 0966147 commit cb46ecf
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 44 deletions.
14 changes: 13 additions & 1 deletion constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ const (
ResultTypeList = "list"
ResultTypeSingle = "single"
ResultTypeUnitialized = "unintialized"
SerialFormatNone = "none (bag as directory)"
SerialFormatTar = "application/tar"
SerializationForbidden = "forbidden"
SerializationOptional = "optional"
SerializationRequired = "required"
Expand Down Expand Up @@ -97,7 +99,17 @@ var AcceptBagItVersion = []string{
}

var AcceptSerialization = []string{
"application/tar",
SerialFormatNone,
SerialFormatTar,
}

// BagWriterTypeFor maps a BagIt serialization format to the
// type of writer that can write that format.
var BagWriterTypeFor = map[string]string{
"": BagWriterTypeFileSystem,
".tar": BagWriterTypeTar,
SerialFormatNone: BagWriterTypeFileSystem,
SerialFormatTar: BagWriterTypeTar,
}

var SerializationOptions = []string{
Expand Down
63 changes: 35 additions & 28 deletions core/bagger.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,38 @@ import (
var bagitTxt embed.FS

type Bagger struct {
Profile *BagItProfile
OutputPath string
FilesToBag []*util.ExtendedFileInfo
Errors map[string]string
MessageChannel chan *EventMessage
PayloadFiles *FileMap
PayloadManifests *FileMap
TagFiles *FileMap
TagManifests *FileMap
ManifestArtifacts map[string]string
TagFileArtifacts map[string]string
writer BagWriter
pathPrefix string
bagName string
currentFileNum int64
totalFileCount int64
Profile *BagItProfile
OutputPath string
FilesToBag []*util.ExtendedFileInfo
Errors map[string]string
MessageChannel chan *EventMessage
PayloadFiles *FileMap
PayloadManifests *FileMap
TagFiles *FileMap
TagManifests *FileMap
ManifestArtifacts map[string]string
TagFileArtifacts map[string]string
SerializationFormat string
writer BagWriter
pathPrefix string
bagName string
currentFileNum int64
totalFileCount int64
}

func NewBagger(outputPath string, profile *BagItProfile, filesToBag []*util.ExtendedFileInfo) *Bagger {
return &Bagger{
Profile: profile,
OutputPath: outputPath,
FilesToBag: filesToBag,
PayloadFiles: NewFileMap(constants.FileTypePayload),
PayloadManifests: NewFileMap(constants.FileTypeManifest),
TagFiles: NewFileMap(constants.FileTypeTag),
TagManifests: NewFileMap(constants.FileTypeTagManifest),
ManifestArtifacts: make(map[string]string),
TagFileArtifacts: make(map[string]string),
Errors: make(map[string]string),
Profile: profile,
OutputPath: outputPath,
FilesToBag: filesToBag,
PayloadFiles: NewFileMap(constants.FileTypePayload),
PayloadManifests: NewFileMap(constants.FileTypeManifest),
SerializationFormat: constants.SerialFormatTar,
TagFiles: NewFileMap(constants.FileTypeTag),
TagManifests: NewFileMap(constants.FileTypeTagManifest),
ManifestArtifacts: make(map[string]string),
TagFileArtifacts: make(map[string]string),
Errors: make(map[string]string),
}
}

Expand Down Expand Up @@ -301,8 +303,13 @@ func (b *Bagger) initWriter() bool {

// START HERE
// Get the right type of bag writer, based on profile serialization.

b.writer = NewTarredBagWriter(b.OutputPath, digestAlgs)
var err error
writerType := constants.BagWriterTypeFor[b.SerializationFormat]
b.writer, err = GetBagWriter(writerType, b.OutputPath, digestAlgs)
if err != nil {
Dart.Log.Errorf("Bagger cannot find writer for serialization type %s: %v", b.SerializationFormat, err)
return false
}
b.writer.Open()
return true
}
Expand Down
2 changes: 1 addition & 1 deletion core/bagit_profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,7 @@ func (p *BagItProfile) ToForm() *Form {
bagitVersionField.Help = "Which BagIt versions are allowed in this profile?"

acceptSerializationField := form.AddMultiValueField("AcceptSerialization", "AcceptSerialization", p.AcceptSerialization, true)
acceptSerializationField.Choices = MakeMultiChoiceList(p.AcceptSerialization, p.AcceptSerialization)
acceptSerializationField.Choices = MakeMultiChoiceList(constants.AcceptSerialization, p.AcceptSerialization)
acceptSerializationField.Help = "If bags using this profile can be serialized to tar, zip or other formats, enter the mime types for those formats here. E.g. application/x-tar, application/zip, etc. See https://en.wikipedia.org/wiki/List_of_archive_formats for a full list."

allowFetch := form.AddField("AllowFetchTxt", "AllowFetchTxt", strconv.FormatBool(p.AllowFetchTxt), true)
Expand Down
2 changes: 1 addition & 1 deletion core/bagit_profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ func TestBagItProfileToForm(t *testing.T) {
assert.Equal(t, constants.AcceptBagItVersion, form.Fields["AcceptBagItVersion"].Values)

require.NotNil(t, form.Fields["AcceptSerialization"])
assert.Equal(t, constants.AcceptSerialization, form.Fields["AcceptSerialization"].Values)
assert.Equal(t, profile.AcceptSerialization, form.Fields["AcceptSerialization"].Values)

require.NotNil(t, form.Fields["AllowFetchTxt"])
assert.Equal(t, strconv.FormatBool(profile.AllowFetchTxt), form.Fields["AllowFetchTxt"].Value)
Expand Down
6 changes: 6 additions & 0 deletions core/file_system_bag_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package core

// START HERE

// TODO: Define bag reader interface, similar to bag writer interface.
// Then implement this so it's interchangeable with TarredBagReader.
3 changes: 2 additions & 1 deletion core/job_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ func (r *Runner) RunPackageOp() bool {
sourceFiles = append(sourceFiles, files...)
}
bagger := NewBagger(op.OutputPath, r.Job.BagItProfile, sourceFiles)
bagger.MessageChannel = r.MessageChannel // Careful! This may be nil.
bagger.SerializationFormat = op.BagItSerialization // tar, loose directory, etc.
bagger.MessageChannel = r.MessageChannel // Careful! This may be nil.
ok := bagger.Run()
r.saveBaggingArtifacts(bagger)
r.Job.ByteCount = bagger.PayloadBytes()
Expand Down
31 changes: 20 additions & 11 deletions server/controllers/job_packaging_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ func JobShowPackaging(c *gin.Context) {
baggingDir = filepath.Join(core.Dart.Paths.Documents, "DART")
core.Dart.Log.Warningf("Bagging Directory not set. Defaulting to %s", baggingDir)
}
// The front end needs to know which profiles require serialization
// (serializationRequired) and which require a *specific* serialization
// format (autosetSerialization).
autoSetSerialization, serializationRequired := getSerlializationAutosets()
data := gin.H{
"job": job,
"form": job.ToForm(),
"pathSeparator": string(os.PathSeparator),
"baggingDir": baggingDir,
"autoSetSerialization": getSerlializationAutosets(),
"helpUrl": GetHelpUrl(c),
"job": job,
"form": job.ToForm(),
"pathSeparator": string(os.PathSeparator),
"baggingDir": baggingDir,
"autoSetSerialization": autoSetSerialization,
"serializationRequired": serializationRequired,
"helpUrl": GetHelpUrl(c),
}
c.HTML(http.StatusOK, "job/packaging.html", data)
}
Expand Down Expand Up @@ -107,18 +112,22 @@ func JobSavePackaging(c *gin.Context) {
c.Redirect(http.StatusFound, nextPage)
}

func getSerlializationAutosets() map[string]string {
func getSerlializationAutosets() (map[string]string, []string) {
autosetMap := make(map[string]string)
serializationRequired := make([]string, 0)
// Typical installation has 3-10 profiles.
result := core.ObjList(constants.TypeBagItProfile, "obj_name", 1000, 0)
if result.Error != nil {
core.Dart.Log.Warningf("Could not load BagIt profiles for serialization auto-set: %s", result.Error.Error())
return autosetMap
return autosetMap, serializationRequired
}
for _, profile := range result.BagItProfiles {
if profile.Serialization == constants.SerializationRequired && len(profile.AcceptSerialization) == 1 {
autosetMap[profile.ID] = profile.AcceptSerialization[0]
if profile.Serialization == constants.SerializationRequired {
serializationRequired = append(serializationRequired, profile.ID)
if len(profile.AcceptSerialization) == 1 {
autosetMap[profile.ID] = profile.AcceptSerialization[0]
}
}
}
return autosetMap
return autosetMap, serializationRequired
}
37 changes: 36 additions & 1 deletion server/views/job/packaging.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ <h2>Packaging</h2>
let baggingDir = {{ .baggingDir }}
let separator = {{ .pathSeparator }}
let autoSetSerialization = {{ .autoSetSerialization }}
let serializationRequired = {{ .serializationRequired }}
let emptySerializationOption = 'none (bag as directory)'

let extensionForType = {
"application/x-7z-compressed": ".7z",
Expand Down Expand Up @@ -81,10 +83,43 @@ <h2>Packaging</h2>
$('#Job_BagItSerialization').on('change', setOutputPath)

function setSerialization() {
let profileId = $(this).val()
let profileId = $('#Job_BagItProfileID').val()
if (serializationRequired.includes(profileId)) {
// Don't show empty serialization option because serializion
// is required for this profile.
removeEmptySerializationOption()
} else {
addEmptySerializationOption()
}
let serializationFormat = autoSetSerialization[profileId]
$('#Job_BagItSerialization').val(serializationFormat)
}

function listHasEmptySerializationOption() {
var hasOption = false
$('#Job_BagItSerialization option').each(function(opt) {
if ($(this).val() == emptySerializationOption) {
hasOption = true
}
})
return hasOption
}
function addEmptySerializationOption() {
if (!listHasEmptySerializationOption()) {
var option = `<option value='${emptySerializationOption}'>${emptySerializationOption}</option>`
$(option).insertAfter($('#Job_BagItSerialization option')[0])
}
}
function removeEmptySerializationOption() {
if (listHasEmptySerializationOption()) {
var option = $('#Job_BagItSerialization option[value="none (bag as directory)"]')
$(option).remove()
}
}

// Run this once on page load, then attach it to the profile
// select list so we can watch for changes.
setSerialization()
$('#Job_BagItProfileID').on('change', setSerialization)

})
Expand Down

0 comments on commit cb46ecf

Please sign in to comment.