Browse Source
Transfer data in chunks of 8k Transferring data byte per byte is slow, running checkout with CleanFilter on a 2.9MB file takes 20 seconds. Using a buffer of 8k shrinks this time to 70ms. Also register the filter commands in a way that the native GIT LFS can be used alongside with JGit. Implements auto-discovery of LFS server URL when cloning from a Gerrit LFS server. Change-Id: I452a5aa177dcb346d92af08b27c2e35200f246fd Also-by: Christian Halstrick <christian.halstrick@sap.com> Signed-off-by: Markus Duft <markus.duft@ssi-schaefer.com>stable-4.11
Markus Duft
8 years ago
committed by
Christian Halstrick
18 changed files with 907 additions and 29 deletions
@ -0,0 +1,143 @@
|
||||
/* |
||||
* Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.lfs.server.fs; |
||||
|
||||
import static org.junit.Assert.assertEquals; |
||||
import static org.junit.Assert.assertFalse; |
||||
|
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
|
||||
import org.eclipse.jgit.api.Git; |
||||
import org.eclipse.jgit.junit.JGitTestUtil; |
||||
import org.eclipse.jgit.junit.TestRepository; |
||||
import org.eclipse.jgit.lfs.CleanFilter; |
||||
import org.eclipse.jgit.lfs.SmudgeFilter; |
||||
import org.eclipse.jgit.lfs.lib.LongObjectId; |
||||
import org.eclipse.jgit.lib.Repository; |
||||
import org.eclipse.jgit.lib.StoredConfig; |
||||
import org.eclipse.jgit.storage.file.FileRepositoryBuilder; |
||||
import org.eclipse.jgit.util.FileUtils; |
||||
import org.junit.After; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class CheckoutTest extends LfsServerTest { |
||||
|
||||
Git git; |
||||
private TestRepository tdb; |
||||
|
||||
@Override |
||||
@Before |
||||
public void setup() throws Exception { |
||||
super.setup(); |
||||
|
||||
SmudgeFilter.register(); |
||||
CleanFilter.register(); |
||||
|
||||
Path tmp = Files.createTempDirectory("jgit_test_"); |
||||
Repository db = FileRepositoryBuilder |
||||
.create(tmp.resolve(".git").toFile()); |
||||
db.create(); |
||||
StoredConfig cfg = db.getConfig(); |
||||
cfg.setString("filter", "lfs", "usejgitbuiltin", "true"); |
||||
cfg.setString("lfs", null, "url", server.getURI().toString() + "/lfs"); |
||||
cfg.save(); |
||||
|
||||
tdb = new TestRepository<>(db); |
||||
tdb.branch("test").commit() |
||||
.add(".gitattributes", |
||||
"*.bin filter=lfs diff=lfs merge=lfs -text ") |
||||
.add("a.bin", |
||||
"version https://git-lfs.github.com/spec/v1\noid sha256:8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414\nsize 7\n") |
||||
.create(); |
||||
git = Git.wrap(db); |
||||
tdb.branch("test2").commit().add(".gitattributes", |
||||
"*.bin filter=lfs diff=lfs merge=lfs -text ").create(); |
||||
} |
||||
|
||||
@After |
||||
public void cleanup() throws Exception { |
||||
tdb.getRepository().close(); |
||||
FileUtils.delete(tdb.getRepository().getWorkTree(), |
||||
FileUtils.RECURSIVE); |
||||
} |
||||
|
||||
@Test |
||||
public void testUnknownContent() throws Exception { |
||||
git.checkout().setName("test").call(); |
||||
// unknown content. We will see the pointer file
|
||||
assertEquals( |
||||
"version https://git-lfs.github.com/spec/v1\noid sha256:8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414\nsize 7\n", |
||||
JGitTestUtil.read(git.getRepository(), "a.bin")); |
||||
assertEquals("[POST /lfs/objects/batch 200]", |
||||
server.getRequests().toString()); |
||||
} |
||||
|
||||
@Test |
||||
public void testKnownContent() throws Exception { |
||||
putContent( |
||||
LongObjectId.fromString( |
||||
"8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414"), |
||||
"1234567"); |
||||
git.checkout().setName("test").call(); |
||||
// known content. we will see the actual content of the LFS blob.
|
||||
assertEquals( |
||||
"1234567", |
||||
JGitTestUtil.read(git.getRepository(), "a.bin")); |
||||
assertEquals( |
||||
"[PUT /lfs/objects/8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414 200" |
||||
+ ", POST /lfs/objects/batch 200" |
||||
+ ", GET /lfs/objects/8bb0cf6eb9b17d0f7d22b456f121257dc1254e1f01665370476383ea776df414 200]", |
||||
server.getRequests().toString()); |
||||
|
||||
git.checkout().setName("test2").call(); |
||||
assertFalse(JGitTestUtil.check(git.getRepository(), "a.bin")); |
||||
git.checkout().setName("test").call(); |
||||
// unknown content. We will see the pointer file
|
||||
assertEquals("1234567", |
||||
JGitTestUtil.read(git.getRepository(), "a.bin")); |
||||
assertEquals(3, server.getRequests().size()); |
||||
} |
||||
|
||||
} |
@ -1,11 +1,17 @@
|
||||
corruptLongObject=The content hash ''{0}'' of the long object ''{1}'' doesn''t match its id, the corrupt object will be deleted. |
||||
incorrectLONG_OBJECT_ID_LENGTH=Incorrect LONG_OBJECT_ID_LENGTH. |
||||
inconsistentMediafileLength=mediafile {0} has unexpected length; expected {1} but found {2}. |
||||
inconsistentMediafileLength=Mediafile {0} has unexpected length; expected {1} but found {2}. |
||||
inconsistentContentLength=Unexpected content length reported by LFS server ({0}), expected {1} but reported was {2} |
||||
invalidLongId=Invalid id: {0} |
||||
invalidLongIdLength=Invalid id length {0}; should be {1} |
||||
lfsUnavailable=LFS is not available for repository {0} |
||||
requiredHashFunctionNotAvailable=Required hash function {0} not available. |
||||
repositoryNotFound=Repository {0} not found |
||||
repositoryReadOnly=Repository {0} is read-only |
||||
lfsUnavailable=LFS is not available for repository {0} |
||||
lfsUnathorized=Not authorized to perform operation {0} on repository {1} |
||||
lfsFailedToGetRepository=failed to get repository {0} |
||||
lfsNoDownloadUrl="Need to download object from LFS server but couldn't determine LFS server URL" |
||||
serverFailure=When trying to open a connection to {0} the server responded with an error code. rc={1} |
||||
wrongAmoutOfDataReceived=While downloading data from the content server {0} {1} bytes have been received while {2} have been expected |
||||
userConfigInvalid="User config file {0} invalid {1}" |
@ -0,0 +1,128 @@
|
||||
/* |
||||
* Copyright (C) 2018, Markus Duft <markus.duft@ssi-schaefer.com> |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.lfs; |
||||
|
||||
import java.io.IOException; |
||||
import java.text.MessageFormat; |
||||
import java.util.concurrent.Callable; |
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException; |
||||
import org.eclipse.jgit.lfs.internal.LfsText; |
||||
import org.eclipse.jgit.lfs.lib.Constants; |
||||
import org.eclipse.jgit.lib.ConfigConstants; |
||||
import org.eclipse.jgit.lib.Repository; |
||||
import org.eclipse.jgit.lib.StoredConfig; |
||||
import org.eclipse.jgit.storage.file.FileBasedConfig; |
||||
import org.eclipse.jgit.util.FS; |
||||
import org.eclipse.jgit.util.SystemReader; |
||||
|
||||
/** |
||||
* Installs all required LFS properties for the current user, analogous to 'git |
||||
* lfs install', but defaulting to using JGit builtin hooks. |
||||
* |
||||
* @since 4.11 |
||||
*/ |
||||
public class InstallLfsCommand implements Callable<Void>{ |
||||
|
||||
private static final String[] ARGS_USER = new String[] { "lfs", "install" }; //$NON-NLS-1$//$NON-NLS-2$
|
||||
|
||||
private static final String[] ARGS_LOCAL = new String[] { "lfs", "install", //$NON-NLS-1$//$NON-NLS-2$
|
||||
"--local" }; //$NON-NLS-1$
|
||||
|
||||
private Repository repository; |
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public Void call() throws Exception { |
||||
StoredConfig cfg = null; |
||||
if (repository == null) { |
||||
cfg = loadUserConfig(); |
||||
} else { |
||||
cfg = repository.getConfig(); |
||||
} |
||||
|
||||
cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION, Constants.LFS, |
||||
ConfigConstants.CONFIG_KEY_USEJGITBUILTIN, true); |
||||
cfg.setBoolean(ConfigConstants.CONFIG_FILTER_SECTION, Constants.LFS, |
||||
ConfigConstants.CONFIG_KEY_REQUIRED, true); |
||||
|
||||
cfg.save(); |
||||
|
||||
// try to run git lfs install, we really don't care if it is present
|
||||
// and/or works here (yet).
|
||||
ProcessBuilder builder = FS.DETECTED.runInShell("git", //$NON-NLS-1$
|
||||
repository == null ? ARGS_USER : ARGS_LOCAL); |
||||
if (repository != null) { |
||||
builder.directory(repository.isBare() ? repository.getDirectory() |
||||
: repository.getWorkTree()); |
||||
} |
||||
FS.DETECTED.runProcess(builder, null, null, (String) null); |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* @param repo |
||||
* the repository to install LFS into locally instead of the user |
||||
* configuration |
||||
*/ |
||||
public void setRepository(Repository repo) { |
||||
this.repository = repo; |
||||
} |
||||
|
||||
private StoredConfig loadUserConfig() throws IOException { |
||||
FileBasedConfig c = SystemReader.getInstance().openUserConfig(null, |
||||
FS.DETECTED); |
||||
try { |
||||
c.load(); |
||||
} catch (ConfigInvalidException e1) { |
||||
throw new IOException(MessageFormat |
||||
.format(LfsText.get().userConfigInvalid, c.getFile() |
||||
.getAbsolutePath(), e1), |
||||
e1); |
||||
} |
||||
|
||||
return c; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,141 @@
|
||||
/* |
||||
* Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> |
||||
* Copyright (C) 2015, Sasa Zivkov <sasa.zivkov@sap.com> |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.lfs; |
||||
|
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* This interface describes the network protocol used between lfs client and lfs |
||||
* server |
||||
* |
||||
* @since 4.11 |
||||
*/ |
||||
public interface Protocol { |
||||
/** A request sent to an LFS server */ |
||||
class Request { |
||||
/** The operation of this request */ |
||||
public String operation; |
||||
|
||||
/** The objects of this request */ |
||||
public List<ObjectSpec> objects; |
||||
} |
||||
|
||||
/** A response received from an LFS server */ |
||||
class Response { |
||||
public List<ObjectInfo> objects; |
||||
} |
||||
|
||||
/** |
||||
* MetaData of an LFS object. Needs to be specified when requesting objects |
||||
* from the LFS server and is also returned in the response |
||||
*/ |
||||
class ObjectSpec { |
||||
public String oid; // the objectid
|
||||
|
||||
public long size; // the size of the object
|
||||
} |
||||
|
||||
/** |
||||
* Describes in a response all actions the LFS server offers for a single |
||||
* object |
||||
*/ |
||||
class ObjectInfo extends ObjectSpec { |
||||
public Map<String, Action> actions; // Maps operation to action
|
||||
|
||||
public Error error; |
||||
} |
||||
|
||||
/** |
||||
* Describes in a Response a single action the client can execute on a |
||||
* single object |
||||
*/ |
||||
class Action { |
||||
public String href; |
||||
|
||||
public Map<String, String> header; |
||||
} |
||||
|
||||
/** Describes an error to be returned by the LFS batch API */ |
||||
class Error { |
||||
public int code; |
||||
|
||||
public String message; |
||||
} |
||||
|
||||
/** |
||||
* The "download" operation |
||||
*/ |
||||
String OPERATION_DOWNLOAD = "download"; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* The "upload" operation |
||||
*/ |
||||
String OPERATION_UPLOAD = "upload"; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* The contenttype used in LFS requests |
||||
*/ |
||||
String CONTENTTYPE_VND_GIT_LFS_JSON = "application/vnd.git-lfs+json; charset=utf-8"; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* Authorization header when auto-discovering via SSH. |
||||
*/ |
||||
String HDR_AUTH = "Authorization"; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* Prefix of authentication token obtained through SSH. |
||||
*/ |
||||
String HDR_AUTH_SSH_PREFIX = "Ssh: "; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* Path to the LFS info servlet. |
||||
*/ |
||||
String INFO_LFS_ENDPOINT = "/info/lfs"; //$NON-NLS-1$
|
||||
|
||||
/** |
||||
* Path to the LFS objects servlet. |
||||
*/ |
||||
String OBJECTS_LFS_ENDPOINT = "/objects/batch"; //$NON-NLS-1$
|
||||
} |
@ -0,0 +1,66 @@
|
||||
/* |
||||
* Copyright (C) 2016, Christian Halstrick <christian.halstrick@sap.com> |
||||
* and other copyright owners as documented in the project's IP log. |
||||
* |
||||
* This program and the accompanying materials are made available |
||||
* under the terms of the Eclipse Distribution License v1.0 which |
||||
* accompanies this distribution, is reproduced below, and is |
||||
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||
* |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or |
||||
* without modification, are permitted provided that the following |
||||
* conditions are met: |
||||
* |
||||
* - Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* - Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following |
||||
* disclaimer in the documentation and/or other materials provided |
||||
* with the distribution. |
||||
* |
||||
* - Neither the name of the Eclipse Foundation, Inc. nor the |
||||
* names of its contributors may be used to endorse or promote |
||||
* products derived from this software without specific prior |
||||
* written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND |
||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, |
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
package org.eclipse.jgit.lfs.errors; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Thrown when a LFS configuration problem has been detected (i.e. unable to |
||||
* find the remote LFS repository URL). |
||||
* |
||||
* @since 4.11 |
||||
*/ |
||||
public class LfsConfigInvalidException extends IOException { |
||||
private static final long serialVersionUID = 1L; |
||||
|
||||
/** |
||||
* Constructor for LfsConfigInvalidException. |
||||
* |
||||
* @param msg |
||||
* the error description |
||||
*/ |
||||
public LfsConfigInvalidException(String msg) { |
||||
super(msg); |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue