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 directory.
*
* @author <a href="mailto:david@markley.cc">David Markley</a>
* @version $Date: 2001/11/05 $ $Revision: #1 $
*/
public final class DirEntry extends SourceControlObject {
private String path;
private DirEntry parent;
private boolean opened = false;
private Vector subdirs = null;
private Vector files = null;
private static HashDecay dirs = null;
/** Default, no-argument constructor. */
public DirEntry() {
super();
subdirs = new Vector();
files = new Vector();
setCache();
}
/**
* Constructs a directory entry.
*
* @param e
* Source control environment to use.
*/
public DirEntry(Env e) {
this();
setEnv(e);
}
/**
* Constructs a directory entry.
*
* @param e
* Source control environment to use.
* @param path
* The path for this directory.
*/
public DirEntry(Env e, String path) {
this(e);
setPath(path);
}
/**
* Constructs a directory entry.
*
* @param base
* Another <code>DirEntry</code> used to set the environment.
* @param path
* The path for this directory.
*/
public DirEntry(DirEntry base, String path) {
this();
setEnv(base.getEnv());
setPath(path);
}
/**
* Loads the directories and files for this directory.
*/
public void sync() {
try {
loadDirs(getEnv());
loadFiles(getEnv(), path);
inSync();
} catch(Exception ex) {
}
}
/**
* Does nothing. Doesn't do anything here, since directories are not really
* stored in perforce.
*/
public void commit() {
}
private static HashDecay setCache() {
if(null == dirs) {
dirs = new HashDecay(120000);
dirs.start();
}
return dirs;
}
public HashDecay getCache() {
return setCache();
}
/**
* Returns a directory entry for the supplied path.
*
* @param env
* Source control environment to use.
* @param path
* The path for this directory.
* @param sync
* Forces the directory information to be current.
*/
public static DirEntry getDirEntry(Env env, String path, boolean sync) {
DirEntry de;
if(null == path || path.trim().equals(""))
return null;
if(null == (de = (DirEntry) setCache().get(path))) {
de = new DirEntry(env, path);
}
if(null != env)
de.setEnv(env);
if(sync)
de.sync();
dirs.put(path, de);
return de;
}
/**
* Sets the path for this directory.
*
* @param path
* New path for this directory.
*/
public void setPath(String path) {
if(null == path)
return;
path = path.trim();
if(path.equals("") || !path.startsWith("//"))
return;
// TODO: Add checks for wildcards here!!!
/*
* if (null != alldirs) { synchronized (alldirs) { if (this ==
* (DirEntry)(alldirs.get(this.path))) { alldirs.remove(this.path); }
* alldirs.put(path, this); } }
*/
this.path = path;
}
/**
* Returns the path for this directory.
*/
public String getPath() {
return this.path;
}
/**
* Returns the base path for this directory. This includes everything up to
* the last path delimeter.
*/
public String getBasePath() {
int pos = path.lastIndexOf('/');
if(-1 == pos) {
return "//";
}
return path.substring(0, pos + 1);
}
/**
* Returns the parent director. Constructs a new <code>DirEntry</code>
* that represents the parent and returns it.
*/
public DirEntry getParent() {
DirEntry parent = null;
int pos;
if(-1 == (pos = path.lastIndexOf('/')))
return null;
String parent_path = path.substring(0, pos);
if(parent_path.equals("/"))
return null;
/*
* if (null != alldirs) { synchronized (alldirs) { parent =
* (DirEntry)alldirs.get(parent_path); } }
*/
if(null == parent) {
parent = new DirEntry(this, parent_path);
}
return parent;
}
/**
* Returns an array of directory names.
*/
public String[] getDirNames() {
return getDirNames(getEnv());
}
/**
* Returns an array of directory names.
*
* @param env
* Source control environment to use.
*/
public String[] getDirNames(Env env) {
String[] names;
loadDirs(env);
synchronized(subdirs) {
names = v2a(subdirs);
}
return names;
}
/**
* Loads the directories, using the default environment.
*/
private void loadDirs() {
loadDirs(getEnv());
}
/**
* Loads the directories, using the specified environment.
*
* @param env
* Source control environment to use.
*/
private void loadDirs(Env env) {
if(!outOfSync(60000))
return;
String[] cmd = { "p4", "dirs", path + "%1" };
String l, dir;
int pos;
synchronized(subdirs) {
subdirs.removeAllElements();
}
try {
P4Process p = new P4Process(env);
p.exec(cmd);
while(null != (l = p.readLine())) {
if((!l.startsWith("//")) || (-1 != l.indexOf(" - "))) {
continue;
}
dir = l.trim();
if(-1 != (pos = dir.lastIndexOf('/'))) {
dir = dir.substring(pos + 1).trim();
}
synchronized(subdirs) {
subdirs.addElement(dir);
}
}
p.close();
} catch(IOException ex) {
Debug.out(Debug.ERROR, ex);
}
}
/**
* Converts a <code>Vector</code> to a <code>String</code>. This shows
* how old this code is. <code>Vector</code> didn't always do this for us.
*/
private String[] v2a(Vector v) {
String[] tmp = new String[v.size()];
for(int i = 0; i < v.size(); i++) {
tmp[i] = (String) v.elementAt(i);
}
return tmp;
}
/**
* Returns an array of file entries for this directory.
*/
public FileEntry[] getFiles() {
return getFiles(getEnv());
}
/**
* Returns an array of file entries for this directory.
*
* @param env
* Source control environment to use.
*/
public FileEntry[] getFiles(Env env) {
loadFiles(env, path);
if(null == files)
return null;
FileEntry[] tmp;
synchronized(files) {
tmp = new FileEntry[files.size()];
for(int i = 0; i < files.size(); i++) {
tmp[i] = (FileEntry) files.elementAt(i);
tmp[i].setEnv(env);
}
}
return tmp;
}
/**
* Returns an array of file names for this directory.
*/
public String[] getFileNames() {
return getFileNames(getEnv());
}
/**
* Returns an array of file names for this directory.
*
* @param env
* Source control environment to use.
*/
public String[] getFileNames(Env env) {
String[] names;
loadFiles(env, path);
if(null == files) {
names = new String[1];
names[0] = "";
return names;
}
synchronized(files) {
names = new String[files.size()];
for(int i = 0; i < files.size(); i++) {
names[i] = ((FileEntry) files.elementAt(i)).getName();
}
}
return names;
}
/**
* Loads the files in this directory.
*/
private void loadFiles() {
loadFiles(getEnv(), path);
}
/**
* Loads the files in this directory.
*
* @param env
* Source control environment to use.
* @param path
* Directory path to use, instead of this one.
*/
private void loadFiles(Env env, String path) {
if(!outOfSync(60000))
return;
files = FileEntry.getFiles(env, path);
}
public String toXML() {
StringBuffer sb = new StringBuffer("<dir path=\"");
sb.append(getPath());
sb.append("\"/>");
return sb.toString();
}
}