diff --git a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java index 06ad574e..1a2b00ea 100644 --- a/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java +++ b/zanata-client-commands/src/main/java/org/zanata/client/commands/init/InitCommand.java @@ -42,6 +42,7 @@ import org.zanata.client.commands.ConsoleInteractorImpl; import org.zanata.client.commands.OptionsUtil; import org.zanata.client.config.ZanataConfig; +import org.zanata.client.util.VersionComparator; import org.zanata.rest.client.ZanataProxyFactory; import com.google.common.annotations.VisibleForTesting; @@ -98,6 +99,8 @@ protected void run() throws Exception { // Search for zanata.ini userConfigHandler.verifyUserConfig(); + ensureServerVersion(); + // If there's a zanata.xml, ask the user projectConfigHandler.handleExistingProjectConfig(); @@ -132,6 +135,18 @@ protected void run() throws Exception { displayAdviceAboutWhatIsNext(projectConfigHandler.hasOldConfig()); } + @VisibleForTesting + protected void ensureServerVersion() { + String serverVersion = + getRequestFactory().getServerVersionInfo().getVersionNo(); + + if (new VersionComparator().compare(serverVersion, "3.4.0") < 0) { + console.printfln(Warning, _("server.incompatible")); + console.printfln(Hint, _("server.incompatible.hint")); + throw new RuntimeException(_("server.incompatible")); + } + } + private void displayAdviceAboutWhatIsNext(boolean hasOldConfig) { console.printfln(_("what.next")); if (hasOldConfig) { diff --git a/zanata-client-commands/src/main/java/org/zanata/client/util/VersionComparator.java b/zanata-client-commands/src/main/java/org/zanata/client/util/VersionComparator.java new file mode 100644 index 00000000..74a0f3fb --- /dev/null +++ b/zanata-client-commands/src/main/java/org/zanata/client/util/VersionComparator.java @@ -0,0 +1,109 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.client.util; + +import java.util.Comparator; +import java.util.List; + +import com.google.common.base.Preconditions; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableList; + +/** + * This class will compare version strings i.e. 3.3.1 to 3.3. It can also + * compare maven snapshot version i.e. 3.3.1-SNAPSHOT is newer than 3.3.1. + * It can NOT handle version like 1.1a or 1.1.Final or 1.1.Alpha. + * + * @author Patrick Huang pahuang@redhat.com + */ +public class VersionComparator implements Comparator { + + private static final Splitter splitter = + Splitter.on(".").omitEmptyStrings().trimResults(); + public static final String SNAPSHOT_SUFFIX = "-SNAPSHOT"; + + @Override + public int compare(String left, String right) { + Preconditions.checkNotNull(left); + Preconditions.checkNotNull(right); + + List leftOrdinals = + ImmutableList.copyOf(splitter.split(left.replace( + SNAPSHOT_SUFFIX, ""))); + List rightOrdinals = + ImmutableList.copyOf(splitter.split(right.replace( + SNAPSHOT_SUFFIX, ""))); + int compareIndex = + firstDiffOrdinalOrLastOrdinalInShortestVer(leftOrdinals, + rightOrdinals); + // compare first different ordinal + if (compareIndex < leftOrdinals.size() + && compareIndex < rightOrdinals.size()) { + Integer leftOrdinal = + getOrdinalAsInteger(leftOrdinals, compareIndex); + Integer rightOrdinal = + getOrdinalAsInteger(rightOrdinals, compareIndex); + + int ordinalDiff = leftOrdinal.compareTo(rightOrdinal); + if (ordinalDiff == 0) { + return compareSnapshot(left, right); + } + return ordinalDiff; + } + + // either equal or one is a substring of another + int sizeDiff = leftOrdinals.size() - rightOrdinals.size(); + if (sizeDiff == 0) { + return compareSnapshot(left, right); + } + return Integer.signum(sizeDiff); + } + + private static int firstDiffOrdinalOrLastOrdinalInShortestVer( + List ver1Ordinals, + List ver2Ordinals) { + int result = 0; + while (result < ver1Ordinals.size() && result < ver2Ordinals.size() + && ver1Ordinals.get(result).equals(ver2Ordinals.get(result))) { + result++; + } + return result; + } + + private static Integer getOrdinalAsInteger(List ordinals, + int index) { + return Integer.valueOf(ordinals.get(index)); + } + + private static int compareSnapshot(String ver1, String ver2) { + boolean ver1IsSnapshot = ver1.endsWith(SNAPSHOT_SUFFIX); + boolean ver2IsSnapshot = ver2.endsWith(SNAPSHOT_SUFFIX); + if (ver1IsSnapshot && !ver2IsSnapshot) { + return -1; + } else if (!ver1IsSnapshot && ver2IsSnapshot) { + return 1; + } else { + return 0; + } + } +} diff --git a/zanata-client-commands/src/main/resources/prompts.properties b/zanata-client-commands/src/main/resources/prompts.properties index 73119aa3..02ff143f 100644 --- a/zanata-client-commands/src/main/resources/prompts.properties +++ b/zanata-client-commands/src/main/resources/prompts.properties @@ -3,6 +3,8 @@ found.servers=Found servers in %s: which.server=Which Zanata server do you want to use? server.selection=You have selected server %s missing.server.url=You do not have a Zanata server URL in your user config file (zanata.ini). Please refer to http://zanata.org/help/cli/cli-configuration/ for how to add a server URL +server.incompatible=Server version does not support this command! Contact your server administrator to upgrade. +server.incompatible.hint=Alternatively, you could manually set up your project by referring to the Maintainer section in http://zanata.org/help/overview/workflow-overview/ project.config.exists=Project config (zanata.xml) already exists. If you continue it will be backed up. continue.yes.no=Do you want to continue (y/n)? @@ -45,6 +47,7 @@ no.source.doc.found=No source documents found. found.source.docs=Found source documents: source.doc.confirm.yes.no=Continue with these source document settings (y/n)? more.src.options.hint=There are more advanced options available which can only be given from commandline. See help for detail. +src.dir.not.exist=Directory %s does not exist! Please re-enter. trans.dir.prompt=What is your base directory for translated files (eg ".", "po", "src/main/resources")? trans.doc.preview=Zanata will put translation files as below (e.g. for locale %s): diff --git a/zanata-client-commands/src/test/java/org/zanata/client/commands/init/InitCommandTest.java b/zanata-client-commands/src/test/java/org/zanata/client/commands/init/InitCommandTest.java index 9653f8c2..e5788b10 100644 --- a/zanata-client-commands/src/test/java/org/zanata/client/commands/init/InitCommandTest.java +++ b/zanata-client-commands/src/test/java/org/zanata/client/commands/init/InitCommandTest.java @@ -1,6 +1,7 @@ package org.zanata.client.commands.init; import static org.hamcrest.MatcherAssert.assertThat; +import static org.mockito.Mockito.when; import static org.zanata.client.commands.HTTPMockContainer.Builder.readFromClasspath; import java.io.BufferedWriter; @@ -17,7 +18,10 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.rules.TemporaryFolder; +import org.mockito.Answers; +import org.mockito.Mock; import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; import org.simpleframework.http.core.Container; import org.simpleframework.http.core.ContainerServer; import org.simpleframework.transport.connect.SocketConnection; @@ -25,6 +29,9 @@ import org.slf4j.LoggerFactory; import org.zanata.client.commands.ConsoleInteractor; import org.zanata.client.commands.HTTPMockContainer; +import org.zanata.client.commands.Messages; +import org.zanata.rest.client.ZanataProxyFactory; +import org.zanata.rest.dto.VersionInfo; import com.google.common.base.Charsets; import com.google.common.base.Joiner; @@ -43,11 +50,15 @@ public class InitCommandTest { private InitCommand command; private InitOptionsImpl opts; private SocketConnection connection; + @Mock + private ConsoleInteractor console; + @Mock + private ZanataProxyFactory requestFactory; @Before public void setUp() throws IOException { + MockitoAnnotations.initMocks(this); opts = new InitOptionsImpl(); - ConsoleInteractor console = Mockito.mock(ConsoleInteractor.class); command = new InitCommand(opts, console, null); } @@ -119,4 +130,18 @@ public void willWriteSrcDirIncludesExcludesToConfigFile() throws Exception { "potpo")); } + @Test + public void willQuitIfServerApiVersionDoesNotSupportInit() + throws Exception { + expectException.expect(RuntimeException.class); + expectException.expectMessage(Matchers.equalTo(Messages + ._("server.incompatible"))); + + when(requestFactory.getServerVersionInfo()).thenReturn( + new VersionInfo("3.3.1", "unknown", "unknown")); + command = new InitCommand(opts, console, requestFactory); + + command.ensureServerVersion(); + } + } diff --git a/zanata-client-commands/src/test/java/org/zanata/client/util/VersionComparatorTest.java b/zanata-client-commands/src/test/java/org/zanata/client/util/VersionComparatorTest.java new file mode 100644 index 00000000..50270560 --- /dev/null +++ b/zanata-client-commands/src/test/java/org/zanata/client/util/VersionComparatorTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2014, Red Hat, Inc. and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.zanata.client.util; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; + +import org.junit.Test; + +public class VersionComparatorTest { + public static final int GREATER = 1; + public static final int EQUAL = 0; + public static final int LESS = -1; + private VersionComparator comparator = new VersionComparator(); + + @Test + public void canCompareVersions() { + assertThat(comparator.compare("3.3.1", "3.3"), equalTo(GREATER)); + assertThat(comparator.compare("3.3.1", "3.3.1"), equalTo(EQUAL)); + assertThat(comparator.compare("3.3.1", "3.3.2"), equalTo(LESS)); + assertThat(comparator.compare("3.3.1-SNAPSHOT", "3.3"), equalTo(GREATER)); + assertThat(comparator.compare("3.3.1-SNAPSHOT", "3.3-SNAPSHOT"), equalTo(GREATER)); + assertThat(comparator.compare("3.3.1-SNAPSHOT", "3.3.1"), equalTo(LESS)); + assertThat(comparator.compare("3.3.1-SNAPSHOT", "3.3.2-SNAPSHOT"), equalTo(LESS)); + assertThat(comparator.compare("3.3.1-SNAPSHOT", "3.3.1-SNAPSHOT"), equalTo(EQUAL)); + } + +} diff --git a/zanata-client-commands/src/test/resources/serverresponse/version.xml b/zanata-client-commands/src/test/resources/serverresponse/version.xml index e606e0a4..be6cc0d8 100644 --- a/zanata-client-commands/src/test/resources/serverresponse/version.xml +++ b/zanata-client-commands/src/test/resources/serverresponse/version.xml @@ -1,6 +1,6 @@ - 3.3.1 + 3.4.0 unknown unknown \ No newline at end of file diff --git a/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java b/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java index bcfc0b36..e4e126fa 100644 --- a/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java +++ b/zanata-rest-client/src/main/java/org/zanata/rest/client/ZanataProxyFactory.java @@ -138,7 +138,7 @@ public void performVersionCheck() { warnMismatchAPIVersion(clientScm, serverScm); } - private VersionInfo getServerVersionInfo() { + public VersionInfo getServerVersionInfo() { IVersionResource iversion = createIVersionResource(); ClientResponse versionResp; try {