/* * Copyright 2016 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.domain.materials.tfs; import com.thoughtworks.go.domain.materials.Modification; import com.thoughtworks.go.domain.materials.Revision; import com.thoughtworks.go.domain.materials.SCMCommand; import com.thoughtworks.go.util.StringUtil; import com.thoughtworks.go.util.command.CommandArgument; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.List; public abstract class AbstractTfsCommand extends SCMCommand implements TfsCommand { private static final Logger LOGGER = Logger.getLogger(AbstractTfsCommand.class); private final CommandArgument url; private final String domain; private final String userName; private final String password; private final String workspace; private final String projectPath; public AbstractTfsCommand(String materialFingerprint, CommandArgument url, String domain, String userName, String password, String workspace, String projectPath) { super(materialFingerprint); this.url = url; this.domain = domain; this.userName = userName; this.password = password; this.workspace = workspace; this.projectPath = projectPath; } protected CommandArgument getUrl() { return url; } protected String getUserName() { return userName; } protected String getPassword() { return password; } protected String getWorkspace() { return workspace; } protected String getProjectPath() { return projectPath; } protected String getDomain() { return domain; } @Override public final void checkout(File workDir, Revision revision) { try { if (workDir.exists()) { FileUtils.deleteQuietly(workDir); } setupWorkspace(workDir); if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("[TFS] Retrieving Files from Workspace %s, Working Folder %s, Revision %s ", workspace, workDir, revision)); } retrieveFiles(workDir, revision); } catch (Exception e) { String exceptionMessage = String.format("Failed while checking out into Working Folder: %s, Project Path: %s, Workspace: %s, Username: %s, Domain: %s, Root Cause: %s", workDir, projectPath, workspace, userName, domain, e.getMessage()); throw new RuntimeException(exceptionMessage, e); } finally { clearMapping(workDir); } } @Override public final List<Modification> latestModification(File workDir) { try { if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("[TFS] History for Workspace: %s, Working Folder: %s, Latest Revision: null, RevToLoad: 1", workspace, workDir)); } return latestInHistory(); } catch (Exception e) { String message = String.format("[TFS] Failed while checking for latest modifications on Server: %s, Project Path: %s, Username: %s, Domain: %s", url, projectPath, userName, domain); throw new RuntimeException(message, e); } } @Override public final List<Modification> modificationsSince(File workDir, Revision revision) { try { if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("[TFS] Modification check for Workspace: %s, Working Folder %s, Revision %s ", workspace, workDir, revision)); } return modificationsSinceRevInHistory(revision); } catch (Exception e) { String message = String.format("Failed while checking for modifications since revision %s on Server: %s, Project Path: %s, Username: %s, Domain: %s," + " Root Cause: %s", revision.getRevision(), url, projectPath, userName, domain, e.getMessage()); throw new RuntimeException(message, e); } } @Override public final void checkConnection() { LOGGER.info(String.format("[TFS] Checking Connection: Server %s, Domain %s, User %s, Project Path %s", url, domain, userName, projectPath)); try { List<Modification> modifications = latestInHistory(); if (modifications.isEmpty()) { throw new IllegalStateException("There might be no commits on the project path, project path might be invalid or user may have insufficient permissions."); } } catch (Exception e) { String message = String.format("Failed while checking connection using Url: %s, Project Path: %s, Username: %s, Domain: %s, Root Cause: %s", url, projectPath, userName, domain, e.getMessage()); throw new RuntimeException(message, e); } } private void setupWorkspace(File workDir) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("[TFS] Initializing Workspace %s, Working Folder %s", workspace, workDir)); } initializeWorkspace(workDir); } private void clearMapping(File workDir) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(String.format("[TFS] Unmapping Project Path %s for Workspace %s, User %s ", projectPath, workspace, userName)); } try { unMap(workDir); } catch (Exception e) { LOGGER.warn(String.format("[TFS] Unmapping Project Path %s failed for Workspace %s, User %s", projectPath, workspace, userName), e); } } protected abstract void unMap(File workDir) throws IOException; private List<Modification> modificationsSinceRevInHistory(Revision revision) { Modification latest = latestInHistory().get(0); long latestRev = Long.parseLong(latest.getRevision()); long sinceRev = Long.parseLong(revision.getRevision()); long numberOfModifications = latestRev - sinceRev; List<Modification> newMods = new ArrayList<>(); if (numberOfModifications > 0) { List<Modification> history = history(latest.getRevision(), numberOfModifications); for (Modification listedMod : history) { String listedRev = listedMod.getRevision(); long listedRevNumber = Long.parseLong(listedRev); if (listedRevNumber <= sinceRev) { break; } newMods.add(listedMod); } } return newMods; } private List<Modification> latestInHistory() { return history(null, 1); } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } AbstractTfsCommand that = (AbstractTfsCommand) o; if (domain != null ? !domain.equals(that.domain) : that.domain != null) { return false; } if (password != null ? !password.equals(that.password) : that.password != null) { return false; } if (projectPath != null ? !projectPath.equals(that.projectPath) : that.projectPath != null) { return false; } if (url != null ? !url.equals(that.url) : that.url != null) { return false; } if (userName != null ? !userName.equals(that.userName) : that.userName != null) { return false; } if (workspace != null ? !workspace.equals(that.workspace) : that.workspace != null) { return false; } return true; } @Override public int hashCode() { int result = url != null ? url.hashCode() : 0; result = 31 * result + (domain != null ? domain.hashCode() : 0); result = 31 * result + (userName != null ? userName.hashCode() : 0); result = 31 * result + (password != null ? password.hashCode() : 0); result = 31 * result + (workspace != null ? workspace.hashCode() : 0); result = 31 * result + (projectPath != null ? projectPath.hashCode() : 0); return result; } protected URI getUri() { try { return new URL(url.toString()).toURI(); } catch (URISyntaxException e) { throw new RuntimeException(String.format("[TFS] Failed when converting the url string to a uri: %s, Project Path: %s, Username: %s, Domain: %s", url, projectPath, userName, domain), e); } catch (MalformedURLException e) { throw new RuntimeException(String.format("[TFS] Failed when converting the url string to a uri: %s, Project Path: %s, Username: %s, Domain: %s", url, projectPath, userName, domain), e); } } protected String usernameWithDomain() { if (StringUtil.isBlank(domain)) { return getUserName(); } else { return String.format("%s\\%s", getDomain(), getUserName()); } } protected abstract List<Modification> history(final String beforeRevision, final long revsToLoad); protected abstract void retrieveFiles(File workDir, Revision revision); protected abstract void initializeWorkspace(File workDir); }