/**
* The MIT License
*
* Copyright (c) 2007-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt,
* Henrik Lynggaard, Peter Liljenberg, Andrew Bayer, Vincent Latombe
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.plugins.clearcase.action;
import hudson.FilePath;
import hudson.Launcher;
import hudson.plugins.clearcase.ClearTool;
import hudson.plugins.clearcase.ConfigSpec;
import java.io.IOException;
import java.io.PrintStream;
import java.util.LinkedHashSet;
import java.util.Set;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.Validate;
/**
* Check out action that will check out files into a snapshot view.
*/
public abstract class AbstractCheckoutAction implements CheckOutAction {
public static class LoadRulesDelta {
private final Set<String> removed;
private final Set<String> added;
public LoadRulesDelta(Set<String> removed, Set<String> added) {
super();
this.removed = removed;
this.added = added;
}
public String[] getAdded() {
return added.toArray(new String[added.size()]);
}
public String[] getRemoved() {
return removed.toArray(new String[removed.size()]);
}
public boolean isEmpty() {
return added.isEmpty() && removed.isEmpty();
}
}
protected final ClearTool cleartool;
protected final String[] loadRules;
protected final boolean useUpdate;
protected final String viewPath;
public AbstractCheckoutAction(ClearTool cleartool, String[] loadRules, boolean useUpdate, String viewPath) {
Validate.notNull(cleartool);
this.cleartool = cleartool;
this.loadRules = loadRules;
this.useUpdate = useUpdate;
this.viewPath = viewPath;
}
@Override
public boolean isViewValid(Launcher launcher, FilePath workspace, String viewTag) throws IOException, InterruptedException {
Validate.notEmpty(viewPath);
FilePath filePath = new FilePath(workspace, viewPath);
boolean viewPathExists = filePath.exists();
return cleartool.doesViewExist(viewTag) && viewPathExists && viewTag.equals(cleartool.lscurrentview(viewPath));
}
/**
* Manages the re-creation of the view if needed. If something exists but not referenced correctly as a view, it will be renamed and the view will be created
* @param workspace The job's workspace
* @param viewTag The view identifier on server. Must be unique on server
* @param viewPath The workspace relative path of the view
* @param streamSelector The stream selector, using streamName[@pvob] format
* @return true if a mkview has been done, false if a view existed and is reused
* @throws IOException
* @throws InterruptedException
*/
protected boolean cleanAndCreateViewIfNeeded(FilePath workspace, String viewTag, String viewPath, String streamSelector) throws IOException, InterruptedException {
Validate.notEmpty(viewPath);
FilePath filePath = new FilePath(workspace, viewPath);
boolean viewPathExists = filePath.exists();
boolean doViewCreation = true;
if (cleartool.doesViewExist(viewTag)) {
if (viewPathExists) {
if (viewTag.equals(cleartool.lscurrentview(viewPath))) {
if (useUpdate) {
doViewCreation = false;
} else {
cleartool.rmview(viewPath);
}
} else {
filePath.renameTo(getUnusedFilePath(workspace, viewPath));
rmviewtag(viewTag);
}
} else {
rmviewtag(viewTag);
}
} else {
if (viewPathExists) {
filePath.renameTo(getUnusedFilePath(workspace, viewPath));
}
}
if (doViewCreation) {
cleartool.mkview(viewPath, viewTag, streamSelector);
}
return doViewCreation;
}
private void rmviewtag(String viewTag) throws InterruptedException, IOException{
try {
cleartool.rmviewtag(viewTag);
} catch(IOException e) {
// ClearCase RT doesn't support rmview -tag
cleartool.rmtag(viewTag);
}
}
protected AbstractCheckoutAction.LoadRulesDelta getLoadRulesDelta(Set<String> configSpecLoadRules, Launcher launcher) {
Set<String> removedLoadRules = new LinkedHashSet<String>(configSpecLoadRules);
Set<String> addedLoadRules = new LinkedHashSet<String>();
if (!ArrayUtils.isEmpty(loadRules)) {
for (String loadRule : loadRules) {
addedLoadRules.add(ConfigSpec.cleanLoadRule(loadRule, launcher.isUnix()));
}
removedLoadRules.removeAll(addedLoadRules);
addedLoadRules.removeAll(configSpecLoadRules);
PrintStream logger = launcher.getListener().getLogger();
for (String removedLoadRule : removedLoadRules) {
logger.println("Removed load rule : " + removedLoadRule);
}
for (String addedLoadRule : addedLoadRules) {
logger.println("Added load rule : " + addedLoadRule);
}
}
return new AbstractCheckoutAction.LoadRulesDelta(removedLoadRules, addedLoadRules);
}
private FilePath getUnusedFilePath(FilePath workspace, String viewName) throws IOException, InterruptedException {
for (int i = 1; i < Integer.MAX_VALUE; i++) {
FilePath result = new FilePath(workspace, viewName + ".keep." + i);
if (!result.exists()) {
return result;
}
}
return null;
}
}