package com.indeed.proctor.store;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class GitWorkspaceProviderImpl implements GitWorkspaceProvider {
    private static final Logger LOGGER = Logger.getLogger(GitWorkspaceProviderImpl.class);
    private static final int LOCK_TIMEOUT_SECONDS = 90;
    /**
     * The root directory into which all workspaces are created
     */
    private final File rootDirectory;
    private final Lock directoryLock;

    public GitWorkspaceProviderImpl(final File rootDirectory) {
        this.rootDirectory = Preconditions.checkNotNull(rootDirectory, "Root Directory cannot be null");
        directoryLock = new ReentrantLock();
        Preconditions.checkArgument(rootDirectory.isDirectory(), "File %s should be a directory", rootDirectory.getAbsolutePath());
        Preconditions.checkArgument(rootDirectory.exists(), "File %s should exist", rootDirectory.getAbsolutePath());
    }

    @Override
    public File getRootDirectory() {
        return rootDirectory;
    }

    @Override
    public <T> T synchronizedOperation(final Callable<T> callable) {
        try {
            if (directoryLock.tryLock(LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
                try {
                    return callable.call();
                } catch (final Exception e) {
                    throw Throwables.propagate(e);
                } finally {
                    directoryLock.unlock();
                }
            } else {
                throw Throwables.propagate(new StoreException("Attempt to acquire lock on working directory was timeout: " + LOCK_TIMEOUT_SECONDS + "s. Maybe due to dead lock"));
            }
        } catch (final InterruptedException e) {
            LOGGER.error("Thread interrupted. ", e);
        }
        return null;
    }

    public boolean cleanWorkingDirectory() {
        synchronizedOperation(new Callable<Void>() {
            @Override
            public Void call() {
                try {
                    FileUtils.cleanDirectory(rootDirectory);
                } catch (final IOException e) {
                    LOGGER.error("Unable to clean working directory", e);
                }
                return null;
            }
        });
        return true;
    }
}
@@ -595,16 +595,24 @@
 nal int 
+DEFAULT_
 LOCK_TIM
@@ -630,16 +630,16 @@
 S = 90;%0A
-
     /**%0A
@@ -785,16 +785,58 @@
 oryLock;
+%0A    private final int lockTimeoutSeconds;
 %0A%0A    pu
@@ -889,24 +889,184 @@
 irectory) %7B%0A
+        this(rootDirectory, DEFAULT_LOCK_TIMEOUT_SECONDS);%0A    %7D%0A%0A    public GitWorkspaceProviderImpl(final File rootDirectory, final int lockTimeoutSeconds) %7B%0A
         this
@@ -1449,24 +1449,78 @@
 utePath());%0A
+        this.lockTimeoutSeconds = lockTimeoutSeconds;%0A
     %7D%0A%0A    @
@@ -1737,36 +1737,34 @@
 tryLock(
-LOCK_TIMEOUT_SECONDS
+lockTimeoutSeconds
 , TimeUn
@@ -2177,36 +2177,34 @@
 ut: %22 + 
-LOCK_TIMEOUT_SECONDS
+lockTimeoutSeconds
  + %22s. M

Update GitWorkspaceProviderImpl to configure timeout