blob: b2e289ce7d40a23f4a59e0415d9a7c9e2189f47a [file] [log] [blame]
/*
* Copyright 2000-2012 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package git4idea.repo;
import git4idea.GitPlatformFacade;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* <p>
* Holds information about a remote in Git repository.
* </p>
*
* <p>
* Git remote as defined in {@code .git/config} may contain url(s) and pushUrl(s). <br/>
* If no pushUrl is given, then url is used to fetch and to push. Otherwise url is used to fetch, pushUrl is used to push.
* If there are several urls and no pushUrls, then 1 url is used to fetch (because it is not possible and makes no sense to fetch
* several urls at once), and all urls are used to push. If there are several urls and at least one pushUrl, then only pushUrl(s)
* are used to push.
* There are also some rules about url substitution, like {@code url.<base>.insteadOf}.
* </p>
* <p>
* GitRemote instance constructed by {@link GitConfig#read(GitPlatformFacade, File)}} has all these rules applied.
* Thus, for example, if only one {@code url} and no {@code pushUrls} are defined for the remote,
* both {@link #getUrls()} and {@link #getPushUrls()} will return this url. <br/>
* This is made to avoid urls transformation logic from the code using GitRemote, leaving it all in GitConfig parsing.
* </p>
* <p>
* Same applies to fetch and push specs: {@link #getPushRefSpecs()} returns the spec,
* even if there are no separate record in {@code .git/config}
* </p>
*
* <p>
* NB: Not all remote preferences (defined in {@code .git/config} are stored in the object.
* If some additional data is needed, add the field, getter, constructor parameter and populate it in {@link GitConfig}.
* </p>
*
* <p>Remotes are compared (via equals, hashcode and compareTo) only by names.</p>
*
* @author Kirill Likhodedov
*/
public final class GitRemote implements Comparable<GitRemote> {
/**
* This is a special instance of GitRemote used in typical git-svn configurations like:
* [branch "trunk"]
* remote = .
* merge = refs/remotes/git-svn
*/
public static final GitRemote DOT = new GitRemote(".", Collections.singletonList("."), Collections.<String>emptyList(),
Collections.<String>emptyList(), Collections.<String>emptyList());
/**
* Default remote name in Git is "origin".
* Usually all Git repositories have an "origin" remote, so it can be used as a default value in some cases.
*/
public static final String ORIGIN_NAME = "origin";
@NotNull private final String myName;
@NotNull private final List<String> myUrls;
@NotNull private final Collection<String> myPushUrls;
@NotNull final List<String> myFetchRefSpecs;
@NotNull private final List<String> myPushRefSpecs;
public GitRemote(@NotNull String name, @NotNull List<String> urls, @NotNull Collection<String> pushUrls,
@NotNull List<String> fetchRefSpecs, @NotNull List<String> pushRefSpecs) {
myName = name;
myUrls = urls;
myPushUrls = pushUrls;
myFetchRefSpecs = fetchRefSpecs;
myPushRefSpecs = pushRefSpecs;
}
@NotNull
public String getName() {
return myName;
}
/**
* Returns all urls specified in gitconfig in {@code remote.<name>.url}.
* If you need url to fetch, use {@link #getFirstUrl()}, because only the first url is fetched by Git,
* others are ignored.
*/
@NotNull
public List<String> getUrls() {
return myUrls;
}
/**
* @return the first url (to fetch) or null if and only if there are no urls defined for the remote.
*/
@Nullable
public String getFirstUrl() {
return myUrls.isEmpty() ? null : myUrls.get(0);
}
@NotNull
public Collection<String> getPushUrls() {
return myPushUrls;
}
@NotNull
public List<String> getFetchRefSpecs() {
return myFetchRefSpecs;
}
@NotNull
public List<String> getPushRefSpecs() {
return myPushRefSpecs;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GitRemote gitRemote = (GitRemote)o;
return myName.equals(gitRemote.myName);
// other parameters don't count: remotes are equal if their names are equal
// TODO: LOG.warn if other parameters differ
}
@Override
public int hashCode() {
return myName.hashCode();
}
@Override
public String toString() {
return String.format("GitRemote{myName='%s', myUrls=%s, myPushUrls=%s, myFetchRefSpec='%s', myPushRefSpec='%s'}",
myName, myUrls, myPushUrls, myFetchRefSpecs, myPushRefSpecs);
}
@Override
public int compareTo(@NotNull GitRemote o) {
return getName().compareTo(o.getName());
}
}