/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/**
* The HistoryGuru is used to implement an transparent layer to the various
* source control systems.
*
* @author Chandan
*/
public final class HistoryGuru {
/** The one and only instance of the HistoryGuru */
/** The history cache to use */
private final int scanningDepth;
/**
* Creates a new instance of HistoryGuru, and try to set the default
* source control system.
*/
private HistoryGuru() {
if (cfg.isHistoryCache()) {
if (cfg.isHistoryCacheInDB()) {
cache = new JDBCHistoryCache();
} else {
cache = new FileHistoryCache();
}
try {
cache.initialize();
} catch (HistoryException he) {
+ he.getMessage());
// Failed to initialize, run without a history cache
}
}
}
/**
* Get the one and only instance of the HistoryGuru
* @return the one and only HistoryGuru instance
*/
return instance;
}
/**
* Check whether a cache should be used for the history log.
* @return {@code true} if the history cache has been enabled and is ready
* for use.
*/
private boolean useCache() {
return historyCache != null;
}
/**
* Get a string with information about the history cache.
*
* @return a free form text string describing the history cache instance
* @throws HistoryException if an error occurred while getting the info
*/
}
/**
* Annotate the specified revision of a file.
*
* @param file the file to annotate
* @param rev the revision to annotate (<code>null</code> means BASE)
* @return file annotation, or <code>null</code> if the
* <code>HistoryParser</code> does not support annotation
* @throws IOException
*/
try {
} catch (HistoryException ex) {
}
// !!! cannot do this because of not matching rev ids (keys)
// first is the most recent one, so we need the position of "rev"
// until the end of the list
//if (hent.indexOf(rev)>0) {
// hent = hent.subList(hent.indexOf(rev), hent.size());
//}
//TODO this is only for mercurial, for other SCMs it might also
// be a problem, we need to revise how we shorten the rev # for
// annotate
}
}
}
}
return ret;
}
/**
* Get the appropriate history reader for the file specified by parent and
* basename.
*
* @param file The file to get the history reader for (canonical path incl.
* source root).
* @throws HistoryException If an error occurs while getting the history
* @return A HistorReader that may be used to read out history data for a
* named file
*/
@SuppressWarnings("resource")
}
/**
* Get the history for the specified file. The type of the returned history
* (directory or file) gets automatically determined: If file physically
* exists and is a directory, directory is assumed, file otherwise.
*
* @param path The file to get the history for (canonical path incl.
* source root).
* @return The history for the given path including a list of files touched
* by each changeset.
* @throws HistoryException on error when accessing the history
*/
return getHistory(path, true);
}
/**
* Get the history for the specified file. The type of the returned history
* (directory or file) gets automatically determined: If file physically
* exists and is a directory, directory is assumed, file otherwise.
*
* @param path The file to get the history for (canonical path incl.
* source root).
* @param withFiles If {@code true} the returned history will contain
* a list of files touched by each changeset (the file list may be
* skipped if {@code false}, but it doesn't have to)
* @return The history for the given path.
* @throws HistoryException on error when accessing the history
*/
throws HistoryException
{
}
/**
* Get the history for the specified path. The type of the returned history
* (directory or file) gets automatically determined: If <var>path</var>
* physically exists and is a directory, directory is assumed, file otherwise.
*
* @param path The path name to get the history for (canonical path
* incl. source root).
* @param withFiles If {@code true} the returned history will contain
* a list of files touched by each changeset (the file list may be
* skipped if {@code false}, but it doesn't have to)
* @param isDir If {@code null} it behaves like
* {@link #getHistory(File, boolean)} (auto detect history type).
* If {@code true} doesn't check the file and blindly assumes type
* directory. Otherwise a file history gets returned.
* @return the history for the given path
* @throws HistoryException on error when accessing the history
* @see #isDirectory(String)
*/
throws HistoryException
{
if (!path.isDirectory()) {
} else {
}
} else if (!isDir.booleanValue()) {
}
.isRemoteScmSupported()))
{
} else {
}
}
return history;
}
/**
* Get a named revision of the specified file.
* @param parent The directory (canonical path incl. source root) containing
* the file.
* @param basename The name of the file.
* @param rev The revision to get.
* @return An InputStream containing the named revision of the file.
* @see "Repository.getHistoryGet(String, String, String)"
*/
{
}
return ret;
}
/**
* Does this directory contain files with source control information?
* In contrast to {@link #isDirectory(String)} this usually doesn't hit the
* history DB but solely ask the repository.
*
* @param file The name of the directory (canonical path incl. source root).
* @return {@code true} if the files in this directory have associated
* revision history
*/
? false
}
/**
* Check if we can annotate the specified file. Doesn't hit the history DB
* but asks the repository.
*
* @param file the file to check (canonical path incl. source root).
* @return {@code true} if the file is under version control and the
* version control system supports annotation.
*/
if (!file.isDirectory()) {
}
}
return false;
}
/**
* Get the last modified times for all files and subdirectories excluding
* '.' and '..' in the specified directory the history cache has information
* about. The returned map is keyed by the name of the file or subdirectory
* and does neither contain a {@code null} key nor a {@code null} value.
*
* @param directory the directory whose files to check (canonical path incl.
* source root).
* @param path2rev If not {@code null}, pathes including their latest
* revisions get stored into this map.
* @return a possible empty map.
*/
{
if (!useCache()) {
return Collections.emptyMap();
}
// if source root
try {
return result;
} catch (HistoryException e) {
}
}
return Collections.emptyMap();
}
// else try repo
if (repository != null) {
try {
return result;
} catch (HistoryException e) {
}
}
}
return Collections.emptyMap();
}
{
}
/**
* recursivelly search for repositories with a depth limit
* @param files list of files to check if they contain a repo
* @param repos list of found repos
* @param ignoredNames what files to ignore
* @param recursiveSearch whether to use recursive search
* @param depth current depth - using global scanningDepth - one can limit
* this to improve scanning performance
*/
try {
} catch (InstantiationException ie) {
+ file + "', could not instantiate the repository: "
+ ie.getMessage());
} catch (IllegalAccessException iae) {
}
if (repository == null) {
// Not a repository, search it's sub-dirs
+ file.getAbsolutePath()
+ "', check access permissions.");
} else if (depth<=scanningDepth) {
}
}
} else {
try {
}
// @TODO: Search only for one type of repository - the one found here
+ file.getAbsolutePath()
+ "', check access permissions.");
} else if (depth<=scanningDepth) {
// Search only one level down - if not: too much
// stat'ing for huge Mercurial repositories
false, depth+1);
}
}
} catch (IOException exp) {
+ file.getAbsolutePath()
}
}
}
}
/**
* Search through the all of the directories and add all of the source
* repositories found.
*
* @param dir the root directory to start the search in.
*/
}
/**
* Update the source the contents in the source repositories.
*/
public void updateRepositories() {
if (repository.isWorking()) {
if (verbose) {
}
try {
repository.update();
} catch (UnsupportedOperationException e) {
} catch (Exception e) {
}
} else {
+ path + "': Missing SCM dependencies?");
}
}
}
/**
* Update the source the contents in the source repositories.
* @param paths A list of files/directories to update
*/
if (repository.isWorking()) {
if (verbose) {
}
try {
repository.update();
} catch (UnsupportedOperationException e) {
+ "': Not implemented");
} catch (Exception e) {
+ e.getMessage());
}
} else {
}
}
}
if (!useCache()) {
return;
}
if (repository.isWorking()) {
if (verbose) {
}
try {
} catch (Exception e) {
}
if (verbose) {
}
} else {
}
}
/**
* Create the history cache for the given repositories, if caching is
* enabled and the repository in question supports history for directories.
* @param allRepos repositories in question. If {@code null} all registered
* repos are used instead.
*/
if (!useCache()) {
return;
}
? this.repositories.values()
+ "history.NumCacheThreads");
try {
} catch (Throwable t) {
+ t.getMessage());
}
}
try {
} catch (HistoryException he) {
continue;
}
@SuppressWarnings("synthetic-access")
public void run() {
}
});
}
while (!executor.isTerminated()) {
try {
// Wait forever
} catch (InterruptedException exp) {
+ exp.getMessage());
}
}
// The cache has been populated. Now, optimize how it is stored on
// disk to enhance performance and save space.
try {
} catch (HistoryException he) {
+ he.getMessage());
}
}
/**
* Remove the history cache for the given repositories.
* @param repositories repositories in question.
* @throws HistoryException
*/
cache = new JDBCHistoryCache();
cache.initialize();
} else {
cache = new FileHistoryCache();
}
}
for (Repository r : repos) {
try {
} catch (HistoryException e) {
}
}
}
/**
* Create the history cache for all of the repositories.
*/
public void createCache() {
}
Repository r = getRepository(f);
if (r == null) {
+ f.getAbsolutePath() + "'");
}
}
return repos;
}
/**
* Check, whether the given path denotes a directory in the history cache.
* This really hits the DB, so caching is advised.
*
* @param path The <em>canonical</em> path to the file in question,
* e.g. sourceRoot + '/' + projectdir + '/' + subdir with '/'
* path separators, only! One trailing slash gets automatically removed
* if it exists.
* @return {@code null} if an error occured, {@code Boolean#TRUE} if there
* is a directory with the given name in the history cache,
* {@link Boolean#FALSE} otherwise.
*/
return null;
}
try {
} catch (HistoryException e) {
return null;
}
}
/**
* Ensure that we have a directory in the cache. If it's not there, fetch
* its history and populate the cache. If it's already there, and the
* cache is able to tell how recent it is, attempt to update it to the
* most recent revision.
*
* @param file the root path to test (canonical path incl. source root).
* @throws HistoryException if an error occurs while accessing the
* history cache
*/
if (!useCache()) {
return;
}
if (repository == null) {
// no repository -> no history :(
return;
}
if (sinceRevision == null) {
// Cache already exists, but we don't know how recent it is,
// so don't do anything.
return;
}
}
// Create cache from the beginning if it doesn't exist, or update it
// incrementally otherwise.
}
/**
* Get the with this instance registered repository for the given file.
* @param path canonical path incl. source root to the source file in
* question.
* @return {@code null} if unknown, the related repository otherwise.
*/
try {
} catch (IOException e) {
+ e.getLocalizedMessage());
return null;
}
if (r != null) {
return r;
}
}
return null;
}
/**
* Invalidate the current list of known repositories!
*
* @param repos The new repositories
*/
{
} else {
for (RepositoryInfo i : repos) {
try {
if (r == null) {
} else {
}
} catch (InstantiationException ex) {
+ " for '" + i.getDirectoryName()
+ "', could not instantiate the repository: "
+ ex.getMessage());
} catch (IllegalAccessException iae) {
+ " for '" + i.getDirectoryName()
}
}
repositories = nrep;
}
}
}