Support root base or home for quickstart #2446 (#2447)

* Support root base or home for quickstart #2446

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Issue #2446 - Root as base for quickstart

+ Adding more tests for differences we have to resolve
  with windows vs linux root path differences.
  and URI's that have an authority vs those without an authority.

  without authority examples:

  file:/code/
  file:/C:/code/

  with authority examples:

  file:///code/
  file:///C:/code/

Signed-off-by: Joakim Erdfelt <joakim.erdfelt@gmail.com>

* Using the canonical URI passes all the tests on linux, but I still have some concerns with the whole approach

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* minor cleanups

Signed-off-by: Greg Wilkins <gregw@webtide.com>

* Handle windows URIs

Because a windows like `file:///F:/` has a path of `/F:/`, then it is OK to strip the trailing `/`, so the
expected normalized value can be `file:///F:`.

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2018-05-03 09:56:08 +10:00 committed by GitHub
parent 5515e13649
commit e59d6fa2c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 202 additions and 58 deletions

View File

@ -63,7 +63,7 @@ public class AttributeNormalizer
{
private static final Logger LOG = Log.getLogger(AttributeNormalizer.class);
private static final Pattern __propertyPattern = Pattern.compile("(?<=[^$]|^)\\$\\{([^}]*)\\}");
private static class Attribute
{
final String key;
@ -78,14 +78,15 @@ public class AttributeNormalizer
}
}
private static URI toCanonicalURI(URI uri)
public static URI toCanonicalURI(URI uri)
{
uri = uri.normalize();
String ascii = uri.toASCIIString();
if (ascii.endsWith("/"))
String path = uri.getPath();
if (path!=null && path.length()>1 && path.endsWith("/"))
{
try
{
String ascii = uri.toASCIIString();
uri = new URI(ascii.substring(0,ascii.length()-1));
}
catch(URISyntaxException e)
@ -96,7 +97,16 @@ public class AttributeNormalizer
return uri;
}
private static Path toCanonicalPath(String path)
public static String toCanonicalURI(String uri)
{
if (uri!=null && uri.length()>1 && uri.endsWith("/"))
{
return uri.substring(0,uri.length()-1);
}
return uri;
}
public static Path toCanonicalPath(String path)
{
if (path == null)
return null;
@ -148,8 +158,8 @@ public class AttributeNormalizer
public URIAttribute(String key, URI uri, int weight)
{
super(key,uri.toASCIIString(),weight);
this.uri = uri;
super(key,toCanonicalURI(uri.toASCIIString()),weight);
this.uri = toCanonicalURI(uri);
}
@Override
@ -198,17 +208,6 @@ public class AttributeNormalizer
}
};
private static void add(List<PathAttribute>paths,List<URIAttribute> uris,String key,int weight)
{
String value = System.getProperty(key);
if (value!=null)
{
Path path = toCanonicalPath(value);
paths.add(new PathAttribute(key,path,weight));
uris.add(new URIAttribute(key+".uri",toCanonicalURI(path.toUri()),weight));
}
}
private URI warURI;
private Map<String,Attribute> attributes = new HashMap<>();
private List<PathAttribute> paths = new ArrayList<>();
@ -223,10 +222,10 @@ public class AttributeNormalizer
if (!warURI.isAbsolute())
throw new IllegalArgumentException("WAR URI is not absolute: " + warURI);
add(paths,uris,"jetty.base",9);
add(paths,uris,"jetty.home",8);
add(paths,uris,"user.home",7);
add(paths,uris,"user.dir",6);
addSystemProperty("jetty.base", 9);
addSystemProperty("jetty.home", 8);
addSystemProperty("user.home", 7);
addSystemProperty("user.dir", 6);
if (warURI.getScheme().equalsIgnoreCase("file"))
paths.add(new PathAttribute("WAR.path",toCanonicalPath(new File(warURI).toString()),10));
@ -244,6 +243,17 @@ public class AttributeNormalizer
{
LOG.debug(attr.toString());
}
}
}
private void addSystemProperty(String key, int weight)
{
String value = System.getProperty(key);
if (value!=null)
{
Path path = toCanonicalPath(value);
paths.add(new PathAttribute(key,path,weight));
uris.add(new URIAttribute(key+".uri",path.toUri(),weight));
}
}
@ -324,35 +334,33 @@ public class AttributeNormalizer
{
for (URIAttribute a : uris)
{
try
{
if (uri.compareTo(a.uri)==0)
return String.format("${%s}",a.key);
if (uri.compareTo(a.uri)==0)
return String.format("${%s}",a.key);
if (!a.uri.getScheme().equalsIgnoreCase(uri.getScheme()))
continue;
if (a.uri.getHost()==null && uri.getHost()!=null)
continue;
if (a.uri.getHost()!=null && !a.uri.getHost().equals(uri.getHost()))
continue;
if (!a.uri.getScheme().equalsIgnoreCase(uri.getScheme()))
continue;
if (a.uri.getHost()==null && uri.getHost()!=null)
continue;
if (a.uri.getHost()!=null && !a.uri.getHost().equals(uri.getHost()))
continue;
if (a.uri.getPath().equals(uri.getPath()))
return a.value;
String aPath = a.uri.getPath();
String uPath = uri.getPath();
if (aPath.equals(uPath))
return a.value;
if (!uri.getPath().startsWith(a.uri.getPath()))
continue;
if (!uPath.startsWith(aPath))
continue;
String s = uri.getPath().substring(a.uri.getPath().length());
if (uPath.length()==aPath.length())
return String.format("${%s}",a.key);
String s = uPath.substring(aPath.length());
if (s.length()>0 && s.charAt(0)!='/')
continue;
return String.format("${%s}%s",a.key,s);
if (s.charAt(0)!='/')
continue;
return String.format("${%s}%s",a.key,new URI(s).toASCIIString());
}
catch(URISyntaxException e)
{
LOG.ignore(e);
}
}
return uri.toASCIIString();
}

