RE: CVSRoot
"Ojares Rami EINT" <[email protected]> Mon, 15 Sep 2003 14:36:48 +0300
| Newsgroups | gmane.comp.java.netbeans.modules.javacvs.devel |
|---|---|
| Message-ID | <[email protected]> |
Here is a new version of CVSRoot.
Most of it was changed and there are long
comments so it should be read from top to bottom.
It tries to address the issues talked but by no
means are all the questions answered.
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) {
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;
}
}
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 int 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;
}
}