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
| | |
| | | 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";
|
| | |
|
| | |
| | | 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 |
| | |
| | | |
| | | 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; |
| | |
| | | //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; |
| | |
| | | stateChangedOn = new Date(); |
| | | repositories = new ArrayList<String>(); |
| | | 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() { |
| | |
| | | } |
| | | |
| | | 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; |
| | |
| | | |
| | | public static enum Status { |
| | | |
| | | ReferenceOnly(-42), |
| | | |
| | | Deleted(-30), |
| | | AuthenticationRequired(-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,
|
| | |
| | |
|
| | | 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;
|
| | |
| | | return FileMode.REGULAR_FILE.equals(mode)
|
| | | || 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 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;
|
| | | }
|
| | |
|
| | |
| | | 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());
|
| | | }
|
| | |
| | | /**
|
| | | * 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";
|
| | | }
|
| | |
|
| | |
| | | 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 {
|
| | |
| | | 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 {
|
| | |
| | |
|
| | | import com.google.inject.Inject;
|
| | | import com.google.inject.Singleton;
|
| | |
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
| | | 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;
|
| | |
| | | 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");
|
| | |
| | | }
|
| | |
|
| | | @Inject
|
| | | public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager) {
|
| | | public DownloadZipServlet(IStoredSettings settings, IRepositoryManager repositoryManager, IFilestoreManager filestoreManager) {
|
| | | this.settings = settings;
|
| | | this.repositoryManager = repositoryManager;
|
| | | this.filestoreManager = filestoreManager;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | 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;
|
| | | }
|
| | |
|
| | |
| | | } |
| | | } else { |
| | | response.setStatus(responseObject.error.code); |
| | | serialize(response, responseObject.error); |
| | | |
| | | if (isMetaRequest) { |
| | | serialize(response, responseObject.error); |
| | | } |
| | | } |
| | | }; |
| | | |
| | |
| | | }
|
| | |
|
| | | /**
|
| | | * 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
|
| | |
| | |
|
| | | /**
|
| | | * 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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | 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)); |
| | | } |
| | | } |
| | | |
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | | 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.
|
| | |
| | | * @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) {
|
| | |
| | | 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);
|
| | |
|
| | | ObjectLoader ldr = repository.open(id);
|
| | | ldr.copyTo(zos);
|
| | | //Handle as per other errors |
| | | throw e; |
| | | }
|
| | | }
|
| | |
|
| | | zos.closeArchiveEntry();
|
| | | }
|
| | | zos.finish();
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @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);
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | * @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) {
|
| | |
| | | if (mode == FileMode.GITLINK || mode == FileMode.TREE) {
|
| | | continue;
|
| | | }
|
| | | |
| | | tw.getObjectId(id, 0);
|
| | |
|
| | | ObjectLoader loader = repository.open(id);
|
| | |
| | | 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();
|
| | | }
|
| | | }
|
| | |
| | | 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;
|
| | |
| | |
|
| | | 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
|
| | |
| | | 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;
|
| | | }
|
| | |
| | | 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:
|
| | |
| | | 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);
|
| | |
| | | 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; |
| | |
| | | |
| | | } |
| | | |
| | | 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. |
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
| | | 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;
|
| | |
|
| | | /**
|
| | |
| | | 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);
|
| | |
| | |
|
| | | 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);
|
| | |
| | | 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;
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | 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);
|
| | | if (!tw.isSubtree() && (tw.getFileMode(0) != FileMode.GITLINK)) {
|
| | |
|
| | | } else if (tw.isSubtree()) {
|
| | | 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()) {
|
| | |
|
| | | // do not display dirs that are behind in the path
|
| | | if (!Strings.isNullOrEmpty(filter)) {
|
| | | pathString = path.replaceFirst(filter + "/", "");
|
| | | }
|
| | |
|
| | | // 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());
|
| | |
|
| | | }
|
| | |
|
| | |
| | | }
|
| | | 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;
|
| | | |
| | | }
|
| | | }
|
| | |
| | | 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;
|
| | |
| | | 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,
|
| | |
| | | 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));
|
| | |
|
| | |
| | | <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>
|
| | |
| | | @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); |
| | |
| | | |
| | | boolean hasSubmodule = false; |
| | | String submodulePath = null; |
| | | |
| | | if (entry.isTree()) { |
| | | // tree |
| | | item.add(new LinkPanel("pathName", null, entry.path, TreePage.class, |
| | |
| | | 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)); |
| | |
| | | .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) |
| | |
| | | <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>
|
| | |
| | | @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);
|
| | |
| | | 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)));
|
| | | }
|
| | | }
|
| | |
|
| | |
|
| | |
| | | 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))
|
| | |
| | | .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)
|
| | |
| | | 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; |
| | | |
| | |
| | | <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>
|
| | |
| | | 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());
|
| | |
|
| | |
| | | @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"));
|
| | |
| | | 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()) {
|
| | |
| | | item.add(new LinkPanel("pathName", "list", entry.name, TreePage.class,
|
| | | WicketUtils.newPathParameter(repositoryName, id,
|
| | | entry.path)));
|
| | |
|
| | | item.add(new Label("filestore", getString("gb.filestore")).setVisible(false));
|
| | |
|
| | | // links
|
| | | Fragment links = new Fragment("pathLinks", "treeLinks", this);
|
| | |
| | | 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));
|
| | |
| | | }
|
| | | 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)));
|
| | |
| | | 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);
|
| | | }
|
| | |
| | | padding-right:15px;
|
| | | }
|
| | |
|
| | | td.filestore {
|
| | | text-align: right;
|
| | | width:1em;
|
| | | padding-right:15px;
|
| | | }
|
| | |
|
| | | td.size {
|
| | | text-align: right;
|
| | | width: 8em;
|
| | |
| | |
|
| | | @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();
|