diff --git a/Documentation/rest-api-config.txt b/Documentation/rest-api-config.txt index 661abb02e5..345f759e4a 100644 --- a/Documentation/rest-api-config.txt +++ b/Documentation/rest-api-config.txt @@ -936,6 +936,103 @@ link:#top-menu-entry-info[TopMenuEntryInfo] entities is returned. ] ---- +[[get-diff-preferences]] +=== Get diff preferences + +-- +'GET /config/server/preferences.diff' +-- + +Returns the default diff preferences for the server. + +.Request +---- + GET /a/config/server/preferences.diff HTTP/1.0 +---- + +As response a link:rest-api-accounts.html#diff-preferences-info[ +DiffPreferencesInfo] is returned. + +.Response +---- + HTTP/1.1 200 OK + Content-Type: application/json; charset=UTF-8 + + )]}' + { + "context": 10, + "tab_size": 8, + "line_length": 100, + "cursor_blink_rate": 0, + "intraline_difference": true, + "show_line_endings": true, + "show_tabs": true, + "show_whitespace_errors": true, + "syntax_highlighting": true, + "auto_hide_diff_table_header": true, + "theme": "DEFAULT", + "ignore_whitespace": "IGNORE_NONE" + } +---- + +[[set-diff-preferences]] +=== Set Diff Preferences + +-- +'PUT /config/server/preferences.diff' +-- + +Sets the default diff preferences for the server. Default diff preferences can +only be set by a Gerrit link:access-control.html#administrators[administrator]. +At least one field of alink:rest-api-accounts.html#diff-preferences-info[ +DiffPreferencesInfo] must be provided in the request body. + +.Request +---- + PUT /a/config/server/preferences.diff HTTP/1.0 + Content-Type: application/json; charset=UTF-8 + + { + "context": 10, + "tab_size": 8, + "line_length": 80, + "cursor_blink_rate": 0, + "intraline_difference": true, + "show_line_endings": true, + "show_tabs": true, + "show_whitespace_errors": true, + "syntax_highlighting": true, + "auto_hide_diff_table_header": true, + "theme": "DEFAULT", + "ignore_whitespace": "IGNORE_NONE" + } +---- + +As response a link:rest-api-accounts.html#diff-preferences-info[ +DiffPreferencesInfo] is returned. + +.Response +---- + HTTP/1.1 200 OK + Content-Type: application/json; charset=UTF-8 + + )]}' + { + "context": 10, + "tab_size": 8, + "line_length": 80, + "cursor_blink_rate": 0, + "intraline_difference": true, + "show_line_endings": true, + "show_tabs": true, + "show_whitespace_errors": true, + "syntax_highlighting": true, + "auto_hide_diff_table_header": true, + "theme": "DEFAULT", + "ignore_whitespace": "IGNORE_NONE" + } +---- + [[ids]] == IDs diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/DiffPreferencesIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/DiffPreferencesIT.java new file mode 100644 index 0000000000..e68b4afebc --- /dev/null +++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/rest/config/DiffPreferencesIT.java @@ -0,0 +1,79 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.google.gerrit.acceptance.rest.config; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.gerrit.server.config.ConfigUtil.skipField; + +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.RestResponse; +import com.google.gerrit.extensions.client.DiffPreferencesInfo; + +import org.junit.Test; + +import java.lang.reflect.Field; + +public class DiffPreferencesIT extends AbstractDaemonTest { + + @Test + public void GetDiffPreferences() throws Exception { + DiffPreferencesInfo result = get(); + assertPrefsEqual(result, DiffPreferencesInfo.defaults()); + } + + @Test + public void SetDiffPreferences() throws Exception { + int newLineLength = DiffPreferencesInfo.defaults().lineLength + 10; + DiffPreferencesInfo update = new DiffPreferencesInfo(); + update.lineLength = newLineLength; + DiffPreferencesInfo result = put(update); + assertThat(result.lineLength).named("lineLength").isEqualTo(newLineLength); + + result = get(); + DiffPreferencesInfo expected = DiffPreferencesInfo.defaults(); + expected.lineLength = newLineLength; + assertPrefsEqual(result, expected); + } + + private DiffPreferencesInfo get() throws Exception { + RestResponse r = adminRestSession.get("/config/server/preferences.diff"); + r.assertOK(); + return newGson().fromJson(r.getReader(), DiffPreferencesInfo.class); + } + + private DiffPreferencesInfo put(DiffPreferencesInfo input) throws Exception { + RestResponse r = adminRestSession.put( + "/config/server/preferences.diff", input); + r.assertOK(); + return newGson().fromJson(r.getReader(), DiffPreferencesInfo.class); + } + + private void assertPrefsEqual(DiffPreferencesInfo actual, + DiffPreferencesInfo expected) throws Exception { + for (Field field : actual.getClass().getDeclaredFields()) { + if (skipField(field)) { + continue; + } + Object actualField = field.get(actual); + Object expectedField = field.get(expected); + Class type = field.getType(); + if ((type == boolean.class || type == Boolean.class) + && actualField == null) { + continue; + } + assertThat(actualField).named(field.getName()).isEqualTo(expectedField); + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java index be87ae73da..2c4a840ff4 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GetDiffPreferences.java @@ -15,6 +15,7 @@ package com.google.gerrit.server.account; import static com.google.gerrit.server.config.ConfigUtil.loadSection; +import static com.google.gerrit.server.config.ConfigUtil.skipField; import com.google.gerrit.extensions.client.DiffPreferencesInfo; import com.google.gerrit.extensions.restapi.AuthException; @@ -31,11 +32,17 @@ import com.google.inject.Singleton; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.lib.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; +import java.lang.reflect.Field; @Singleton public class GetDiffPreferences implements RestReadView { + private static final Logger log = + LoggerFactory.getLogger(GetDiffPreferences.class); + private final Provider self; private final Provider allUsersName; private final GitRepositoryManager gitMgr; @@ -66,13 +73,41 @@ public class GetDiffPreferences implements RestReadView { DiffPreferencesInfo in) throws IOException, ConfigInvalidException, RepositoryNotFoundException { try (Repository git = gitMgr.openRepository(allUsersName)) { + // Load all users prefs. + VersionedAccountPreferences dp = + VersionedAccountPreferences.forDefault(); + dp.load(git); + DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo(); + loadSection(dp.getConfig(), UserConfigSections.DIFF, null, allUserPrefs, + DiffPreferencesInfo.defaults(), in); + + // Load user prefs VersionedAccountPreferences p = VersionedAccountPreferences.forUser(id); p.load(git); DiffPreferencesInfo prefs = new DiffPreferencesInfo(); loadSection(p.getConfig(), UserConfigSections.DIFF, null, prefs, - DiffPreferencesInfo.defaults(), in); + updateDefaults(allUserPrefs), in); return prefs; } } + + private static DiffPreferencesInfo updateDefaults(DiffPreferencesInfo input) { + DiffPreferencesInfo result = DiffPreferencesInfo.defaults(); + try { + for (Field field : input.getClass().getDeclaredFields()) { + if (skipField(field)) { + continue; + } + Object newVal = field.get(input); + if (newVal != null) { + field.set(result, newVal); + } + } + } catch (IllegalAccessException e) { + log.warn("Cannot get default diff preferences from All-Users", e); + return DiffPreferencesInfo.defaults(); + } + return result; + } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java index e124e486d0..eaeb850643 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/ConfigUtil.java @@ -382,16 +382,16 @@ public class ConfigUtil { return s; } + public static boolean skipField(Field field) { + int modifiers = field.getModifiers(); + return Modifier.isFinal(modifiers) || Modifier.isTransient(modifiers); + } + private static boolean isCollectionOrMap(Class t) { return Collection.class.isAssignableFrom(t) || Map.class.isAssignableFrom(t); } - private static boolean skipField(Field field) { - int modifiers = field.getModifiers(); - return Modifier.isFinal(modifiers) || Modifier.isTransient(modifiers); - } - private static boolean isString(Class t) { return String.class == t; } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetDiffPreferences.java new file mode 100644 index 0000000000..1c10f17270 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GetDiffPreferences.java @@ -0,0 +1,67 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.gerrit.server.config; + +import static com.google.gerrit.server.config.ConfigUtil.loadSection; + +import com.google.gerrit.extensions.client.DiffPreferencesInfo; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.RestReadView; +import com.google.gerrit.server.account.VersionedAccountPreferences; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.UserConfigSections; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.eclipse.jgit.lib.Repository; + +import java.io.IOException; + +@Singleton +public class GetDiffPreferences implements RestReadView { + + private final AllUsersName allUsersName; + private final GitRepositoryManager gitManager; + + @Inject + GetDiffPreferences(GitRepositoryManager gitManager, + AllUsersName allUsersName) { + this.allUsersName = allUsersName; + this.gitManager = gitManager; + } + + @Override + public DiffPreferencesInfo apply(ConfigResource configResource) + throws BadRequestException, ResourceConflictException, Exception { + return readFromGit(gitManager, allUsersName, null); + } + + static DiffPreferencesInfo readFromGit(GitRepositoryManager gitMgr, + AllUsersName allUsersName, DiffPreferencesInfo in) + throws IOException, ConfigInvalidException, RepositoryNotFoundException { + try (Repository git = gitMgr.openRepository(allUsersName)) { + // Load all users prefs. + VersionedAccountPreferences dp = + VersionedAccountPreferences.forDefault(); + dp.load(git); + DiffPreferencesInfo allUserPrefs = new DiffPreferencesInfo(); + loadSection(dp.getConfig(), UserConfigSections.DIFF, null, allUserPrefs, + DiffPreferencesInfo.defaults(), in); + return allUserPrefs; + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java index e909f17072..a05058ee03 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/Module.java @@ -38,6 +38,8 @@ public class Module extends RestApiModule { get(CONFIG_KIND, "info").to(GetServerInfo.class); get(CONFIG_KIND, "preferences").to(GetPreferences.class); put(CONFIG_KIND, "preferences").to(SetPreferences.class); + get(CONFIG_KIND, "preferences.diff").to(GetDiffPreferences.class); + put(CONFIG_KIND, "preferences.diff").to(SetDiffPreferences.class); put(CONFIG_KIND, "email.confirm").to(ConfirmEmail.class); } } diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/SetDiffPreferences.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetDiffPreferences.java new file mode 100644 index 0000000000..8ad34ea4e1 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/SetDiffPreferences.java @@ -0,0 +1,105 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package com.google.gerrit.server.config; + +import static com.google.gerrit.server.config.ConfigUtil.loadSection; +import static com.google.gerrit.server.config.ConfigUtil.skipField; +import static com.google.gerrit.server.config.ConfigUtil.storeSection; +import static com.google.gerrit.server.config.GetDiffPreferences.readFromGit; + +import com.google.gerrit.common.data.GlobalCapability; +import com.google.gerrit.extensions.annotations.RequiresCapability; +import com.google.gerrit.extensions.client.DiffPreferencesInfo; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.server.account.VersionedAccountPreferences; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.MetaDataUpdate; +import com.google.gerrit.server.git.UserConfigSections; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; +import org.eclipse.jgit.errors.ConfigInvalidException; +import org.eclipse.jgit.errors.RepositoryNotFoundException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.lang.reflect.Field; + +@RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER) +@Singleton +public class SetDiffPreferences implements + RestModifyView { + private static final Logger log = + LoggerFactory.getLogger(SetDiffPreferences.class); + + private final Provider metaDataUpdateFactory; + private final AllUsersName allUsersName; + private final GitRepositoryManager gitManager; + + @Inject + SetDiffPreferences(GitRepositoryManager gitManager, + Provider metaDataUpdateFactory, + AllUsersName allUsersName) { + this.gitManager = gitManager; + this.metaDataUpdateFactory = metaDataUpdateFactory; + this.allUsersName = allUsersName; + } + + @Override + public Object apply(ConfigResource configResource, DiffPreferencesInfo in) + throws BadRequestException, Exception { + if (in == null) { + throw new BadRequestException("input must be provided"); + } + if (!hasSetFields(in)) { + throw new BadRequestException("unsupported option"); + } + return writeToGit(readFromGit(gitManager, allUsersName, in)); + } + + private DiffPreferencesInfo writeToGit(DiffPreferencesInfo in) + throws RepositoryNotFoundException, IOException, ConfigInvalidException { + DiffPreferencesInfo out = new DiffPreferencesInfo(); + try (MetaDataUpdate md = metaDataUpdateFactory.get().create(allUsersName)) { + VersionedAccountPreferences prefs = + VersionedAccountPreferences.forDefault(); + prefs.load(md); + DiffPreferencesInfo defaults = DiffPreferencesInfo.defaults(); + storeSection(prefs.getConfig(), UserConfigSections.DIFF, null, in, + defaults); + prefs.commit(md); + loadSection(prefs.getConfig(), UserConfigSections.DIFF, null, out, + DiffPreferencesInfo.defaults(), null); + } + return out; + } + + private static boolean hasSetFields(DiffPreferencesInfo in) { + try { + for (Field field : in.getClass().getDeclaredFields()) { + if (skipField(field)) { + continue; + } + if (field.get(in) != null) { + return true; + } + } + } catch (IllegalAccessException e) { + log.warn("Unable to verify input", e); + } + return false; + } +}