RE: CVSRoot
"Ojares Rami EINT" <[email protected]> Mon, 15 Sep 2003 14:39:51 +0300
| Newsgroups | gmane.comp.java.netbeans.modules.javacvs.devel |
|---|---|
| Message-ID | <[email protected]> |
Here is CVSRoot again but this time it compiles
import java.io.*;
import java.util.*;
import java.util.regex.*;
public class CVSRoot {
/*
Martin Entlicher has found somewhere in cvshome.org the syntax of cvsroot
[:method:][[user][:password]@]hostname[:[port]]/path/to/repository
This would allow urls like
cvs.acme.comC:\@progs\cvs\repository
This is supposed to represent hostname and repository. Obviously this is not easy/possible to parse correctly
Also hostname is in practice optional for local urls that many times have only the repository component.
So I have broken down this to two different syntax alternatives
*/
/*
LOCAL_FORMAT
[[:method:][[user][:password]@]]/path/to/repository
There are still complications Eg.
:local:c:\@progs\cvs
would be interpreted as
method = local
user = c
password = \
repository = progs\cvs
So the recommendation is not to use @ sign in repository (not many do but it is legal and when it happens it can cause a long debugging session for some poor user)
*/
private static final int LOCAL_FORMAT = 0;
/*
SERVER_FORMAT
:method:[user][:password]@hostname:[port]/path/to/repository
This is more robust and as far as I know does not have any possibility for error
Note: because method is obligatory it means that when method is missing it is interpreted as LOCAL_FORMAT
*/
private static final int SERVER_FORMAT = 1;
// cvsroot as string
String cvsroot;
// connectionType is always represented in lowercase
String connectionType;
// url format (default 0)
int urlFormat;
// user (default = null)
String username;
// password (default = null)
String password;
// host (default = null)
String host;
// port (default = 0)
int port;
// repository as string representation
String repository;
/**
This constructor allows to construct CVSRoot from Properties object.
The names are exactly the same as the attribute names in this class
*/
public CVSRoot(Properties props) throws IllegalArgumentException {
String ct = props.getProperty("connectionType");
if (ct == null || ct.length() == 0)
this.connectionType = "local";
else
connectionType = ct.toLowerCase();
if (connectionType.equals("local") || connectionType.equals("fork"))
this.urlFormat = LOCAL_FORMAT;
else
this.urlFormat = SERVER_FORMAT;
// user & password (they are always optional)
this.username = props.getProperty("username");
this.password = props.getProperty("password");
if (this.urlFormat == SERVER_FORMAT) {
// host & port
this.host = props.getProperty("host");
if (this.host == null || this.host.length() == 0)
throw new IllegalArgumentException("host is obligatory in non local connections.");
try {
int p = Integer.parseInt(props.getProperty("port"));
if (p > 0)
this.port = p;
}
catch (Exception e) {
// never mind
}
}
// and the most important which is repository
String r = props.getProperty("repository");
if (r == null)
throw new IllegalArgumentException("Repository is obligatory.");
else
this.repository = r;
// construct string representation of cvsroot (ignore user & password in local format)
if (this.urlFormat == LOCAL_FORMAT) {
this.cvsroot = ":" + this.connectionType + ":" + repository;
}
if (this.urlFormat == SERVER_FORMAT) {
// connection type
String str = ":" + this.connectionType + ":";
// don't put password in cvsroot
if (this.username != null)
str += this.username;
// host
str += "@" + this.host + ":";
// port
if (this.port > 0)
str += "" + this.port;
// repository
str += this.repository;
this.cvsroot = str;
}
}
/**
Is cvsroot case sensitive or not ??? If not then this constructor needs modification.
There can be some problems parsing local cvsroot eg.
:local:c:\@progs\cvs
This would be parsed currently
user = c
password = \
repository progs\cvs
*/
public CVSRoot(String cvsroot) throws IllegalArgumentException {
// keep the cvsroot as it is given (no normalization)
this.cvsroot = cvsroot;
if (cvsroot.startsWith(":")) {
// connection method is given so parse it
int conEndColon = cvsroot.indexOf(":", 1);
this.connectionType = cvsroot.substring(1, conEndColon);
// Figure out url syntax
if (this.connectionType.equals("local") ||
this.connectionType.equals("fork"))
this.urlFormat = LOCAL_FORMAT;
else
this.urlFormat = SERVER_FORMAT;
if (this.urlFormat == LOCAL_FORMAT) {
// upEnd = end position of user and password combination
// here is the possibility of error when repository contains @
int upEnd = cvsroot.indexOf("@", conEndColon+1);
if (upEnd != -1) {
String up = cvsroot.substring(conEndColon+1, upEnd);
int upDivider = up.indexOf(":");
if (upDivider != -1) {
this.username = up.substring(0, upDivider);
this.password = up.substring(upDivider+1);
}
else {
this.username = up;
}
// everything after @ is repository
this.repository = cvsroot.substring(upEnd+1);
}
else {
// everything after method is repository
this.repository = cvsroot.substring(conEndColon+1);
}
}
else {
// So now we parse SERVER_FORMAT
// :method:[user][:password]@hostname:[port]/path/to/repository
int at = cvsroot.indexOf("@", conEndColon+1);
if (at == -1)
throw new IllegalArgumentException("@ sign was not found in cvsroot even though connection type was " + this.connectionType);
// up = username + password
String up = cvsroot.substring(conEndColon+1, at);
if (up.length() > 0) {
int upDivider = up.indexOf(":");
if (upDivider != -1) {
this.username = up.substring(0, upDivider);
this.password = up.substring(upDivider+1);
}
else {
this.username = up;
}
}
// host
int hostEndColon = cvsroot.indexOf(":", at+1);
if (hostEndColon == -1)
throw new IllegalArgumentException("You must end hostname with : sign");
this.host = cvsroot.substring(at+1, hostEndColon);
// pr = port + repository
String pr = cvsroot.substring(hostEndColon+1);
Matcher matcher = Pattern.compile("\\d+").matcher(pr);
if (matcher.lookingAt()) {
try {
this.port = Integer.parseInt(matcher.group());
} catch(NumberFormatException e) {}
this.repository = pr.substring(matcher.end());
}
else {
this.repository = pr;
}
}
}
else {
// method was not given so cvsroot == repository
this.connectionType = "local";
this.repository = cvsroot;
}
}
public String toString() {
return this.cvsroot;
}
/*
All CVSRoots that have the LOCAL_FORMAT are considered the same if they have the same repository.
All CVSRoots that have the SERVER_FORMAT are considered the same if
- host is the same
- repository is the same
This means that
:pserver:[email protected]:/data/cvs is the same as
:ext:[email protected]:/data/cvs
Because they both point to the same cvs repository
This interpretation implies that the connection method is only a means to get to a repository and equality is only concerned with the actual location of the repository
QUESTION:
If I use cvsroot :fork:C:\cvs and the Administrative files have Root
C:\cvs does this create problems for javacvs?
*/
public boolean equals(Object o) {
CVSRoot compared;
try {
compared = (CVSRoot) o;
}
catch(ClassCastException cce) {
return false;
}
// connection comparison
if (this.urlFormat == compared.urlFormat) {
try {
if (this.urlFormat == LOCAL_FORMAT) {
if (
(new File(this.repository)).getCanonicalFile().equals(
new File(compared.repository).getCanonicalFile()
)
)
return true;
else
return false;
}
else {
// host is compared case insensitively
if (
this.host.equalsIgnoreCase(compared.host)
&&
this.port == compared.port
&&
(new File(this.repository)).getCanonicalFile().equals(
new File(compared.repository).getCanonicalFile()
)
)
return true;
else
return false;
}
}
catch (IOException ioe) {
// something went wrong when invoking getCanonicalFile() so return false
return false;
}
}
else
return false;
}
public int hashCode() {
if (this.urlFormat == LOCAL_FORMAT)
return this.repository.hashCode();
else
return this.host.hashCode() + this.repository.hashCode();
}
// at the moment no setters, because they have effect on cvsroot
// need to think whether this should be modified in code after creation.
public String getCvsroot() {
return cvsroot;
}
public String getConnectionType() {
return connectionType;
}
public int getUrlFormat() {
return urlFormat;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getRepository() {
return repository;
}
}