diff --git a/hack/ccp/go.mod b/hack/ccp/go.mod index 6ccda5110..c2f757ed5 100644 --- a/hack/ccp/go.mod +++ b/hack/ccp/go.mod @@ -3,38 +3,37 @@ module github.com/artefactual/archivematica/hack/ccp go 1.22.3 require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.33.0-20240401165935-b983156c5e99.1 - connectrpc.com/connect v1.16.1 + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.1-20240508200655-46a4cf4ba109.1 + connectrpc.com/connect v1.16.2 connectrpc.com/grpchealth v1.3.0 connectrpc.com/grpcreflect v1.2.0 - github.com/artefactual-labs/gearmin v0.0.0-20240506072626-8c1a583fd630 + github.com/artefactual-labs/gearmin v0.0.0-20240507145739-e15b2dbf710c github.com/bufbuild/protovalidate-go v0.6.2 github.com/doug-martin/goqu/v9 v9.19.0 github.com/elliotchance/orderedmap/v2 v2.2.0 github.com/fsnotify/fsnotify v1.7.0 github.com/go-logr/logr v1.4.1 github.com/go-sql-driver/mysql v1.8.1 - github.com/gohugoio/hugo v0.125.7 + github.com/gohugoio/hugo v0.126.1 github.com/google/uuid v1.6.0 github.com/hashicorp/go-retryablehttp v0.7.6 github.com/microsoft/kiota-abstractions-go v1.6.0 - github.com/microsoft/kiota-http-go v1.3.3 github.com/mikespook/gearman-go v0.0.0-20220520031403-2a518e866145 github.com/peterbourgon/ff/v3 v3.4.0 github.com/rs/cors v1.11.0 github.com/tailscale/hujson v0.0.0-20221223112325-20486734a56a - github.com/testcontainers/testcontainers-go v0.30.0 - github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0 - go.artefactual.dev/ssclient v0.2.3 - go.artefactual.dev/tools v0.10.0 + github.com/testcontainers/testcontainers-go v0.31.0 + github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 + go.artefactual.dev/ssclient v0.3.0 + go.artefactual.dev/tools v0.12.0 go.nhat.io/httpmock v0.11.0 - go.starlark.net v0.0.0-20240411212711-9b43f0afd521 + go.starlark.net v0.0.0-20240510163022-f457c4c2b267 go.uber.org/goleak v1.3.0 go.uber.org/mock v0.4.0 - golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 golang.org/x/net v0.25.0 golang.org/x/sync v0.7.0 - google.golang.org/protobuf v1.33.0 + google.golang.org/protobuf v1.34.1 gotest.tools/v3 v3.5.1 ) @@ -52,7 +51,7 @@ require ( github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cjlapao/common-go v0.0.39 // indirect github.com/cli/safeexec v1.0.1 // indirect - github.com/containerd/containerd v1.7.12 // indirect + github.com/containerd/containerd v1.7.15 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -75,6 +74,7 @@ require ( github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/microsoft/kiota-http-go v1.4.1 // indirect github.com/microsoft/kiota-serialization-form-go v1.0.0 // indirect github.com/microsoft/kiota-serialization-json-go v1.0.7 // indirect github.com/microsoft/kiota-serialization-multipart-go v1.0.0 // indirect @@ -116,10 +116,11 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.23.0 // indirect golang.org/x/mod v0.17.0 // indirect golang.org/x/sys v0.20.0 // indirect golang.org/x/text v0.15.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/tools v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect google.golang.org/grpc v1.62.1 // indirect diff --git a/hack/ccp/go.sum b/hack/ccp/go.sum index 64a2c4417..f64f62e19 100644 --- a/hack/ccp/go.sum +++ b/hack/ccp/go.sum @@ -1,8 +1,8 @@ -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.33.0-20240401165935-b983156c5e99.1 h1:2IGhRovxlsOIQgx2ekZWo4wTPAYpck41+18ICxs37is= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.33.0-20240401165935-b983156c5e99.1/go.mod h1:Tgn5bgL220vkFOI0KPStlcClPeOJzAv4uT+V8JXGUnw= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.1-20240508200655-46a4cf4ba109.1 h1:LEXWFH/xZ5oOWrC3oOtHbUyBdzRWMCPpAQmKC9v05mA= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.1-20240508200655-46a4cf4ba109.1/go.mod h1:XF+P8+RmfdufmIYpGUC+6bF7S+IlmHDEnCrO3OXaUAQ= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -connectrpc.com/connect v1.16.1 h1:rOdrK/RTI/7TVnn3JsVxt3n028MlTRwmK5Q4heSpjis= -connectrpc.com/connect v1.16.1/go.mod h1:XpZAduBQUySsb4/KO5JffORVkDI4B6/EYPi7N8xpNZw= +connectrpc.com/connect v1.16.2 h1:ybd6y+ls7GOlb7Bh5C8+ghA6SvCBajHwxssO2CGFjqE= +connectrpc.com/connect v1.16.2/go.mod h1:n2kgwskMHXC+lVqb18wngEpF95ldBHXjZYJussz5FRc= connectrpc.com/grpchealth v1.3.0 h1:FA3OIwAvuMokQIXQrY5LbIy8IenftksTP/lG4PbYN+E= connectrpc.com/grpchealth v1.3.0/go.mod h1:3vpqmX25/ir0gVgW6RdnCPPZRcR6HvqtXX5RNPmDXHM= connectrpc.com/grpcreflect v1.2.0 h1:Q6og1S7HinmtbEuBvARLNwYmTbhEGRpHDhqrPNlmK+U= @@ -30,8 +30,8 @@ github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c h1:651/eoCRnQ7YtSjAnSzRucrJz+3iGEFt+ysraELS81M= github.com/armon/go-radix v1.0.1-0.20221118154546-54df44f2176c/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/artefactual-labs/gearmin v0.0.0-20240506072626-8c1a583fd630 h1:eJfMprHs8o9O6cRbp3O8V92IG3vHsqplH48BkI7WpQo= -github.com/artefactual-labs/gearmin v0.0.0-20240506072626-8c1a583fd630/go.mod h1:C+JaJpQwRvWN3sa2z2jy+ziy7mQuuTIsTiRFJbUBO38= +github.com/artefactual-labs/gearmin v0.0.0-20240507145739-e15b2dbf710c h1:vf3GatdfaJojurMPb5g4V2yujXPGwSQZnEs37crmfcA= +github.com/artefactual-labs/gearmin v0.0.0-20240507145739-e15b2dbf710c/go.mod h1:C+JaJpQwRvWN3sa2z2jy+ziy7mQuuTIsTiRFJbUBO38= github.com/bep/clocks v0.5.0 h1:hhvKVGLPQWRVsBP/UB7ErrHYIO42gINVbvqxvYTPVps= github.com/bep/clocks v0.5.0/go.mod h1:SUq3q+OOq41y2lRQqH5fsOoxN8GbxSiT6jvoVVLCVhU= github.com/bep/debounce v1.2.0 h1:wXds8Kq8qRfwAOpAxHrJDbCXgC5aHSzgQb/0gKsHQqo= @@ -73,8 +73,8 @@ github.com/cli/safeexec v1.0.0/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5 github.com/cli/safeexec v1.0.1 h1:e/C79PbXF4yYTN/wauC4tviMxEV13BwljGj0N9j+N00= github.com/cli/safeexec v1.0.1/go.mod h1:Z/D4tTN8Vs5gXYHDCbaM1S/anmEDnJb1iW0+EJ5zx3Q= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/containerd/containerd v1.7.12 h1:+KQsnv4VnzyxWcfO9mlxxELaoztsDEjOuCMPAuPqgU0= -github.com/containerd/containerd v1.7.12/go.mod h1:/5OMpE1p0ylxtEUGY8kuCYkDRzJm9NO1TFMWjUpdevk= +github.com/containerd/containerd v1.7.15 h1:afEHXdil9iAm03BmhjzKyXnnEBtjaLJefdU7DV0IFes= +github.com/containerd/containerd v1.7.15/go.mod h1:ISzRRTMF8EXNpJlTzyr2XMhN+j9K302C21/+cr3kUnY= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= @@ -147,8 +147,10 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e h1:QArsSubW7eDh8APMXkByjQWvuljwPGAGQpJEFn0F0wY= github.com/gohugoio/go-i18n/v2 v2.1.3-0.20230805085216-e63c13218d0e/go.mod h1:3Ltoo9Banwq0gOtcOwxuHG6omk+AwsQPADyw2vQYOJQ= -github.com/gohugoio/hugo v0.125.7 h1:2V0jHo/FNigM3WtqTJZN7k4RAEE9EK0PJzsF9FU/y5w= -github.com/gohugoio/hugo v0.125.7/go.mod h1:SsHQwk6Ma4OlGuBF3UmVfTPyWKiZMwBmMZSEdyV4hw0= +github.com/gohugoio/hugo v0.126.1 h1:jzs1VX6Ru/NR0luf4Z9ahKLVmYzQEox4Cxd/kyzgN9A= +github.com/gohugoio/hugo v0.126.1/go.mod h1:wo66RnKrp9Mx0WeeF22LJxPY6YB+v2weKdZpHa8fI/A= +github.com/gohugoio/hugo-goldmark-extensions/extras v0.1.0 h1:YhxZNU8y2vxV6Ibr7QJzzUlpr8oHHWX/l+Q1R/a5Zao= +github.com/gohugoio/hugo-goldmark-extensions/extras v0.1.0/go.mod h1:0cuvOnGKW7WeXA3i7qK6IS07FH1bgJ2XzOjQ7BMJYH4= github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.2.0 h1:PCtO5l++psZf48yen2LxQ3JiOXxaRC6v0594NeHvGZg= github.com/gohugoio/hugo-goldmark-extensions/passthrough v0.2.0/go.mod h1:g9CCh+Ci2IMbPUrVJuXbBTrA+rIIx5+hDQ4EXYaQDoM= github.com/gohugoio/locales v0.14.0 h1:Q0gpsZwfv7ATHMbcTNepFd59H7GoykzWJIxi113XGDc= @@ -239,8 +241,8 @@ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/microsoft/kiota-abstractions-go v1.6.0 h1:qbGBNMU0/o5myKbikCBXJFohVCFrrpx2cO15Rta2WyA= github.com/microsoft/kiota-abstractions-go v1.6.0/go.mod h1:7YH20ZbRWXGfHSSvdHkdztzgCB9mRdtFx13+hrYIEpo= -github.com/microsoft/kiota-http-go v1.3.3 h1:FKjK5BLFONu5eIBxtrkirkixFQmcPwitZ8iwZHKbESo= -github.com/microsoft/kiota-http-go v1.3.3/go.mod h1:IWw/PwtBs/GYz+Pa75gPW7MFNFv0aKPFsLw5WqzL1SE= +github.com/microsoft/kiota-http-go v1.4.1 h1:zR54JahUOcu8h9C5z00fcQChzX8d01+BwhkTS8H16Ro= +github.com/microsoft/kiota-http-go v1.4.1/go.mod h1:Kup5nMDD3a9sjdgRKHCqZWqtrv3FbprjcPaGjLR6FzM= github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI= github.com/microsoft/kiota-serialization-form-go v1.0.0/go.mod h1:h4mQOO6KVTNciMF6azi1J9QB19ujSw3ULKcSNyXXOMA= github.com/microsoft/kiota-serialization-json-go v1.0.7 h1:yMbckSTPrjZdM4EMXgzLZSA3CtDaUBI350u0VoYRz7Y= @@ -349,10 +351,10 @@ github.com/tdewolff/parse/v2 v2.7.13 h1:iSiwOUkCYLNfapHoqdLcqZVgvQ0jrsao8YYKP/UJ github.com/tdewolff/parse/v2 v2.7.13/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA= github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE= -github.com/testcontainers/testcontainers-go v0.30.0 h1:jmn/XS22q4YRrcMwWg0pAwlClzs/abopbsBzrepyc4E= -github.com/testcontainers/testcontainers-go v0.30.0/go.mod h1:K+kHNGiM5zjklKjgTtcrEetF3uhWbMUyqAQoyoh8Pf0= -github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0 h1:wrePvxfU/2HFALKyBqpNs6VoPPvThzHy9aN+PCxse9g= -github.com/testcontainers/testcontainers-go/modules/mysql v0.30.0/go.mod h1:Srnlf7wwA7s6K4sKKhjAoBHJcKorRINR/i5dCA4ZyGk= +github.com/testcontainers/testcontainers-go v0.31.0 h1:W0VwIhcEVhRflwL9as3dhY6jXjVCA27AkmbnZ+UTh3U= +github.com/testcontainers/testcontainers-go v0.31.0/go.mod h1:D2lAoA0zUFiSY+eAflqK5mcUx/A5hrrORaEQrd0SefI= +github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0 h1:790+S8ewZYCbG+o8IiFlZ8ZZ33XbNO6zV9qhU6xhlRk= +github.com/testcontainers/testcontainers-go/modules/mysql v0.31.0/go.mod h1:REFmO+lSG9S6uSBEwIMZCxeI36uhScjTwChYADeO3JA= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= @@ -371,10 +373,10 @@ github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GA github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.artefactual.dev/ssclient v0.2.3 h1:tVkjQEycs6420Ky++1aZZUBoz94wWS2FoiVzqBNH2gM= -go.artefactual.dev/ssclient v0.2.3/go.mod h1:ImaAHtgGIbKlnrOUzczBMmltNVbhYkKZ7ujUjfBtUj8= -go.artefactual.dev/tools v0.10.0 h1:+LeZS5oHupAQBXvLQ4aGIuZyqf7zCpD7s3UpyDl9zn4= -go.artefactual.dev/tools v0.10.0/go.mod h1:PIy0RtC45gC4sASb4r26g0aCU24kSWIp+mcV1p2gtpY= +go.artefactual.dev/ssclient v0.3.0 h1:1Pp996L08nTf4taY6k2KWQLQZw9Hlcn+jeGC5FvEAl4= +go.artefactual.dev/ssclient v0.3.0/go.mod h1:ZtoXTqqbUM2+hKVcHwgEAP4t/AyfVGUCJOXAsgRl5dg= +go.artefactual.dev/tools v0.12.0 h1:NxSnKoTcYEwnr91/8fOjC5gr20uhVlU5ouboIHAhT9M= +go.artefactual.dev/tools v0.12.0/go.mod h1:exAc0MSKv1oXXb3FuSwkN+tg0n95HHGKpM18lxu4CKU= go.nhat.io/httpmock v0.11.0 h1:GSADjr4/sn1HXqnyluPr9PYpSmMh/h3ty0O7lEozD3c= go.nhat.io/httpmock v0.11.0/go.mod h1:276uIJ0K7BYfC8EW2WUK4S9PyEjiR71Ex0+43b3eNtk= go.nhat.io/matcher/v2 v2.0.0 h1:W+rbHi0hKuZHtOQH4U5g+KwyKyfVioIxrxjoGRcUETE= @@ -397,8 +399,8 @@ go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= -go.starlark.net v0.0.0-20240411212711-9b43f0afd521 h1:1Ufp2S2fPpj0RHIQ4rbzpCdPLCPkzdK7BaVFH3nkYBQ= -go.starlark.net v0.0.0-20240411212711-9b43f0afd521/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= +go.starlark.net v0.0.0-20240510163022-f457c4c2b267 h1:nHGP5vKtg2WaXA/AozoZWx/DI9wvwxCeikONJbdKdFo= +go.starlark.net v0.0.0-20240510163022-f457c4c2b267/go.mod h1:YKMCv9b1WrfWmeqdV5MAuEHWsu5iC+fe6kYl2sQjdI8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= @@ -412,11 +414,13 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw= -golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= -golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8= -golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw= +golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -456,6 +460,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= @@ -470,8 +476,8 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -499,8 +505,8 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/hack/ccp/hack/make/enums.mk b/hack/ccp/hack/make/enums.mk index 01b060b6c..451aee372 100644 --- a/hack/ccp/hack/make/enums.mk +++ b/hack/ccp/hack/make/enums.mk @@ -1,4 +1,5 @@ ENUMS = \ + internal/ssclient/enums/location_purpose_enum.go \ internal/store/enums/package_status_enum.go \ internal/store/enums/package_type_enum.go \ internal/store/enums/transfer_type_enum.go \ diff --git a/hack/ccp/internal/api/admin/admin.go b/hack/ccp/internal/api/admin/admin.go index 06b33698d..a2f741ccf 100644 --- a/hack/ccp/internal/api/admin/admin.go +++ b/hack/ccp/internal/api/admin/admin.go @@ -105,19 +105,14 @@ func (s *Server) CreatePackage(ctx context.Context, req *connect.Request[adminv1 return nil, connect.NewError(connect.CodeInvalidArgument, err) } - autoApprove := req.Msg.AutoApprove == nil || req.Msg.AutoApprove.Value - s.logger.Info("CreatePackage", "autoApprove", autoApprove) - - resp := &adminv1.CreatePackageResponse{} - - if pkg, err := s.ctrl.Submit(ctx, req.Msg); err != nil { + pkg, err := s.ctrl.Submit(ctx, req.Msg) + if err != nil { return nil, connect.NewError(connect.CodeUnknown, err) - } else { - s.logger.Info("TODO: return identifier", "pkg", pkg.Name()) - resp.Id = uuid.New().String() } - return connect.NewResponse(resp), nil + return connect.NewResponse(&adminv1.CreatePackageResponse{ + Id: pkg.ID().String(), + }), nil } func (s *Server) ApproveTransfer(ctx context.Context, req *connect.Request[adminv1.ApproveTransferRequest]) (*connect.Response[adminv1.ApproveTransferResponse], error) { diff --git a/hack/ccp/internal/api/admin/validation_test.go b/hack/ccp/internal/api/admin/validation_test.go index 75ac0d9a1..5e7b70a0f 100644 --- a/hack/ccp/internal/api/admin/validation_test.go +++ b/hack/ccp/internal/api/admin/validation_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/bufbuild/protovalidate-go" + "google.golang.org/protobuf/types/known/wrapperspb" "gotest.tools/v3/assert" adminv1 "github.com/artefactual/archivematica/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1" @@ -12,19 +13,36 @@ import ( func TestValidation(t *testing.T) { t.Parallel() - v, err := protovalidate.New() - assert.NilError(t, err) + t.Run("Passes validation", func(t *testing.T) { + t.Parallel() - req := &adminv1.CreatePackageRequest{ - Name: "asdf", - Path: []string{"/tmp"}, - } - err = v.Validate(req) - assert.NilError(t, err) + v, err := protovalidate.New() + assert.NilError(t, err) - req = &adminv1.CreatePackageRequest{} - err = v.Validate(req) - assert.Error(t, err, `validation error: + req := &adminv1.CreatePackageRequest{ + Name: "asdf", + Path: []string{"/tmp"}, + } + err = v.Validate(req) + assert.NilError(t, err) + }) + + t.Run("Reports validation issues", func(t *testing.T) { + t.Parallel() + + v, err := protovalidate.New() + assert.NilError(t, err) + + req := &adminv1.CreatePackageRequest{ + MetadataSetId: &wrapperspb.StringValue{ + Value: "12345", + }, + } + err = v.Validate(req) + + assert.Error(t, err, `validation error: - name: value length must be at least 1 characters [string.min_len] - - path: value must contain at least 1 item(s) [repeated.min_items]`) + - path: value must contain at least 1 item(s) [repeated.min_items] + - metadata_set_id: value must be a valid UUID [string.uuid]`) + }) } diff --git a/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1/admin.pb.go b/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1/admin.pb.go index 9e27e31aa..8515862b2 100644 --- a/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1/admin.pb.go +++ b/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1/admin.pb.go @@ -108,7 +108,7 @@ type CreatePackageRequest struct { // be relative to the location. The strings should be base64-encoded. Path []string `protobuf:"bytes,5,rep,name=path,proto3" json:"path,omitempty"` // The identifier of the metadata set to be included in this submission. - MetadataSetId string `protobuf:"bytes,6,opt,name=metadata_set_id,json=metadataSetId,proto3" json:"metadata_set_id,omitempty"` + MetadataSetId *wrapperspb.StringValue `protobuf:"bytes,6,opt,name=metadata_set_id,json=metadataSetId,proto3" json:"metadata_set_id,omitempty"` // An option to auto-approve the package. It is enabled by default. AutoApprove *wrapperspb.BoolValue `protobuf:"bytes,7,opt,name=auto_approve,json=autoApprove,proto3" json:"auto_approve,omitempty"` // Name of the processing configuration file to be included. @@ -182,11 +182,11 @@ func (x *CreatePackageRequest) GetPath() []string { return nil } -func (x *CreatePackageRequest) GetMetadataSetId() string { +func (x *CreatePackageRequest) GetMetadataSetId() *wrapperspb.StringValue { if x != nil { return x.MetadataSetId } - return "" + return nil } func (x *CreatePackageRequest) GetAutoApprove() *wrapperspb.BoolValue { @@ -613,7 +613,7 @@ var file_archivematica_ccp_admin_v1beta1_admin_proto_rawDesc = []byte{ 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, - 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x03, 0x0a, 0x14, + 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xad, 0x03, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, @@ -629,128 +629,130 @@ var file_archivematica_ccp_admin_v1beta1_admin_proto_rawDesc = []byte{ 0x73, 0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x42, 0x13, 0xba, 0x48, 0x10, 0x92, 0x01, 0x0d, 0x08, 0x01, 0x10, 0xf4, 0x03, 0x18, 0x01, 0x22, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, - 0x26, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x5f, - 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, - 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x41, - 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, - 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x22, 0x27, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x16, - 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, - 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, - 0x74, 0x6f, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, - 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, - 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x29, 0x0a, 0x17, 0x41, 0x70, 0x70, 0x72, 0x6f, + 0x4e, 0x0a, 0x0f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x65, 0x74, 0x5f, + 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x08, 0xba, 0x48, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, + 0x52, 0x0d, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x53, 0x65, 0x74, 0x49, 0x64, 0x12, + 0x3d, 0x0a, 0x0c, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x61, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x6f, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x12, 0x2b, + 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x27, 0x0a, 0x15, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x79, 0x0a, 0x16, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x41, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2d, 0x2e, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x29, 0x0a, 0x17, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, + 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x1b, 0x0a, 0x19, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x32, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x35, 0x0a, 0x1d, 0x4c, + 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, + 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x21, 0x0a, 0x1f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, + 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x8d, 0x02, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, + 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x52, 0x41, 0x4e, + 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x4e, 0x53, + 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, + 0x44, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5a, 0x49, 0x50, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x12, + 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x5a, 0x49, 0x50, 0x50, 0x45, 0x44, 0x5f, 0x42, 0x41, 0x47, 0x10, 0x03, 0x12, + 0x1c, 0x0a, 0x18, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x5a, 0x49, 0x50, 0x50, 0x45, 0x44, 0x5f, 0x42, 0x41, 0x47, 0x10, 0x04, 0x12, 0x18, 0x0a, + 0x14, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, + 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x4e, 0x53, + 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x41, 0x49, 0x4c, 0x44, 0x49, 0x52, + 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x49, 0x4d, 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x52, + 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41, + 0x56, 0x45, 0x52, 0x53, 0x45, 0x10, 0x08, 0x32, 0xe8, 0x05, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x80, 0x01, 0x0a, 0x0d, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x35, 0x2e, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x36, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, + 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x86, 0x01, 0x0a, 0x0f, + 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, + 0x37, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, + 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, + 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x1b, 0x0a, 0x19, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, - 0x32, 0x0a, 0x1a, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, - 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x22, 0x1e, 0x0a, 0x1c, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, - 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x22, 0x35, 0x0a, 0x1d, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, - 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x20, 0x0a, 0x1e, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x21, 0x0a, 0x1f, - 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, - 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, - 0x8d, 0x02, 0x0a, 0x0c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x1d, 0x0a, 0x19, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, - 0x1a, 0x0a, 0x16, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x53, 0x54, 0x41, 0x4e, 0x44, 0x41, 0x52, 0x44, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x54, - 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5a, 0x49, 0x50, - 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x02, 0x12, 0x1e, 0x0a, 0x1a, 0x54, 0x52, 0x41, 0x4e, 0x53, - 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x5a, 0x49, 0x50, 0x50, 0x45, - 0x44, 0x5f, 0x42, 0x41, 0x47, 0x10, 0x03, 0x12, 0x1c, 0x0a, 0x18, 0x54, 0x52, 0x41, 0x4e, 0x53, - 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x5a, 0x49, 0x50, 0x50, 0x45, 0x44, 0x5f, - 0x42, 0x41, 0x47, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, - 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x53, 0x50, 0x41, 0x43, 0x45, 0x10, 0x05, 0x12, - 0x19, 0x0a, 0x15, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, - 0x5f, 0x4d, 0x41, 0x49, 0x4c, 0x44, 0x49, 0x52, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x54, 0x52, - 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x54, 0x52, 0x49, 0x4d, - 0x10, 0x07, 0x12, 0x1b, 0x0a, 0x17, 0x54, 0x52, 0x41, 0x4e, 0x53, 0x46, 0x45, 0x52, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x44, 0x41, 0x54, 0x41, 0x56, 0x45, 0x52, 0x53, 0x45, 0x10, 0x08, 0x32, - 0xe8, 0x05, 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x80, 0x01, 0x0a, 0x0d, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x12, 0x35, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, - 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x61, 0x72, 0x63, 0x68, - 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x86, 0x01, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, - 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x12, 0x37, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x8f, 0x01, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, + 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, - 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x38, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, + 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x98, 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, + 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x3d, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2e, 0x41, 0x70, 0x70, 0x72, 0x6f, 0x76, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x66, - 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x8f, 0x01, 0x0a, - 0x12, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x73, 0x12, 0x3a, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, - 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, - 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x3b, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, + 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x3e, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x76, 0x65, 0x50, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x98, - 0x01, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, - 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x3d, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, + 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, + 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x2e, + 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, + 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, + 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, + 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, + 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, + 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0xbd, 0x02, 0x0a, 0x23, 0x63, 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, - 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3e, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, - 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x41, 0x77, - 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x9e, 0x01, 0x0a, 0x17, 0x52, 0x65, - 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, - 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x41, - 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x40, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, - 0x41, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0xbd, 0x02, 0x0a, 0x23, 0x63, - 0x6f, 0x6d, 0x2e, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, - 0x2e, 0x63, 0x63, 0x70, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x42, 0x0a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, - 0x5a, 0x6b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x74, - 0x65, 0x66, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x2f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, - 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x68, 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x63, 0x70, 0x2f, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, - 0x2f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x63, - 0x63, 0x70, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, - 0x41, 0x43, 0x41, 0xaa, 0x02, 0x1f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, - 0x69, 0x63, 0x61, 0x2e, 0x43, 0x63, 0x70, 0x2e, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x31, - 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1f, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, - 0x61, 0x74, 0x69, 0x63, 0x61, 0x5c, 0x43, 0x63, 0x70, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, - 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x2b, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, - 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x5c, 0x43, 0x63, 0x70, 0x5c, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x22, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, - 0x61, 0x74, 0x69, 0x63, 0x61, 0x3a, 0x3a, 0x43, 0x63, 0x70, 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, - 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x69, 0x6e, 0x2e, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x0a, 0x41, 0x64, 0x6d, 0x69, + 0x6e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x6b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x72, 0x74, 0x65, 0x66, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, + 0x2f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x68, + 0x61, 0x63, 0x6b, 0x2f, 0x63, 0x63, 0x70, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, + 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x63, 0x63, 0x70, 0x2f, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2f, 0x76, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x76, 0x31, + 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x41, 0x43, 0x41, 0xaa, 0x02, 0x1f, 0x41, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x2e, 0x43, 0x63, 0x70, 0x2e, + 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1f, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x5c, 0x43, 0x63, + 0x70, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, + 0x02, 0x2b, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x5c, + 0x43, 0x63, 0x70, 0x5c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x5c, 0x56, 0x31, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x22, + 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x3a, 0x3a, 0x43, + 0x63, 0x70, 0x3a, 0x3a, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -779,27 +781,29 @@ var file_archivematica_ccp_admin_v1beta1_admin_proto_goTypes = []interface{}{ (*ListAwaitingDecisionsResponse)(nil), // 8: archivematica.ccp.admin.v1beta1.ListAwaitingDecisionsResponse (*ResolveAwaitingDecisionRequest)(nil), // 9: archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionRequest (*ResolveAwaitingDecisionResponse)(nil), // 10: archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionResponse - (*wrapperspb.BoolValue)(nil), // 11: google.protobuf.BoolValue + (*wrapperspb.StringValue)(nil), // 11: google.protobuf.StringValue + (*wrapperspb.BoolValue)(nil), // 12: google.protobuf.BoolValue } var file_archivematica_ccp_admin_v1beta1_admin_proto_depIdxs = []int32{ 0, // 0: archivematica.ccp.admin.v1beta1.CreatePackageRequest.type:type_name -> archivematica.ccp.admin.v1beta1.TransferType - 11, // 1: archivematica.ccp.admin.v1beta1.CreatePackageRequest.auto_approve:type_name -> google.protobuf.BoolValue - 0, // 2: archivematica.ccp.admin.v1beta1.ApproveTransferRequest.type:type_name -> archivematica.ccp.admin.v1beta1.TransferType - 1, // 3: archivematica.ccp.admin.v1beta1.AdminService.CreatePackage:input_type -> archivematica.ccp.admin.v1beta1.CreatePackageRequest - 3, // 4: archivematica.ccp.admin.v1beta1.AdminService.ApproveTransfer:input_type -> archivematica.ccp.admin.v1beta1.ApproveTransferRequest - 5, // 5: archivematica.ccp.admin.v1beta1.AdminService.ListActivePackages:input_type -> archivematica.ccp.admin.v1beta1.ListActivePackagesRequest - 7, // 6: archivematica.ccp.admin.v1beta1.AdminService.ListAwaitingDecisions:input_type -> archivematica.ccp.admin.v1beta1.ListAwaitingDecisionsRequest - 9, // 7: archivematica.ccp.admin.v1beta1.AdminService.ResolveAwaitingDecision:input_type -> archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionRequest - 2, // 8: archivematica.ccp.admin.v1beta1.AdminService.CreatePackage:output_type -> archivematica.ccp.admin.v1beta1.CreatePackageResponse - 4, // 9: archivematica.ccp.admin.v1beta1.AdminService.ApproveTransfer:output_type -> archivematica.ccp.admin.v1beta1.ApproveTransferResponse - 6, // 10: archivematica.ccp.admin.v1beta1.AdminService.ListActivePackages:output_type -> archivematica.ccp.admin.v1beta1.ListActivePackagesResponse - 8, // 11: archivematica.ccp.admin.v1beta1.AdminService.ListAwaitingDecisions:output_type -> archivematica.ccp.admin.v1beta1.ListAwaitingDecisionsResponse - 10, // 12: archivematica.ccp.admin.v1beta1.AdminService.ResolveAwaitingDecision:output_type -> archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionResponse - 8, // [8:13] is the sub-list for method output_type - 3, // [3:8] is the sub-list for method input_type - 3, // [3:3] is the sub-list for extension type_name - 3, // [3:3] is the sub-list for extension extendee - 0, // [0:3] is the sub-list for field type_name + 11, // 1: archivematica.ccp.admin.v1beta1.CreatePackageRequest.metadata_set_id:type_name -> google.protobuf.StringValue + 12, // 2: archivematica.ccp.admin.v1beta1.CreatePackageRequest.auto_approve:type_name -> google.protobuf.BoolValue + 0, // 3: archivematica.ccp.admin.v1beta1.ApproveTransferRequest.type:type_name -> archivematica.ccp.admin.v1beta1.TransferType + 1, // 4: archivematica.ccp.admin.v1beta1.AdminService.CreatePackage:input_type -> archivematica.ccp.admin.v1beta1.CreatePackageRequest + 3, // 5: archivematica.ccp.admin.v1beta1.AdminService.ApproveTransfer:input_type -> archivematica.ccp.admin.v1beta1.ApproveTransferRequest + 5, // 6: archivematica.ccp.admin.v1beta1.AdminService.ListActivePackages:input_type -> archivematica.ccp.admin.v1beta1.ListActivePackagesRequest + 7, // 7: archivematica.ccp.admin.v1beta1.AdminService.ListAwaitingDecisions:input_type -> archivematica.ccp.admin.v1beta1.ListAwaitingDecisionsRequest + 9, // 8: archivematica.ccp.admin.v1beta1.AdminService.ResolveAwaitingDecision:input_type -> archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionRequest + 2, // 9: archivematica.ccp.admin.v1beta1.AdminService.CreatePackage:output_type -> archivematica.ccp.admin.v1beta1.CreatePackageResponse + 4, // 10: archivematica.ccp.admin.v1beta1.AdminService.ApproveTransfer:output_type -> archivematica.ccp.admin.v1beta1.ApproveTransferResponse + 6, // 11: archivematica.ccp.admin.v1beta1.AdminService.ListActivePackages:output_type -> archivematica.ccp.admin.v1beta1.ListActivePackagesResponse + 8, // 12: archivematica.ccp.admin.v1beta1.AdminService.ListAwaitingDecisions:output_type -> archivematica.ccp.admin.v1beta1.ListAwaitingDecisionsResponse + 10, // 13: archivematica.ccp.admin.v1beta1.AdminService.ResolveAwaitingDecision:output_type -> archivematica.ccp.admin.v1beta1.ResolveAwaitingDecisionResponse + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name } func init() { file_archivematica_ccp_admin_v1beta1_admin_proto_init() } diff --git a/hack/ccp/internal/controller/controller.go b/hack/ccp/internal/controller/controller.go index 6cb27153e..8505d9408 100644 --- a/hack/ccp/internal/controller/controller.go +++ b/hack/ccp/internal/controller/controller.go @@ -102,35 +102,22 @@ func (c *Controller) Run() error { return nil } -// Submit a new package to the queue. +// Submit a transfer request. func (c *Controller) Submit(ctx context.Context, req *adminv1.CreatePackageRequest) (*Package, error) { - // 1. Create Package (Transfer). - // transfer = models.Transfer.objects.create(**kwargs) - // if not processing_configuration_file_exists(processing_config): processing_config = "default" - // transfer.set_processing_configuration(processing_config) - // transfer.update_active_agent(user_id) - // 2. Create temporary directory inside sharedDir/tmp. - // tmpdir = mkdtemp(dir=os.path.join(_get_setting("SHARED_DIRECTORY"), "tmp")) - // 3. Identify starting point. - // starting_point = PACKAGE_TYPE_STARTING_POINTS.get(type_) - // 4. Start creation. - // params = (transfer, name, path, tmpdir, starting_point) - // if auto_approve: - // params = params + (workflow, package_queue) - // result = executor.submit(_start_package_transfer_with_auto_approval, *params) - // else: - // result = executor.submit(_start_package_transfer, *params) - // 5. Adjust permissions? - // result.add_done_callback(lambda f: os.chmod(tmpdir, 0o770)) - - pkg, err := NewTransferPackage(c.groupCtx, c.logger.WithName("package"), c.store, c.sharedDir, req) + // TODO: have NewTransferPackage return a function we can schedule here. + var once sync.Once + queue := func(pkg *Package) { + once.Do(func() { + c.queue(pkg) + c.pick() // Start work right away, we don't want to wait for the next tick. + }) + } + + pkg, err := NewTransferPackage(c.groupCtx, c.logger.WithName("package"), c.store, c.ssclient, c.sharedDir, req, queue) if err != nil { return nil, fmt.Errorf("create package: %v", err) } - c.queue(pkg) - c.pick() // Start work right away, we don't want to wait for the next tick. - return pkg, nil } diff --git a/hack/ccp/internal/controller/iterator.go b/hack/ccp/internal/controller/iterator.go index 1eae8489d..5ba0a3d02 100644 --- a/hack/ccp/internal/controller/iterator.go +++ b/hack/ccp/internal/controller/iterator.go @@ -75,7 +75,7 @@ func NewIterator(logger logr.Logger, gearman *gearmin.Server, wf *workflow.Docum gearman: gearman, wf: wf, p: p, - startAt: p.watchedAt.ChainID, + startAt: p.startAt, waitCh: make(chan waitSignal, 10), } diff --git a/hack/ccp/internal/controller/package.go b/hack/ccp/internal/controller/package.go index 075a87f95..51acf0bb2 100644 --- a/hack/ccp/internal/controller/package.go +++ b/hack/ccp/internal/controller/package.go @@ -18,6 +18,7 @@ import ( adminv1 "github.com/artefactual/archivematica/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1" "github.com/artefactual/archivematica/hack/ccp/internal/python" + "github.com/artefactual/archivematica/hack/ccp/internal/ssclient" "github.com/artefactual/archivematica/hack/ccp/internal/store" "github.com/artefactual/archivematica/hack/ccp/internal/store/enums" "github.com/artefactual/archivematica/hack/ccp/internal/workflow" @@ -42,9 +43,8 @@ type Package struct { // Current path, populated by hydrate(). path string - // Watched directory workflow document. Used by the iterator to discover - // the starting chain. - watchedAt *workflow.WatchedDirectory + // Identifier of the chain where the iterator must start processing. + startAt uuid.UUID // User decisinon manager decision decision @@ -68,7 +68,7 @@ func NewPackage(ctx context.Context, logger logr.Logger, store store.Store, shar pkg := newPackage(logger, store, sharedDir) pkg.path = path - pkg.watchedAt = wd + pkg.startAt = wd.ChainID switch { case wd.UnitType == "Transfer": @@ -89,30 +89,119 @@ func NewPackage(ctx context.Context, logger logr.Logger, store store.Store, shar } // NewTransferPackage creates a new package after an API request. -func NewTransferPackage(ctx context.Context, logger logr.Logger, store store.Store, sharedDir string, req *adminv1.CreatePackageRequest) (*Package, error) { - pkg := &Package{ - logger: logger, - store: store, +// +// 1. Create Package (Transfer). +// transfer = models.Transfer.objects.create(**kwargs) +// if not processing_configuration_file_exists(processing_config): processing_config = "default" +// transfer.set_processing_configuration(processing_config) +// transfer.update_active_agent(user_id) +// +// 2. Create temporary directory inside sharedDir/tmp. [DONE] +// tmpdir = mkdtemp(dir=os.path.join(_get_setting("SHARED_DIRECTORY"), "tmp")) +// +// 3. Identify starting point. [DONE] +// starting_point = PACKAGE_TYPE_STARTING_POINTS.get(type_) +// +// 4. Start creation. +// params = (transfer, name, path, tmpdir, starting_point) +// if auto_approve: +// params = params + (workflow, package_queue) +// result = executor.submit(_start_package_transfer_with_auto_approval, *params) +// else: +// result = executor.submit(_start_package_transfer, *params) +// +// 5. Adjust permissions? +// result.add_done_callback(lambda f: os.chmod(tmpdir, 0o770)) +func NewTransferPackage( + ctx context.Context, + logger logr.Logger, + store store.Store, + ssclient ssclient.Client, + sharedDir string, + req *adminv1.CreatePackageRequest, + queue func(pkg *Package), +) (*Package, error) { + // TODO: implement transfer submissions without auto-approval (see: copyTransferIntoActiveTransfers). + autoApprove := req.AutoApprove == nil || req.AutoApprove.Value + if !autoApprove { + return nil, errors.New("submissions with auto-approve disabled are not supported yet") } + pkg := newPackage(logger, store, sharedDir) + pkg.id = uuid.New() pkg.unit = &Transfer{pkg: pkg} + pkg.startAt = Transfers.WithType(req.Type).Chain + + var msID uuid.UUID + if req.MetadataSetId != nil { + msID, _ = uuid.Parse(req.MetadataSetId.Value) + } - tmpDir, err := os.MkdirTemp(filepath.Join(sharedDir, "tmp"), "") + err := store.CreateTransfer(ctx, pkg.id, req.Accession, req.AccessSystemId, msID) if err != nil { return nil, err } - transferType := Transfers.WithName("standard") - - logger.Info("Here we are.", "tmpdir", tmpDir, "transferType", transferType) + if req.ProcessingConfig == "" { + req.ProcessingConfig = "default" + } + if err := pkg.saveValue(ctx, "processingConfiguration", req.ProcessingConfig); err != nil { + return nil, err + } - if err := pkg.hydrate(ctx, "", ""); err != nil { - return nil, fmt.Errorf("hydrate: %v", err) + if err := pkg.updateActiveAgent(ctx, "TODO"); err != nil { + return nil, err } + // TODO: copy of transfer needs to happen asynchronously because we can't + // block the user request. This should however be done within workflow for + // better tracking. + // + // Perhaps for now we can have a pool to cap the total amount of work that + // we are willing to do at any given time, i.e. to be nice with Storage. + go func() (err error) { + logger := logger + + defer func() { + if err != nil { + logger.Info("Opsie!", "err", err) + } else { + logger.Info("Done!") + } + }() + + // Create temporary directory. + tmpDir, err := os.MkdirTemp(filepath.Join(sharedDir, "tmp"), "") + if err != nil { + return err + } + _ = os.Chmod(tmpDir, os.FileMode(0o770)) + logger = logger.WithValues("tmpDir", tmpDir) + + // Copy into new location. + path, err := copyTransfer(ctx, ssclient, sharedDir, tmpDir, req.Name, req.Path[0]) + if err != nil { + return fmt.Errorf("copy transfer: %v", err) + } + pkg.UpdatePath(path) + logger = logger.WithValues("path", path) + if err := store.UpdateTransferLocation(ctx, pkg.id, path); err != nil { + logger.Info("Unable to update the transfer location.", "id", pkg.id, "path", path, "err", err) + } + + queue(pkg) // Start work. + + return nil + }() // nolint:errcheck + return pkg, nil } +// ID returns the identifier of the package. +func (p *Package) ID() uuid.UUID { + return p.id +} + // Path returns the real (no share dir vars) path to the package. func (p *Package) Path() string { return strings.Replace(p.path, "%sharedPath%", p.sharedDir, 1) @@ -315,6 +404,10 @@ func (p *Package) markAsDone(ctx context.Context) error { return p.store.UpdatePackageStatus(ctx, p.id, p.packageType(), enums.PackageStatusDone) } +func (p *Package) updateActiveAgent(ctx context.Context, userID string) error { + return nil // TODO: we have not implemented auth yet! +} + // unit represents logic that is specific to a particular type of package, e.g. Transfer. type unit interface { // hydrate assits NewPackage in creating a package record in the database. diff --git a/hack/ccp/internal/controller/path.go b/hack/ccp/internal/controller/path.go index f5c0fa253..267686368 100644 --- a/hack/ccp/internal/controller/path.go +++ b/hack/ccp/internal/controller/path.go @@ -22,15 +22,43 @@ func uuidFromPath(path string) uuid.UUID { } // joinPath is like filepath.Join but appends the ending separator when the last -// element provided is an empty string. +// element provided is an empty string or ends with a slash. func joinPath(elem ...string) string { - if len(elem) == 0 { + const sep = string(os.PathSeparator) + ln := len(elem) + if ln == 0 { return "" } ret := filepath.Join(elem...) - if elem[len(elem)-1] == "" { - ret += string(os.PathSeparator) + last := elem[ln-1] + if last == "" || strings.HasSuffix(last, sep) { + ret += sep } return ret } + +// locationPath extracts the location identifier and path from a locationPath. +// It returs the nil value of uuid.UUID (uuid.Nil) when the identifier is not +// part of the path. +func locationPath(locationPath string) (id uuid.UUID, path string) { + before, after, found := strings.Cut(locationPath, ":") + + if found { + id, _ = uuid.Parse(before) + path = after + } else { + path = before + } + + return id, path +} + +func isDir(path string) bool { + info, err := os.Stat(path) + if err != nil { + return false + } + + return info.IsDir() +} diff --git a/hack/ccp/internal/controller/path_test.go b/hack/ccp/internal/controller/path_test.go index 6401cb8ae..6a7f0201c 100644 --- a/hack/ccp/internal/controller/path_test.go +++ b/hack/ccp/internal/controller/path_test.go @@ -59,6 +59,10 @@ func TestJoinPath(t *testing.T) { elem: []string{"a", "b", "c"}, want: "a/b/c", }, + { + elem: []string{"a", "b/"}, + want: "a/b/", + }, { elem: nil, want: "", @@ -72,3 +76,34 @@ func TestJoinPath(t *testing.T) { }) } } + +func TestLocationPath(t *testing.T) { + t.Parallel() + + tests := []struct { + arg string + id uuid.UUID + path string + }{ + { + arg: "c059a454-dafa-418e-a126-74d0c7219ce6:/tmp", + id: uuid.MustParse("c059a454-dafa-418e-a126-74d0c7219ce6"), + path: "/tmp", + }, + { + arg: "/tmp", + id: uuid.Nil, + path: "/tmp", + }, + { + arg: "12345:/tmp", + id: uuid.Nil, + path: "/tmp", + }, + } + for _, tc := range tests { + id, path := locationPath(tc.arg) + assert.Equal(t, id, tc.id) + assert.Equal(t, path, tc.path) + } +} diff --git a/hack/ccp/internal/controller/source.go b/hack/ccp/internal/controller/source.go index 7b849b363..6f9bb1b41 100644 --- a/hack/ccp/internal/controller/source.go +++ b/hack/ccp/internal/controller/source.go @@ -12,6 +12,7 @@ import ( "github.com/artefactual/archivematica/hack/ccp/internal/derrors" "github.com/artefactual/archivematica/hack/ccp/internal/ssclient" + "github.com/artefactual/archivematica/hack/ccp/internal/ssclient/enums" ) // This file contains functions that relate to the process of retrieving @@ -19,7 +20,7 @@ import ( // Archivematica Storage Service. This is built after what we have in the // `server.packages` Python module. -// StartTransfer starts a transfer. +// copyTransfer copies the contents of a transfer into the processing directory. // // The transfer is deposited into the internal processing directory and the // workflow is triggered manually. @@ -27,27 +28,25 @@ import ( // This method does not rely on the activeTransfer watched directory. It does // not prompt the user to accept the transfer because we go directly into the // next chain link. -func StartTransfer(ctx context.Context, ssclient ssclient.Client, sharedDir, tmpDir, name, path string) error { - destRel, destAbs, src := determineTransferPaths(sharedDir, tmpDir, name, path) - fmt.Println(destRel, destAbs, src) +func copyTransfer(ctx context.Context, ssclient ssclient.Client, sharedDir, tmpDir, name, path string) (string, error) { + destRel, destAbs, _ := determineTransferPaths(sharedDir, tmpDir, name, path) - _ = copyFromTransferSources(ctx, ssclient, []string{path}, destRel) + if err := copyFromTransferSources(ctx, ssclient, sharedDir, []string{path}, destRel); err != nil { + return "", err + } - tsrc, tdst := "", "" - dst, err := moveToInternalSharedDir(sharedDir, tsrc, tdst) + final, err := moveToInternalSharedDir( + destAbs, + filepath.Join(joinPath(sharedDir, "currentlyProcessing")), + ) if err != nil { - return err + return "", err } - fmt.Println("The transfer is now in the internal processing directory!", dst) - - // TODO: update transfer.currentlocation in the database. - // TODO: schedule job chain. - - return nil + return final, err } -// StartTransferWithWatchedDir starts a transfer using watched directories. +// copyTransferIntoActiveTransfers starts a transfer using watched directories. // // This means copying the transfer into one of the standard watched dirs. // MCPServer will continue the processing and prompt the user once the @@ -56,7 +55,7 @@ func StartTransfer(ctx context.Context, ssclient ssclient.Client, sharedDir, tmp // // With this method of starting a transfer, the workflow requires user approval. // This allows for adding metadata to the transfer before accepting it. -func StartTransferWithWatchedDir() { +func copyTransferIntoActiveTransfers() { // nolint: unused panic("not implemented") // _determine_transfer_paths // _copy_from_transfer_sources @@ -64,19 +63,6 @@ func StartTransferWithWatchedDir() { // update transfer.currentlocation with the new destination } -func locationPath(locPath string) (id uuid.UUID, path string) { - before, after, found := strings.Cut(locPath, ":") - - if found { - id, _ = uuid.Parse(before) - path = after - } else { - path = before - } - - return id, path -} - // determineTransferPaths // // name and path are part of the client transfer request. @@ -110,28 +96,28 @@ func determineTransferPaths(sharedDir, tmpDir, name, path string) (string, strin } // moveToInternalSharedDir moves a transfer into an internal directory. -func moveToInternalSharedDir(sharedDir, path, dest string) (_ string, err error) { - defer derrors.Add(&err, "moveToInternalSharedDir(%s, %s, %s)", sharedDir, path, dest) +func moveToInternalSharedDir(src, dst string) (_ string, err error) { + defer derrors.Add(&err, "moveToInternalSharedDir(%s, %s)", src, dst) // Validate path. - if path == "" { + if src == "" { return "", errors.New("no path provided") } - if strings.Contains(path, "..") { + if strings.Contains(src, "..") { return "", errors.New("illegal path") } - if _, err := os.Stat(path); os.IsNotExist(err) { + if _, err := os.Stat(src); os.IsNotExist(err) { return "", errors.New("path does not exist") } var ( attempt = 0 - suggested = filepath.Join(dest, filepath.Base(path)) + suggested = filepath.Join(dst, filepath.Base(src)) newPath = suggested ) for { if _, err := os.Stat(newPath); os.IsNotExist(err) { - if err := os.Rename(path, newPath); os.IsExist(err) { + if err := os.Rename(src, newPath); os.IsExist(err) { goto incr // Magic! } else if err != nil { return "", err @@ -146,18 +132,18 @@ func moveToInternalSharedDir(sharedDir, path, dest string) (_ string, err error) return "", fmt.Errorf("reached max. number of attempts: %d", attempt) } - ext := filepath.Ext(dest) + ext := filepath.Ext(dst) base := strings.TrimSuffix(suggested, ext) newPath = fmt.Sprintf("%s_%d%s", base, attempt, ext) } } -func copyFromTransferSources(ctx context.Context, c ssclient.Client, paths []string, destRel string) (err error) { +func copyFromTransferSources(ctx context.Context, c ssclient.Client, sharedDir string, paths []string, destRel string) (err error) { derrors.Add(&err, "copyFromTransferSources()") // We'll use the default transfer source location when a request does not // indicate its source. - defaultTransferSource, err := c.ReadDefaultLocation(ctx, "TS") + defaultTransferSource, err := c.ReadDefaultLocation(ctx, enums.LocationPurposeTS) if err != nil { return err } @@ -170,7 +156,7 @@ func copyFromTransferSources(ctx context.Context, c ssclient.Client, paths []str // filesByLocID is a list of all the copy operations that we'll be making, // indexed by the identifier of the transfer source location. - transferSources, err := c.ListLocations(ctx, "", "TS") + transferSources, err := c.ListLocations(ctx, "", enums.LocationPurposeTS) if err != nil { return err } @@ -178,9 +164,9 @@ func copyFromTransferSources(ctx context.Context, c ssclient.Client, paths []str transferSource *ssclient.Location files [][2]string // src, dst } - filesByLocID := map[uuid.UUID]sourceFiles{} + filesByLocID := map[uuid.UUID]*sourceFiles{} for _, loc := range transferSources { - filesByLocID[loc.ID] = sourceFiles{ + filesByLocID[loc.ID] = &sourceFiles{ transferSource: loc, files: [][2]string{}, } @@ -196,24 +182,34 @@ func copyFromTransferSources(ctx context.Context, c ssclient.Client, paths []str return fmt.Errorf("location %s is not associated with this pipeline", locID) } + dir := isDir(filepath.Join(sharedDir, "tmp", strings.TrimPrefix("/", destRel))) + + // Source relative to the transfer source path. source := strings.Replace(path, ops.transferSource.Path, "", 1) source = strings.TrimPrefix(source, "/") + // # Use the last segment of the path for the destination - basename for + // # a file, or the last folder if not. Keep the trailing / for folders. + // + // TODO: this is broken. var lastSegment string - if strings.HasSuffix(source, "/") { - lastSegment = joinPath(filepath.Base(strings.TrimSuffix(source, "/")), "") + if dir { + lastSegment = joinPath(filepath.Base(filepath.Dir(source)), "") } else { lastSegment = filepath.Base(source) } - - destination := filepath.Join(currentlyProcessing.Path, destRel, lastSegment) + destination := joinPath(currentlyProcessing.Path, destRel, lastSegment) destination = strings.Replace(destination, "%sharedPath%", "", 1) + // { + // "archivematica/archivematica-sampledata/SampleTransfers/Images/pictures" + // "/var/archivematica/sharedDirectory/tmp/3598350318/Prueba/Images/" + // } ops.files = append(ops.files, [2]string{source, destination}) } for _, sf := range filesByLocID { - if copyErr := c.MoveFiles(ctx, sf.transferSource, currentlyProcessing, sf.files); err != nil { + if copyErr := c.MoveFiles(ctx, sf.transferSource, currentlyProcessing, sf.files); copyErr != nil { err = errors.Join(err, copyErr) } } diff --git a/hack/ccp/internal/controller/source_test.go b/hack/ccp/internal/controller/source_test.go index b96b796ac..7f97c4963 100644 --- a/hack/ccp/internal/controller/source_test.go +++ b/hack/ccp/internal/controller/source_test.go @@ -4,7 +4,6 @@ import ( "path/filepath" "testing" - "github.com/google/uuid" "gotest.tools/v3/assert" "gotest.tools/v3/fs" ) @@ -100,7 +99,6 @@ func TestMoveToInternalSharedDir(t *testing.T) { ) dest, err := moveToInternalSharedDir( - tmpDir.Join("sharedDir"), tmpDir.Join("source", "Images"), tmpDir.Join("sharedDir", "deposits"), ) @@ -109,34 +107,3 @@ func TestMoveToInternalSharedDir(t *testing.T) { assert.Equal(t, dest, tmpDir.Join("sharedDir", "deposits", filepath.Base(dest))) assert.Assert(t, fs.Equal(dest, fs.Expected(t, fs.WithFile("MARBLES.TGA", "contents"), fs.MatchAnyFileMode))) } - -func TestLocationPath(t *testing.T) { - t.Parallel() - - tests := []struct { - arg string - id uuid.UUID - path string - }{ - { - arg: "c059a454-dafa-418e-a126-74d0c7219ce6:/tmp", - id: uuid.MustParse("c059a454-dafa-418e-a126-74d0c7219ce6"), - path: "/tmp", - }, - { - arg: "/tmp", - id: uuid.Nil, - path: "/tmp", - }, - { - arg: "12345:/tmp", - id: uuid.Nil, - path: "/tmp", - }, - } - for _, tc := range tests { - id, path := locationPath(tc.arg) - assert.Equal(t, id, tc.id) - assert.Equal(t, path, tc.path) - } -} diff --git a/hack/ccp/internal/controller/transfer.go b/hack/ccp/internal/controller/transfer.go index 2555dfde2..9edb13e52 100644 --- a/hack/ccp/internal/controller/transfer.go +++ b/hack/ccp/internal/controller/transfer.go @@ -4,6 +4,7 @@ import ( "github.com/google/uuid" adminv1 "github.com/artefactual/archivematica/hack/ccp/internal/api/gen/archivematica/ccp/admin/v1beta1" + "github.com/artefactual/archivematica/hack/ccp/internal/workflow" ) type TransferType struct { @@ -29,6 +30,10 @@ type TransferType struct { Decision uuid.UUID } +func (t TransferType) WatchedDirDoc(wf *workflow.Document) *workflow.WatchedDirectory { + return nil +} + type TransferTypes []TransferType // Decide resolves the workflow decision point that implements the approval. diff --git a/hack/ccp/internal/python/python.go b/hack/ccp/internal/python/python.go index cfaf8623d..8263a92a3 100644 --- a/hack/ccp/internal/python/python.go +++ b/hack/ccp/internal/python/python.go @@ -11,7 +11,7 @@ import ( func eval(literal string) (starlark.Value, error) { thread := &starlark.Thread{Name: "main"} - fileOptions := syntax.FileOptions{ + fileOptions := &syntax.FileOptions{ Set: false, While: false, TopLevelControl: false, @@ -25,7 +25,7 @@ func eval(literal string) (starlark.Value, error) { return nil, fmt.Errorf("parse expression: %v", err) } - val, err := starlark.EvalExpr(thread, expr, nil) + val, err := starlark.EvalExprOptions(fileOptions, thread, expr, nil) if err != nil { return nil, fmt.Errorf("eval expression: %v", err) } diff --git a/hack/ccp/internal/servercmd/cmd.go b/hack/ccp/internal/servercmd/cmd.go index 48f76b613..287c99408 100644 --- a/hack/ccp/internal/servercmd/cmd.go +++ b/hack/ccp/internal/servercmd/cmd.go @@ -31,7 +31,7 @@ func New(rootConfig *rootcmd.Config, out io.Writer) *ffcli.Command { fs.StringVar(&cfg.workflow, "workflow", "", "Workflow document") fs.StringVar(&cfg.db.driver, "db.driver", "", "Database driver") fs.StringVar(&cfg.db.dsn, "db.dsn", "", "Database DSN") - fs.StringVar(&cfg.api.admin.Addr, "api.admin.addr", "", "Admin API listen address") + fs.StringVar(&cfg.api.admin.Addr, "api.admin.addr", ":8000", "Admin API listen address") fs.StringVar(&cfg.gearmin.addr, "gearmin.addr", ":4730", "Gearmin job server listen address") fs.StringVar(&cfg.ssclient.BaseURL, "ssclient.url", "", "Storage Service API base URL") fs.StringVar(&cfg.ssclient.Username, "ssclient.username", "", "Storage Service API username") diff --git a/hack/ccp/internal/servercmd/server.go b/hack/ccp/internal/servercmd/server.go index 6ed37e962..9ebeb2269 100644 --- a/hack/ccp/internal/servercmd/server.go +++ b/hack/ccp/internal/servercmd/server.go @@ -109,8 +109,9 @@ func (s *Server) Run() error { } s.logger.V(1).Info("Creating ssclient.") - httpClient := retryablehttp.NewClient().StandardClient() - ssclient, err := ssclient.NewClient(httpClient, s.store, s.config.ssclient) + retryableClient := retryablehttp.NewClient() + retryableClient.Logger = nil + ssclient, err := ssclient.NewClient(retryableClient.StandardClient(), s.store, s.config.ssclient) if err != nil { return fmt.Errorf("error creating ssclient: %v", err) } diff --git a/hack/ccp/internal/ssclient/convert.go b/hack/ccp/internal/ssclient/convert.go index d3feaa844..5384f37fe 100644 --- a/hack/ccp/internal/ssclient/convert.go +++ b/hack/ccp/internal/ssclient/convert.go @@ -6,6 +6,7 @@ import ( "go.artefactual.dev/tools/ref" "github.com/artefactual/archivematica/hack/ccp/internal/derrors" + "github.com/artefactual/archivematica/hack/ccp/internal/ssclient/enums" ) // TODO: why is kiota using ptrs for mandatory fields? @@ -41,10 +42,7 @@ func convertLocation(m models.Locationable) (_ *Location, err error) { r.Path = ref.DerefZero(m.GetPath()) r.RelativePath = ref.DerefZero(m.GetRelativePath()) r.Pipelines = m.GetPipeline() - - if ps := m.GetPurpose(); ps != nil { - r.Purpose = ps.String() - } + r.Purpose = enums.LocationPurpose(ref.DerefDefault(m.GetPurpose(), -1)) return r, nil } diff --git a/hack/ccp/internal/ssclient/enums/location_purpose.go b/hack/ccp/internal/ssclient/enums/location_purpose.go new file mode 100644 index 000000000..c2cc92939 --- /dev/null +++ b/hack/ccp/internal/ssclient/enums/location_purpose.go @@ -0,0 +1,16 @@ +package enums + +// LocationPurpose is a our local version of the enum in ssclient-go. +// +// ENUM( +// AR +// AS +// CP +// DS +// SD +// SS +// BL +// TS +// RP +// ). +type LocationPurpose int diff --git a/hack/ccp/internal/ssclient/enums/location_purpose_enum.go b/hack/ccp/internal/ssclient/enums/location_purpose_enum.go new file mode 100644 index 000000000..6da321e03 --- /dev/null +++ b/hack/ccp/internal/ssclient/enums/location_purpose_enum.go @@ -0,0 +1,228 @@ +// Code generated by go-enum DO NOT EDIT. +// Version: 0.6.0 +// Revision: 919e61c0174b91303753ee3898569a01abb32c97 +// Build Date: 2023-12-18T15:54:43Z +// Built By: goreleaser + +package enums + +import ( + "database/sql/driver" + "errors" + "fmt" + "strings" +) + +const ( + // LocationPurposeAR is a LocationPurpose of type AR. + LocationPurposeAR LocationPurpose = iota + // LocationPurposeAS is a LocationPurpose of type AS. + LocationPurposeAS + // LocationPurposeCP is a LocationPurpose of type CP. + LocationPurposeCP + // LocationPurposeDS is a LocationPurpose of type DS. + LocationPurposeDS + // LocationPurposeSD is a LocationPurpose of type SD. + LocationPurposeSD + // LocationPurposeSS is a LocationPurpose of type SS. + LocationPurposeSS + // LocationPurposeBL is a LocationPurpose of type BL. + LocationPurposeBL + // LocationPurposeTS is a LocationPurpose of type TS. + LocationPurposeTS + // LocationPurposeRP is a LocationPurpose of type RP. + LocationPurposeRP +) + +var ErrInvalidLocationPurpose = fmt.Errorf("not a valid LocationPurpose, try [%s]", strings.Join(_LocationPurposeNames, ", ")) + +const _LocationPurposeName = "ARASCPDSSDSSBLTSRP" + +var _LocationPurposeNames = []string{ + _LocationPurposeName[0:2], + _LocationPurposeName[2:4], + _LocationPurposeName[4:6], + _LocationPurposeName[6:8], + _LocationPurposeName[8:10], + _LocationPurposeName[10:12], + _LocationPurposeName[12:14], + _LocationPurposeName[14:16], + _LocationPurposeName[16:18], +} + +// LocationPurposeNames returns a list of possible string values of LocationPurpose. +func LocationPurposeNames() []string { + tmp := make([]string, len(_LocationPurposeNames)) + copy(tmp, _LocationPurposeNames) + return tmp +} + +var _LocationPurposeMap = map[LocationPurpose]string{ + LocationPurposeAR: _LocationPurposeName[0:2], + LocationPurposeAS: _LocationPurposeName[2:4], + LocationPurposeCP: _LocationPurposeName[4:6], + LocationPurposeDS: _LocationPurposeName[6:8], + LocationPurposeSD: _LocationPurposeName[8:10], + LocationPurposeSS: _LocationPurposeName[10:12], + LocationPurposeBL: _LocationPurposeName[12:14], + LocationPurposeTS: _LocationPurposeName[14:16], + LocationPurposeRP: _LocationPurposeName[16:18], +} + +// String implements the Stringer interface. +func (x LocationPurpose) String() string { + if str, ok := _LocationPurposeMap[x]; ok { + return str + } + return fmt.Sprintf("LocationPurpose(%d)", x) +} + +// IsValid provides a quick way to determine if the typed value is +// part of the allowed enumerated values +func (x LocationPurpose) IsValid() bool { + _, ok := _LocationPurposeMap[x] + return ok +} + +var _LocationPurposeValue = map[string]LocationPurpose{ + _LocationPurposeName[0:2]: LocationPurposeAR, + strings.ToLower(_LocationPurposeName[0:2]): LocationPurposeAR, + _LocationPurposeName[2:4]: LocationPurposeAS, + strings.ToLower(_LocationPurposeName[2:4]): LocationPurposeAS, + _LocationPurposeName[4:6]: LocationPurposeCP, + strings.ToLower(_LocationPurposeName[4:6]): LocationPurposeCP, + _LocationPurposeName[6:8]: LocationPurposeDS, + strings.ToLower(_LocationPurposeName[6:8]): LocationPurposeDS, + _LocationPurposeName[8:10]: LocationPurposeSD, + strings.ToLower(_LocationPurposeName[8:10]): LocationPurposeSD, + _LocationPurposeName[10:12]: LocationPurposeSS, + strings.ToLower(_LocationPurposeName[10:12]): LocationPurposeSS, + _LocationPurposeName[12:14]: LocationPurposeBL, + strings.ToLower(_LocationPurposeName[12:14]): LocationPurposeBL, + _LocationPurposeName[14:16]: LocationPurposeTS, + strings.ToLower(_LocationPurposeName[14:16]): LocationPurposeTS, + _LocationPurposeName[16:18]: LocationPurposeRP, + strings.ToLower(_LocationPurposeName[16:18]): LocationPurposeRP, +} + +// ParseLocationPurpose attempts to convert a string to a LocationPurpose. +func ParseLocationPurpose(name string) (LocationPurpose, error) { + if x, ok := _LocationPurposeValue[name]; ok { + return x, nil + } + // Case insensitive parse, do a separate lookup to prevent unnecessary cost of lowercasing a string if we don't need to. + if x, ok := _LocationPurposeValue[strings.ToLower(name)]; ok { + return x, nil + } + return LocationPurpose(0), fmt.Errorf("%s is %w", name, ErrInvalidLocationPurpose) +} + +func (x LocationPurpose) Ptr() *LocationPurpose { + return &x +} + +// MarshalText implements the text marshaller method. +func (x LocationPurpose) MarshalText() ([]byte, error) { + return []byte(x.String()), nil +} + +// UnmarshalText implements the text unmarshaller method. +func (x *LocationPurpose) UnmarshalText(text []byte) error { + name := string(text) + tmp, err := ParseLocationPurpose(name) + if err != nil { + return err + } + *x = tmp + return nil +} + +var errLocationPurposeNilPtr = errors.New("value pointer is nil") // one per type for package clashes + +// Scan implements the Scanner interface. +func (x *LocationPurpose) Scan(value interface{}) (err error) { + if value == nil { + *x = LocationPurpose(0) + return + } + + // A wider range of scannable types. + // driver.Value values at the top of the list for expediency + switch v := value.(type) { + case int64: + *x = LocationPurpose(v) + case string: + *x, err = ParseLocationPurpose(v) + case []byte: + *x, err = ParseLocationPurpose(string(v)) + case LocationPurpose: + *x = v + case int: + *x = LocationPurpose(v) + case *LocationPurpose: + if v == nil { + return errLocationPurposeNilPtr + } + *x = *v + case uint: + *x = LocationPurpose(v) + case uint64: + *x = LocationPurpose(v) + case *int: + if v == nil { + return errLocationPurposeNilPtr + } + *x = LocationPurpose(*v) + case *int64: + if v == nil { + return errLocationPurposeNilPtr + } + *x = LocationPurpose(*v) + case float64: // json marshals everything as a float64 if it's a number + *x = LocationPurpose(v) + case *float64: // json marshals everything as a float64 if it's a number + if v == nil { + return errLocationPurposeNilPtr + } + *x = LocationPurpose(*v) + case *uint: + if v == nil { + return errLocationPurposeNilPtr + } + *x = LocationPurpose(*v) + case *uint64: + if v == nil { + return errLocationPurposeNilPtr + } + *x = LocationPurpose(*v) + case *string: + if v == nil { + return errLocationPurposeNilPtr + } + *x, err = ParseLocationPurpose(*v) + } + + return +} + +// Value implements the driver Valuer interface. +func (x LocationPurpose) Value() (driver.Value, error) { + return x.String(), nil +} + +// Set implements the Golang flag.Value interface func. +func (x *LocationPurpose) Set(val string) error { + v, err := ParseLocationPurpose(val) + *x = v + return err +} + +// Get implements the Golang flag.Getter interface func. +func (x *LocationPurpose) Get() interface{} { + return *x +} + +// Type implements the github.com/spf13/pFlag Value interface. +func (x *LocationPurpose) Type() string { + return "LocationPurpose" +} diff --git a/hack/ccp/internal/ssclient/ssclient.go b/hack/ccp/internal/ssclient/ssclient.go index 7b4e65c73..325f506f5 100644 --- a/hack/ccp/internal/ssclient/ssclient.go +++ b/hack/ccp/internal/ssclient/ssclient.go @@ -1,24 +1,24 @@ package ssclient import ( + "bytes" "context" "errors" "fmt" "net/http" - "strings" "sync" "time" "github.com/google/uuid" - kiotaabs "github.com/microsoft/kiota-abstractions-go" - kiotahttp "github.com/microsoft/kiota-http-go" + "github.com/hashicorp/go-retryablehttp" + "github.com/microsoft/kiota-abstractions-go/serialization" ssclientlib "go.artefactual.dev/ssclient" - "go.artefactual.dev/ssclient/kiota" "go.artefactual.dev/ssclient/kiota/api" "go.artefactual.dev/ssclient/kiota/models" "go.artefactual.dev/tools/ref" "github.com/artefactual/archivematica/hack/ccp/internal/derrors" + "github.com/artefactual/archivematica/hack/ccp/internal/ssclient/enums" "github.com/artefactual/archivematica/hack/ccp/internal/store" ) @@ -32,7 +32,7 @@ type Pipeline struct { type Location struct { ID uuid.UUID URI string - Purpose string + Purpose enums.LocationPurpose Path string RelativePath string Pipelines []string @@ -43,9 +43,9 @@ type Location struct { // to page results and populate the default location. type Client interface { ReadPipeline(ctx context.Context, id uuid.UUID) (*Pipeline, error) - ReadDefaultLocation(ctx context.Context, purpose string) (*Location, error) + ReadDefaultLocation(ctx context.Context, purpose enums.LocationPurpose) (*Location, error) ReadProcessingLocation(ctx context.Context) (*Location, error) - ListLocations(ctx context.Context, path, purpose string) ([]*Location, error) + ListLocations(ctx context.Context, path string, purpose enums.LocationPurpose) ([]*Location, error) // MoveFiles moves files between locations. `files` is a list of pairs // indicating the paths of the source file and its destination (both paths @@ -55,8 +55,9 @@ type Client interface { // clientImpl implements Client. type clientImpl struct { - client *kiota.Client + client *api.V2RequestBuilder store store.Store + config *Config // Cached pipeline with the last retrieval timestamp and protected. p *Pipeline @@ -67,23 +68,20 @@ type clientImpl struct { var _ Client = (*clientImpl)(nil) func NewClient(httpClient *http.Client, store store.Store, config Config) (*clientImpl, error) { - if httpClient == nil { - httpClient = http.DefaultClient - } k, err := ssclientlib.New(httpClient, config.BaseURL, config.Username, config.Key) if err != nil { return nil, err } - c := &clientImpl{client: k, store: store} + c := &clientImpl{client: k.Api().V2(), store: store, config: &config} return c, nil } func (c *clientImpl) ReadPipeline(ctx context.Context, id uuid.UUID) (_ *Pipeline, err error) { - derrors.Add(&err, "ReadPipeline(%s)", id) + defer derrors.Add(&err, "ReadPipeline(%s)", id) - m, err := c.client.Api().V2().Pipeline().ByUuid(id.String()).Get(ctx, nil) + m, err := c.client.Pipeline().ByUuid(id.String()).Get(ctx, nil) if err != nil { return nil, err } @@ -96,37 +94,25 @@ func (c *clientImpl) ReadPipeline(ctx context.Context, id uuid.UUID) (_ *Pipelin return p, nil } -func (c *clientImpl) ReadDefaultLocation(ctx context.Context, purpose string) (_ *Location, err error) { - derrors.Add(&err, "ReadDefaultLocation(%s)", purpose) +func (c *clientImpl) ReadDefaultLocation(ctx context.Context, purpose enums.LocationPurpose) (_ *Location, err error) { + defer derrors.Add(&err, "ReadDefaultLocation(%s)", purpose) p, err := c.pipeline(ctx) if err != nil { return nil, err } - headerOptions := kiotahttp.NewHeadersInspectionOptions() - headerOptions.InspectResponseHeaders = true - - reqConfig := &api.V2LocationDefaultWithPurposeItemRequestBuilderGetRequestConfiguration{ - Options: []kiotaabs.RequestOption{headerOptions}, - } - if err := c.client.Api().V2().Location().DefaultEscaped().ByPurpose(purpose).Get(ctx, reqConfig); err != nil { - return nil, err - } - - uris := headerOptions.ResponseHeaders.Get("Location") - if len(uris) < 1 { - return nil, ErrLocationNotAvailable - } - uri := uris[0] - if uri == "" { - return nil, ErrLocationNotAvailable - } - - // Capture the UUID in the URI, e.g. "/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0/". - id := strings.TrimSuffix(strings.TrimPrefix(uri, "/api/v2/location/"), "/") - - res, err := c.client.Api().V2().Location().ByUuid(id).Get(ctx, nil) + // We're asking for a models.Locationable using ByUuuid while rewriting the + // URL template to hit the Default Location API instead. ssclient-go follows + // the redirects automatically, so we don't have to. + // + // I originally tried to inspect the Location header but DefaultEscaped() + // is returning the location itself anyways. I tried to pass options to the + // redirect handler but it's ignoring me. + req := c.client.Location().ByUuid(uuid.Nil.String()) + req.UrlTemplate = fmt.Sprintf("{+baseurl}/api/v2/location/default/%s/", purpose.String()) + + res, err := req.Get(ctx, nil) if err != nil { return nil, err } @@ -152,9 +138,9 @@ func (c *clientImpl) ReadDefaultLocation(ctx context.Context, purpose string) (_ } func (c *clientImpl) ReadProcessingLocation(ctx context.Context) (_ *Location, err error) { - derrors.Add(&err, "ReadProcessingLocation") + defer derrors.Add(&err, "ReadProcessingLocation") - res, err := c.ListLocations(ctx, "", models.CP_LOCATIONPURPOSE.String()) + res, err := c.ListLocations(ctx, "", enums.LocationPurposeCP) if err != nil { return nil, err } @@ -167,8 +153,8 @@ func (c *clientImpl) ReadProcessingLocation(ctx context.Context) (_ *Location, e return res[0], nil } -func (c *clientImpl) ListLocations(ctx context.Context, path, purpose string) (_ []*Location, err error) { - derrors.Add(&err, "ListLocations(%s, %s)", path, purpose) +func (c *clientImpl) ListLocations(ctx context.Context, path string, purpose enums.LocationPurpose) (_ []*Location, err error) { + defer derrors.Add(&err, "ListLocations(%s, %s)", path, purpose) p, err := c.pipeline(ctx) if err != nil { @@ -186,19 +172,10 @@ func (c *clientImpl) ListLocations(ctx context.Context, path, purpose string) (_ reqConfig.QueryParameters.Relative_path = &path } - if purpose != "" { - ps, err := models.ParseLocationPurpose(purpose) - if err != nil { - return nil, err - } - if mps, ok := ps.(*models.LocationPurpose); ok { - reqConfig.QueryParameters.PurposeAsLocationPurpose = mps - } else { - return nil, fmt.Errorf("invalid purpose value: %v", ps) - } - } + ps := models.LocationPurpose(int(purpose)) + reqConfig.QueryParameters.PurposeAsLocationPurpose = &ps - list, err := c.client.Api().V2().Location().Get(ctx, reqConfig) + list, err := c.client.Location().Get(ctx, reqConfig) if err != nil { return nil, err } @@ -217,7 +194,7 @@ func (c *clientImpl) ListLocations(ctx context.Context, path, purpose string) (_ } func (c *clientImpl) MoveFiles(ctx context.Context, src, dst *Location, files [][2]string) (err error) { - derrors.Add(&err, "MoveFiles()") + defer derrors.Add(&err, "MoveFiles()") p, err := c.pipeline(ctx) if err != nil { @@ -237,7 +214,25 @@ func (c *clientImpl) MoveFiles(ctx context.Context, src, dst *Location, files [] } body.SetFiles(moves) - _, err = c.client.Api().V2().Location().ByUuid(dst.ID.String()).Post(ctx, body, nil) + // TODO: why is this not working? + // _, err = c.client.Location().ByUuid(dst.ID.String()).Post(context.Background(), body, nil) + + payload, err := serialization.SerializeToJson(body) + if err != nil { + return err + } + httpClient := retryablehttp.NewClient().StandardClient() + url := fmt.Sprintf("%s/api/v2/location/%s/", c.config.BaseURL, dst.ID.String()) + req, _ := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(payload)) + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", fmt.Sprintf("ApiKey %s:%s", c.config.Username, c.config.Key)) + resp, err := httpClient.Do(req) + if err != nil { + return err + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("request not ok: status code %d", resp.StatusCode) + } return err } diff --git a/hack/ccp/internal/ssclient/ssclient_test.go b/hack/ccp/internal/ssclient/ssclient_test.go index 0057976be..709ea8b94 100644 --- a/hack/ccp/internal/ssclient/ssclient_test.go +++ b/hack/ccp/internal/ssclient/ssclient_test.go @@ -13,6 +13,7 @@ import ( "gotest.tools/v3/assert/cmp" "github.com/artefactual/archivematica/hack/ccp/internal/ssclient" + "github.com/artefactual/archivematica/hack/ccp/internal/ssclient/enums" "github.com/artefactual/archivematica/hack/ccp/internal/store/storemock" ) @@ -56,7 +57,7 @@ func TestClient(t *testing.T) { _, err := c.ReadPipeline(ctx, uuid.Nil) - assert.Assert(t, cmp.ErrorIs(err, context.Canceled)) + assert.Assert(t, cmp.ErrorContains(err, "context canceled")) }, }, @@ -79,34 +80,31 @@ func TestClient(t *testing.T) { }) // It looks up the default location for the given purpose. - s.ExpectGet("/api/v2/location/default/AS"). - ReturnHeader("Location", "/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0/") - - // It looks up the location to confirm that is available to this pipeline. - s.ExpectGet("/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0"). + // The redirect is followed, we're returning the Location instead. + s.ExpectGet("/api/v2/location/default/AS/"). ReturnHeader("Content-Type", "application/json"). Return(`{ - "description": "Store AIP in standard Archivematica Directory", - "enabled": true, - "path": "/var/archivematica/sharedDirectory/www/AIPsStore", - "pipeline": ["/api/v2/pipeline/fb2b8866-6f39-4616-b6cd-fa73193a3b05/"], - "purpose": "AS", - "quota": null, - "relative_path": "var/archivematica/sharedDirectory/www/AIPsStore", - "resource_uri": "/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0/", - "space": "/api/v2/space/b4785c92-74c5-44d0-8d48-7f776fa55da7/", - "used": 0, - "uuid": "be68cfa8-d32a-44ba-a140-2ec5d6b903e0" - }`) + "description": "Store AIP in standard Archivematica Directory", + "enabled": true, + "path": "/var/archivematica/sharedDirectory/www/AIPsStore", + "pipeline": ["/api/v2/pipeline/fb2b8866-6f39-4616-b6cd-fa73193a3b05/"], + "purpose": "AS", + "quota": null, + "relative_path": "var/archivematica/sharedDirectory/www/AIPsStore", + "resource_uri": "/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0/", + "space": "/api/v2/space/b4785c92-74c5-44d0-8d48-7f776fa55da7/", + "used": 0, + "uuid": "be68cfa8-d32a-44ba-a140-2ec5d6b903e0" + }`) }), client: func(t *testing.T, c ssclient.Client) { - ret, err := c.ReadDefaultLocation(context.Background(), "AS") + ret, err := c.ReadDefaultLocation(context.Background(), enums.LocationPurposeAS) assert.NilError(t, err) assert.DeepEqual(t, ret, &ssclient.Location{ ID: uuid.MustParse("be68cfa8-d32a-44ba-a140-2ec5d6b903e0"), URI: "/api/v2/location/be68cfa8-d32a-44ba-a140-2ec5d6b903e0/", - Purpose: "AS", + Purpose: enums.LocationPurposeAS, Path: "/var/archivematica/sharedDirectory/www/AIPsStore", RelativePath: "var/archivematica/sharedDirectory/www/AIPsStore", Pipelines: []string{"/api/v2/pipeline/fb2b8866-6f39-4616-b6cd-fa73193a3b05/"}, @@ -167,7 +165,7 @@ func TestClient(t *testing.T) { assert.DeepEqual(t, ret, &ssclient.Location{ ID: uuid.MustParse("df192133-3b13-4292-a219-50887d285cb3"), URI: "/api/v2/location/df192133-3b13-4292-a219-50887d285cb3/", - Purpose: "CP", + Purpose: enums.LocationPurposeCP, Path: "/var/archivematica/sharedDirectory", RelativePath: "var/archivematica/sharedDirectory/", Pipelines: []string{"/api/v2/pipeline/fb2b8866-6f39-4616-b6cd-fa73193a3b05/"}, @@ -222,14 +220,14 @@ func TestClient(t *testing.T) { }`) }), client: func(t *testing.T, c ssclient.Client) { - ret, err := c.ListLocations(context.Background(), "", "DS") + ret, err := c.ListLocations(context.Background(), "", enums.LocationPurposeDS) assert.NilError(t, err) assert.DeepEqual(t, ret, []*ssclient.Location{ { ID: uuid.MustParse("18d6c0c4-afcd-4ee5-a9b0-19158cb199af"), URI: "/api/v2/location/18d6c0c4-afcd-4ee5-a9b0-19158cb199af/", - Purpose: "DS", + Purpose: enums.LocationPurposeDS, Path: "/var/archivematica/sharedDirectory/www/DIPsStore", RelativePath: "var/archivematica/sharedDirectory/www/DIPsStore", Pipelines: []string{"/api/v2/pipeline/fb2b8866-6f39-4616-b6cd-fa73193a3b05/"}, diff --git a/hack/ccp/internal/ssclient/ssclientmock/mock_ssclient.go b/hack/ccp/internal/ssclient/ssclientmock/mock_ssclient.go index 8bbfb5e0a..2ce22e06f 100644 --- a/hack/ccp/internal/ssclient/ssclientmock/mock_ssclient.go +++ b/hack/ccp/internal/ssclient/ssclientmock/mock_ssclient.go @@ -14,6 +14,7 @@ import ( reflect "reflect" ssclient "github.com/artefactual/archivematica/hack/ccp/internal/ssclient" + enums "github.com/artefactual/archivematica/hack/ccp/internal/ssclient/enums" uuid "github.com/google/uuid" gomock "go.uber.org/mock/gomock" ) @@ -41,85 +42,85 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder { return m.recorder } -// CopyFiles mocks base method. -func (m *MockClient) CopyFiles(ctx context.Context, l *ssclient.Location, files []string) error { +// ListLocations mocks base method. +func (m *MockClient) ListLocations(ctx context.Context, path string, purpose enums.LocationPurpose) ([]*ssclient.Location, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CopyFiles", ctx, l, files) - ret0, _ := ret[0].(error) - return ret0 + ret := m.ctrl.Call(m, "ListLocations", ctx, path, purpose) + ret0, _ := ret[0].([]*ssclient.Location) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// CopyFiles indicates an expected call of CopyFiles. -func (mr *MockClientMockRecorder) CopyFiles(ctx, l, files any) *MockClientCopyFilesCall { +// ListLocations indicates an expected call of ListLocations. +func (mr *MockClientMockRecorder) ListLocations(ctx, path, purpose any) *MockClientListLocationsCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CopyFiles", reflect.TypeOf((*MockClient)(nil).CopyFiles), ctx, l, files) - return &MockClientCopyFilesCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListLocations", reflect.TypeOf((*MockClient)(nil).ListLocations), ctx, path, purpose) + return &MockClientListLocationsCall{Call: call} } -// MockClientCopyFilesCall wrap *gomock.Call -type MockClientCopyFilesCall struct { +// MockClientListLocationsCall wrap *gomock.Call +type MockClientListLocationsCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockClientCopyFilesCall) Return(arg0 error) *MockClientCopyFilesCall { - c.Call = c.Call.Return(arg0) +func (c *MockClientListLocationsCall) Return(arg0 []*ssclient.Location, arg1 error) *MockClientListLocationsCall { + c.Call = c.Call.Return(arg0, arg1) return c } // Do rewrite *gomock.Call.Do -func (c *MockClientCopyFilesCall) Do(f func(context.Context, *ssclient.Location, []string) error) *MockClientCopyFilesCall { +func (c *MockClientListLocationsCall) Do(f func(context.Context, string, enums.LocationPurpose) ([]*ssclient.Location, error)) *MockClientListLocationsCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockClientCopyFilesCall) DoAndReturn(f func(context.Context, *ssclient.Location, []string) error) *MockClientCopyFilesCall { +func (c *MockClientListLocationsCall) DoAndReturn(f func(context.Context, string, enums.LocationPurpose) ([]*ssclient.Location, error)) *MockClientListLocationsCall { c.Call = c.Call.DoAndReturn(f) return c } -// ListLocations mocks base method. -func (m *MockClient) ListLocations(ctx context.Context, path, purpose string) ([]*ssclient.Location, error) { +// MoveFiles mocks base method. +func (m *MockClient) MoveFiles(ctx context.Context, src, dst *ssclient.Location, files [][2]string) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListLocations", ctx, path, purpose) - ret0, _ := ret[0].([]*ssclient.Location) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "MoveFiles", ctx, src, dst, files) + ret0, _ := ret[0].(error) + return ret0 } -// ListLocations indicates an expected call of ListLocations. -func (mr *MockClientMockRecorder) ListLocations(ctx, path, purpose any) *MockClientListLocationsCall { +// MoveFiles indicates an expected call of MoveFiles. +func (mr *MockClientMockRecorder) MoveFiles(ctx, src, dst, files any) *MockClientMoveFilesCall { mr.mock.ctrl.T.Helper() - call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListLocations", reflect.TypeOf((*MockClient)(nil).ListLocations), ctx, path, purpose) - return &MockClientListLocationsCall{Call: call} + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MoveFiles", reflect.TypeOf((*MockClient)(nil).MoveFiles), ctx, src, dst, files) + return &MockClientMoveFilesCall{Call: call} } -// MockClientListLocationsCall wrap *gomock.Call -type MockClientListLocationsCall struct { +// MockClientMoveFilesCall wrap *gomock.Call +type MockClientMoveFilesCall struct { *gomock.Call } // Return rewrite *gomock.Call.Return -func (c *MockClientListLocationsCall) Return(arg0 []*ssclient.Location, arg1 error) *MockClientListLocationsCall { - c.Call = c.Call.Return(arg0, arg1) +func (c *MockClientMoveFilesCall) Return(arg0 error) *MockClientMoveFilesCall { + c.Call = c.Call.Return(arg0) return c } // Do rewrite *gomock.Call.Do -func (c *MockClientListLocationsCall) Do(f func(context.Context, string, string) ([]*ssclient.Location, error)) *MockClientListLocationsCall { +func (c *MockClientMoveFilesCall) Do(f func(context.Context, *ssclient.Location, *ssclient.Location, [][2]string) error) *MockClientMoveFilesCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockClientListLocationsCall) DoAndReturn(f func(context.Context, string, string) ([]*ssclient.Location, error)) *MockClientListLocationsCall { +func (c *MockClientMoveFilesCall) DoAndReturn(f func(context.Context, *ssclient.Location, *ssclient.Location, [][2]string) error) *MockClientMoveFilesCall { c.Call = c.Call.DoAndReturn(f) return c } // ReadDefaultLocation mocks base method. -func (m *MockClient) ReadDefaultLocation(ctx context.Context, purpose string) (*ssclient.Location, error) { +func (m *MockClient) ReadDefaultLocation(ctx context.Context, purpose enums.LocationPurpose) (*ssclient.Location, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ReadDefaultLocation", ctx, purpose) ret0, _ := ret[0].(*ssclient.Location) @@ -146,13 +147,13 @@ func (c *MockClientReadDefaultLocationCall) Return(arg0 *ssclient.Location, arg1 } // Do rewrite *gomock.Call.Do -func (c *MockClientReadDefaultLocationCall) Do(f func(context.Context, string) (*ssclient.Location, error)) *MockClientReadDefaultLocationCall { +func (c *MockClientReadDefaultLocationCall) Do(f func(context.Context, enums.LocationPurpose) (*ssclient.Location, error)) *MockClientReadDefaultLocationCall { c.Call = c.Call.Do(f) return c } // DoAndReturn rewrite *gomock.Call.DoAndReturn -func (c *MockClientReadDefaultLocationCall) DoAndReturn(f func(context.Context, string) (*ssclient.Location, error)) *MockClientReadDefaultLocationCall { +func (c *MockClientReadDefaultLocationCall) DoAndReturn(f func(context.Context, enums.LocationPurpose) (*ssclient.Location, error)) *MockClientReadDefaultLocationCall { c.Call = c.Call.DoAndReturn(f) return c } @@ -195,3 +196,42 @@ func (c *MockClientReadPipelineCall) DoAndReturn(f func(context.Context, uuid.UU c.Call = c.Call.DoAndReturn(f) return c } + +// ReadProcessingLocation mocks base method. +func (m *MockClient) ReadProcessingLocation(ctx context.Context) (*ssclient.Location, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ReadProcessingLocation", ctx) + ret0, _ := ret[0].(*ssclient.Location) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ReadProcessingLocation indicates an expected call of ReadProcessingLocation. +func (mr *MockClientMockRecorder) ReadProcessingLocation(ctx any) *MockClientReadProcessingLocationCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadProcessingLocation", reflect.TypeOf((*MockClient)(nil).ReadProcessingLocation), ctx) + return &MockClientReadProcessingLocationCall{Call: call} +} + +// MockClientReadProcessingLocationCall wrap *gomock.Call +type MockClientReadProcessingLocationCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockClientReadProcessingLocationCall) Return(arg0 *ssclient.Location, arg1 error) *MockClientReadProcessingLocationCall { + c.Call = c.Call.Return(arg0, arg1) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockClientReadProcessingLocationCall) Do(f func(context.Context) (*ssclient.Location, error)) *MockClientReadProcessingLocationCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockClientReadProcessingLocationCall) DoAndReturn(f func(context.Context) (*ssclient.Location, error)) *MockClientReadProcessingLocationCall { + c.Call = c.Call.DoAndReturn(f) + return c +} diff --git a/hack/ccp/internal/store/mysql.go b/hack/ccp/internal/store/mysql.go index 9e24f349c..346ab3bc1 100644 --- a/hack/ccp/internal/store/mysql.go +++ b/hack/ccp/internal/store/mysql.go @@ -214,6 +214,24 @@ func (s *mysqlStoreImpl) ReadTransferLocation(ctx context.Context, id uuid.UUID) return ret.Currentlocation, nil } +func (s *mysqlStoreImpl) CreateTransfer(ctx context.Context, id uuid.UUID, accessionID, accessSystemID string, metadataSetID uuid.UUID) (err error) { + defer wrap(&err, "CreateTransfer(%s, %s, %s, %d)", id, accessionID, accessSystemID, metadataSetID) + + params := &sqlc.CreateTransferParams{ + Transferuuid: id, + Accessionid: accessionID, + AccessSystemID: accessSystemID, + } + if metadataSetID != uuid.Nil { + params.Transfermetadatasetrowuuid = uuid.NullUUID{ + UUID: metadataSetID, + Valid: true, + } + } + + return s.queries.CreateTransfer(ctx, params) +} + func (s *mysqlStoreImpl) UpsertTransfer(ctx context.Context, id uuid.UUID, path string) (_ bool, err error) { defer wrap(&err, "UpsertTransfer(%s, %s)", id, path) @@ -292,6 +310,15 @@ func (s *mysqlStoreImpl) EnsureTransfer(ctx context.Context, path string) (_ uui return id, false, nil // Transfer found! } +func (s *mysqlStoreImpl) UpdateTransferLocation(ctx context.Context, id uuid.UUID, path string) (err error) { + defer wrap(&err, "UpdateTransferLocation(%s, %s)", id, path) + + return s.queries.UpdateTransferLocation(ctx, &sqlc.UpdateTransferLocationParams{ + Transferuuid: id, + Currentlocation: path, + }) +} + func (s *mysqlStoreImpl) ReadSIP(ctx context.Context, id uuid.UUID) (_ SIP, err error) { defer wrap(&err, "ReadSIP(%s)", id) diff --git a/hack/ccp/internal/store/sqlcmysql/models.go b/hack/ccp/internal/store/sqlcmysql/models.go index 852916216..cb6859285 100644 --- a/hack/ccp/internal/store/sqlcmysql/models.go +++ b/hack/ccp/internal/store/sqlcmysql/models.go @@ -606,7 +606,7 @@ type Transfer struct { Description string Notes string Hidden bool - Transfermetadatasetrowuuid uuid.UUID + Transfermetadatasetrowuuid uuid.NullUUID Diruuids bool AccessSystemID string CompletedAt sql.NullTime diff --git a/hack/ccp/internal/store/sqlcmysql/query.sql.go b/hack/ccp/internal/store/sqlcmysql/query.sql.go index a834277dd..69b878aba 100644 --- a/hack/ccp/internal/store/sqlcmysql/query.sql.go +++ b/hack/ccp/internal/store/sqlcmysql/query.sql.go @@ -127,17 +127,27 @@ func (q *Queries) CreateSIP(ctx context.Context, arg *CreateSIPParams) error { const createTransfer = `-- name: CreateTransfer :exec -INSERT INTO Transfers (transferUUID, currentLocation, type, accessionID, sourceOfAcquisition, typeOfTransfer, description, notes, access_system_id, hidden, transferMetadataSetRowUUID, dirUUIDs, status, completed_at) VALUES (?, ?, '', '', '', '', '', '', '', 0, NULL, 0, 0, NULL) +INSERT INTO Transfers (transferUUID, currentLocation, type, accessionID, sourceOfAcquisition, typeOfTransfer, description, notes, access_system_id, hidden, transferMetadataSetRowUUID, dirUUIDs, status, completed_at) +VALUES (?, ?, '', ?, '', '', '', '', ?, 0, ?, 0, 0, NULL) ` type CreateTransferParams struct { - Transferuuid uuid.UUID - Currentlocation string + Transferuuid uuid.UUID + Currentlocation string + Accessionid string + AccessSystemID string + Transfermetadatasetrowuuid uuid.NullUUID } // Transfers func (q *Queries) CreateTransfer(ctx context.Context, arg *CreateTransferParams) error { - _, err := q.exec(ctx, q.createTransferStmt, createTransfer, arg.Transferuuid, arg.Currentlocation) + _, err := q.exec(ctx, q.createTransferStmt, createTransfer, + arg.Transferuuid, + arg.Currentlocation, + arg.Accessionid, + arg.AccessSystemID, + arg.Transfermetadatasetrowuuid, + ) return err } diff --git a/hack/ccp/internal/store/store.go b/hack/ccp/internal/store/store.go index 5a58f4fed..82d64bd51 100644 --- a/hack/ccp/internal/store/store.go +++ b/hack/ccp/internal/store/store.go @@ -37,6 +37,9 @@ type Store interface { // ReadTransferLocation returns the current path of a Transfer. ReadTransferLocation(ctx context.Context, id uuid.UUID) (loc string, err error) + // CreateTransfer creates a new transfer not downloaded yet (without path). + CreateTransfer(ctx context.Context, id uuid.UUID, accessionID, accessSystemID string, metadataSetID uuid.UUID) (err error) + // UpsertTransfer checks for a Transfer using the specified UUID. It updates // the current location if the Transfer exists, or it creates a new Transfer // with the provided UUID and location if it does not exist. @@ -46,6 +49,9 @@ type Store interface { // a new Transfer with a new UUID otherwise. EnsureTransfer(ctx context.Context, path string) (id uuid.UUID, created bool, err error) + // UpdateTransferLocation updates the current location of a given transfer. + UpdateTransferLocation(ctx context.Context, id uuid.UUID, path string) error + // ReadSIP returns a SIP given its identifier. ReadSIP(ctx context.Context, id uuid.UUID) (sip SIP, err error) diff --git a/hack/ccp/internal/store/storemock/mock_store.go b/hack/ccp/internal/store/storemock/mock_store.go index 9aec07b71..2267f3854 100644 --- a/hack/ccp/internal/store/storemock/mock_store.go +++ b/hack/ccp/internal/store/storemock/mock_store.go @@ -157,6 +157,44 @@ func (c *MockStoreCreateTasksCall) DoAndReturn(f func(context.Context, []*store. return c } +// CreateTransfer mocks base method. +func (m *MockStore) CreateTransfer(ctx context.Context, id uuid.UUID, accessionID, accessSystemID string, metadataSetID uuid.UUID) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "CreateTransfer", ctx, id, accessionID, accessSystemID, metadataSetID) + ret0, _ := ret[0].(error) + return ret0 +} + +// CreateTransfer indicates an expected call of CreateTransfer. +func (mr *MockStoreMockRecorder) CreateTransfer(ctx, id, accessionID, accessSystemID, metadataSetID any) *MockStoreCreateTransferCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTransfer", reflect.TypeOf((*MockStore)(nil).CreateTransfer), ctx, id, accessionID, accessSystemID, metadataSetID) + return &MockStoreCreateTransferCall{Call: call} +} + +// MockStoreCreateTransferCall wrap *gomock.Call +type MockStoreCreateTransferCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockStoreCreateTransferCall) Return(err error) *MockStoreCreateTransferCall { + c.Call = c.Call.Return(err) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockStoreCreateTransferCall) Do(f func(context.Context, uuid.UUID, string, string, uuid.UUID) error) *MockStoreCreateTransferCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockStoreCreateTransferCall) DoAndReturn(f func(context.Context, uuid.UUID, string, string, uuid.UUID) error) *MockStoreCreateTransferCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // CreateUnitVar mocks base method. func (m *MockStore) CreateUnitVar(ctx context.Context, id uuid.UUID, packageType enums.PackageType, name, value string, linkID uuid.UUID, update bool) error { m.ctrl.T.Helper() @@ -857,6 +895,44 @@ func (c *MockStoreUpdatePackageStatusCall) DoAndReturn(f func(context.Context, u return c } +// UpdateTransferLocation mocks base method. +func (m *MockStore) UpdateTransferLocation(ctx context.Context, id uuid.UUID, path string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateTransferLocation", ctx, id, path) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateTransferLocation indicates an expected call of UpdateTransferLocation. +func (mr *MockStoreMockRecorder) UpdateTransferLocation(ctx, id, path any) *MockStoreUpdateTransferLocationCall { + mr.mock.ctrl.T.Helper() + call := mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTransferLocation", reflect.TypeOf((*MockStore)(nil).UpdateTransferLocation), ctx, id, path) + return &MockStoreUpdateTransferLocationCall{Call: call} +} + +// MockStoreUpdateTransferLocationCall wrap *gomock.Call +type MockStoreUpdateTransferLocationCall struct { + *gomock.Call +} + +// Return rewrite *gomock.Call.Return +func (c *MockStoreUpdateTransferLocationCall) Return(arg0 error) *MockStoreUpdateTransferLocationCall { + c.Call = c.Call.Return(arg0) + return c +} + +// Do rewrite *gomock.Call.Do +func (c *MockStoreUpdateTransferLocationCall) Do(f func(context.Context, uuid.UUID, string) error) *MockStoreUpdateTransferLocationCall { + c.Call = c.Call.Do(f) + return c +} + +// DoAndReturn rewrite *gomock.Call.DoAndReturn +func (c *MockStoreUpdateTransferLocationCall) DoAndReturn(f func(context.Context, uuid.UUID, string) error) *MockStoreUpdateTransferLocationCall { + c.Call = c.Call.DoAndReturn(f) + return c +} + // UpsertDIP mocks base method. func (m *MockStore) UpsertDIP(ctx context.Context, id uuid.UUID, path string) (bool, error) { m.ctrl.T.Helper() diff --git a/hack/ccp/proto/archivematica/ccp/admin/v1beta1/admin.proto b/hack/ccp/proto/archivematica/ccp/admin/v1beta1/admin.proto index 0f1bb31b3..c3cb55660 100644 --- a/hack/ccp/proto/archivematica/ccp/admin/v1beta1/admin.proto +++ b/hack/ccp/proto/archivematica/ccp/admin/v1beta1/admin.proto @@ -88,8 +88,9 @@ message CreatePackageRequest { }, }]; - // The identifier of the metadata set to be included in this submission. - string metadata_set_id = 6; + // The identifier (UUIDv4) of the metadata set to be included in this + // submission. + google.protobuf.StringValue metadata_set_id = 6 [(buf.validate.field).string.uuid = true]; // An option to auto-approve the package. It is enabled by default. google.protobuf.BoolValue auto_approve = 7; diff --git a/hack/ccp/sqlc/mysql/query.sql b/hack/ccp/sqlc/mysql/query.sql index 01dae44bd..b67134f22 100644 --- a/hack/ccp/sqlc/mysql/query.sql +++ b/hack/ccp/sqlc/mysql/query.sql @@ -13,7 +13,8 @@ UPDATE Jobs SET currentStep = ? WHERE jobUUID = ?; -- -- name: CreateTransfer :exec -INSERT INTO Transfers (transferUUID, currentLocation, type, accessionID, sourceOfAcquisition, typeOfTransfer, description, notes, access_system_id, hidden, transferMetadataSetRowUUID, dirUUIDs, status, completed_at) VALUES (?, ?, '', '', '', '', '', '', '', 0, NULL, 0, 0, NULL); +INSERT INTO Transfers (transferUUID, currentLocation, type, accessionID, sourceOfAcquisition, typeOfTransfer, description, notes, access_system_id, hidden, transferMetadataSetRowUUID, dirUUIDs, status, completed_at) +VALUES (?, ?, '', ?, '', '', '', '', ?, 0, ?, 0, 0, NULL); -- name: ReadTransferLocation :one SELECT transferUUID, currentLocation FROM Transfers WHERE transferUUID = ?; diff --git a/hack/ccp/sqlc/sqlc.yaml b/hack/ccp/sqlc/sqlc.yaml index 5a9b00ff3..60fba1e28 100644 --- a/hack/ccp/sqlc/sqlc.yaml +++ b/hack/ccp/sqlc/sqlc.yaml @@ -4,10 +4,10 @@ cloud: project: "01HECEDJYX2P7ZW9DJ34T9AB0Y" plugins: -- name: golang - wasm: - url: https://downloads.sqlc.dev/plugin/sqlc-gen-go_1.3.0.wasm - sha256: e8206081686f95b461daf91a307e108a761526c6768d6f3eca9781b0726b7ec8 + - name: golang + wasm: + url: https://downloads.sqlc.dev/plugin/sqlc-gen-go_1.3.0.wasm + sha256: e8206081686f95b461daf91a307e108a761526c6768d6f3eca9781b0726b7ec8 sql: - schema: mysql/schema.sql @@ -16,42 +16,51 @@ sql: database: managed: true codegen: - - plugin: golang - out: ../internal/store/sqlcmysql - options: - package: sqlcmysql - emit_interface: false - emit_prepared_queries: true - emit_empty_slices: true - emit_result_struct_pointers: true - emit_params_struct_pointers: true - rename: - "pk": "ID" - "uuid": "UUID" - "jobuuid": "ID" - "jobtype": "Type" - "sipuuid": "SIPID" - "createdtime": "CreatedAt" - "updatedtime": "UpdatedAt" - "microservicechainlink": "LinkID" - # table todo - # left: name of table, lowercase, also singualrized otherwise it doesn't match + - plugin: golang + out: ../internal/store/sqlcmysql + options: + package: sqlcmysql + emit_interface: false + emit_prepared_queries: true + emit_empty_slices: true + emit_result_struct_pointers: true + emit_params_struct_pointers: true + rename: + "pk": "ID" + "uuid": "UUID" + "jobuuid": "ID" + "jobtype": "Type" + "sipuuid": "SIPID" + "createdtime": "CreatedAt" + "updatedtime": "UpdatedAt" + "microservicechainlink": "LinkID" + # table todo + # left: name of table, lowercase, also singualrized otherwise it doesn't match - - # In overrides, `column` must refer to the table and column name in the - # database schema, but matching is only possible in lowercase. - overrides: - - column: "*.*uuid" - go_type: &t_uuid - import: "github.com/google/uuid" - package: "uuid" - type: "UUID" - pointer: false - - column: "unitvariables.pk" - go_type: *t_uuid - - column: "unitvariables.microservicechainlink" - go_type: &t_nulluuid - import: "github.com/google/uuid" - package: "uuid" - type: "NullUUID" - pointer: false + # In overrides, `column` must refer to the table and column name in the + # database schema, but matching is only possible in lowercase. + overrides: + - column: "unitvariables.microservicechainlink" + go_type: + import: "github.com/google/uuid" + package: "uuid" + type: "NullUUID" + pointer: false + - column: "transfers.transfermetadatasetrowuuid" + go_type: + import: "github.com/google/uuid" + package: "uuid" + type: "NullUUID" + pointer: false + - column: "*.*uuid" + go_type: + import: "github.com/google/uuid" + package: "uuid" + type: "UUID" + pointer: false + - column: "unitvariables.pk" + go_type: + import: "github.com/google/uuid" + package: "uuid" + type: "UUID" + pointer: false diff --git a/hack/ccp/web/src/gen/archivematica/ccp/admin/v1beta1/admin_pb.ts b/hack/ccp/web/src/gen/archivematica/ccp/admin/v1beta1/admin_pb.ts index e708bf971..d3860a26a 100644 --- a/hack/ccp/web/src/gen/archivematica/ccp/admin/v1beta1/admin_pb.ts +++ b/hack/ccp/web/src/gen/archivematica/ccp/admin/v1beta1/admin_pb.ts @@ -4,7 +4,7 @@ // @ts-nocheck import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf"; -import { BoolValue, Message, proto3 } from "@bufbuild/protobuf"; +import { BoolValue, Message, proto3, StringValue } from "@bufbuild/protobuf"; /** * Different types of transfers. @@ -114,9 +114,9 @@ export class CreatePackageRequest extends Message { /** * The identifier of the metadata set to be included in this submission. * - * @generated from field: string metadata_set_id = 6; + * @generated from field: google.protobuf.StringValue metadata_set_id = 6; */ - metadataSetId = ""; + metadataSetId?: string; /** * An option to auto-approve the package. It is enabled by default. @@ -145,7 +145,7 @@ export class CreatePackageRequest extends Message { { no: 3, name: "accession", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 4, name: "access_system_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, { no: 5, name: "path", kind: "scalar", T: 9 /* ScalarType.STRING */, repeated: true }, - { no: 6, name: "metadata_set_id", kind: "scalar", T: 9 /* ScalarType.STRING */ }, + { no: 6, name: "metadata_set_id", kind: "message", T: StringValue }, { no: 7, name: "auto_approve", kind: "message", T: BoolValue }, { no: 8, name: "processing_config", kind: "scalar", T: 9 /* ScalarType.STRING */ }, ]);