1

I am unable to delete folder containing a cloned repository created using jgit. I have tried all kinds of utility delete methods but none works. The error thrown while using FileUtils.deleteDirectory(file) is as follows

java.nio.file.AccessDeniedException: \repositories\Test\Test\.git\objects\pack\pack-21cdd19e90e9e6bd2e8d295ea04201969594fe96.idx

Tried the following,

  1. I have seen a range of other answers, for example [1] and [2]. They are all concerned with cases wherein they created a repository with jgit first and then deleted it immediately after that. In my current scenario I want to check if a repository is already cloned at given path and delete if present. After doing this task, I want to clone a repository using jgit on the same path.
  2. I tried cases wherein I created the repository with jgit, shut down my server. Started it again and then simply called a function to delete the folder created earlier. This again failed with the same error.
  3. I also completely removed jgit from my initial code and from pom since it might be getting into loaded into classpath. I still get the same error when trying to delete. Tried again after restarting just to check, the issue still persists.
  4. However, when I run the same deletion code from another Java program, it succeeds.

[1] How to remove local repository by Java code that was cloned by JGit java library?
[2] How do I release file system locks after cloning repo via JGit

Here is the original code snippet for reference,

    File file = null;
    try {
        file = new File(localRepositoryPath);

        // Delete directory if already present
        String localRepositoryParentPath = GitUtils.getRepositoryPath(projectName, null);
        File parentDirectory = new File(localRepositoryParentPath);
        FileUtils.deleteDirectory(parentDirectory);

        // Create directory where repository will be cloned
        if(!file.mkdirs()) {
            throw new GitServiceException(
                GitUtils.getCloneFailureMessage("Unable to create directory",
                    projectName,
                    repoName));
        }
    } catch (NullPointerException | SecurityException | IOException e) {
        logger.info(Arrays.toString(e.getStackTrace()));
        logger.error("IO Error cloning repository {} and project {}. Stacktrace {} ",
            repoName,
            projectName,
            e.getStackTrace());
        throw new GitServiceException(
            GitUtils.getCloneFailureMessage("IO Error while cloning",
                projectName,
                repoName));
    }

    // Clone the git repository
    try (Git git = Git.cloneRepository()
            .setURI(repoUrl)
            .setDirectory(file)
            .setBranchesToClone(List.of("refs/heads/" + branchToClone))
            .setBranch("refs/heads/" + branchToClone)
            .setCredentialsProvider(new UsernamePasswordCredentialsProvider( "token", this.credentials.getGitToken()))
            .call();
    ) {
        logger.info("Successfully cloned branch {} on path {} for repository {} and project {}",
            branchToClone,
            localRepositoryPath,
            repoName,
            projectName);
    } catch (Exception exception) {
        logger.error("Error cloning repository {} and project {}. Stacktrace {} ",
            repoName,
            projectName,
            exception.getStackTrace());
        throw new GitServiceException(
            GitUtils.getCloneFailureMessage("Unable to clone repository locally",
                projectName,
                repoName));
    }

Edit

Adding error stacktrace

