Skip to content

Commit df65573

Browse files
authored
Merge pull request #16977 from iterate-ch/bugfix/GH-16976
Allow to remove metadata
2 parents 3b6d56a + 59cf9f0 commit df65573

File tree

11 files changed

+71
-21
lines changed

11 files changed

+71
-21
lines changed

azure/src/test/java/ch/cyberduck/core/azure/AzureMetadataFeatureTest.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,16 @@ public void testSetMetadata() throws Exception {
2424
final Path container = new Path("cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
2525
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
2626
new AzureTouchFeature(session, null).touch(test, new TransferStatus());
27+
final TransferStatus status = new TransferStatus();
2728
final String v = new AlphanumericRandomStringService().random();
28-
new AzureMetadataFeature(session, null).setMetadata(test, Collections.singletonMap("Test", v));
29-
final Map<String, String> metadata = new AzureMetadataFeature(session, null).getMetadata(test);
29+
final AzureMetadataFeature feature = new AzureMetadataFeature(session, null);
30+
feature.setMetadata(test, status.setMetadata(Collections.singletonMap("Test", v)));
31+
final Map<String, String> metadata = feature.getMetadata(test);
3032
assertFalse(metadata.isEmpty());
3133
assertTrue(metadata.containsKey("Test"));
3234
assertEquals(v, metadata.get("Test"));
35+
feature.setMetadata(test, status.setMetadata(Collections.emptyMap()));
36+
assertFalse(feature.getMetadata(test).containsKey("Test"));
3337
new AzureDeleteFeature(session, null).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
3438
}
3539

googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveAttributesFinderFeature.java

+3
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,9 @@ public PathAttributes toAttributes(final File f) {
128128
.getBytes(Charset.defaultCharset()).length);
129129
}
130130
}
131+
if(null != f.getProperties()) {
132+
attributes.setMetadata(f.getProperties());
133+
}
131134
return attributes;
132135
}
133136
}

googledrive/src/main/java/ch/cyberduck/core/googledrive/DriveMetadataFeature.java

+15-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@
2323

2424
import java.io.IOException;
2525
import java.util.Collections;
26+
import java.util.HashMap;
2627
import java.util.Map;
2728

2829
import com.google.api.services.drive.model.File;
2930

