\r
<bean class="jetbrains.buildServer.nuget.server.feed.reader.FeedClient" destroy-method="dispose"/>\r
<bean class="jetbrains.buildServer.nuget.server.feed.reader.NuGetFeedReader"/>\r
+ <bean class="jetbrains.buildServer.nuget.server.feed.reader.FeedGetMethodFactory"/>\r
+ <bean class="jetbrains.buildServer.nuget.server.feed.reader.UrlResolver"/>\r
\r
</beans>
\ No newline at end of file
--- /dev/null
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.server.feed.reader;\r
+\r
+import org.apache.http.HttpVersion;\r
+import org.apache.http.NameValuePair;\r
+import org.apache.http.client.methods.HttpGet;\r
+import org.apache.http.client.utils.URLEncodedUtils;\r
+import org.apache.http.params.HttpProtocolParams;\r
+import org.apache.http.protocol.HTTP;\r
+import org.jetbrains.annotations.NotNull;\r
+\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+ * Date: 12.08.11 12:28\r
+ */\r
+public class FeedGetMethodFactory {\r
+ @NotNull\r
+ public HttpGet createGet(@NotNull final String url, NameValuePair... getParams) {\r
+ String argz = URLEncodedUtils.format(Arrays.asList(getParams), HTTP.ISO_8859_1);\r
+ if (argz.length() > 0) {\r
+ argz = (url.contains("?") ? "&" : "?") + argz;\r
+ }\r
+ final HttpGet get = new HttpGet(url + argz);\r
+ HttpProtocolParams.setVersion(get.getParams(), HttpVersion.HTTP_1_1);\r
+\r
+ return get;\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.server.feed.reader;\r
+\r
+import jetbrains.buildServer.nuget.common.PackageInfo;\r
+import org.jetbrains.annotations.NotNull;\r
+\r
+/**\r
+ * Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+ * Date: 12.08.11 13:43\r
+ */\r
+public class FeedPackage implements Comparable<FeedPackage>{\r
+ private final String myAtomId;\r
+ private final PackageInfo myInfo;\r
+ private final boolean myLatestVersion;\r
+ private final String myDescription;\r
+\r
+ private final String myDownloadUrl;\r
+\r
+ public FeedPackage(@NotNull String atomId,\r
+ @NotNull PackageInfo info,\r
+ boolean latestVersion,\r
+ @NotNull String description,\r
+ @NotNull String downloadUrl) {\r
+ myAtomId = atomId;\r
+ myInfo = info;\r
+ myLatestVersion = latestVersion;\r
+ myDescription = description;\r
+ myDownloadUrl = downloadUrl;\r
+ }\r
+\r
+ @NotNull\r
+ public String getAtomId() {\r
+ return myAtomId;\r
+ }\r
+\r
+ @NotNull\r
+ public PackageInfo getInfo() {\r
+ return myInfo;\r
+ }\r
+\r
+ public boolean isLatestVersion() {\r
+ return myLatestVersion;\r
+ }\r
+\r
+ @NotNull\r
+ public String getDescription() {\r
+ return myDescription;\r
+ }\r
+\r
+ @NotNull\r
+ public String getDownloadUrl() {\r
+ return myDownloadUrl;\r
+ }\r
+\r
+ @Override\r
+ public boolean equals(Object o) {\r
+ if (this == o) return true;\r
+ if (o == null || getClass() != o.getClass()) return false;\r
+ FeedPackage that = (FeedPackage) o;\r
+ return myInfo.equals(that.myInfo);\r
+ }\r
+\r
+ @Override\r
+ public int hashCode() {\r
+ return myInfo.hashCode();\r
+ }\r
+\r
+ public int compareTo(@NotNull FeedPackage o) {\r
+ return myInfo.compareTo(o.myInfo);\r
+ }\r
+\r
+ @Override\r
+ public String toString() {\r
+ return "FeedPackage{" +\r
+ "myAtomId='" + myAtomId + '\'' +\r
+ ", myInfo=" + myInfo +\r
+ ", myLatestVersion=" + myLatestVersion +\r
+ ", myDescription='" + myDescription + '\'' +\r
+ ", myDownloadUrl='" + myDownloadUrl + '\'' +\r
+ '}';\r
+ }\r
+}\r
import org.jetbrains.annotations.NotNull;\r
\r
import java.io.IOException;\r
-import java.net.URISyntaxException;\r
\r
/**\r
* Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
private static final Logger LOG = Logger.getInstance(NuGetFeedReader.class.getName());\r
private final FeedClient myClient;\r
private final UrlResolver myResolver;\r
+ private final FeedGetMethodFactory myMethodFactory;\r
\r
- public NuGetFeedReader(FeedClient client, UrlResolver resolver) {\r
+ public NuGetFeedReader(FeedClient client, UrlResolver resolver, FeedGetMethodFactory methodFactory) {\r
myClient = client;\r
myResolver = resolver;\r
+ myMethodFactory = methodFactory;\r
}\r
\r
-\r
public void queryPackage(@NotNull String feedUrl,\r
@NotNull String packageId) throws IOException {\r
LOG.debug("Connecting to NuGet feed url: " + feedUrl);\r
feedUrl = pair.first;\r
LOG.debug("Resolved NuGet feed URL to " + feedUrl);\r
final Element element = toDocument(pair.second);\r
-\r
LOG.debug("Recieved xml: " + XmlUtil.to_s(element));\r
- HttpGet get = new HttpGet(feedUrl + "/Packages()?$filter=Id%20eq%20'" + packageId +"'");\r
+\r
+ final HttpGet get = myMethodFactory.createGet(feedUrl + "/Packages()",\r
+ new Param("$filter", "Id eq '" + packageId + "'")\r
+ );\r
get.setHeader(HttpHeaders.ACCEPT_ENCODING, "application/atom+xml");\r
- final HttpResponse execute = myClient.getClient().execute(get);\r
\r
+ LOG.debug("Query for packages: " + get.getURI());\r
+\r
+ final HttpResponse execute = myClient.getClient().execute(get);\r
System.out.println(execute);\r
execute.getEntity().writeTo(System.out);\r
}\r
--- /dev/null
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.server.feed.reader;\r
+\r
+import com.intellij.openapi.diagnostic.Logger;\r
+import jetbrains.buildServer.nuget.common.PackageInfo;\r
+import jetbrains.buildServer.util.StringUtil;\r
+import org.jdom.Element;\r
+import org.jdom.Namespace;\r
+import org.jetbrains.annotations.NotNull;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
+/**\r
+ * Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+ * Date: 12.08.11 13:42\r
+ */\r
+public class PackagesFeedParser {\r
+ private static final Logger LOG = Logger.getInstance(PackagesFeedParser.class.getName());\r
+\r
+ private static final Namespace atom = Namespace.getNamespace("http://www.w3.org/2005/Atom");\r
+ private static final Namespace metadata = Namespace.getNamespace("http://schemas.microsoft.com/ado/2007/08/dataservices/metadata");\r
+ private static final Namespace services = Namespace.getNamespace("http://schemas.microsoft.com/ado/2007/08/dataservices");\r
+\r
+ public Collection<FeedPackage> readPackages(@NotNull Element root) {\r
+ final List<FeedPackage> result = new ArrayList<FeedPackage>();\r
+\r
+ final List entries = root.getChildren("entry", atom);\r
+ for (Object o : entries) {\r
+ final Element entry = (Element) o;\r
+ try {\r
+ final FeedPackage e = parseOneEntry(entry);\r
+ result.add(e);\r
+ } catch (InvalidXmlException e) {\r
+ LOG.debug("Failed to parse feed entry. " + e.getMessage());\r
+ }\r
+ }\r
+ Collections.sort(result);\r
+ return result;\r
+ }\r
+\r
+ @NotNull\r
+ private FeedPackage parseOneEntry(Element entry) throws InvalidXmlException {\r
+ final Element atomIdElement = getChild(entry, "id", atom);\r
+ final String atomId = atomIdElement.getText();\r
+\r
+ final String content = getChildAttribute(entry, "content", atom, "src");\r
+ final Element props = getChild(entry, "properties", metadata);\r
+\r
+ final String packageId = getChildText(props, "Id", services);\r
+ final String version = getChildText(props, "Version", services);\r
+ final String desription = getChildText(props, "Description", services);\r
+ final String summary = getChildText(props, "Summary", services);\r
+ final boolean isLatestVersion = "true".equalsIgnoreCase(getChildTextSafe(props, "IsLatestVersion", services));\r
+\r
+ return new FeedPackage(\r
+ atomId,\r
+ new PackageInfo(packageId, version),\r
+ isLatestVersion,\r
+ StringUtil.isEmptyOrSpaces(desription) ? summary : desription,\r
+ content);\r
+ }\r
+\r
+ @NotNull\r
+ private String getChildTextSafe(@NotNull Element element,\r
+ @NotNull String name,\r
+ @NotNull Namespace ns) {\r
+ try {\r
+ return getChildText(element, name, ns);\r
+ } catch (InvalidXmlException e) {\r
+ return "";\r
+ }\r
+ }\r
+\r
+ @NotNull\r
+ private String getChildText(@NotNull Element element,\r
+ @NotNull String name,\r
+ @NotNull Namespace ns) throws InvalidXmlException {\r
+ final Element data = getChild(element, name, ns);\r
+ final String text = data.getText();\r
+ if (StringUtil.isEmptyOrSpaces(text)) {\r
+ throw new InvalidXmlException("Element " + name + " must have a content. ");\r
+ }\r
+ return text;\r
+ }\r
+\r
+ @NotNull\r
+ private String getChildAttribute(@NotNull Element element,\r
+ @NotNull String name,\r
+ @NotNull Namespace ns,\r
+ @NotNull String attribute) throws InvalidXmlException {\r
+ final Element data = getChild(element, name, ns);\r
+ final String text = data.getAttributeValue(attribute);\r
+ if (StringUtil.isEmptyOrSpaces(text)) {\r
+ throw new InvalidXmlException("Element " + name + " must have non-empty attribute " + attribute + ". ");\r
+ }\r
+ return text;\r
+ }\r
+\r
+ @NotNull\r
+ private Element getChild(Element element, String name, Namespace ns) throws InvalidXmlException {\r
+ final Element data = element.getChild(name, ns);\r
+ if (data == null) {\r
+ throw new InvalidXmlException("Element " + name + " was not found. ");\r
+ }\r
+ return data;\r
+ }\r
+\r
+ private static class InvalidXmlException extends Exception {\r
+ private InvalidXmlException(String message) {\r
+ super(message);\r
+ }\r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.server.feed.reader;\r
+\r
+import org.apache.http.NameValuePair;\r
+import org.jetbrains.annotations.NotNull;\r
+\r
+/**\r
+* Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+* Date: 12.08.11 12:50\r
+*/\r
+public class Param implements NameValuePair {\r
+ private final String myName;\r
+ private final String myValue;\r
+\r
+ public Param(@NotNull final String name, @NotNull final String value) {\r
+ myName = name;\r
+ myValue = value;\r
+ }\r
+\r
+ public String getName() {\r
+ return myName;\r
+ }\r
+\r
+ @NotNull\r
+ public String getValue() {\r
+ return myValue;\r
+ }\r
+}\r
*/\r
public class UrlResolver {\r
private final FeedClient myClient;\r
+ private final FeedGetMethodFactory myMethods;\r
\r
- public UrlResolver(FeedClient client) {\r
+ public UrlResolver(@NotNull final FeedClient client,\r
+ @NotNull final FeedGetMethodFactory methods) {\r
myClient = client;\r
+ myMethods = methods;\r
}\r
\r
/**\r
@NotNull\r
public Pair<String, HttpResponse> resolvePath(@NotNull String feedUrl) throws IOException {\r
for(int _ = 100; _-->0;) {\r
- HttpGet ping = new HttpGet(feedUrl);\r
+ HttpGet ping = myMethods.createGet(feedUrl);\r
ping.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);\r
+\r
final HttpResponse execute = myClient.getClient().execute(ping);\r
final int statusCode = execute.getStatusLine().getStatusCode();\r
if (statusCode / 100 == 3) {\r
continue;\r
}\r
}\r
+\r
if (statusCode != HttpStatus.SC_OK) {\r
throw new IOException("Failed to connect to " + feedUrl);\r
}\r
package jetbrains.buildServer.nuget.tests.integration;\r
\r
import jetbrains.buildServer.BaseTestCase;\r
-import jetbrains.buildServer.nuget.server.feed.reader.FeedClient;\r
-import jetbrains.buildServer.nuget.server.feed.reader.FeedConstants;\r
-import jetbrains.buildServer.nuget.server.feed.reader.NuGetFeedReader;\r
-import jetbrains.buildServer.nuget.server.feed.reader.UrlResolver;\r
+import jetbrains.buildServer.nuget.server.feed.reader.*;\r
import org.apache.log4j.ConsoleAppender;\r
import org.apache.log4j.Level;\r
import org.apache.log4j.Logger;\r
protected void setUp() throws Exception {\r
super.setUp();\r
myClient = new FeedClient();\r
- myReader = new NuGetFeedReader(myClient, new UrlResolver(myClient));\r
+ final FeedGetMethodFactory methods = new FeedGetMethodFactory();\r
+ myReader = new NuGetFeedReader(myClient, new UrlResolver(myClient, methods), methods);\r
}\r
\r
@AfterMethod\r
--- /dev/null
+/*\r
+ * Copyright 2000-2011 JetBrains s.r.o.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package jetbrains.buildServer.nuget.tests.server;\r
+\r
+import jetbrains.buildServer.BaseTestCase;\r
+import jetbrains.buildServer.nuget.server.feed.reader.FeedPackage;\r
+import jetbrains.buildServer.nuget.server.feed.reader.PackagesFeedParser;\r
+import jetbrains.buildServer.nuget.tests.integration.Paths;\r
+import jetbrains.buildServer.util.FileUtil;\r
+import org.jdom.Element;\r
+import org.jdom.JDOMException;\r
+import org.testng.Assert;\r
+import org.testng.annotations.Test;\r
+\r
+import java.io.IOException;\r
+import java.util.Collection;\r
+\r
+/**\r
+ * Created by Eugene Petrenko (eugene.petrenko@gmail.com)\r
+ * Date: 12.08.11 13:44\r
+ */\r
+public class FeedPackagesParserTest extends BaseTestCase {\r
+ private PackagesFeedParser myParser = new PackagesFeedParser();\r
+\r
+ @Test\r
+ public void test_ParseRealFeed() throws JDOMException, IOException {\r
+ final Element doc = FileUtil.parseDocument(Paths.getTestDataPath("feed/reader/feed-response.xml"));\r
+ boolean hasLatest = false;\r
+ final Collection<FeedPackage> feedPackages = myParser.readPackages(doc);\r
+ for (FeedPackage feedPackage : feedPackages) {\r
+ Assert.assertFalse(hasLatest && feedPackage.isLatestVersion(), "There could be only one latest");\r
+ hasLatest |= feedPackage.isLatestVersion();\r
+ System.out.println("feedPackage = " + feedPackage);\r
+ }\r
+ }\r
+\r
+ @Test\r
+ public void test_ParseOnePackage() throws JDOMException, IOException {\r
+ final Element doc = FileUtil.parseDocument(Paths.getTestDataPath("feed/reader/feed-one.xml"));\r
+ final Collection<FeedPackage> packages = myParser.readPackages(doc);\r
+\r
+ Assert.assertEquals(packages.size(), 1);\r
+ final FeedPackage pkg = packages.iterator().next();\r
+\r
+ Assert.assertEquals(pkg.getAtomId(), "http://packages.nuget.org/v1/FeedService.svc/Packages(Id='NuGet.CommandLine',Version='1.0.11220.26')");\r
+ Assert.assertEquals(pkg.getDownloadUrl(), "http://packages.nuget.org/v1/Package/Download/NuGet.CommandLine/1.0.11220.26");\r
+ Assert.assertEquals(pkg.getInfo().getId(), "NuGet.CommandLine");\r
+ Assert.assertEquals(pkg.getInfo().getVersion(), "1.0.11220.26");\r
+ Assert.assertEquals(pkg.isLatestVersion(), false);\r
+ Assert.assertTrue(pkg.getDescription().length() > 0, "package should have deseciription");\r
+ }\r
+\r
+ @Test\r
+ public void test_broken() {\r
+ Element el = new Element("broken");\r
+ final Collection<FeedPackage> feedPackages = myParser.readPackages(el);\r
+ Assert.assertTrue(feedPackages.isEmpty());\r
+ }\r
+}\r
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">\r
<suite name="nuget">\r
-\r
<test name="fast tests">\r
<classes>\r
<class name="jetbrains.buildServer.nuget.tests.RunTypeNameTest"/>\r
<class name="jetbrains.buildServer.nuget.tests.server.NamedPackagesUpdateCheckerTest"/>\r
\r
<class name="jetbrains.buildServer.nuget.tests.agent.MatchFilesBuildProcessTest"/>\r
+\r
+ <class name="jetbrains.buildServer.nuget.tests.server.FeedPackagesParserTest"/>\r
</classes>\r
</test>\r
</suite>\r