/**
* 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.ucm;
import hudson.FilePath;
import hudson.plugins.clearcase.Baseline;
import hudson.plugins.clearcase.ClearTool;
import hudson.plugins.clearcase.ClearTool.DiffBlOptions;
import hudson.plugins.clearcase.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import org.apache.commons.lang.StringUtils;
/**
* @author kyosi
*/
public class UcmCommon {
/**
* Takes a list of baselines as argument, and return the load rules for all components matching these baselines
* @param clearTool
* @param stream
* @param baselines
* @return
* @throws IOException
* @throws InterruptedException
*/
public static String[] generateLoadRulesFromBaselines(ClearTool clearTool, String stream, List<Baseline> baselines) throws IOException, InterruptedException {
if (baselines == null) {
return null;
}
List<String> loadRules = new ArrayList<String>();
int i = 0;
for(Baseline bl : baselines) {
Reader reader = clearTool.describe("%[root_dir]p\\n", "component:" + bl.getComponentName());
BufferedReader br = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
for(String line = br.readLine(); line != null; line = br.readLine()){
if (StringUtils.isNotBlank(line)) {
sb.append(line.substring(1)); // Remove leading separator
}
}
String loadRule = sb.toString();
if (StringUtils.isNotBlank(loadRule)) {
loadRules.add(loadRule);
}
}
return loadRules.toArray(new String[loadRules.size()]);
}
/**
* @param clearToolLauncher
* @param isUseDynamicView
* @param viewName
* @param filePath
* @param readWriteComponents . if null both baselines on read and read-write components will be returned
* @return List of latest baselines on read write components (only)
* @throws InterruptedException
* @throws IOException
* @throws Exception
*/
public static List<String> getLatestBaselineNames(ClearTool clearTool, boolean isUseDynamicView, String viewName, FilePath filePath,
List<String> readWriteComponents) throws IOException, InterruptedException {
String output = clearTool.lsstream(null, viewName, "%[latest_bls]Xp");
String prefix = "baseline:";
List<String> baselineNames = new ArrayList<String>();
if (StringUtils.startsWith(output, prefix)) {
String[] baselineNamesSplit = output.split("baseline:");
for (String baselineName : baselineNamesSplit) {
if (StringUtils.isNotBlank(baselineName)) {
String baselineNameTrimmed = StringUtils.trim(baselineName);
// Retrict to baseline bind to read/write component
String blComp = getDataforBaseline(clearTool, filePath, baselineNameTrimmed).getBaselineName();
if (readWriteComponents == null || readWriteComponents.contains(blComp)) {
baselineNames.add(baselineNameTrimmed);
}
}
}
}
return baselineNames;
}
/**
* @param clearToolLauncher
* @param isUseDynamicView
* @param viewName
* @param filePath
* @param baselinesNames
* @return list of BaselineDesc (baseline name and component name)
* @throws InterruptedException
* @throws IOException
*/
public static List<Baseline> getComponentsForBaselines(ClearTool clearTool, List<Component> componentsList, boolean isUseDynamicView, String viewName,
FilePath filePath, List<String> baselinesNames) throws InterruptedException, IOException {
List<Baseline> baselinesList = new ArrayList<Baseline>();
// loop through baselines
for (String blName : baselinesNames) {
Baseline baseline = getDataforBaseline(clearTool, filePath, blName);
Component matchComponentDesc = null;
// find the equivalent componentDesc element
for (Component componentDesc : componentsList) {
if (getNoVob(componentDesc.getName()).equals(getNoVob(baseline.getComponentName()))) {
matchComponentDesc = componentDesc;
baselinesList.add(new Baseline(blName, matchComponentDesc, baseline.isNotLabeled()));
break;
}
}
if (matchComponentDesc == null) {
clearTool.getLauncher().getListener().error("Could not find a component matching baseline " + blName);
}
}
return baselinesList;
}
/**
* Get the component binding to the baseline
*
* @param clearToolLauncher
* @param filePath
* @param blName the baseline name like 'deskCore_3.2-146_2008-11-14_18-07-22.3543@\P_ORC'
* @return the component name like 'Desk_Core@\P_ORC'
* @throws InterruptedException
* @throws IOException
*/
public static Baseline getDataforBaseline(ClearTool clearTool, FilePath filePath, String blName) throws InterruptedException, IOException {
String cleartoolResult = clearTool.lsbl(blName, "%[label_status]p|%[component]Xp");
String[] arr = cleartoolResult.split("\\|");
boolean isNotLabeled = arr[0].contains("Not Labeled");
String prefix = "component:";
String componentName = arr[1].substring(cleartoolResult.indexOf(cleartoolResult) + prefix.length());
return new Baseline(componentName, isNotLabeled);
}
public static List<Baseline> getLatestBaselines(ClearTool clearTool, String stream) throws IOException, InterruptedException {
return getBaselinesDesc(clearTool, stream, "%[latest_bls]Xp\\n");
}
public static List<Baseline> getFoundationBaselines(ClearTool clearTool, String stream) throws IOException, InterruptedException {
return getBaselinesDesc(clearTool, stream, "%[found_bls]Xp\\n");
}
private static List<Baseline> getBaselinesDesc(ClearTool clearTool, String stream, String format) throws IOException,
InterruptedException {
BufferedReader rd = new BufferedReader(clearTool.describe(format, "stream:" + stream));
List<String> baselines = new ArrayList<String>();
try {
for (String line = rd.readLine(); line != null; line = rd.readLine()) {
if (!line.startsWith("cleartool: Error:")) {
String[] bl = line.split(" ");
for (String b : bl) {
if (StringUtils.isNotBlank(b)) {
baselines.add(b);
}
}
}
}
} finally {
rd.close();
}
List<Baseline> foundationBaselines = new ArrayList<Baseline>();
for (String baseline : baselines) {
BufferedReader br = new BufferedReader(clearTool.describe("%[component]Xp\\n", baseline));
try {
foundationBaselines.add(new Baseline(StringUtils.removeStart(baseline, "baseline:"), StringUtils.removeStart(br.readLine(), "component:")));
} finally {
br.close();
}
}
return foundationBaselines;
}
/**
* @param clearToolLauncher
* @param streamName
* @return list of components - name and isModifiable
* @throws IOException
* @throws InterruptedException
*/
public static List<Component> getStreamComponentsDesc(ClearTool clearTool, String streamName) throws IOException, InterruptedException {
List<Component> componentsDescList = new ArrayList<Component>();
Reader reader = clearTool.describe(null, "stream:" + streamName);
BufferedReader bufferedReader = new BufferedReader(reader);
StringBuilder sb = new StringBuilder();
while (bufferedReader.ready()) {
sb.append(bufferedReader.readLine());
}
String output = sb.toString();
// searching in the result for the pattern (<component-name> (modifiable | non-modifiable)
int idx = 0;
int idx1;
int idx2;
String searchFor = "modifiable)";
while (idx >= 0) {
idx = output.indexOf(searchFor, idx + 1);
if (idx > 0) {
// get the component state part: modifiable or non-modifiable
idx1 = output.lastIndexOf("(", idx - 1);
idx2 = output.indexOf(")", idx1);
String componentState = output.substring(idx1 + 1, idx2);
// get the component name
idx1 = output.lastIndexOf("(", idx1 - 1);
idx2 = output.indexOf(")", idx1);
// add to the result
Component componentDesc = new Component(output.substring(idx1 + 1, idx2), componentState.equals("modifiable"));
componentsDescList.add(componentDesc);
}
}
return componentsDescList;
}
/**
* @return List of latest BaseLineDesc (baseline + component) for stream. Only baselines on read-write components
* are returned
* @throws InterruptedException
* @throws IOException
* @throws Exception
*/
public static List<Baseline> getLatestBlsWithCompOnStream(ClearTool clearTool, String stream, String view) throws IOException, InterruptedException {
// get the components on the build stream
List<Component> componentsList = getStreamComponentsDesc(clearTool, stream);
// get latest baselines on the stream (name only)
List<String> latestBlsOnBuildStream = getLatestBaselineNames(clearTool, true, view, null, null);
// add component information to baselines
List<Baseline> latestBlsWithComp = getComponentsForBaselines(clearTool, componentsList, true, view, null, latestBlsOnBuildStream);
return latestBlsWithComp;
}
/**
* @param componentsDesc
* @return list of read-write components out of components list (removing read-only components)
*/
public static List<String> getReadWriteComponents(List<Component> components) {
List<String> res = new ArrayList<String>();
for (Component comp : components) {
if (comp.isModifiable()) {
res.add(comp.getName());
}
}
return res;
}
/**
* @param clearToolLauncher
* @param viewRootDirectory
* @param bl1
* @param bl2
* @return list of versions that were changed between two baselines
* @throws IOException
* @throws InterruptedException
*/
public static List<String> getDiffBlVersions(ClearTool clearTool, String viewRootDirectory, String bl1, String bl2) throws IOException,
InterruptedException {
Reader rd = clearTool.diffbl(EnumSet.of(DiffBlOptions.VERSIONS), bl1, bl2, viewRootDirectory);
BufferedReader br = new BufferedReader(rd);
List<String> versionList = new ArrayList<String>();
// remove ">>" from result
for (String line = br.readLine(); br.ready(); line = br.readLine()) {
if (line.startsWith(">>")) {
line = line.replaceAll(">>", "");
versionList.add(line.trim());
}
}
return versionList;
}
/**
* @param clearToolLauncher
* @param version
* @return version description
* @throws IOException
* @throws InterruptedException
*/
public static String getVersionDescription(ClearTool clearTool, String version, String format) throws IOException, InterruptedException {
Reader rd = clearTool.describe(format, version);
BufferedReader bufferedReader = new BufferedReader(rd);
StringBuilder sb = new StringBuilder();
while (bufferedReader.ready()) {
sb.append(bufferedReader.readLine());
}
return sb.toString();
}
/**
* @param clearToolLauncher
* @param stream
* @param baselines
* @throws IOException
* @throws InterruptedException
*/
public static void rebase(ClearTool clearTool, String viewName, List<Baseline> baselines) throws IOException, InterruptedException {
StringBuilder sb = new StringBuilder();
for (Baseline bl : baselines) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(bl.getBaselineName());
}
clearTool.rebaseDynamic(viewName, sb.toString());
}
/**
* @param clearToolLauncher
* @param element
* @return
*/
public static String getNoVob(String element) {
return element.split("@")[0];
}
public static String getVob(String element) {
return element.split("@")[1];
}
}