31+
import static com.google.api.client.util.Data.NULL_STRING;
32+
3033
public class DriveMetadataFeature implements Metadata {
3134

3235
private final DriveSession session;
@@ -63,10 +66,18 @@ public void setMetadata(final Path file, final TransferStatus status) throws Bac
6366
try {
6467
final String fileid = this.fileid.getFileId(file);
6568
final File body = new File();
66-
body.setProperties(status.getMetadata());
67-
final File properties = session.getClient().files().update(fileid, body).setFields("properties").
68-
setSupportsAllDrives(HostPreferencesFactory.get(session.getHost()).getBoolean("googledrive.teamdrive.enable")).execute();
69-
status.setResponse(new DriveAttributesFinderFeature(session, this.fileid).toAttributes(properties));
69+
final Map<String, String> properties = new HashMap<>(status.getMetadata());
70+
for(String key : file.attributes().getMetadata().keySet()) {
71+
if(!properties.containsKey(key)) {
72+
// Entries with null values are cleared in update and copy requests
73+
properties.put(key, NULL_STRING);
74+
}
75+
}
76+
body.setProperties(properties);
77+
status.setResponse(new DriveAttributesFinderFeature(session, this.fileid).toAttributes(
78+
session.getClient().files().update(fileid, body).setFields("properties").
79+
setSupportsAllDrives(HostPreferencesFactory.get(session.getHost()).getBoolean("googledrive.teamdrive.enable")).execute()
80+
));
7081
}
7182
catch(IOException e) {
7283
throw new DriveExceptionMappingService(fileid).map("Failure to write attributes of {0}", e, file);

googledrive/src/test/java/ch/cyberduck/core/googledrive/DriveMetadataFeatureTest.java

+14-7
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import java.util.Collections;
3131
import java.util.EnumSet;
32+
import java.util.Map;
3233
import java.util.UUID;
3334

3435
import static ch.cyberduck.core.googledrive.DriveHomeFinderService.MYDRIVE_FOLDER;
@@ -39,14 +40,20 @@ public class DriveMetadataFeatureTest extends AbstractDriveTest {
3940

4041
@Test
4142
public void setMetadata() throws Exception {
42-
final Path home = DriveHomeFinderService.MYDRIVE_FOLDER;
43-
final Path test = new Path(home, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
43+
final Path test = new Path(DriveHomeFinderService.MYDRIVE_FOLDER, UUID.randomUUID().toString(), EnumSet.of(Path.Type.file));
4444
final DriveFileIdProvider fileid = new DriveFileIdProvider(session);
45-
new DriveTouchFeature(session, fileid).touch(test, new TransferStatus());
46-
assertEquals(Collections.emptyMap(), new DriveMetadataFeature(session, fileid).getMetadata(test));
47-
new DriveMetadataFeature(session, fileid).setMetadata(test, Collections.singletonMap("test", "t"));
48-
assertEquals(Collections.singletonMap("test", "t"), new DriveMetadataFeature(session, fileid).getMetadata(test));
49-
new DriveDeleteFeature(session, fileid).delete(Collections.<Path>singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
45+
final TransferStatus status = new TransferStatus();
46+
new DriveTouchFeature(session, fileid).touch(test, status);
47+
final DriveMetadataFeature feature = new DriveMetadataFeature(session, fileid);
48+
assertEquals(Collections.emptyMap(), feature.getMetadata(test));
49+
feature.setMetadata(test, Collections.singletonMap("test", "t"));
50+
final Map<String, String> metadata = feature.getMetadata(test);
51+
assertEquals(Collections.singletonMap("test", "t"), metadata);
52+
test.attributes().setMetadata(metadata);
53+
feature.setMetadata(test, status.setMetadata(Collections.emptyMap()));
54+
assertFalse(status.getResponse().getMetadata().containsKey("test"));
55+
assertFalse(feature.getMetadata(test).containsKey("test"));
56+
new DriveDeleteFeature(session, fileid).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
5057
}
5158

5259
@Test

googlestorage/src/test/java/ch/cyberduck/core/googlestorage/GoogleStorageMetadataFeatureTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ public void testGetMetadataFile() throws Exception {
5757
final Map<String, String> get = feature.getMetadata(test);
5858
assertTrue(get.containsKey("k"));
5959
assertEquals("v", get.get("k"));
60+
feature.setMetadata(test, status.setMetadata(Collections.emptyMap()));
61+
assertTrue(feature.getMetadata(test).isEmpty());
6062
new GoogleStorageDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
6163
}
6264

openstack/src/test/java/ch/cyberduck/core/openstack/SwiftMetadataFeatureTest.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,15 @@ public void testSetMetadata() throws Exception {
5252
final Path test = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
5353
new SwiftTouchFeature(session, new SwiftRegionService(session)).touch(test, new TransferStatus().setMime("text/plain"));
5454
final String v = UUID.randomUUID().toString();
55-
new SwiftMetadataFeature(session).setMetadata(test, Collections.<String, String>singletonMap("Test", v));
56-
final Map<String, String> metadata = new SwiftMetadataFeature(session).getMetadata(test);
55+
final SwiftMetadataFeature feature = new SwiftMetadataFeature(session);
56+
feature.setMetadata(test, Collections.singletonMap("Test", v));
57+
final Map<String, String> metadata = feature.getMetadata(test);
5758
assertFalse(metadata.isEmpty());
5859
assertTrue(metadata.containsKey("X-Object-Meta-Test"));
5960
assertEquals(v, metadata.get("X-Object-Meta-Test"));
6061
assertEquals("text/plain", metadata.get("Content-Type"));
62+
feature.setMetadata(test, Collections.emptyMap());
63+
assertFalse(feature.getMetadata(test).containsKey("Test"));
6164
new SwiftDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
6265
}
6366
}

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
<log4j-version>2.24.3</log4j-version>
8989
<bouncycastle-version>1.80</bouncycastle-version>
9090
<httpclient-version>4.5.14</httpclient-version>
91-
<google-http-client.version>1.42.3</google-http-client.version>
91+
<google-http-client.version>1.46.3</google-http-client.version>
9292
<jwt.version>4.5.0</jwt.version>
9393
<ikvm-version>8.0.312.b07-8</ikvm-version>
9494
<java-native-dll>8u312b07</java-native-dll>

s3/src/test/java/ch/cyberduck/core/s3/S3MetadataFeatureTest.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ public void testGetMetadataFile() throws Exception {
5555
new S3TouchFeature(session, acl).touch(test, new TransferStatus()
5656
.setMetadata(Collections.singletonMap("app", "cyberduck"))
5757
.setMime("text/plain"));
58-
final Map<String, String> metadata = new S3MetadataFeature(session, acl).getMetadata(test);
58+
final S3MetadataFeature feature = new S3MetadataFeature(session, acl);
59+
final Map<String, String> metadata = feature.getMetadata(test);
5960
assertFalse(metadata.isEmpty());
6061
assertTrue(metadata.containsKey("app"));
6162
assertEquals("cyberduck", metadata.get("app"));
@@ -64,6 +65,8 @@ public void testGetMetadataFile() throws Exception {
6465
assertFalse(metadata.containsKey(Constants.KEY_FOR_USER_METADATA));
6566
assertFalse(metadata.containsKey(Constants.KEY_FOR_SERVICE_METADATA));
6667
assertFalse(metadata.containsKey(Constants.KEY_FOR_COMPLETE_METADATA));
68+
feature.setMetadata(test, Collections.emptyMap());
69+
assertFalse(feature.getMetadata(test).containsKey("app"));
6770
new S3DefaultDeleteFeature(session, acl).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
6871
}
6972

webdav/src/main/java/ch/cyberduck/core/dav/DAVMetadataFeature.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
import com.github.sardine.impl.SardineException;
4343
import com.github.sardine.util.SardineUtil;
4444

45+
import javax.xml.namespace.QName;
46+
4547
public class DAVMetadataFeature implements Headers {
4648
private static final Logger log = LogManager.getLogger(DAVMetadataFeature.class);
4749

@@ -84,12 +86,20 @@ public Map<String, String> getMetadata(final Path file) throws BackgroundExcepti
8486
public void setMetadata(final Path file, final TransferStatus status) throws BackgroundException {
8587
log.debug("Write metadata {} for file {}", status, file);
8688
try {
87-
final List<Element> props = new ArrayList<>();
89+
final List<Element> setProps = new ArrayList<>();
8890
for(Map.Entry<String, String> entry : status.getMetadata().entrySet()) {
89-
Element element = SardineUtil.createElement(
91+
final Element element = SardineUtil.createElement(
9092
SardineUtil.createQNameWithCustomNamespace(entry.getKey()));
9193
element.setTextContent(entry.getValue());
92-
props.add(element);
94+
setProps.add(element);
95+
}
96+
final List<QName> removeProps = new ArrayList<>();
97+
for(String key : file.attributes().getMetadata().keySet()) {
98+
final Element element = SardineUtil.createElement(SardineUtil.createQNameWithCustomNamespace(key));
99+
if(!setProps.contains(element)) {
100+
// Deleted property
101+
removeProps.add(SardineUtil.createQNameWithCustomNamespace(key));
102+
}
93103
}
94104
final Map<String, String> headers;
95105
if(session.getFeature(Lock.class) != null && status.getLockId() != null) {
@@ -98,7 +108,7 @@ public void setMetadata(final Path file, final TransferStatus status) throws Bac
98108
else {
99109
headers = Collections.emptyMap();
100110
}
101-
session.getClient().patch(new DAVPathEncoder().encode(file), props, Collections.emptyList(), headers);
111+
session.getClient().patch(new DAVPathEncoder().encode(file), setProps, removeProps, headers);
102112
}
103113
catch(SardineException e) {
104114
throw new DAVExceptionMappingService().map("Failure to write attributes of {0}", e, file);

webdav/src/test/java/ch/cyberduck/core/dav/DAVMetadataFeatureTest.java

+3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ public void testSetMetadataFile() throws Exception {
4949
assertTrue(metadata.containsKey("Test"));
5050
assertEquals(v, metadata.get("Test"));
5151
assertEquals(status.getMetadata(), metadata);
52+
test.attributes().setMetadata(metadata);
53+
feature.setMetadata(test, status.setMetadata(Collections.emptyMap()));
54+
assertFalse(feature.getMetadata(test).containsKey("Test"));
5255
new DAVDeleteFeature(session).delete(Collections.singletonList(test), new DisabledLoginCallback(), new Delete.DisabledCallback());
5356
}
5457

webdav/src/test/java/ch/cyberduck/core/dav/DAVTimestampFeatureTest.java

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ public void testSetTimestamp() throws Exception {
4747
assertEquals(5000L, attr.getModificationDate());
4848
assertEquals(status.getResponse(), attr);
4949
assertEquals(5000L, new DefaultAttributesFinderFeature(session).find(file).getModificationDate());
50+
new DAVMetadataFeature(session).setMetadata(file, status.setMetadata(Collections.singletonMap("Test", "Value")));
51+
assertEquals(5000L, new DAVAttributesFinderFeature(session).find(file).getModificationDate());
52+
new DAVMetadataFeature(session).setMetadata(file, status.setMetadata(Collections.emptyMap()));
53+
assertEquals(5000L, new DAVAttributesFinderFeature(session).find(file).getModificationDate());
5054
new DAVDeleteFeature(session).delete(Collections.<Path>singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
5155
}
5256

0 commit comments

Comments
 (0)