package com.perforce.api;
import java.io.*;
import java.util.*;
/*
* Copyright (c) 2001, Perforce Software, All rights reserved.
*
* 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.
*/
/**
* Representation of a source control branch. There are static class methods
* that can be used to list <a href="#getBranches()">all P4 branches</a> or to
* get <a href="#getBranch(java.lang.String)">a particular branch</a>.
*
* @author <a href="mailto:david@markley.cc">David Markley</a>
* @version $Date: 2002/08/05 $ $Revision: #3 $
*/
public class Branch extends Mapping {
private static HashDecay branches = null;
/**
* Default no-argument constructor.
*/
public Branch() {
super();
getCache();
}
/**
* Constructor that is passed the branch name.
*/
public Branch(String name) {
this();
setName(name);
}
private static HashDecay setCache() {
if(null == branches) {
branches = new HashDecay(1200000);
branches.start();
}
return branches;
}
public HashDecay getCache() {
return setCache();
}
/**
* Returns a list of branches that begin with the specified prefix.
*
* @param prefix
* Prefix for all branches to be returned
* @return List of branches matching the prefix.
*/
public static Enumeration lookupBranches(String prefix) {
return lookupMappings(branches, prefix);
}
/**
* Loads the list of branches using the default environment.
*
* @see Env
*/
public static void loadBranches() {
loadBranches(null);
}
/**
* Loads a list of all the branches into an internal class HashDecay. This
* method will only be called by the class itself if the HashDecay is empty.
* Users should call this method if they believe the p4 branch information
* needs to be brought up to date.
*
* @param env
* Environment to use when working with P4
* @see HashDecay
*/
public static void loadBranches(Env env) {
String l, name;
String[] cmd = { "p4", "branches" };
StringTokenizer st;
Branch b;
setCache();
try {
P4Process p = new P4Process(env);
p.exec(cmd);
while(null != (l = p.readLine())) {
if(!l.startsWith("Branch")) {
continue;
}
st = new StringTokenizer(l);
if(6 > st.countTokens()) {
continue;
}
st.nextToken();
name = st.nextToken();
synchronized(branches) {
if(null == (b = (Branch) branches.get(name))) {
b = new Branch(name);
b.setEnv(env);
} else {
b.refreshUpdateTime();
continue;
}
}
st.nextToken();
st.nextToken("'");
b.setDescription(st.nextToken());
branches.put(b.getName(), b);
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* Returns list of all branch names.
*
* @return <code>Enumeration</code> of <code>String</code>s containing
* branch names.
*/
public static Enumeration getBranchNames(Env env) {
loadBranches(env);
return branches.keys();
}
/**
* Returns list of all branches.
*
* @return <code>Enumeration</code> of <code>Branch</code>es.
* @deprecated
*/
public static Enumeration getBranches() {
return getBranches(null);
}
/**
* @param env
* Source control environment.
* @return <code>Enumeration</code> of <code>Branch</code>es.
*/
public static Enumeration getBranches(Env env) {
return Utils.getEnumeration(getBranchIterator(env));
}
/**
* @param env
* Source control environment.
* @return <code>Iterator</code> of <code>Branch</code>es.
*/
public static Iterator getBranchIterator(Env env) {
loadBranches(env);
Enumeration en = branches.elements();
TreeSet ts = new TreeSet();
while(en.hasMoreElements()) {
ts.add(en.nextElement());
}
return ts.iterator();
}
/**
* Returns a Branch with the specified name, or null if not found.
*
* @param name
* Name of the branch to find.
*/
public static synchronized Branch getBranch(String name) {
return getBranch(null, name, true);
}
/**
* Returns a Branch with the specified name, or null if not found.
*
* @param env
* Environment to use when working with P4.
* @param name
* Name of the branch to find.
* @param force
* Indicates that the Branch should be sync'd.
*/
public static synchronized Branch getBranch(Env env, String name, boolean force) {
Branch b;
if(null == name || name.trim().equals(""))
return null;
if(null == (b = (Branch) setCache().get(name)))
b = new Branch(name);
if(null != env)
b.setEnv(env);
b.sync();
branches.put(name, b);
return b;
}
/**
* Integrate a set of files using the named branch. Creates a Change that
* contains the integraed files. The change will be *PENDING* after this
* completes.
*
* @param env
* environment to use when working with P4.
* @param fents
* list of FileEntries to be integrated.
* @param branch
* name of the branch to integrate with.
* @param sb
* buffer that will contain a log of the integration.
* @param description
* description to be used for the Change created.
* @return Change containing the files integrated.
* @see Change
*/
public static Change integrate(Env env, Vector fents, String branch, StringBuffer sb, String description)
throws CommitException, PerforceException {
Change c = new Change();
c.setEnv(env);
c.setDescription(description);
c.setUser(User.getUser(env.getUser()));
c.setClientName(env.getClient());
c.commit();
return integrate(env, fents, branch, sb, c);
}
/**
* Integrate a set of files using the named branch. Uses the Change passed
* in to contain the integraed files. The change will be *PENDING* after
* this completes.
*
* @param env
* environment to use when working with P4.
* @param fents
* list of FileEntries to be integrated.
* @param branch
* name of the branch to integrate with.
* @param sb
* buffer that will contain a log of the integration.
* @param c
* Change to be used to contain the integrated files.
* @return Change containing the files integrated.
* @see Change
*/
public static Change integrate(Env env, Vector fents, String branch, StringBuffer sb, Change c)
throws PerforceException {
FileEntry fent;
Enumeration en = fents.elements();
while(en.hasMoreElements()) {
fent = (FileEntry) en.nextElement();
integrate(env, fent.getDepotPath() + "#" + fent.getHeadRev(), branch, sb, c);
}
return c;
}
/**
* Class method for integrating using the instantiated Branch.
*
* @param source
* source files to integrate from.
* @param sb
* buffer that will contain a log of the integration.
* @param c
* Change to be used to contain the integrated files.
* @see Branch#integrate(Env,String,String,StringBuffer,Change)
*/
public Change integrate(String source, StringBuffer sb, Change c) throws PerforceException {
if(null == c) {
c = new Change();
c.setDescription("Automated Integration");
c.commit();
}
return Branch.integrate(this.getEnv(), source, this.getName(), sb, c);
}
/**
* Integrate a set of files using the named branch. Uses the Change passed
* in to contain the integraed files. The change will be *PENDING* after
* this completes.
*
* @param env
* environment to use when working with P4.
* @param source
* source files to integrate from.
* @param branch
* name of the branch to integrate with.
* @param sb
* buffer that will contain a log of the integration.
* @param c
* Change to be used to contain the integrated files.
* @return Change containing the files integrated.
* @see Change
*/
public static Change integrate(Env env, String source, String branch, StringBuffer sb, Change c)
throws PerforceException {
String[] intcmd = { "p4", "integrate", "-v", "-d", "-c", String.valueOf(c.getNumber()), "-b", branch, "-s",
source };
P4Process p;
String l;
intcmd[5] = String.valueOf(c.getNumber());
for(int i = 0; i < 8; i++) {
sb.append(intcmd[i]);
sb.append(' ');
}
sb.append('\n');
try {
p = new P4Process(env);
p.exec(intcmd);
while(null != (l = p.readLine())) {
if(null != sb) {
sb.append(l);
sb.append('\n');
}
}
p.close();
} catch(Exception ex) {
throw new PerforceException(ex.getMessage());
}
return c;
}
/**
* Stores the branch information back into p4, creating the branch if it
* didn't already exist.
*
* @deprecated Use {@link #commit() commit()} instead.
*/
public void store() throws CommitException {
this.commit();
}
public void commit() throws CommitException {
String[] cmd = { "p4", "branch", "-i" };
String l;
try {
P4Process p = new P4Process(getEnv());
p.exec(cmd);
while(null != (l = p.readLine())) {
p.println("Branch: " + getName());
p.println("Owner: " + getOwner());
p.println("View:");
p.println(getView());
p.flush();
p.outClose();
while(null != (l = p.readLine())) {
}
p.close();
}
} catch(Exception ex) {
throw new CommitException(ex.getMessage());
}
}
public void sync() {
sync(getName());
}
/**
* Synchronizes the Branch with the latest information from P4. This method
* forces the Branch to contain the latest, correct information if it didn't
* already.
*
* @param name
* Name of the Branch to synchronize.
*/
public void sync(String name) {
if(!outOfSync(300000))
return;
setName(name);
String description = "";
String l;
String[] cmd = { "p4", "branch", "-o", "name" };
cmd[3] = name;
try {
P4Process p = new P4Process(getEnv());
p.exec(cmd);
while(null != (l = p.readLine())) {
if(l.startsWith("#")) {
continue;
}
if(l.startsWith("Branch:")) {
setName(l.substring(8).trim());
} else if(l.startsWith("Owner:")) {
setOwner(l.substring(7).trim());
} else if(l.startsWith("Description:")) {
while(null != (l = p.readLine())) {
if(!l.startsWith("\t"))
break;
description += l + "\n";
}
setDescription(description);
} else if(l.startsWith("View:")) {
while(null != (l = p.readLine())) {
if(!(l.startsWith("\t") || l.startsWith(" ") || l.startsWith("//")))
break;
this.addView(l);
}
}
}
p.close();
inSync();
} catch(IOException ex) {
Debug.out(Debug.ERROR, ex);
}
}
public String toXML() {
StringBuffer sb = new StringBuffer("<branch name=\"");
sb.append(getName());
sb.append("\" owner=\"");
sb.append(getOwner());
sb.append("\">");
sb.append(super.toXML());
sb.append("</branch>");
return sb.toString();
}
}