From 9120d492ab4763cde5bd8686b5fa8376efb42348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Fri, 4 Oct 2019 19:46:16 +0200 Subject: [PATCH 01/10] LFS upload POC --- .../scm/repository/spi/GitModifyCommand.java | 13 ++- .../spi/GitRepositoryServiceProvider.java | 2 +- .../spi/LfsBlobStoreCleanFilter.java | 101 ++++++++++++++++++ .../spi/LfsBlobStoreCleanFilterFactory.java | 26 +++++ .../repository/spi/GitModifyCommandTest.java | 6 +- .../spi/GitModifyCommand_LFSTest.java | 83 ++++++++++++++ 6 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java create mode 100644 scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 0f7c9296a7..19f18f0625 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -3,6 +3,7 @@ package sonia.scm.repository.spi; import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.attributes.FilterCommandRegistry; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.revwalk.RevCommit; @@ -12,6 +13,7 @@ import sonia.scm.ContextEntry; import sonia.scm.repository.GitWorkdirFactory; import sonia.scm.repository.InternalRepositoryException; import sonia.scm.repository.Repository; +import sonia.scm.web.lfs.LfsBlobStoreFactory; import java.io.File; import java.io.IOException; @@ -30,10 +32,12 @@ import static sonia.scm.ScmConstraintViolationException.Builder.doThrow; public class GitModifyCommand extends AbstractGitCommand implements ModifyCommand { private final GitWorkdirFactory workdirFactory; + private final LfsBlobStoreFactory lfsBlobStoreFactory; - GitModifyCommand(GitContext context, Repository repository, GitWorkdirFactory workdirFactory) { + GitModifyCommand(GitContext context, Repository repository, GitWorkdirFactory workdirFactory, LfsBlobStoreFactory lfsBlobStoreFactory) { super(context, repository); this.workdirFactory = workdirFactory; + this.lfsBlobStoreFactory = lfsBlobStoreFactory; } @Override @@ -87,10 +91,17 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman throw alreadyExists(createFileContext(toBeCreated)); } } + + LfsBlobStoreCleanFilterFactory cleanFilterFactory = new LfsBlobStoreCleanFilterFactory(lfsBlobStoreFactory, repository, targetFile); + + String registerKey = "git-lfs clean -- '" + toBeCreated + "'"; + FilterCommandRegistry.register(registerKey, cleanFilterFactory::createFilter); try { addFileToGit(toBeCreated); } catch (GitAPIException e) { throwInternalRepositoryException("could not add new file to index", e); + } finally { + FilterCommandRegistry.unregister(registerKey); } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java index 4c02a3a73c..dc43b8d9b7 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitRepositoryServiceProvider.java @@ -273,7 +273,7 @@ public class GitRepositoryServiceProvider extends RepositoryServiceProvider @Override public ModifyCommand getModifyCommand() { - return new GitModifyCommand(context, repository, handler.getWorkdirFactory()); + return new GitModifyCommand(context, repository, handler.getWorkdirFactory(), lfsBlobStoreFactory); } @Override diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java new file mode 100644 index 0000000000..d47673c970 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java @@ -0,0 +1,101 @@ +package sonia.scm.repository.spi; + +import org.eclipse.jgit.attributes.FilterCommand; +import org.eclipse.jgit.lfs.Lfs; +import org.eclipse.jgit.lfs.LfsPointer; +import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.LongObjectId; +import org.eclipse.jgit.lib.Repository; +import sonia.scm.store.Blob; +import sonia.scm.store.BlobStore; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import static org.eclipse.jgit.lfs.lib.Constants.LONG_HASH_FUNCTION; + +/** + * Adapted version of JGit's {@link org.eclipse.jgit.lfs.CleanFilter} to write the + * lfs file directly to the lfs blob store. + */ +public class LfsBlobStoreCleanFilter extends FilterCommand { + + + private Lfs lfsUtil; + private final BlobStore lfsBlobStore; + private final Path targetFile; + private final DigestOutputStream digestOutputStream; + + private long size; + + public LfsBlobStoreCleanFilter(Repository db, InputStream in, OutputStream out, BlobStore lfsBlobStore, Path targetFile) + throws IOException { + super(in, out); + lfsUtil = new Lfs(db); + this.lfsBlobStore = lfsBlobStore; + this.targetFile = targetFile; + Files.createDirectories(lfsUtil.getLfsTmpDir()); + + + MessageDigest md ; + try { + md = MessageDigest.getInstance(LONG_HASH_FUNCTION); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + digestOutputStream = new DigestOutputStream(new OutputStream() { + @Override + public void write(int b) { + } + }, md); + + } + + @Override + public int run() throws IOException { + try { + byte[] buf = new byte[8192]; + int length = in.read(buf); + if (length != -1) { + digestOutputStream.write(buf, 0, length); + size += length; + return length; + } else { + digestOutputStream.close(); + AnyLongObjectId loid = LongObjectId.fromRaw(digestOutputStream.getMessageDigest().digest()); + + Blob existingBlob = lfsBlobStore.get(loid.getName()); + if (existingBlob != null) { + long blobSize = existingBlob.getSize(); + if (blobSize != size) { + throw new RuntimeException("lfs entry already exists for loid " + loid.getName() + " but has wrong size"); + } + } else { + Blob newBlob = lfsBlobStore.create(loid.getName()); + OutputStream outputStream = newBlob.getOutputStream(); + Files.copy(targetFile, outputStream); + newBlob.commit(); + } + + LfsPointer lfsPointer = new LfsPointer(loid, size); + lfsPointer.encode(out); + in.close(); + out.close(); + return -1; + } + } catch (IOException e) { + if (digestOutputStream != null) { + digestOutputStream.close(); + } + in.close(); + out.close(); + throw e; + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java new file mode 100644 index 0000000000..6951ec1b14 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java @@ -0,0 +1,26 @@ +package sonia.scm.repository.spi; + +import org.eclipse.jgit.lib.Repository; +import sonia.scm.web.lfs.LfsBlobStoreFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Path; + +public class LfsBlobStoreCleanFilterFactory { + + private final LfsBlobStoreFactory blobStoreFactory; + private final sonia.scm.repository.Repository repository; + private final Path targetFile; + + public LfsBlobStoreCleanFilterFactory(LfsBlobStoreFactory blobStoreFactory, sonia.scm.repository.Repository repository, Path targetFile) { + this.blobStoreFactory = blobStoreFactory; + this.repository = repository; + this.targetFile = targetFile; + } + + LfsBlobStoreCleanFilter createFilter(Repository db, InputStream in, OutputStream out) throws IOException { + return new LfsBlobStoreCleanFilter(db, in, out, blobStoreFactory.getLfsBlobStore(repository), targetFile); + } +} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java index 4fbf7eaf02..e26458a4ec 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommandTest.java @@ -20,12 +20,14 @@ import sonia.scm.NotFoundException; import sonia.scm.ScmConstraintViolationException; import sonia.scm.repository.Person; import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.web.lfs.LfsBlobStoreFactory; import java.io.File; import java.io.IOException; import java.nio.file.Files; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; @SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret") public class GitModifyCommandTest extends AbstractGitCommandTestBase { @@ -37,6 +39,8 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase { @Rule public ShiroRule shiro = new ShiroRule(); + private final LfsBlobStoreFactory lfsBlobStoreFactory = mock(LfsBlobStoreFactory.class); + @Test public void shouldCreateCommit() throws IOException, GitAPIException { File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile(); @@ -296,7 +300,7 @@ public class GitModifyCommandTest extends AbstractGitCommandTestBase { } private GitModifyCommand createCommand() { - return new GitModifyCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider())); + return new GitModifyCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider()), lfsBlobStoreFactory); } @FunctionalInterface diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java new file mode 100644 index 0000000000..9414497bcb --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -0,0 +1,83 @@ +package sonia.scm.repository.spi; + +import com.github.sdorra.shiro.ShiroRule; +import com.github.sdorra.shiro.SubjectAware; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.eclipse.jgit.revwalk.RevCommit; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import sonia.scm.repository.Person; +import sonia.scm.repository.util.WorkdirProvider; +import sonia.scm.store.Blob; +import sonia.scm.store.BlobStore; +import sonia.scm.web.lfs.LfsBlobStoreFactory; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@SubjectAware(configuration = "classpath:sonia/scm/configuration/shiro.ini", username = "admin", password = "secret") +public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Rule + public BindTransportProtocolRule transportProtocolRule = new BindTransportProtocolRule(); + @Rule + public ShiroRule shiro = new ShiroRule(); + + private final LfsBlobStoreFactory lfsBlobStoreFactory = mock(LfsBlobStoreFactory.class); + + @Test + public void shouldCreateCommit() throws IOException, GitAPIException { + BlobStore blobStore = mock(BlobStore.class); + Blob blob = mock(Blob.class); + when(lfsBlobStoreFactory.getLfsBlobStore(any())).thenReturn(blobStore); + when(blobStore.create("fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601")).thenReturn(blob); + when(blobStore.get("fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601")).thenReturn(null, blob); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + when(blob.getOutputStream()).thenReturn(outputStream); + when(blob.getSize()).thenReturn((long) "new content".length()); + + File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile(); + + GitModifyCommand command = createCommand(); + + ModifyCommandRequest request = new ModifyCommandRequest(); + request.setCommitMessage("test commit"); + request.addRequest(new ModifyCommandRequest.CreateFileRequest("new_lfs.png", newFile, false)); + request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det")); + + String newRef = command.execute(request); + + try (Git git = new Git(createContext().open())) { + RevCommit lastCommit = getLastCommit(git); + assertThat(lastCommit.getFullMessage()).isEqualTo("test commit"); + assertThat(lastCommit.getAuthorIdent().getName()).isEqualTo("Dirk Gently"); + assertThat(newRef).isEqualTo(lastCommit.toObjectId().name()); + } + + assertThat(outputStream.toString()).isEqualTo("new content"); + } + + private RevCommit getLastCommit(Git git) throws GitAPIException { + return git.log().setMaxCount(1).call().iterator().next(); + } + + private GitModifyCommand createCommand() { + return new GitModifyCommand(createContext(), repository, new SimpleGitWorkdirFactory(new WorkdirProvider()), lfsBlobStoreFactory); + } + + @Override + protected String getZippedRepositoryResource() { + return "sonia/scm/repository/spi/scm-git-spi-lfs-test.zip"; + } +} From 100c73c33657cf809e45f10c7aa1d348719c2534 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pfeuffer?= Date: Sun, 6 Oct 2019 19:41:23 +0200 Subject: [PATCH 02/10] Add missing test repository --- .../scm/repository/spi/scm-git-spi-lfs-test.zip | Bin 0 -> 14315 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-lfs-test.zip diff --git a/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-lfs-test.zip b/scm-plugins/scm-git-plugin/src/test/resources/sonia/scm/repository/spi/scm-git-spi-lfs-test.zip new file mode 100644 index 0000000000000000000000000000000000000000..b97f51968427060cc523a8b1594930e1cd487f9a GIT binary patch literal 14315 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 literal 0 HcmV?d00001 From a1da5eaddbef039809d3fdd203946d25d763ba9a Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 7 Oct 2019 18:25:31 +0200 Subject: [PATCH 03/10] Simplify --- .../spi/LfsBlobStoreCleanFilter.java | 90 +++++++++---------- 1 file changed, 40 insertions(+), 50 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java index d47673c970..c320cf23d4 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java @@ -1,5 +1,6 @@ package sonia.scm.repository.spi; +import com.google.common.io.ByteStreams; import org.eclipse.jgit.attributes.FilterCommand; import org.eclipse.jgit.lfs.Lfs; import org.eclipse.jgit.lfs.LfsPointer; @@ -8,6 +9,7 @@ import org.eclipse.jgit.lfs.lib.LongObjectId; import org.eclipse.jgit.lib.Repository; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; +import sonia.scm.util.IOUtil; import java.io.IOException; import java.io.InputStream; @@ -30,9 +32,6 @@ public class LfsBlobStoreCleanFilter extends FilterCommand { private Lfs lfsUtil; private final BlobStore lfsBlobStore; private final Path targetFile; - private final DigestOutputStream digestOutputStream; - - private long size; public LfsBlobStoreCleanFilter(Repository db, InputStream in, OutputStream out, BlobStore lfsBlobStore, Path targetFile) throws IOException { @@ -41,61 +40,52 @@ public class LfsBlobStoreCleanFilter extends FilterCommand { this.lfsBlobStore = lfsBlobStore; this.targetFile = targetFile; Files.createDirectories(lfsUtil.getLfsTmpDir()); - - - MessageDigest md ; - try { - md = MessageDigest.getInstance(LONG_HASH_FUNCTION); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } - digestOutputStream = new DigestOutputStream(new OutputStream() { - @Override - public void write(int b) { - } - }, md); - } @Override public int run() throws IOException { + DigestOutputStream digestOutputStream = createDigestStream(); try { - byte[] buf = new byte[8192]; - int length = in.read(buf); - if (length != -1) { - digestOutputStream.write(buf, 0, length); - size += length; - return length; - } else { - digestOutputStream.close(); - AnyLongObjectId loid = LongObjectId.fromRaw(digestOutputStream.getMessageDigest().digest()); + long size = ByteStreams.copy(in, digestOutputStream); + AnyLongObjectId loid = LongObjectId.fromRaw(digestOutputStream.getMessageDigest().digest()); - Blob existingBlob = lfsBlobStore.get(loid.getName()); - if (existingBlob != null) { - long blobSize = existingBlob.getSize(); - if (blobSize != size) { - throw new RuntimeException("lfs entry already exists for loid " + loid.getName() + " but has wrong size"); - } - } else { - Blob newBlob = lfsBlobStore.create(loid.getName()); - OutputStream outputStream = newBlob.getOutputStream(); - Files.copy(targetFile, outputStream); - newBlob.commit(); + Blob existingBlob = lfsBlobStore.get(loid.getName()); + if (existingBlob != null) { + long blobSize = existingBlob.getSize(); + if (blobSize != size) { + // Mathematicians say this will never happen + throw new RuntimeException("lfs entry already exists for loid " + loid.getName() + " but has wrong size"); } + } else { + Blob newBlob = lfsBlobStore.create(loid.getName()); + OutputStream outputStream = newBlob.getOutputStream(); + Files.copy(targetFile, outputStream); + newBlob.commit(); + } - LfsPointer lfsPointer = new LfsPointer(loid, size); - lfsPointer.encode(out); - in.close(); - out.close(); - return -1; - } - } catch (IOException e) { - if (digestOutputStream != null) { - digestOutputStream.close(); - } - in.close(); - out.close(); - throw e; + LfsPointer lfsPointer = new LfsPointer(loid, size); + lfsPointer.encode(out); + return -1; + } finally { + IOUtil.close(digestOutputStream); + IOUtil.close(in); + IOUtil.close(out); } } + + private DigestOutputStream createDigestStream() { + MessageDigest md ; + try { + md = MessageDigest.getInstance(LONG_HASH_FUNCTION); + } catch (NoSuchAlgorithmException e) { + // Yes there is such a hash function (should be sha256) + throw new RuntimeException(e); + } + return new DigestOutputStream(new OutputStream() { + @Override + public void write(int b) { + // no further target here, we are just interested in the digest + } + }, md); + } } From 24e18b4414b453faccd4b6b4fa2b4455c7faf995 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Mon, 7 Oct 2019 18:45:12 +0200 Subject: [PATCH 04/10] Use no-op filter as default for lfs --- pom.xml | 2 +- .../repository/spi/GitLfsFilterModule.java | 36 ++++++++++++ .../scm/repository/spi/GitModifyCommand.java | 38 +++++++----- .../spi/GitModifyCommand_LFSTest.java | 58 +++++++++++++------ 4 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java diff --git a/pom.xml b/pom.xml index 3ab3cb82a3..c14ce8b39b 100644 --- a/pom.xml +++ b/pom.xml @@ -843,7 +843,7 @@ 1.4.0 - v5.4.0.201906121030-r-scm1 + v5.4.0.201906121030-r-scm2 1.9.0-scm3 diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java new file mode 100644 index 0000000000..2faa2f550f --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java @@ -0,0 +1,36 @@ +package sonia.scm.repository.spi; + +import com.google.common.io.ByteStreams; +import com.google.inject.Binder; +import com.google.inject.Module; +import org.eclipse.jgit.attributes.FilterCommand; +import org.eclipse.jgit.attributes.FilterCommandRegistry; +import org.eclipse.jgit.lib.Repository; +import sonia.scm.plugin.Extension; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.regex.Pattern; + +@Extension +public class GitLfsFilterModule implements Module { + @Override + public void configure(Binder binder) { + FilterCommandRegistry.register(Pattern.compile("git-lfs (smudge|clean) -- .*"), NoOpFilterCommand::new); + } + + private static class NoOpFilterCommand extends FilterCommand { + NoOpFilterCommand(Repository db, InputStream in, OutputStream out) { + super(in, out); + } + + @Override + public int run() throws IOException { + ByteStreams.copy(in, out); + in.close(); + out.close(); + return -1; + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 19f18f0625..1b748a6f1e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -1,5 +1,6 @@ package sonia.scm.repository.spi; +import com.google.common.util.concurrent.Striped; import org.apache.commons.lang.StringUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; @@ -22,6 +23,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; import java.util.Optional; +import java.util.concurrent.locks.Lock; import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; import static sonia.scm.AlreadyExistsException.alreadyExists; @@ -31,6 +33,8 @@ import static sonia.scm.ScmConstraintViolationException.Builder.doThrow; public class GitModifyCommand extends AbstractGitCommand implements ModifyCommand { + private static final Striped REGISTER_LOCKS = Striped.lock(5); + private final GitWorkdirFactory workdirFactory; private final LfsBlobStoreFactory lfsBlobStoreFactory; @@ -92,17 +96,7 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman } } - LfsBlobStoreCleanFilterFactory cleanFilterFactory = new LfsBlobStoreCleanFilterFactory(lfsBlobStoreFactory, repository, targetFile); - - String registerKey = "git-lfs clean -- '" + toBeCreated + "'"; - FilterCommandRegistry.register(registerKey, cleanFilterFactory::createFilter); - try { - addFileToGit(toBeCreated); - } catch (GitAPIException e) { - throwInternalRepositoryException("could not add new file to index", e); - } finally { - FilterCommandRegistry.unregister(registerKey); - } + addToGitWithLfsSupport(toBeCreated, targetFile); } @Override @@ -113,10 +107,26 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman throw notFound(createFileContext(path)); } Files.move(file.toPath(), targetFile, REPLACE_EXISTING); + + addToGitWithLfsSupport(path, targetFile); + } + + private void addToGitWithLfsSupport(String path, Path targetFile) { + REGISTER_LOCKS.get(targetFile).lock(); try { - addFileToGit(path); - } catch (GitAPIException e) { - throwInternalRepositoryException("could not add new file to index", e); + LfsBlobStoreCleanFilterFactory cleanFilterFactory = new LfsBlobStoreCleanFilterFactory(lfsBlobStoreFactory, repository, targetFile); + + String registerKey = "git-lfs clean -- '" + path + "'"; + FilterCommandRegistry.register(registerKey, cleanFilterFactory::createFilter); + try { + addFileToGit(path); + } catch (GitAPIException e) { + throwInternalRepositoryException("could not add file to index", e); + } finally { + FilterCommandRegistry.unregister(registerKey); + } + } finally { + REGISTER_LOCKS.get(targetFile).unlock(); } } diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index 9414497bcb..c7bbb2a71f 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -38,25 +38,8 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { @Test public void shouldCreateCommit() throws IOException, GitAPIException { - BlobStore blobStore = mock(BlobStore.class); - Blob blob = mock(Blob.class); - when(lfsBlobStoreFactory.getLfsBlobStore(any())).thenReturn(blobStore); - when(blobStore.create("fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601")).thenReturn(blob); - when(blobStore.get("fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601")).thenReturn(null, blob); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - when(blob.getOutputStream()).thenReturn(outputStream); - when(blob.getSize()).thenReturn((long) "new content".length()); - - File newFile = Files.write(temporaryFolder.newFile().toPath(), "new content".getBytes()).toFile(); - - GitModifyCommand command = createCommand(); - - ModifyCommandRequest request = new ModifyCommandRequest(); - request.setCommitMessage("test commit"); - request.addRequest(new ModifyCommandRequest.CreateFileRequest("new_lfs.png", newFile, false)); - request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det")); - - String newRef = command.execute(request); + String newRef = createCommit("new_lfs.png", "new content", "fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601", outputStream); try (Git git = new Git(createContext().open())) { RevCommit lastCommit = getLastCommit(git); @@ -68,6 +51,45 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { assertThat(outputStream.toString()).isEqualTo("new content"); } + @Test + public void shouldCreateSecondCommits() throws IOException, GitAPIException { + new GitLfsFilterModule().configure(null); + createCommit("new_lfs.png", "new content", "fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601", new ByteArrayOutputStream()); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + String newRef = createCommit("more_lfs.png", "more content", "2c2316737c9313956dfc0083da3a2a62ce259f66484f3e26440f0d1b02dd4128", outputStream); + + try (Git git = new Git(createContext().open())) { + RevCommit lastCommit = getLastCommit(git); + assertThat(lastCommit.getFullMessage()).isEqualTo("test commit"); + assertThat(lastCommit.getAuthorIdent().getName()).isEqualTo("Dirk Gently"); + assertThat(newRef).isEqualTo(lastCommit.toObjectId().name()); + } + + assertThat(outputStream.toString()).isEqualTo("more content"); + } + + private String createCommit(String fileName, String content, String hashOfContent, ByteArrayOutputStream outputStream) throws IOException { + BlobStore blobStore = mock(BlobStore.class); + Blob blob = mock(Blob.class); + when(lfsBlobStoreFactory.getLfsBlobStore(any())).thenReturn(blobStore); + when(blobStore.create(hashOfContent)).thenReturn(blob); + when(blobStore.get(hashOfContent)).thenReturn(null, blob); + when(blob.getOutputStream()).thenReturn(outputStream); + when(blob.getSize()).thenReturn((long) content.length()); + + File newFile = Files.write(temporaryFolder.newFile().toPath(), content.getBytes()).toFile(); + + GitModifyCommand command = createCommand(); + + ModifyCommandRequest request = new ModifyCommandRequest(); + request.setCommitMessage("test commit"); + request.addRequest(new ModifyCommandRequest.CreateFileRequest(fileName, newFile, false)); + request.setAuthor(new Person("Dirk Gently", "dirk@holistic.det")); + + return command.execute(request); + } + private RevCommit getLastCommit(Git git) throws GitAPIException { return git.log().setMaxCount(1).call().iterator().next(); } From 7af882fe8efe154cbc2c1f1d5ac35234fcddcbab Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Tue, 8 Oct 2019 16:19:30 +0200 Subject: [PATCH 05/10] Insert some logging --- .../sonia/scm/repository/spi/GitModifyCommand.java | 5 +++++ .../scm/repository/spi/LfsBlobStoreCleanFilter.java | 13 ++++++++++--- .../repository/spi/GitModifyCommand_LFSTest.java | 1 - 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 7c7f948846..72238e117e 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -6,6 +6,8 @@ import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.attributes.FilterCommandRegistry; import org.eclipse.jgit.revwalk.RevCommit; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.BadRequestException; import sonia.scm.ConcurrentModificationException; import sonia.scm.ContextEntry; @@ -30,6 +32,7 @@ import static sonia.scm.NotFoundException.notFound; public class GitModifyCommand extends AbstractGitCommand implements ModifyCommand { + private static final Logger LOG = LoggerFactory.getLogger(GitModifyCommand.class); private static final Striped REGISTER_LOCKS = Striped.lock(5); private final GitWorkdirFactory workdirFactory; @@ -109,12 +112,14 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman LfsBlobStoreCleanFilterFactory cleanFilterFactory = new LfsBlobStoreCleanFilterFactory(lfsBlobStoreFactory, repository, targetFile); String registerKey = "git-lfs clean -- '" + path + "'"; + LOG.info("register lfs filter command factory for command '{}'", registerKey); FilterCommandRegistry.register(registerKey, cleanFilterFactory::createFilter); try { addFileToGit(path); } catch (GitAPIException e) { throwInternalRepositoryException("could not add file to index", e); } finally { + LOG.info("unregister lfs filter command factory for command \"{}\"", registerKey); FilterCommandRegistry.unregister(registerKey); } } finally { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java index c320cf23d4..3ab8a3e8cf 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java @@ -7,6 +7,8 @@ import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; import org.eclipse.jgit.lfs.lib.LongObjectId; import org.eclipse.jgit.lib.Repository; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; import sonia.scm.util.IOUtil; @@ -28,6 +30,7 @@ import static org.eclipse.jgit.lfs.lib.Constants.LONG_HASH_FUNCTION; */ public class LfsBlobStoreCleanFilter extends FilterCommand { + private static final Logger LOG = LoggerFactory.getLogger(LfsBlobStoreCleanFilter.class); private Lfs lfsUtil; private final BlobStore lfsBlobStore; @@ -44,20 +47,24 @@ public class LfsBlobStoreCleanFilter extends FilterCommand { @Override public int run() throws IOException { + LOG.info("running scm lfs filter for file {}", targetFile); DigestOutputStream digestOutputStream = createDigestStream(); try { long size = ByteStreams.copy(in, digestOutputStream); AnyLongObjectId loid = LongObjectId.fromRaw(digestOutputStream.getMessageDigest().digest()); + String hash = loid.getName(); - Blob existingBlob = lfsBlobStore.get(loid.getName()); + Blob existingBlob = lfsBlobStore.get(hash); if (existingBlob != null) { + LOG.info("found existing lfs blob for oid {}", hash); long blobSize = existingBlob.getSize(); if (blobSize != size) { // Mathematicians say this will never happen - throw new RuntimeException("lfs entry already exists for loid " + loid.getName() + " but has wrong size"); + throw new RuntimeException("lfs entry already exists for loid " + hash + " but has wrong size"); } } else { - Blob newBlob = lfsBlobStore.create(loid.getName()); + LOG.info("uploading new lfs blob for oid {}", hash); + Blob newBlob = lfsBlobStore.create(hash); OutputStream outputStream = newBlob.getOutputStream(); Files.copy(targetFile, outputStream); newBlob.commit(); diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index 8ecca84812..b0b2b675b4 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -65,7 +65,6 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { @Test public void shouldCreateSecondCommits() throws IOException, GitAPIException { - new GitLfsFilterModule().configure(null); createCommit("new_lfs.png", "new content", "fe32608c9ef5b6cf7e3f946480253ff76f24f4ec0678f3d0f07f9844cbff9601", new ByteArrayOutputStream()); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); From a81049eea3706ce6ab05b227c10b3508acc77ed3 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Wed, 9 Oct 2019 10:57:58 +0200 Subject: [PATCH 06/10] Register own git config --- .../spi/GitLfsFilterContextListener.java | 77 +++++++++++++++++++ .../repository/spi/GitLfsFilterModule.java | 43 ----------- .../spi/GitModifyCommand_LFSTest.java | 4 +- 3 files changed, 79 insertions(+), 45 deletions(-) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterContextListener.java delete mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterContextListener.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterContextListener.java new file mode 100644 index 0000000000..101c242d65 --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterContextListener.java @@ -0,0 +1,77 @@ +package sonia.scm.repository.spi; + +import com.google.common.io.ByteStreams; +import org.eclipse.jgit.attributes.FilterCommand; +import org.eclipse.jgit.attributes.FilterCommandRegistry; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.util.FS; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import sonia.scm.SCMContextProvider; +import sonia.scm.plugin.Extension; + +import javax.inject.Inject; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; + +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING; + +@Extension +public class GitLfsFilterContextListener implements ServletContextListener { + + public static final String GITCONFIG = "[filter \"lfs\"]\n" + + "clean = git-lfs clean -- %f\n" + + "smudge = git-lfs smudge -- %f\n" + + "process = git-lfs filter-process\n" + + "required = true\n"; + public static final Pattern COMMAND_NAME_PATTERN = Pattern.compile("git-lfs (smudge|clean) -- .*"); + + private static final Logger LOG = LoggerFactory.getLogger(GitLfsFilterContextListener.class); + + private final SCMContextProvider contextProvider; + + @Inject + public GitLfsFilterContextListener(SCMContextProvider contextProvider) { + this.contextProvider = contextProvider; + } + + @Override + public void contextInitialized(ServletContextEvent sce) { + Path gitconfig = contextProvider.getBaseDirectory().toPath().resolve("gitconfig"); + try { + Files.write(gitconfig, GITCONFIG.getBytes(Charset.defaultCharset()), TRUNCATE_EXISTING, CREATE); + FS.DETECTED.setGitSystemConfig(gitconfig.toFile()); + LOG.info("wrote git config file: {}", gitconfig); + } catch (IOException e) { + LOG.error("could not write git config in path {}; git lfs support may not work correctly", gitconfig, e); + } + FilterCommandRegistry.register(COMMAND_NAME_PATTERN, NoOpFilterCommand::new); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + FilterCommandRegistry.unregister(COMMAND_NAME_PATTERN); + } + + private static class NoOpFilterCommand extends FilterCommand { + NoOpFilterCommand(Repository db, InputStream in, OutputStream out) { + super(in, out); + } + + @Override + public int run() throws IOException { + ByteStreams.copy(in, out); + in.close(); + out.close(); + return -1; + } + } +} diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java deleted file mode 100644 index 912379fd7b..0000000000 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitLfsFilterModule.java +++ /dev/null @@ -1,43 +0,0 @@ -package sonia.scm.repository.spi; - -import com.google.common.io.ByteStreams; -import com.google.inject.Binder; -import com.google.inject.Module; -import org.eclipse.jgit.attributes.FilterCommand; -import org.eclipse.jgit.attributes.FilterCommandRegistry; -import org.eclipse.jgit.lib.Repository; -import sonia.scm.plugin.Extension; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.regex.Pattern; - -@Extension -public class GitLfsFilterModule implements Module { - - public static final Pattern COMMAND_NAME_PATTERN = Pattern.compile("git-lfs (smudge|clean) -- .*"); - - @Override - public void configure(Binder binder) { - FilterCommandRegistry.register(COMMAND_NAME_PATTERN, NoOpFilterCommand::new); - } - - void unregister() { - FilterCommandRegistry.unregister(COMMAND_NAME_PATTERN); - } - - private static class NoOpFilterCommand extends FilterCommand { - NoOpFilterCommand(Repository db, InputStream in, OutputStream out) { - super(in, out); - } - - @Override - public int run() throws IOException { - ByteStreams.copy(in, out); - in.close(); - out.close(); - return -1; - } - } -} diff --git a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java index b0b2b675b4..b1a5c7bbcc 100644 --- a/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java +++ b/scm-plugins/scm-git-plugin/src/test/java/sonia/scm/repository/spi/GitModifyCommand_LFSTest.java @@ -40,12 +40,12 @@ public class GitModifyCommand_LFSTest extends AbstractGitCommandTestBase { @Before public void registerFilter() { - new GitLfsFilterModule().configure(null); + new GitLfsFilterContextListener(contextProvider).contextInitialized(null); } @After public void unregisterFilter() { - new GitLfsFilterModule().unregister(); + new GitLfsFilterContextListener(contextProvider).contextDestroyed(null); } @Test From 369ad9e788483a426b7c480fb43f674643d3c7cc Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Wed, 9 Oct 2019 11:27:54 +0200 Subject: [PATCH 07/10] Reduce log levels --- .../scm/repository/spi/GitModifyCommand.java | 4 ++-- .../spi/LfsBlobStoreCleanFilter.java | 21 ++++++++----------- .../spi/LfsBlobStoreCleanFilterFactory.java | 9 ++++---- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 72238e117e..f87dc038c0 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -112,14 +112,14 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman LfsBlobStoreCleanFilterFactory cleanFilterFactory = new LfsBlobStoreCleanFilterFactory(lfsBlobStoreFactory, repository, targetFile); String registerKey = "git-lfs clean -- '" + path + "'"; - LOG.info("register lfs filter command factory for command '{}'", registerKey); + LOG.debug("register lfs filter command factory for command '{}'", registerKey); FilterCommandRegistry.register(registerKey, cleanFilterFactory::createFilter); try { addFileToGit(path); } catch (GitAPIException e) { throwInternalRepositoryException("could not add file to index", e); } finally { - LOG.info("unregister lfs filter command factory for command \"{}\"", registerKey); + LOG.debug("unregister lfs filter command factory for command \"{}\"", registerKey); FilterCommandRegistry.unregister(registerKey); } } finally { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java index 3ab8a3e8cf..7c9c3d3225 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java @@ -2,11 +2,9 @@ package sonia.scm.repository.spi; import com.google.common.io.ByteStreams; import org.eclipse.jgit.attributes.FilterCommand; -import org.eclipse.jgit.lfs.Lfs; import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; import org.eclipse.jgit.lfs.lib.LongObjectId; -import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.store.Blob; @@ -28,26 +26,24 @@ import static org.eclipse.jgit.lfs.lib.Constants.LONG_HASH_FUNCTION; * Adapted version of JGit's {@link org.eclipse.jgit.lfs.CleanFilter} to write the * lfs file directly to the lfs blob store. */ -public class LfsBlobStoreCleanFilter extends FilterCommand { +class LfsBlobStoreCleanFilter extends FilterCommand { private static final Logger LOG = LoggerFactory.getLogger(LfsBlobStoreCleanFilter.class); - private Lfs lfsUtil; private final BlobStore lfsBlobStore; private final Path targetFile; - public LfsBlobStoreCleanFilter(Repository db, InputStream in, OutputStream out, BlobStore lfsBlobStore, Path targetFile) - throws IOException { + LfsBlobStoreCleanFilter(InputStream in, OutputStream out, BlobStore lfsBlobStore, Path targetFile) { super(in, out); - lfsUtil = new Lfs(db); this.lfsBlobStore = lfsBlobStore; this.targetFile = targetFile; - Files.createDirectories(lfsUtil.getLfsTmpDir()); } @Override + // Suppress warning for RuntimeException after check for wrong size, because mathematicians say this will never happen + @SuppressWarnings("squid:S00112") public int run() throws IOException { - LOG.info("running scm lfs filter for file {}", targetFile); + LOG.debug("running scm lfs filter for file {}", targetFile); DigestOutputStream digestOutputStream = createDigestStream(); try { long size = ByteStreams.copy(in, digestOutputStream); @@ -56,14 +52,13 @@ public class LfsBlobStoreCleanFilter extends FilterCommand { Blob existingBlob = lfsBlobStore.get(hash); if (existingBlob != null) { - LOG.info("found existing lfs blob for oid {}", hash); + LOG.debug("found existing lfs blob for oid {}", hash); long blobSize = existingBlob.getSize(); if (blobSize != size) { - // Mathematicians say this will never happen throw new RuntimeException("lfs entry already exists for loid " + hash + " but has wrong size"); } } else { - LOG.info("uploading new lfs blob for oid {}", hash); + LOG.debug("uploading new lfs blob for oid {}", hash); Blob newBlob = lfsBlobStore.create(hash); OutputStream outputStream = newBlob.getOutputStream(); Files.copy(targetFile, outputStream); @@ -80,6 +75,8 @@ public class LfsBlobStoreCleanFilter extends FilterCommand { } } + // Suppress warning for RuntimeException after check for wrong size, because hash alg for sha256 is built in + @SuppressWarnings("squid:S00112") private DigestOutputStream createDigestStream() { MessageDigest md ; try { diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java index 6951ec1b14..d6de8e83df 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilterFactory.java @@ -8,19 +8,20 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Path; -public class LfsBlobStoreCleanFilterFactory { +class LfsBlobStoreCleanFilterFactory { private final LfsBlobStoreFactory blobStoreFactory; private final sonia.scm.repository.Repository repository; private final Path targetFile; - public LfsBlobStoreCleanFilterFactory(LfsBlobStoreFactory blobStoreFactory, sonia.scm.repository.Repository repository, Path targetFile) { + LfsBlobStoreCleanFilterFactory(LfsBlobStoreFactory blobStoreFactory, sonia.scm.repository.Repository repository, Path targetFile) { this.blobStoreFactory = blobStoreFactory; this.repository = repository; this.targetFile = targetFile; } - LfsBlobStoreCleanFilter createFilter(Repository db, InputStream in, OutputStream out) throws IOException { - return new LfsBlobStoreCleanFilter(db, in, out, blobStoreFactory.getLfsBlobStore(repository), targetFile); + @SuppressWarnings("squid:S1172") // suppress unused parameter to keep the api compatible to jgit's FilterCommandFactory + LfsBlobStoreCleanFilter createFilter(Repository db, InputStream in, OutputStream out) { + return new LfsBlobStoreCleanFilter(in, out, blobStoreFactory.getLfsBlobStore(repository), targetFile); } } From 5eab6f5af4ba81c5d7f3afdbcdd3dc3f512fae07 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Wed, 9 Oct 2019 11:47:56 +0200 Subject: [PATCH 08/10] Fix sonar issues --- .../sonia/scm/repository/spi/GitModifyCommand.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java index 83ca05fb03..a68be0a4da 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/GitModifyCommand.java @@ -54,10 +54,9 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman @Override String run() throws IOException { getClone().getRepository().getFullBranch(); - if (!StringUtils.isEmpty(request.getExpectedRevision())) { - if (!request.getExpectedRevision().equals(getCurrentRevision().getName())) { - throw new ConcurrentModificationException("branch", request.getBranch() == null? "default": request.getBranch()); - } + if (!StringUtils.isEmpty(request.getExpectedRevision()) + && !request.getExpectedRevision().equals(getCurrentRevision().getName())) { + throw new ConcurrentModificationException("branch", request.getBranch() == null ? "default" : request.getBranch()); } for (ModifyCommandRequest.PartialRequest r : request.getRequests()) { r.execute(this); @@ -128,9 +127,9 @@ public class GitModifyCommand extends AbstractGitCommand implements ModifyComman } return path; } - } - private String throwInternalRepositoryException(String message, Exception e) { - throw new InternalRepositoryException(context.getRepository(), message, e); + private String throwInternalRepositoryException(String message, Exception e) { + throw new InternalRepositoryException(context.getRepository(), message, e); + } } } From 38f0ed3bbda1dba597b3f25caa10fee9c6155384 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Wed, 9 Oct 2019 13:56:44 +0200 Subject: [PATCH 09/10] Use constant from jgit --- .../repository/spi/LfsBlobStoreCleanFilter.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java index 7c9c3d3225..bb54ea162a 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/repository/spi/LfsBlobStoreCleanFilter.java @@ -4,6 +4,7 @@ import com.google.common.io.ByteStreams; import org.eclipse.jgit.attributes.FilterCommand; import org.eclipse.jgit.lfs.LfsPointer; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; +import org.eclipse.jgit.lfs.lib.Constants; import org.eclipse.jgit.lfs.lib.LongObjectId; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -17,10 +18,6 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestOutputStream; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import static org.eclipse.jgit.lfs.lib.Constants.LONG_HASH_FUNCTION; /** * Adapted version of JGit's {@link org.eclipse.jgit.lfs.CleanFilter} to write the @@ -75,21 +72,12 @@ class LfsBlobStoreCleanFilter extends FilterCommand { } } - // Suppress warning for RuntimeException after check for wrong size, because hash alg for sha256 is built in - @SuppressWarnings("squid:S00112") private DigestOutputStream createDigestStream() { - MessageDigest md ; - try { - md = MessageDigest.getInstance(LONG_HASH_FUNCTION); - } catch (NoSuchAlgorithmException e) { - // Yes there is such a hash function (should be sha256) - throw new RuntimeException(e); - } return new DigestOutputStream(new OutputStream() { @Override public void write(int b) { // no further target here, we are just interested in the digest } - }, md); + }, Constants.newMessageDigest()); } } From b999062535d991599a61a17d87be3da9a4b3dfe1 Mon Sep 17 00:00:00 2001 From: Eduard Heimbuch Date: Wed, 9 Oct 2019 12:06:07 +0000 Subject: [PATCH 10/10] Close branch feature/lfs_upload