提交 8a0a23e0 编写于 作者: K kohsuke

artifact listing became more intelligent. It now prints a part of path if...

artifact listing became more intelligent. It now prints a part of path if that's necessary to disambiguate them (#1435)


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@7897 71c3de6d-444a-0410-be80-ed276b4c234a
上级 538ee523
...@@ -50,6 +50,9 @@ import java.util.List; ...@@ -50,6 +50,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.Locale; import java.util.Locale;
import java.util.Set;
import java.util.HashSet;
import java.util.HashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
...@@ -487,8 +490,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -487,8 +490,9 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* Gets the first {@value #CUTOFF} artifacts (relative to {@link #getArtifactsDir()}. * Gets the first {@value #CUTOFF} artifacts (relative to {@link #getArtifactsDir()}.
*/ */
public List<Artifact> getArtifacts() { public List<Artifact> getArtifacts() {
List<Artifact> r = new ArrayList<Artifact>(); ArtifactList r = new ArtifactList();
addArtifacts(getArtifactsDir(),"",r); addArtifacts(getArtifactsDir(),"",r);
r.computeDisplayName();
return r; return r;
} }
...@@ -519,6 +523,77 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -519,6 +523,77 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
private static final int CUTOFF = 17; // 0, 1,... 16, and then "too many" private static final int CUTOFF = 17; // 0, 1,... 16, and then "too many"
public final class ArtifactList extends ArrayList<Artifact> {
public void computeDisplayName() {
if(size()>CUTOFF) return; // we are not going to display file names, so no point in computing this
int maxDepth = 0;
int[] len = new int[size()];
String[][] tokens = new String[size()][];
for( int i=0; i<tokens.length; i++ ) {
tokens[i] = get(i).relativePath.split("[\\\\/]+");
maxDepth = Math.max(maxDepth,tokens[i].length);
len[i] = 1;
}
boolean collision;
int depth=0;
do {
collision = false;
Map<String,Integer/*index*/> names = new HashMap<String,Integer>();
for (int i = 0; i < tokens.length; i++) {
String[] token = tokens[i];
String displayName = combineLast(token,len[i]);
Integer j = names.put(displayName, i);
if(j!=null) {
collision = true;
if(j>=0)
len[j]++;
len[i]++;
names.put(displayName,-1); // occupy this name but don't let len[i] incremented with additional collisions
}
}
} while(collision && depth++<maxDepth);
for (int i = 0; i < tokens.length; i++)
get(i).displayPath = combineLast(tokens[i],len[i]);
// OUTER:
// for( int n=1; n<maxLen; n++ ) {
// // if we just display the last n token, would it be suffice for disambiguation?
// Set<String> names = new HashSet<String>();
// for (String[] token : tokens) {
// if(!names.add(combineLast(token,n)))
// continue OUTER; // collision. Increase n and try again
// }
//
// // this n successfully diambiguates
// for (int i = 0; i < tokens.length; i++) {
// String[] token = tokens[i];
// get(i).displayPath = combineLast(token,n);
// }
// return;
// }
// // it's impossible to get here, as that means
// // we have the same artifacts archived twice, but be defensive
// for (Artifact a : this)
// a.displayPath = a.relativePath;
}
/**
* Combines last N token into the "a/b/c" form.
*/
private String combineLast(String[] token, int n) {
StringBuffer buf = new StringBuffer();
for( int i=Math.max(0,token.length-n); i<token.length; i++ ) {
if(buf.length()>0) buf.append('/');
buf.append(token[i]);
}
return buf.toString();
}
}
/** /**
* A build artifact. * A build artifact.
*/ */
...@@ -526,9 +601,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -526,9 +601,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/** /**
* Relative path name from {@link Run#getArtifactsDir()} * Relative path name from {@link Run#getArtifactsDir()}
*/ */
private final String relativePath; public final String relativePath;
/**
* Truncated form of {@link #relativePath} just enough
* to disambiguate {@link Artifact}s.
*/
/*package*/ String displayPath;
private Artifact(String relativePath) { /*package for test*/ Artifact(String relativePath) {
this.relativePath = relativePath; this.relativePath = relativePath;
} }
...@@ -546,6 +627,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -546,6 +627,10 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
return getFile().getName(); return getFile().getName();
} }
public String getDisplayPath() {
return displayPath;
}
public String toString() { public String toString() {
return relativePath; return relativePath;
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
<ul> <ul>
<j:forEach var="f" items="${artifacts}"> <j:forEach var="f" items="${artifacts}">
<li> <li>
<a href="${baseURL}artifact/${f}">${f.fileName}</a> <a href="${baseURL}artifact/${f}">${f.displayPath}</a>
<st:nbsp/> <st:nbsp/>
<a href="${baseURL}artifact/${f}/*fingerprint*/"><img src="${imagesURL}/16x16/fingerprint.gif" alt="[fingerprint]" /></a> <a href="${baseURL}artifact/${f}/*fingerprint*/"><img src="${imagesURL}/16x16/fingerprint.gif" alt="[fingerprint]" /></a>
</li> </li>
......
package hudson.model;
import junit.framework.TestCase;
import java.util.GregorianCalendar;
import java.util.List;
/**
* @author Kohsuke Kawaguchi
*/
public class RunTest extends TestCase {
private List<Run<?,?>.Artifact> createArtifactList(String... paths) {
Run<?,?> r = new Run(null,new GregorianCalendar()) {
};
Run<?,?>.ArtifactList list = r.new ArtifactList();
for (String p : paths) {
list.add(r.new Artifact(p));
}
list.computeDisplayName();
return list;
}
public void testArtifactListDisambiguation1() {
List<Run<?, ?>.Artifact> a = createArtifactList("a/b/c.xml", "d/f/g.xml", "h/i/j.xml");
assertEquals(a.get(0).getDisplayPath(),"c.xml");
assertEquals(a.get(1).getDisplayPath(),"g.xml");
assertEquals(a.get(2).getDisplayPath(),"j.xml");
}
public void testArtifactListDisambiguation2() {
List<Run<?, ?>.Artifact> a = createArtifactList("a/b/c.xml", "d/f/g.xml", "h/i/g.xml");
assertEquals(a.get(0).getDisplayPath(),"c.xml");
assertEquals(a.get(1).getDisplayPath(),"f/g.xml");
assertEquals(a.get(2).getDisplayPath(),"i/g.xml");
}
public void testArtifactListDisambiguation3() {
List<Run<?, ?>.Artifact> a = createArtifactList("a.xml","a/a.xml");
assertEquals(a.get(0).getDisplayPath(),"a.xml");
assertEquals(a.get(1).getDisplayPath(),"a/a.xml");
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册