snapshotting: ability to specify timestamp location != UTC (#801)
This PR adds a new field optional field `timestamp_location` that allows the user to specify a timezone different than the default UTC for use in the snapshot suffix. I took @mjasnik 's PR https://github.com/zrepl/zrepl/pull/785 and refactored+extended it as follows: * move all formatting logic into its own package * disallow `dense` and `human` with formats != UTC to protect users from stupidity * document behavior more clearly * regression test for existing users
This commit is contained in:
committed by
GitHub
parent
904c1512a3
commit
b9b9ad10cf
+11
-9
@@ -55,22 +55,22 @@ var componentValidChar = regexp.MustCompile(`^[0-9a-zA-Z-_\.: ]+$`)
|
||||
// [-_.: ]
|
||||
func ComponentNamecheck(datasetPathComponent string) error {
|
||||
if len(datasetPathComponent) == 0 {
|
||||
return fmt.Errorf("path component must not be empty")
|
||||
return fmt.Errorf("must not be empty")
|
||||
}
|
||||
if len(datasetPathComponent) > MaxDatasetNameLen {
|
||||
return fmt.Errorf("path component must not be longer than %d chars", MaxDatasetNameLen)
|
||||
return fmt.Errorf("must not be longer than %d chars", MaxDatasetNameLen)
|
||||
}
|
||||
|
||||
if !(isASCII(datasetPathComponent)) {
|
||||
return fmt.Errorf("path component must be ASCII")
|
||||
return fmt.Errorf("must be ASCII")
|
||||
}
|
||||
|
||||
if !componentValidChar.MatchString(datasetPathComponent) {
|
||||
return fmt.Errorf("path component must only contain alphanumeric chars and any in %q", "-_.: ")
|
||||
return fmt.Errorf("must only contain alphanumeric chars and any in %q", "-_.: ")
|
||||
}
|
||||
|
||||
if datasetPathComponent == "." || datasetPathComponent == ".." {
|
||||
return fmt.Errorf("path component must not be '%s'", datasetPathComponent)
|
||||
return fmt.Errorf("must not be '%s'", datasetPathComponent)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -155,8 +155,9 @@ func EntityNamecheck(path string, t EntityType) (err *PathValidationError) {
|
||||
|
||||
if bookmarkOrSnapshotDelims == 0 {
|
||||
// hot path, all but last component
|
||||
if err := ComponentNamecheck(string(comp)); err != nil {
|
||||
return pve(err.Error())
|
||||
component := string(comp)
|
||||
if err := ComponentNamecheck(component); err != nil {
|
||||
return pve(fmt.Sprintf("component %q: %s", component, err.Error()))
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -172,8 +173,9 @@ func EntityNamecheck(path string, t EntityType) (err *PathValidationError) {
|
||||
}
|
||||
|
||||
for _, comp := range subComps {
|
||||
if err := ComponentNamecheck(string(comp)); err != nil {
|
||||
return pve(err.Error())
|
||||
component := string(comp)
|
||||
if err := ComponentNamecheck(component); err != nil {
|
||||
return pve(fmt.Sprintf("component %q: %s", component, err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,10 @@ func TestEntityNamecheck(t *testing.T) {
|
||||
{strings.Repeat("a", MaxDatasetNameLen-2) + "/a", EntityTypeFilesystem, true},
|
||||
{strings.Repeat("a", MaxDatasetNameLen-4) + "/a@b", EntityTypeSnapshot, true},
|
||||
{strings.Repeat("a", MaxDatasetNameLen) + "/a@b", EntityTypeSnapshot, false},
|
||||
// + is not allowed, and particularly relevant to test here because
|
||||
// common timestamp formats usually use `+` as a delimiter for numeric timezone offset
|
||||
// => cf with package `timestamp_formatting`
|
||||
{"foo/bar@23+42", EntityTypeSnapshot, false},
|
||||
}
|
||||
|
||||
for idx := range tcs {
|
||||
|
||||
Reference in New Issue
Block a user