org.apache.commons.io.IOExceptionList: 1 exceptions: [java.io.IOException: Unable to delete file: \repositories\Test\Test\.git]
at org.apache.commons.io.FileUtils.cleanDirectory(FileUtils.java:345)
at org.apache.commons.io.FileUtils.deleteDirectory(FileUtils.java:1206)
at com.adobe.mdloc.controller.TestController.post(TestController.java:57)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.adobe.asr.filter.AsrRequestResponseFilter.doFilterInternal(AsrRequestResponseFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.adobe.asr.logging.http.servlet.AsrLoggingFilter.doFilter(AsrLoggingFilter.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.adobe.asr.filter.AsrRequestIdFilter.doFilterInternal(AsrRequestIdFilter.java:99)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.adobe.asr.exception.AsrExceptionFilter.doFilterInternal(AsrExceptionFilter.java:82)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)

Caused by: java.io.IOException: Unable to delete file: \repositories\Test\Test\.git
at org.apache.commons.io.FileUtils.forceDelete(FileUtils.java:1425)
at org.apache.commons.io.FileUtils.cleanDirectory(FileUtils.java:338)
... 71 more

Caused by: java.nio.file.AccessDeniedException: \repositories\Test\Test\.git\objects\pack\pack-21cdd19e90e9e6bd2e8d295ea04201969594fe96.idx
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:89)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
at java.base/sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:274)
at java.base/sun.nio.fs.AbstractFileSystemProvider.deleteIfExists(AbstractFileSystemProvider.java:110)
at java.base/java.nio.file.Files.deleteIfExists(Files.java:1180)
at org.apache.commons.io.file.DeletingPathVisitor.visitFile(DeletingPathVisitor.java:142)
at org.apache.commons.io.file.DeletingPathVisitor.visitFile(DeletingPathVisitor.java:36)
at java.base/java.nio.file.Files.walkFileTree(Files.java:2724)
at java.base/java.nio.file.Files.walkFileTree(Files.java:2796)
at org.apache.commons.io.file.PathUtils.visitFileTree(PathUtils.java:687)
at org.apache.commons.io.file.PathUtils.deleteDirectory(PathUtils.java:328)
at org.apache.commons.io.file.PathUtils.delete(PathUtils.java:303)
at org.apache.commons.io.file.PathUtils.delete(PathUtils.java:280)
at org.apache.commons.io.FileUtils.forceDelete(FileUtils.java:1423)
... 72 more
arjunkhera
  • 929
  • 6
  • 23
  • Would need to see more of the exception to see what thee real cause is.... however, 2 things come to mind easy: permissions of the user that is running the process _and_ that the process be actually standing on that repo directory as its PWD. – eftshift0 Jun 07 '21 at 15:36
  • To do a quick test, I just wrote a simple java program with the just the deletion code, It worked fine. Looking at the error I can make out it has access issues for the particular mentioned git file. What I cannot figure out is why specifically it does not work for this. I will do some more check, maybe am missing something obvious – arjunkhera Jun 07 '21 at 15:44
  • Is it running on a windows box? If that's the case, _perhaps_ the file is open at the time (which is a **no-go** in windows, if the file is open). – eftshift0 Jun 07 '21 at 15:49
  • What does `GitUtils.getRepositoryPath` do exactly? You certainly need to close the repo before deleting it, see also https://stackoverflow.com/questions/45266021/java-jgit-files-delete-fails-to-delete-a-file-but-file-delete-succeeds – Rüdiger Herrmann Jun 07 '21 at 23:27
  • I was using try with resource semantics as documented here https://github.com/centic9/jgit-cookbook/blob/master/src/main/java/org/dstadler/jgit/porcelain/CloneRemoteRepository.java#L46. The function you are asking is just a utility to obtain the path where I want to clone the repo. – arjunkhera Jun 08 '21 at 14:53
  • @eftshift0 the files were not open. I have been bitten by that mistake before so am careful about this. And yes, for better or worse, I am working on windows :) – arjunkhera Jun 08 '21 at 14:58
  • Just in case, I don't mean the project files but the _repo_ files. I am assuming that you are closing the repo before trying to delete it. – eftshift0 Jun 08 '21 at 15:10
  • As of now, I have just started from clone, which as you can see from the code I attached, that I check no previous repo was present, on that path before cloning. But if there was, I need to delete it. Currently I am not working on the repo files anywhere else that would lead to locking of files by jgit. – arjunkhera Jun 08 '21 at 15:15

2 Answers2

1

Apparently the Apache Commons IO function was throwing the error. Recursively traversing all files and deleting them using the java.io delete command worked perfectly fine.

Here is the code snippet used for reference,

public static boolean deleteDirectory(File file) {
    File[] children = file.listFiles();
    if (children != null) {
        for (File child : children) {
            deleteDirectory(child);
        }
    }
    return file.delete();
}
arjunkhera
  • 929
  • 6
  • 23
0

Use .close() method post Git clone and this will solve your issue.

try (Git git = Git.cloneRepository()
        .setURI(repoUrl)
        .setDirectory(file)
        .setBranchesToClone(List.of("refs/heads/" + branchToClone))
        .setBranch("refs/heads/" + branchToClone)
        .setCredentialsProvider(new UsernamePasswordCredentialsProvider( "token", this.credentials.getGitToken()))
        .call()
        .close();