View File

@ -62,6 +62,16 @@ public class AttributeNormalizerTest
data.add(new Object[]{arch, title, env});
// ------
title = "Old Setup";
env = new HashMap<>();
env.put("jetty.home", asTargetPath(title,"jetty-distro"));
env.put("jetty.base", asTargetPath(title,"jetty-distro"));
env.put("WAR", asTargetPath(title,"jetty-distro/webapps/FOO"));
data.add(new Object[]{arch, title, env});
// ------
// This puts the jetty.home inside of the jetty.base
title = "Overlap Setup";
@ -82,6 +92,17 @@ public class AttributeNormalizerTest
env.put("WAR", asTargetPath(title,"app%2Fnasty/base/webapps/FOO"));
data.add(new Object[]{arch, title, env});
// ------
title = "Root Path Setup";
env = new HashMap<>();
Path rootPath = MavenTestingUtils.getTargetPath().getRoot();
env.put("jetty.home", rootPath.toString());
env.put("jetty.base", rootPath.toString());
env.put("WAR", rootPath.resolve("webapps/root").toString());
data.add(new Object[]{arch, title, env});
return data;
}
@ -96,8 +117,8 @@ public class AttributeNormalizerTest
}
private Map<String, String> oldValues = new HashMap<>();
private final String jettyHome;
private final String jettyBase;
private final Path jettyHome;
private final Path jettyBase;
private final String war;
private final String arch;
private final String title;
@ -118,8 +139,8 @@ public class AttributeNormalizerTest
});
// Grab specific values of interest in general
jettyHome = env.get("jetty.home");
jettyBase = env.get("jetty.base");
jettyHome = new File(env.get("jetty.home")).toPath().toAbsolutePath();
jettyBase = new File(env.get("jetty.base")).toPath().toAbsolutePath();
war = env.get("WAR");
// Set environment (skipping null and WAR)
@ -176,42 +197,79 @@ public class AttributeNormalizerTest
public void testNormalizeJettyBaseAsFile()
{
// Normalize jetty.base as File path
assertNormalize(new File(jettyBase), "${jetty.base}");
assertNormalize(jettyBase.toFile(), "${jetty.base}");
}
@Test
public void testNormalizeJettyHomeAsFile()
{
// Normalize jetty.home as File path
assertNormalize(new File(jettyHome), "${jetty.home}");
String expected = jettyBase.equals(jettyHome)?"${jetty.base}":"${jetty.home}";
assertNormalize(jettyHome.toFile(), expected);
}
@Test
public void testNormalizeJettyBaseAsPath()
{
// Normalize jetty.base as File path
assertNormalize(jettyBase, "${jetty.base}");
}
@Test
public void testNormalizeJettyHomeAsPath()
{
// Normalize jetty.home as File path
String expected = jettyBase.equals(jettyHome)?"${jetty.base}":"${jetty.home}";
assertNormalize(jettyHome, expected);
}
@Test
public void testNormalizeJettyBaseAsURI()
public void testNormalizeJettyBaseAsURI_WithAuthority()
{
// Normalize jetty.base as URI path
assertNormalize(new File(jettyBase).toURI(), "${jetty.base.uri}");
// Path.toUri() typically includes an URI authority
assertNormalize(jettyBase.toUri(), "${jetty.base.uri}");
}
@Test
public void testNormalizeJettyBaseAsURI_WithoutAuthority()
{
// Normalize jetty.base as URI path
// File.toURI() typically DOES NOT include an URI authority
assertNormalize(jettyBase.toFile().toURI(), "${jetty.base.uri}");
}
@Test
public void testNormalizeJettyHomeAsURI()
public void testNormalizeJettyHomeAsURI_WithAuthority()
{
// Normalize jetty.home as URI path
String expected = jettyBase.equals(jettyHome)?"${jetty.base.uri}":"${jetty.home.uri}";
// Path.toUri() typically includes an URI authority
assertNormalize(jettyHome.toUri(), expected);
}
@Test
public void testNormalizeJettyHomeAsURI_WithoutAuthority()
{
// Normalize jetty.home as URI path
assertNormalize(new File(jettyHome).toURI(), "${jetty.home.uri}");
String expected = jettyBase.equals(jettyHome)?"${jetty.base.uri}":"${jetty.home.uri}";
// File.toURI() typically DOES NOT include an URI authority
assertNormalize(jettyHome.toFile().toURI(), expected);
}
@Test
public void testExpandJettyBase()
{
// Expand jetty.base
assertExpandPath("${jetty.base}", jettyBase);
assertExpandPath("${jetty.base}", jettyBase.toString());
}
@Test
public void testExpandJettyHome()
{
// Expand jetty.home
assertExpandPath("${jetty.home}", jettyHome);
assertExpandPath("${jetty.home}", jettyHome.toString());
}
@Test

View File

@ -0,0 +1,78 @@
//
// ========================================================================
// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.quickstart;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import java.net.URI;
import java.nio.file.FileSystems;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class AttributeNormalizer_ToCanonicalUriTest
{
@Parameterized.Parameters(name = "[{index}] {0} - {1}")
public static List<Object[]> data()
{
List<Object[]> data = new ArrayList<>();
// root without authority
data.add(new String[]{ "file:/", "file:/" });
data.add(new String[]{ "file:/F:/", "file:/F:" });
// root with empty authority
data.add(new String[]{ "file:///", "file:///" });
data.add(new String[]{ "file:///F:/", "file:///F:" });
// deep directory - no authority
data.add(new String[]{ "file:/home/user/code/", "file:/home/user/code" });
data.add(new String[]{ "file:/C:/code/", "file:/C:/code" });
// deep directory - with authority
data.add(new String[]{ "file:///home/user/code/", "file:///home/user/code" });
data.add(new String[]{ "file:///C:/code/", "file:///C:/code" });
// Some non-file tests
data.add(new String[]{ "http://webtide.com/", "http://webtide.com/" });
data.add(new String[]{ "http://webtide.com/cometd/", "http://webtide.com/cometd" });
return data;
}
@Parameterized.Parameter
public String input;
@Parameterized.Parameter(1)
public String expected;
@Test
public void testCanonicalURI()
{
URI inputURI = URI.create(input);
URI actual = AttributeNormalizer.toCanonicalURI(inputURI);
assertThat(input, actual.toASCIIString(), is(expected));
}
}