diff options
author | Paul Martin <paul@paulsputer.com> | 2015-12-25 22:35:11 +0000 |
---|---|---|
committer | Paul Martin <paul@paulsputer.com> | 2015-12-25 22:35:11 +0000 |
commit | 46f33f87750573713509fbdbd0fc2ae51dc12044 (patch) | |
tree | aa227353d88fa97da0b40c02c46d45862c7013d3 /src | |
parent | 2539ceea0d47467d54cedd340afa6ede2909b2bd (diff) | |
download | gitblit-46f33f87750573713509fbdbd0fc2ae51dc12044.tar.gz gitblit-46f33f87750573713509fbdbd0fc2ae51dc12044.zip |
Fix for #976 - Filestore links via browser
+ GitLFS client support
+ FilestoreModel now parses meta file
+ Read meta heading from cache if available
+ Authentication based on accept headers for browser view filestore login
+ PathModel & PathChangeModel now understands filestore items
+ Zip & Rar downloads contain include filestore items
+ Filestore servlet returns LFS JSON error only if accepted by client
+ DiffStat now knows repository to allow identification of filestore items
+ Filestore items identified and returned via view, raw & blob links on
blame, commitDiff, commit and Tree pages
Diffstat (limited to 'src')
24 files changed, 468 insertions, 131 deletions
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 0a99953a..6232552e 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -94,6 +94,10 @@ public class Constants { public static final int LEN_SHORTLOG = 78;
public static final int LEN_SHORTLOG_REFS = 60;
+
+ public static final int LEN_FILESTORE_META_MIN = 125;
+
+ public static final int LEN_FILESTORE_META_MAX = 146;
public static final String DEFAULT_BRANCH = "default";
diff --git a/src/main/java/com/gitblit/models/FilestoreModel.java b/src/main/java/com/gitblit/models/FilestoreModel.java index 4144df6b..2ed1ede9 100644 --- a/src/main/java/com/gitblit/models/FilestoreModel.java +++ b/src/main/java/com/gitblit/models/FilestoreModel.java @@ -20,6 +20,10 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.NoSuchElementException; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.gitblit.Constants; /** * A FilestoreModel represents a file stored outside a repository but referenced by the repository using a unique objectID @@ -31,6 +35,18 @@ public class FilestoreModel implements Serializable { private static final long serialVersionUID = 1L; + private static final String metaRegexText = new StringBuilder() + .append("version\\shttps://git-lfs.github.com/spec/v1\\s+") + .append("oid\\ssha256:(" + Constants.REGEX_SHA256 + ")\\s+") + .append("size\\s([0-9]+)") + .toString(); + + private static final Pattern metaRegex = Pattern.compile(metaRegexText); + + private static final int metaRegexIndexSHA = 1; + + private static final int metaRegexIndexSize = 2; + public final String oid; private Long size; @@ -43,6 +59,12 @@ public class FilestoreModel implements Serializable { //Access Control private List<String> repositories; + public FilestoreModel(String id, long definedSize) { + oid = id; + size = definedSize; + status = Status.ReferenceOnly; + } + public FilestoreModel(String id, long expectedSize, UserModel user, String repo) { oid = id; size = expectedSize; @@ -53,6 +75,29 @@ public class FilestoreModel implements Serializable { repositories.add(repo); } + /* + * Attempts to create a FilestoreModel from the given meta string + * + * @return A valid FilestoreModel if successful, otherwise null + */ + public static FilestoreModel fromMetaString(String meta) { + + Matcher m = metaRegex.matcher(meta); + + if (m.find()) { + try + { + final Long size = Long.parseLong(m.group(metaRegexIndexSize)); + final String sha = m.group(metaRegexIndexSHA); + return new FilestoreModel(sha, size); + } catch (Exception e) { + //Fail silent - it is not a valid filestore item + } + } + + return null; + } + public synchronized long getSize() { return size; } @@ -102,19 +147,25 @@ public class FilestoreModel implements Serializable { } public synchronized void addRepository(String repo) { - if (!repositories.contains(repo)) { - repositories.add(repo); - } + if (status != Status.ReferenceOnly) { + if (!repositories.contains(repo)) { + repositories.add(repo); + } + } } public synchronized void removeRepository(String repo) { - repositories.remove(repo); + if (status != Status.ReferenceOnly) { + repositories.remove(repo); + } } public synchronized boolean isInRepositoryList(List<String> repoList) { - for (String name : repositories) { - if (repoList.contains(name)) { - return true; + if (status != Status.ReferenceOnly) { + for (String name : repositories) { + if (repoList.contains(name)) { + return true; + } } } return false; @@ -122,6 +173,8 @@ public class FilestoreModel implements Serializable { public static enum Status { + ReferenceOnly(-42), + Deleted(-30), AuthenticationRequired(-20), diff --git a/src/main/java/com/gitblit/models/PathModel.java b/src/main/java/com/gitblit/models/PathModel.java index bf585425..3c280eb4 100644 --- a/src/main/java/com/gitblit/models/PathModel.java +++ b/src/main/java/com/gitblit/models/PathModel.java @@ -15,11 +15,20 @@ */
package com.gitblit.models;
+import java.io.IOException;
import java.io.Serializable;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffEntry.ChangeType;
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+import com.gitblit.manager.FilestoreManager;
+import com.gitblit.utils.JGitUtils;
/**
* PathModel is a serializable model class that represents a file or a folder,
@@ -34,16 +43,18 @@ public class PathModel implements Serializable, Comparable<PathModel> { public final String name;
public final String path;
+ private final FilestoreModel filestoreItem;
public final long size;
public final int mode;
public final String objectId;
public final String commitId;
public boolean isParentPath;
-
- public PathModel(String name, String path, long size, int mode, String objectId, String commitId) {
+
+ public PathModel(String name, String path, FilestoreModel filestoreItem, long size, int mode, String objectId, String commitId) {
this.name = name;
this.path = path;
- this.size = size;
+ this.filestoreItem = filestoreItem;
+ this.size = (filestoreItem == null) ? size : filestoreItem.getSize();
this.mode = mode;
this.objectId = objectId;
this.commitId = commitId;
@@ -66,6 +77,18 @@ public class PathModel implements Serializable, Comparable<PathModel> { || FileMode.EXECUTABLE_FILE.equals(mode)
|| (FileMode.MISSING.equals(mode) && !isSymlink() && !isSubmodule() && !isTree());
}
+
+ public boolean isFilestoreItem() {
+ return filestoreItem != null;
+ }
+
+ public String getFilestoreOid() {
+ if (filestoreItem != null) {
+ return filestoreItem.oid;
+ }
+
+ return null;
+ }
@Override
public int hashCode() {
@@ -119,9 +142,9 @@ public class PathModel implements Serializable, Comparable<PathModel> { public int deletions;
- public PathChangeModel(String name, String path, long size, int mode, String objectId,
+ public PathChangeModel(String name, String path, FilestoreModel filestoreItem, long size, int mode, String objectId,
String commitId, ChangeType type) {
- super(name, path, size, mode, objectId, commitId);
+ super(name, path, filestoreItem, size, mode, objectId, commitId);
this.changeType = type;
}
@@ -148,18 +171,33 @@ public class PathModel implements Serializable, Comparable<PathModel> { return super.equals(o);
}
- public static PathChangeModel from(DiffEntry diff, String commitId) {
+ public static PathChangeModel from(DiffEntry diff, String commitId, Repository repository) {
PathChangeModel pcm;
+ FilestoreModel filestoreItem = null;
+ long size = 0;
+
+ if (repository != null) {
+ try (RevWalk revWalk = new RevWalk(repository)) {
+ size = revWalk.getObjectReader().getObjectSize(diff.getNewId().toObjectId(), Constants.OBJ_BLOB);
+
+ if (JGitUtils.isPossibleFilestoreItem(size)) {
+ filestoreItem = JGitUtils.getFilestoreItem(revWalk.getObjectReader().open(diff.getNewId().toObjectId()));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
if (diff.getChangeType().equals(ChangeType.DELETE)) {
- pcm = new PathChangeModel(diff.getOldPath(), diff.getOldPath(), 0, diff
+ pcm = new PathChangeModel(diff.getOldPath(), diff.getOldPath(), filestoreItem, size, diff
.getNewMode().getBits(), diff.getOldId().name(), commitId, diff
.getChangeType());
} else if (diff.getChangeType().equals(ChangeType.RENAME)) {
- pcm = new PathChangeModel(diff.getOldPath(), diff.getNewPath(), 0, diff
+ pcm = new PathChangeModel(diff.getOldPath(), diff.getNewPath(), filestoreItem, size, diff
.getNewMode().getBits(), diff.getNewId().name(), commitId, diff
.getChangeType());
} else {
- pcm = new PathChangeModel(diff.getNewPath(), diff.getNewPath(), 0, diff
+ pcm = new PathChangeModel(diff.getNewPath(), diff.getNewPath(), filestoreItem, size, diff
.getNewMode().getBits(), diff.getNewId().name(), commitId, diff
.getChangeType());
}
diff --git a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java index b9cb0885..e1d76db0 100644 --- a/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java +++ b/src/main/java/com/gitblit/servlet/AccessRestrictionFilter.java @@ -133,10 +133,11 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter { /**
* Allows authentication header to be altered based on the action requested
* Default is WWW-Authenticate
+ * @param httpRequest
* @param action
* @return authentication type header
*/
- protected String getAuthenticationHeader(String action) {
+ protected String getAuthenticationHeader(HttpServletRequest httpRequest, String action) {
return "WWW-Authenticate";
}
@@ -192,7 +193,7 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter { logger.info(MessageFormat.format("ARF: CREATE CHALLENGE {0}", fullUrl));
}
- httpResponse.setHeader(getAuthenticationHeader(urlRequestType), CHALLENGE);
+ httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
} else {
@@ -239,7 +240,7 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter { if (runtimeManager.isDebugMode()) {
logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
}
- httpResponse.setHeader(getAuthenticationHeader(urlRequestType), CHALLENGE);
+ httpResponse.setHeader(getAuthenticationHeader(httpRequest, urlRequestType), CHALLENGE);
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return;
} else {
diff --git a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java index 07562561..319c4f91 100644 --- a/src/main/java/com/gitblit/servlet/DownloadZipServlet.java +++ b/src/main/java/com/gitblit/servlet/DownloadZipServlet.java @@ -22,6 +22,7 @@ import java.util.Date; import com.google.inject.Inject;
import com.google.inject.Singleton;
+
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
@@ -34,6 +35,7 @@ import org.slf4j.LoggerFactory; import com.gitblit.Constants;
import com.gitblit.IStoredSettings;
import com.gitblit.Keys;
+import com.gitblit.manager.IFilestoreManager;
import com.gitblit.manager.IRepositoryManager;
import com.gitblit.utils.CompressionUtils;
import com.gitblit.utils.JGitUtils;
@@ -57,6 +59,8 @@ public class DownloadZipServlet extends HttpServlet { private IStoredSettings settings;
private IRepositoryManager repositoryManager;
+
+ private IFilestoreManager filestoreManager;
public static enum Format {
zip(".zip"), tar(".tar"), gz(".tar.gz"), xz(".tar.xz"), bzip2(".tar.bzip2");
@@ -78,9 +82,10 @@ public class DownloadZipServlet extends HttpServlet { }
@Inject
- public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager) {
+ public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager, IFilestoreManager filestoreManager) {
this.settings = settings;
this.repositoryManager = repositoryManager;
+ this.filestoreManager = filestoreManager;
}
/**
@@ -169,22 +174,23 @@ public class DownloadZipServlet extends HttpServlet { response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
+
try {
switch (format) {
case zip:
- CompressionUtils.zip(r, basePath, objectId, response.getOutputStream());
+ CompressionUtils.zip(r, filestoreManager, basePath, objectId, response.getOutputStream());
break;
case tar:
- CompressionUtils.tar(r, basePath, objectId, response.getOutputStream());
+ CompressionUtils.tar(r, filestoreManager, basePath, objectId, response.getOutputStream());
break;
case gz:
- CompressionUtils.gz(r, basePath, objectId, response.getOutputStream());
+ CompressionUtils.gz(r, filestoreManager, basePath, objectId, response.getOutputStream());
break;
case xz:
- CompressionUtils.xz(r, basePath, objectId, response.getOutputStream());
+ CompressionUtils.xz(r, filestoreManager, basePath, objectId, response.getOutputStream());
break;
case bzip2:
- CompressionUtils.bzip2(r, basePath, objectId, response.getOutputStream());
+ CompressionUtils.bzip2(r, filestoreManager, basePath, objectId, response.getOutputStream());
break;
}
diff --git a/src/main/java/com/gitblit/servlet/FilestoreServlet.java b/src/main/java/com/gitblit/servlet/FilestoreServlet.java index 8f303fcf..4af9084d 100644 --- a/src/main/java/com/gitblit/servlet/FilestoreServlet.java +++ b/src/main/java/com/gitblit/servlet/FilestoreServlet.java @@ -238,7 +238,10 @@ public class FilestoreServlet extends HttpServlet { } } else { response.setStatus(responseObject.error.code); - serialize(response, responseObject.error); + + if (isMetaRequest) { + serialize(response, responseObject.error); + } } }; diff --git a/src/main/java/com/gitblit/servlet/GitFilter.java b/src/main/java/com/gitblit/servlet/GitFilter.java index 27408f02..9522893e 100644 --- a/src/main/java/com/gitblit/servlet/GitFilter.java +++ b/src/main/java/com/gitblit/servlet/GitFilter.java @@ -102,8 +102,8 @@ public class GitFilter extends AccessRestrictionFilter { }
/**
- * Analyze the url and returns the action of the request. Return values are
- * either "/git-receive-pack" or "/git-upload-pack".
+ * Analyze the url and returns the action of the request. Return values are:
+ * "/git-receive-pack", "/git-upload-pack" or "/info/lfs".
*
* @param serverUrl
* @return action of the request
@@ -316,18 +316,22 @@ public class GitFilter extends AccessRestrictionFilter { /**
* Git lfs action uses an alternative authentication header,
+ * dependent on the viewing method.
*
+ * @param httpRequest
* @param action
* @return
*/
@Override
- protected String getAuthenticationHeader(String action) {
+ protected String getAuthenticationHeader(HttpServletRequest httpRequest, String action) {
if (action.equals(gitLfs)) {
- return "LFS-Authenticate";
+ if (hasContentInRequestHeader(httpRequest, "Accept", FilestoreServlet.GIT_LFS_META_MIME)) {
+ return "LFS-Authenticate";
+ }
}
- return super.getAuthenticationHeader(action);
+ return super.getAuthenticationHeader(httpRequest, action);
}
/**
diff --git a/src/main/java/com/gitblit/servlet/RawServlet.java b/src/main/java/com/gitblit/servlet/RawServlet.java index 897047d8..dca57730 100644 --- a/src/main/java/com/gitblit/servlet/RawServlet.java +++ b/src/main/java/com/gitblit/servlet/RawServlet.java @@ -364,7 +364,7 @@ public class RawServlet extends HttpServlet { if (pathEntries.get(0).path.indexOf('/') > -1) { // we are in a subdirectory, add parent directory link String pp = URLEncoder.encode(requestedPath, Constants.ENCODING); - pathEntries.add(0, new PathModel("..", pp + "/..", 0, FileMode.TREE.getBits(), null, null)); + pathEntries.add(0, new PathModel("..", pp + "/..", null, 0, FileMode.TREE.getBits(), null, null)); } } diff --git a/src/main/java/com/gitblit/utils/CompressionUtils.java b/src/main/java/com/gitblit/utils/CompressionUtils.java index b06edd22..1b8e6fc3 100644 --- a/src/main/java/com/gitblit/utils/CompressionUtils.java +++ b/src/main/java/com/gitblit/utils/CompressionUtils.java @@ -16,6 +16,9 @@ package com.gitblit.utils;
import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.MessageFormat;
@@ -28,9 +31,11 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry; import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.CompressorException;
import org.apache.commons.compress.compressors.CompressorStreamFactory;
+import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
@@ -41,6 +46,11 @@ import org.eclipse.jgit.treewalk.filter.PathFilter; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.gitblit.GitBlit;
+import com.gitblit.manager.IFilestoreManager;
+import com.gitblit.models.FilestoreModel;
+import com.gitblit.models.FilestoreModel.Status;
+
/**
* Collection of static methods for retrieving information from a repository.
*
@@ -87,7 +97,7 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- public static boolean zip(Repository repository, String basePath, String objectId,
+ public static boolean zip(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
RevCommit commit = JGitUtils.getCommit(repository, objectId);
if (commit == null) {
@@ -115,16 +125,40 @@ public class CompressionUtils { continue;
}
tw.getObjectId(id, 0);
-
+
+ ObjectLoader loader = repository.open(id);
+
ZipArchiveEntry entry = new ZipArchiveEntry(tw.getPathString());
- entry.setSize(reader.getObjectSize(id, Constants.OBJ_BLOB));
+
+ FilestoreModel filestoreItem = null;
+
+ if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) {
+ filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id));
+ }
+
+ final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize();
+
+ entry.setSize(size);
entry.setComment(commit.getName());
entry.setUnixMode(mode.getBits());
entry.setTime(modified);
zos.putArchiveEntry(entry);
+
+ if (filestoreItem == null) {
+ //Copy repository stored file
+ loader.copyTo(zos);
+ } else {
+ //Copy filestore file
+ try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) {
+ IOUtils.copyLarge(streamIn, zos);
+ } catch (Throwable e) {
+ LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e);
+
+ //Handle as per other errors
+ throw e;
+ }
+ }
- ObjectLoader ldr = repository.open(id);
- ldr.copyTo(zos);
zos.closeArchiveEntry();
}
zos.finish();
@@ -151,9 +185,9 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- public static boolean tar(Repository repository, String basePath, String objectId,
+ public static boolean tar(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
- return tar(null, repository, basePath, objectId, os);
+ return tar(null, repository, filestoreManager, basePath, objectId, os);
}
/**
@@ -169,9 +203,9 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- public static boolean gz(Repository repository, String basePath, String objectId,
+ public static boolean gz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
- return tar(CompressorStreamFactory.GZIP, repository, basePath, objectId, os);
+ return tar(CompressorStreamFactory.GZIP, repository, filestoreManager, basePath, objectId, os);
}
/**
@@ -187,9 +221,9 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- public static boolean xz(Repository repository, String basePath, String objectId,
+ public static boolean xz(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
- return tar(CompressorStreamFactory.XZ, repository, basePath, objectId, os);
+ return tar(CompressorStreamFactory.XZ, repository, filestoreManager, basePath, objectId, os);
}
/**
@@ -205,10 +239,10 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- public static boolean bzip2(Repository repository, String basePath, String objectId,
+ public static boolean bzip2(Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
- return tar(CompressorStreamFactory.BZIP2, repository, basePath, objectId, os);
+ return tar(CompressorStreamFactory.BZIP2, repository, filestoreManager, basePath, objectId, os);
}
/**
@@ -227,7 +261,7 @@ public class CompressionUtils { * @return true if repository was successfully zipped to supplied output
* stream
*/
- private static boolean tar(String algorithm, Repository repository, String basePath, String objectId,
+ private static boolean tar(String algorithm, Repository repository, IFilestoreManager filestoreManager, String basePath, String objectId,
OutputStream os) {
RevCommit commit = JGitUtils.getCommit(repository, objectId);
if (commit == null) {
@@ -263,6 +297,7 @@ public class CompressionUtils { if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
continue;
}
+
tw.getObjectId(id, 0);
ObjectLoader loader = repository.open(id);
@@ -278,9 +313,34 @@ public class CompressionUtils { TarArchiveEntry entry = new TarArchiveEntry(tw.getPathString());
entry.setMode(mode.getBits());
entry.setModTime(modified);
- entry.setSize(loader.getSize());
+
+ FilestoreModel filestoreItem = null;
+
+ if (JGitUtils.isPossibleFilestoreItem(loader.getSize())) {
+ filestoreItem = JGitUtils.getFilestoreItem(tw.getObjectReader().open(id));
+ }
+
+ final long size = (filestoreItem == null) ? loader.getSize() : filestoreItem.getSize();
+
+ entry.setSize(size);
tos.putArchiveEntry(entry);
- loader.copyTo(tos);
+
+ if (filestoreItem == null) {
+ //Copy repository stored file
+ loader.copyTo(tos);
+ } else {
+ //Copy filestore file
+ try (FileInputStream streamIn = new FileInputStream(filestoreManager.getStoragePath(filestoreItem.oid))) {
+
+ IOUtils.copyLarge(streamIn, tos);
+ } catch (Throwable e) {
+ LOGGER.error(MessageFormat.format("Failed to archive filestore item {0}", filestoreItem.oid), e);
+
+ //Handle as per other errors
+ throw e;
+ }
+ }
+
tos.closeArchiveEntry();
}
}
diff --git a/src/main/java/com/gitblit/utils/DiffStatFormatter.java b/src/main/java/com/gitblit/utils/DiffStatFormatter.java index 572046ee..a6c3ae29 100644 --- a/src/main/java/com/gitblit/utils/DiffStatFormatter.java +++ b/src/main/java/com/gitblit/utils/DiffStatFormatter.java @@ -20,6 +20,7 @@ import java.io.IOException; import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawText;
+import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.io.NullOutputStream;
import com.gitblit.models.PathModel.PathChangeModel;
@@ -37,9 +38,9 @@ public class DiffStatFormatter extends DiffFormatter { private PathChangeModel path;
- public DiffStatFormatter(String commitId) {
+ public DiffStatFormatter(String commitId, Repository repository) {
super(NullOutputStream.INSTANCE);
- diffStat = new DiffStat(commitId);
+ diffStat = new DiffStat(commitId, repository);
}
@Override
diff --git a/src/main/java/com/gitblit/utils/DiffUtils.java b/src/main/java/com/gitblit/utils/DiffUtils.java index cdebec1b..41aab4cf 100644 --- a/src/main/java/com/gitblit/utils/DiffUtils.java +++ b/src/main/java/com/gitblit/utils/DiffUtils.java @@ -157,13 +157,16 @@ public class DiffUtils { public final List<PathChangeModel> paths = new ArrayList<PathChangeModel>();
private final String commitId;
+
+ private final Repository repository;
- public DiffStat(String commitId) {
+ public DiffStat(String commitId, Repository repository) {
this.commitId = commitId;
+ this.repository = repository;
}
public PathChangeModel addPath(DiffEntry entry) {
- PathChangeModel pcm = PathChangeModel.from(entry, commitId);
+ PathChangeModel pcm = PathChangeModel.from(entry, commitId, repository);
paths.add(pcm);
return pcm;
}
@@ -379,7 +382,7 @@ public class DiffUtils { DiffFormatter df;
switch (outputType) {
case HTML:
- df = new GitBlitDiffFormatter(commit.getName(), path, handler, tabLength);
+ df = new GitBlitDiffFormatter(commit.getName(), repository, path, handler, tabLength);
break;
case PLAIN:
default:
@@ -548,7 +551,7 @@ public class DiffUtils { DiffStat stat = null;
try {
RawTextComparator cmp = RawTextComparator.DEFAULT;
- DiffStatFormatter df = new DiffStatFormatter(commit.getName());
+ DiffStatFormatter df = new DiffStatFormatter(commit.getName(), repository);
df.setRepository(repository);
df.setDiffComparator(cmp);
df.setDetectRenames(true);
diff --git a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java index 86b7ca2e..8ebadbf1 100644 --- a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java +++ b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java @@ -33,6 +33,7 @@ import org.eclipse.jgit.diff.DiffEntry; import org.eclipse.jgit.diff.DiffEntry.ChangeType; import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawText; +import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.util.RawParseUtils; import com.gitblit.models.PathModel.PathChangeModel; @@ -164,11 +165,11 @@ public class GitBlitDiffFormatter extends DiffFormatter { } - public GitBlitDiffFormatter(String commitId, String path, BinaryDiffHandler handler, int tabLength) { + public GitBlitDiffFormatter(String commitId, Repository repository, String path, BinaryDiffHandler handler, int tabLength) { super(new DiffOutputStream()); this.os = (DiffOutputStream) getOutputStream(); this.os.setFormatter(this, handler); - this.diffStat = new DiffStat(commitId); + this.diffStat = new DiffStat(commitId, repository); this.tabLength = tabLength; // If we have a full commitdiff, install maxima to avoid generating a super-long diff listing that // will only tax the browser too much. diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java index c3d02073..7a008139 100644 --- a/src/main/java/com/gitblit/utils/JGitUtils.java +++ b/src/main/java/com/gitblit/utils/JGitUtils.java @@ -28,6 +28,7 @@ import java.util.Iterator; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.filefilter.TrueFileFilter;
@@ -42,6 +43,7 @@ import org.eclipse.jgit.diff.DiffFormatter; import org.eclipse.jgit.diff.RawTextComparator;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.LargeObjectException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.StopWalkException;
import org.eclipse.jgit.lib.BlobBasedConfig;
@@ -84,12 +86,16 @@ import org.eclipse.jgit.util.FS; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
+import com.gitblit.manager.GitblitManager;
+import com.gitblit.models.FilestoreModel;
import com.gitblit.models.GitNote;
import com.gitblit.models.PathModel;
import com.gitblit.models.PathModel.PathChangeModel;
import com.gitblit.models.RefModel;
import com.gitblit.models.SubmoduleModel;
+import com.gitblit.servlet.FilestoreServlet;
import com.google.common.base.Strings;
/**
@@ -993,23 +999,40 @@ public class JGitUtils { tw.setRecursive(true);
tw.addTree(commit.getTree());
while (tw.next()) {
- list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw
- .getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
+ long size = 0;
+ FilestoreModel filestoreItem = null;
+ ObjectId objectId = tw.getObjectId(0);
+
+ try {
+ if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
+
+ size = tw.getObjectReader().getObjectSize(objectId, Constants.OBJ_BLOB);
+
+ if (isPossibleFilestoreItem(size)) {
+ filestoreItem = getFilestoreItem(tw.getObjectReader().open(objectId));
+ }
+ }
+ } catch (Throwable t) {
+ error(t, null, "failed to retrieve blob size for " + tw.getPathString());
+ }
+
+ list.add(new PathChangeModel(tw.getPathString(), tw.getPathString(),filestoreItem, size, tw
+ .getRawMode(0), objectId.getName(), commit.getId().getName(),
ChangeType.ADD));
}
tw.close();
} else {
RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
- DiffStatFormatter df = new DiffStatFormatter(commit.getName());
+ DiffStatFormatter df = new DiffStatFormatter(commit.getName(), repository);
df.setRepository(repository);
df.setDiffComparator(RawTextComparator.DEFAULT);
df.setDetectRenames(true);
List<DiffEntry> diffs = df.scan(parent.getTree(), commit.getTree());
for (DiffEntry diff : diffs) {
// create the path change model
- PathChangeModel pcm = PathChangeModel.from(diff, commit.getName());
-
- if (calculateDiffStat) {
+ PathChangeModel pcm = PathChangeModel.from(diff, commit.getName(), repository);
+
+ if (calculateDiffStat) {
// update file diffstats
df.format(diff);
PathChangeModel pathStat = df.getDiffStat().getPath(pcm.path);
@@ -1083,7 +1106,7 @@ public class JGitUtils { List<DiffEntry> diffEntries = df.scan(startCommit.getTree(), endCommit.getTree());
for (DiffEntry diff : diffEntries) {
- PathChangeModel pcm = PathChangeModel.from(diff, endCommit.getName());
+ PathChangeModel pcm = PathChangeModel.from(diff, endCommit.getName(), repository);
list.add(pcm);
}
Collections.sort(list);
@@ -1167,22 +1190,55 @@ public class JGitUtils { private static PathModel getPathModel(TreeWalk tw, String basePath, RevCommit commit) {
String name;
long size = 0;
+
if (StringUtils.isEmpty(basePath)) {
name = tw.getPathString();
} else {
name = tw.getPathString().substring(basePath.length() + 1);
}
ObjectId objectId = tw.getObjectId(0);
+ FilestoreModel filestoreItem = null;
+
try {
if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
+
size = tw.getObjectReader().getObjectSize(objectId, Constants.OBJ_BLOB);
+
+ if (isPossibleFilestoreItem(size)) {
+ filestoreItem = getFilestoreItem(tw.getObjectReader().open(objectId));
+ }
}
} catch (Throwable t) {
error(t, null, "failed to retrieve blob size for " + tw.getPathString());
}
- return new PathModel(name, tw.getPathString(), size, tw.getFileMode(0).getBits(),
+ return new PathModel(name, tw.getPathString(), filestoreItem, size, tw.getFileMode(0).getBits(),
objectId.getName(), commit.getName());
}
+
+ public static boolean isPossibleFilestoreItem(long size) {
+ return ( (size >= com.gitblit.Constants.LEN_FILESTORE_META_MIN)
+ && (size <= com.gitblit.Constants.LEN_FILESTORE_META_MAX));
+ }
+
+ /**
+ *
+ * @return Representative FilestoreModel if valid, otherwise null
+ */
+ public static FilestoreModel getFilestoreItem(ObjectLoader obj){
+ try {
+ final byte[] blob = obj.getCachedBytes(com.gitblit.Constants.LEN_FILESTORE_META_MAX);
+ final String meta = new String(blob, "UTF-8");
+
+ return FilestoreModel.fromMetaString(meta);
+
+ } catch (LargeObjectException e) {
+ //Intentionally failing silent
+ } catch (Exception e) {
+ error(e, null, "failed to retrieve filestoreItem " + obj.toString());
+ }
+
+ return null;
+ }
/**
* Returns a path model by path string
@@ -1197,29 +1253,34 @@ public class JGitUtils { throws IOException {
long size = 0;
+ FilestoreModel filestoreItem = null;
TreeWalk tw = TreeWalk.forPath(repo, path, commit.getTree());
String pathString = path;
- if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
- size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);
- pathString = PathUtils.getLastPathComponent(pathString);
-
- } else if (tw.isSubtree()) {
+ if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
- // do not display dirs that are behind in the path
- if (!Strings.isNullOrEmpty(filter)) {
- pathString = path.replaceFirst(filter + "/", "");
- }
+ pathString = PathUtils.getLastPathComponent(pathString);
+
+ size = tw.getObjectReader().getObjectSize(tw.getObjectId(0), Constants.OBJ_BLOB);
+
+ if (isPossibleFilestoreItem(size)) {
+ filestoreItem = getFilestoreItem(tw.getObjectReader().open(tw.getObjectId(0)));
+ }
+ } else if (tw.isSubtree()) {
- // remove the last slash from path in displayed link
- if (pathString != null && pathString.charAt(pathString.length()-1) == '/') {
- pathString = pathString.substring(0, pathString.length()-1);
- }
+ // do not display dirs that are behind in the path
+ if (!Strings.isNullOrEmpty(filter)) {
+ pathString = path.replaceFirst(filter + "/", "");
}
- return new PathModel(pathString, tw.getPathString(), size, tw.getFileMode(0).getBits(),
- tw.getObjectId(0).getName(), commit.getName());
+ // remove the last slash from path in displayed link
+ if (pathString != null && pathString.charAt(pathString.length()-1) == '/') {
+ pathString = pathString.substring(0, pathString.length()-1);
+ }
+ }
+ return new PathModel(pathString, tw.getPathString(), filestoreItem, size, tw.getFileMode(0).getBits(),
+ tw.getObjectId(0).getName(), commit.getName());
}
@@ -2513,4 +2574,27 @@ public class JGitUtils { }
return new MergeResult(MergeStatus.FAILED, null);
}
+
+
+ /**
+ * Returns the LFS URL for the given oid
+ * Currently assumes that the Gitblit Filestore is used
+ *
+ * @param baseURL
+ * @param repository name
+ * @param oid of lfs item
+ * @return the lfs item URL
+ */
+ public static String getLfsRepositoryUrl(String baseURL, String repositoryName, String oid) {
+
+ if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {
+ baseURL = baseURL.substring(0, baseURL.length() - 1);
+ }
+
+ return baseURL + com.gitblit.Constants.R_PATH
+ + repositoryName + "/"
+ + com.gitblit.Constants.R_LFS
+ + "objects/" + oid;
+
+ }
}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlamePage.java b/src/main/java/com/gitblit/wicket/pages/BlamePage.java index e45bbbc8..2fcca0ae 100644 --- a/src/main/java/com/gitblit/wicket/pages/BlamePage.java +++ b/src/main/java/com/gitblit/wicket/pages/BlamePage.java @@ -32,6 +32,7 @@ import org.apache.wicket.PageParameters; import org.apache.wicket.behavior.SimpleAttributeModifier;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.ExternalLink;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
@@ -93,9 +94,34 @@ public class BlamePage extends RepositoryPage { final BlameType activeBlameType = BlameType.get(blameTypeParam);
RevCommit commit = getCommit();
-
- add(new BookmarkablePageLink<Void>("blobLink", BlobPage.class,
- WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+
+ PathModel pathModel = null;
+
+ List<PathModel> paths = JGitUtils.getFilesInPath(getRepository(), StringUtils.getRootPath(blobPath), commit);
+ for (PathModel path : paths) {
+ if (path.path.equals(blobPath)) {
+ pathModel = path;
+ break;
+ }
+ }
+
+ if (pathModel == null) {
+ final String notFound = MessageFormat.format("Blame page failed to find {0} in {1} @ {2}",
+ blobPath, repositoryName, objectId);
+ logger.error(notFound);
+ add(new Label("annotation").setVisible(false));
+ add(new Label("missingBlob", missingBlob(blobPath, commit)).setEscapeModelStrings(false));
+ return;
+ }
+
+ if (pathModel.isFilestoreItem()) {
+ String rawUrl = JGitUtils.getLfsRepositoryUrl(getContextUrl(), repositoryName, pathModel.getFilestoreOid());
+ add(new ExternalLink("blobLink", rawUrl));
+ } else {
+ add(new BookmarkablePageLink<Void>("blobLink", BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, objectId, blobPath)));
+ }
+
add(new BookmarkablePageLink<Void>("commitLink", CommitPage.class,
WicketUtils.newObjectParameter(repositoryName, objectId)));
add(new BookmarkablePageLink<Void>("commitDiffLink", CommitDiffPage.class,
@@ -134,23 +160,9 @@ public class BlamePage extends RepositoryPage { final DateFormat df = new SimpleDateFormat(format);
df.setTimeZone(getTimeZone());
- PathModel pathModel = null;
- List<PathModel> paths = JGitUtils.getFilesInPath(getRepository(), StringUtils.getRootPath(blobPath), commit);
- for (PathModel path : paths) {
- if (path.path.equals(blobPath)) {
- pathModel = path;
- break;
- }
- }
+
- if (pathModel == null) {
- final String notFound = MessageFormat.format("Blame page failed to find {0} in {1} @ {2}",
- blobPath, repositoryName, objectId);
- logger.error(notFound);
- add(new Label("annotation").setVisible(false));
- add(new Label("missingBlob", missingBlob(blobPath, commit)).setEscapeModelStrings(false));
- return;
- }
+
add(new Label("missingBlob").setVisible(false));
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html index 2e0d57ce..254d7d0c 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.html @@ -45,6 +45,7 @@ <td class="changeType"><span wicket:id="changeType">[change type]</span></td>
<td class="path"><span wicket:id="pathName">[commit path]</span></td>
<td class="hidden-phone rightAlign">
+ <span wicket:id="filestore" style="margin-right:20px;" class="aui-lozenge aui-lozenge-moved"></span>
<span class="hidden-tablet" style="padding-right:20px;" wicket:id="diffStat"></span>
<span class="link">
<span class="hidden-tablet"><a wicket:id="patch"><wicket:message key="gb.patch"></wicket:message></a> | </span><a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a><span class="hidden-tablet"> | <a wicket:id="raw"><wicket:message key="gb.raw"></wicket:message></a></span> | <a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java index b56d721c..9bc1570d 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java +++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java @@ -135,6 +135,8 @@ public class CommitDiffPage extends RepositoryPage { @Override public void populateItem(final Item<PathChangeModel> item) { final PathChangeModel entry = item.getModelObject(); + final String filestoreItemUrl = entry.isFilestoreItem() ? JGitUtils.getLfsRepositoryUrl(getContextUrl(), repositoryName, entry.getFilestoreOid()) : null; + Label changeType = new Label("changeType", ""); WicketUtils.setChangeTypeCssClass(changeType, entry.changeType); setChangeTypeTooltip(changeType, entry.changeType); @@ -143,6 +145,7 @@ public class CommitDiffPage extends RepositoryPage { boolean hasSubmodule = false; String submodulePath = null; + if (entry.isTree()) { // tree item.add(new LinkPanel("pathName", null, entry.path, TreePage.class, @@ -159,11 +162,13 @@ public class CommitDiffPage extends RepositoryPage { item.add(new LinkPanel("pathName", "list", entry.path + " @ " + getShortObjectId(submoduleId), "#n" + entry.objectId)); } else { // add relative link - item.add(new LinkPanel("pathName", "list", entry.path, "#n" + entry.objectId)); + item.add(new LinkPanel("pathName", "list", entry.path, entry.isFilestoreItem() ? filestoreItemUrl : "#n" + entry.objectId)); } // quick links if (entry.isSubmodule()) { + item.add(new Label("filestore", getString("gb.filestore")).setVisible(false)); + item.add(new ExternalLink("raw", "").setEnabled(false)); // submodule item.add(new ExternalLink("patch", "").setEnabled(false)); @@ -179,12 +184,24 @@ public class CommitDiffPage extends RepositoryPage { .newPathParameter(repositoryName, entry.commitId, entry.path)) .setEnabled(!entry.changeType.equals(ChangeType.ADD) && !entry.changeType.equals(ChangeType.DELETE))); - item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils - .newPathParameter(repositoryName, entry.commitId, entry.path)) - .setEnabled(!entry.changeType.equals(ChangeType.DELETE))); - String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path); - item.add(new ExternalLink("raw", rawUrl) - .setEnabled(!entry.changeType.equals(ChangeType.DELETE))); + + if (entry.isFilestoreItem()) { + item.add(new Label("filestore", getString("gb.filestore")).setVisible(true)); + + item.add(new ExternalLink("view", filestoreItemUrl)); + item.add(new ExternalLink("raw", filestoreItemUrl)); + } else { + + item.add(new Label("filestore", getString("gb.filestore")).setVisible(false)); + + item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils + .newPathParameter(repositoryName, entry.commitId, entry.path)) + .setEnabled(!entry.changeType.equals(ChangeType.DELETE))); + + item.add(new ExternalLink("raw", RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path)) + .setEnabled(!entry.changeType.equals(ChangeType.DELETE))); + } + item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils .newPathParameter(repositoryName, entry.commitId, entry.path)) .setEnabled(!entry.changeType.equals(ChangeType.ADD) diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.html b/src/main/java/com/gitblit/wicket/pages/CommitPage.html index 2aa10f26..23e94380 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitPage.html +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.html @@ -77,8 +77,9 @@ <table class="pretty">
<tr wicket:id="changedPath">
<td class="changeType"><span wicket:id="changeType">[change type]</span></td>
- <td class="path"><span wicket:id="pathName">[commit path]</span></td>
+ <td class="path"><span wicket:id="pathName">[commit path]</span></td>
<td class="hidden-phone rightAlign">
+ <span wicket:id="filestore" style="margin-right:20px;" class="aui-lozenge aui-lozenge-moved"></span>
<span class="hidden-tablet" style="padding-right:20px;" wicket:id="diffStat"></span>
<span class="link">
<a wicket:id="diff"><wicket:message key="gb.diff"></wicket:message></a> | <span class="hidden-tablet"><a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="raw"><wicket:message key="gb.raw"></wicket:message></a> | </span><a wicket:id="blame"><wicket:message key="gb.blame"></wicket:message></a> | <a wicket:id="history"><wicket:message key="gb.history"></wicket:message></a>
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitPage.java b/src/main/java/com/gitblit/wicket/pages/CommitPage.java index 0a1a68d4..c8411738 100644 --- a/src/main/java/com/gitblit/wicket/pages/CommitPage.java +++ b/src/main/java/com/gitblit/wicket/pages/CommitPage.java @@ -163,6 +163,8 @@ public class CommitPage extends RepositoryPage { @Override
public void populateItem(final Item<PathChangeModel> item) {
final PathChangeModel entry = item.getModelObject();
+ final String filestoreItemUrl = entry.isFilestoreItem() ? JGitUtils.getLfsRepositoryUrl(getContextUrl(), repositoryName, entry.getFilestoreOid()) : null;
+
Label changeType = new Label("changeType", "");
WicketUtils.setChangeTypeCssClass(changeType, entry.changeType);
setChangeTypeTooltip(changeType, entry.changeType);
@@ -194,9 +196,13 @@ public class CommitPage extends RepositoryPage { path = JGitUtils.getStringContent(getRepository(), getCommit().getTree(), path);
displayPath = entry.path + " -> " + path;
}
- item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
- WicketUtils
- .newPathParameter(repositoryName, entry.commitId, path)));
+
+ if (entry.isFilestoreItem()) {
+ item.add(new LinkPanel("pathName", "list", entry.path, filestoreItemUrl));
+ } else {
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, entry.commitId, path)));
+ }
}
@@ -204,6 +210,8 @@ public class CommitPage extends RepositoryPage { if (entry.isSubmodule()) {
item.add(new ExternalLink("raw", "").setEnabled(false));
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
+
// submodule
item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, WicketUtils
.newPathParameter(repositoryName, entry.commitId, entry.path))
@@ -220,12 +228,22 @@ public class CommitPage extends RepositoryPage { .newPathParameter(repositoryName, entry.commitId, entry.path))
.setEnabled(!entry.changeType.equals(ChangeType.ADD)
&& !entry.changeType.equals(ChangeType.DELETE)));
- item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
- .newPathParameter(repositoryName, entry.commitId, entry.path))
- .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
- String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path);
- item.add(new ExternalLink("raw", rawUrl)
- .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
+
+ if (entry.isFilestoreItem()) {
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(true));
+
+ item.add(new ExternalLink("view", filestoreItemUrl));
+ item.add(new ExternalLink("raw", filestoreItemUrl));
+ } else {
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
+
+ item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils
+ .newPathParameter(repositoryName, entry.commitId, entry.path))
+ .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
+ String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, entry.commitId, entry.path);
+ item.add(new ExternalLink("raw", rawUrl)
+ .setEnabled(!entry.changeType.equals(ChangeType.DELETE)));
+ }
item.add(new BookmarkablePageLink<Void>("blame", BlamePage.class, WicketUtils
.newPathParameter(repositoryName, entry.commitId, entry.path))
.setEnabled(!entry.changeType.equals(ChangeType.ADD)
diff --git a/src/main/java/com/gitblit/wicket/pages/FilestorePage.java b/src/main/java/com/gitblit/wicket/pages/FilestorePage.java index be0181bf..7c3bb9d3 100644 --- a/src/main/java/com/gitblit/wicket/pages/FilestorePage.java +++ b/src/main/java/com/gitblit/wicket/pages/FilestorePage.java @@ -35,7 +35,6 @@ import com.gitblit.models.UserModel; import com.gitblit.wicket.CacheControl; import com.gitblit.wicket.FilestoreUI; import com.gitblit.wicket.GitBlitWebSession; -import com.gitblit.wicket.RequiresAdminRole; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.CacheControl.LastModified; diff --git a/src/main/java/com/gitblit/wicket/pages/TreePage.html b/src/main/java/com/gitblit/wicket/pages/TreePage.html index 51a996ff..c07f9c50 100644 --- a/src/main/java/com/gitblit/wicket/pages/TreePage.html +++ b/src/main/java/com/gitblit/wicket/pages/TreePage.html @@ -22,7 +22,8 @@ <table style="width:100%" class="pretty">
<tr wicket:id="changedPath">
<td class="hidden-phone icon"><img wicket:id="pathIcon" /></td>
- <td><span wicket:id="pathName"></span></td>
+ <td><span wicket:id="pathName"></span></td>
+ <td class="hidden-phone filestore"><span wicket:id="filestore" class="aui-lozenge aui-lozenge-moved"></span></td>
<td class="hidden-phone size"><span wicket:id="pathSize">[path size]</span></td>
<td class="hidden-phone mode"><span wicket:id="pathPermissions">[path permissions]</span></td>
<td class="treeLinks"><span wicket:id="pathLinks">[path links]</span></td>
diff --git a/src/main/java/com/gitblit/wicket/pages/TreePage.java b/src/main/java/com/gitblit/wicket/pages/TreePage.java index d7899dcb..f1382147 100644 --- a/src/main/java/com/gitblit/wicket/pages/TreePage.java +++ b/src/main/java/com/gitblit/wicket/pages/TreePage.java @@ -70,12 +70,13 @@ public class TreePage extends RepositoryPage { if (path.lastIndexOf('/') > -1) {
parentPath = path.substring(0, path.lastIndexOf('/'));
}
- PathModel model = new PathModel("..", parentPath, 0, FileMode.TREE.getBits(), null, objectId);
+ PathModel model = new PathModel("..", parentPath, null, 0, FileMode.TREE.getBits(), null, objectId);
model.isParentPath = true;
paths.add(0, model);
}
final String id = getBestCommitId(commit);
+
final ByteFormat byteFormat = new ByteFormat();
final String baseUrl = WicketUtils.getGitblitURL(getRequest());
@@ -88,7 +89,9 @@ public class TreePage extends RepositoryPage { @Override
public void populateItem(final Item<PathModel> item) {
PathModel entry = item.getModelObject();
+
item.add(new Label("pathPermissions", JGitUtils.getPermissionsFromMode(entry.mode)));
+
if (entry.isParentPath) {
// parent .. path
item.add(WicketUtils.newBlankImage("pathIcon"));
@@ -96,6 +99,7 @@ public class TreePage extends RepositoryPage { item.add(new LinkPanel("pathName", null, entry.name, TreePage.class,
WicketUtils
.newPathParameter(repositoryName, id, entry.path)));
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
item.add(new Label("pathLinks", ""));
} else {
if (entry.isTree()) {
@@ -106,6 +110,8 @@ public class TreePage extends RepositoryPage { WicketUtils.newPathParameter(repositoryName, id,
entry.path)));
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
+
// links
Fragment links = new Fragment("pathLinks", "treeLinks", this);
links.add(new BookmarkablePageLink<Void>("tree", TreePage.class,
@@ -133,6 +139,8 @@ public class TreePage extends RepositoryPage { getShortObjectId(submoduleId), TreePage.class,
WicketUtils.newPathParameter(submodulePath, submoduleId, "")).setEnabled(hasSubmodule));
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
+
Fragment links = new Fragment("pathLinks", "submoduleLinks", this);
links.add(new BookmarkablePageLink<Void>("view", SummaryPage.class,
WicketUtils.newRepositoryParameter(submodulePath)).setEnabled(hasSubmodule));
@@ -155,17 +163,33 @@ public class TreePage extends RepositoryPage { }
item.add(WicketUtils.getFileImage("pathIcon", entry.name));
item.add(new Label("pathSize", byteFormat.format(entry.size)));
- item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
- WicketUtils.newPathParameter(repositoryName, id,
- path)));
-
+
// links
Fragment links = new Fragment("pathLinks", "blobLinks", this);
- links.add(new BookmarkablePageLink<Void>("view", BlobPage.class,
- WicketUtils.newPathParameter(repositoryName, id,
- path)));
- String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, id, path);
- links.add(new ExternalLink("raw", rawUrl));
+
+ if (entry.isFilestoreItem()) {
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(true));
+
+ final String filestoreItemUrl = JGitUtils.getLfsRepositoryUrl(getContextUrl(), repositoryName, entry.getFilestoreOid());
+
+ item.add(new LinkPanel("pathName", "list", displayPath, filestoreItemUrl));
+ links.add(new ExternalLink("view", filestoreItemUrl));
+ links.add(new ExternalLink("raw", filestoreItemUrl));
+
+ } else {
+ item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
+
+ item.add(new LinkPanel("pathName", "list", displayPath, BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, id,
+ path)));
+
+ links.add(new BookmarkablePageLink<Void>("view", BlobPage.class,
+ WicketUtils.newPathParameter(repositoryName, id,
+ path)));
+ String rawUrl = RawServlet.asLink(getContextUrl(), repositoryName, id, path);
+ links.add(new ExternalLink("raw", rawUrl));
+ }
+
links.add(new BookmarkablePageLink<Void>("blame", BlamePage.class,
WicketUtils.newPathParameter(repositoryName, id,
path)));
diff --git a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java index a3f127b1..75fd70e7 100644 --- a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java @@ -109,7 +109,7 @@ public class HistoryPanel extends BasePanel { tw.setFilter(PathFilterGroup.createFromStrings(Collections.singleton(path)));
while (tw.next()) {
if (tw.getPathString().equals(path)) {
- matchingPath = new PathChangeModel(tw.getPathString(), tw.getPathString(), 0, tw
+ matchingPath = new PathChangeModel(tw.getPathString(), tw.getPathString(), null, 0, tw
.getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
ChangeType.MODIFY);
}
diff --git a/src/main/resources/gitblit.css b/src/main/resources/gitblit.css index 0cc8fd02..0d36da7f 100644 --- a/src/main/resources/gitblit.css +++ b/src/main/resources/gitblit.css @@ -1944,6 +1944,12 @@ td.mode { padding-right:15px;
}
+td.filestore {
+ text-align: right;
+ width:1em;
+ padding-right:15px;
+}
+
td.size {
text-align: right;
width: 8em;
diff --git a/src/test/java/com/gitblit/tests/JGitUtilsTest.java b/src/test/java/com/gitblit/tests/JGitUtilsTest.java index 2cf4a5a1..c273e860 100644 --- a/src/test/java/com/gitblit/tests/JGitUtilsTest.java +++ b/src/test/java/com/gitblit/tests/JGitUtilsTest.java @@ -585,16 +585,16 @@ public class JGitUtilsTest extends GitblitUnitTest { @Test
public void testZip() throws Exception {
- assertFalse(CompressionUtils.zip(null, null, null, null));
+ assertFalse(CompressionUtils.zip(null, null, null, null, null));
Repository repository = GitBlitSuite.getHelloworldRepository();
File zipFileA = new File(GitBlitSuite.REPOSITORIES, "helloworld.zip");
FileOutputStream fosA = new FileOutputStream(zipFileA);
- boolean successA = CompressionUtils.zip(repository, null, Constants.HEAD, fosA);
+ boolean successA = CompressionUtils.zip(repository, null, null, Constants.HEAD, fosA);
fosA.close();
File zipFileB = new File(GitBlitSuite.REPOSITORIES, "helloworld-java.zip");
FileOutputStream fosB = new FileOutputStream(zipFileB);
- boolean successB = CompressionUtils.zip(repository, "java.java", Constants.HEAD, fosB);
+ boolean successB = CompressionUtils.zip(repository, null, "java.java", Constants.HEAD, fosB);
fosB.close();
repository.close();
|