/*
* 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 (env.useHistoryCache()) {
if (env.storeHistoryCacheInDB()) {
cache = new JDBCHistoryCache();
} else {
cache = new FileHistoryCache();
}
try {
cache.initialize();
} catch (HistoryException he) {
"Failed to initialize the history cache", he);
// 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;
}
/**
* Return whether or not a cache should be used for the history log.
* @return {@code true} if the history cache has been enabled and
* initialized, {@code false} otherwise
*/
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 get messages for tooltip: ", 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
* @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
*/
}
/**
* Get the history for the specified file.
*
* @param file the file to get the history for
* @return history for the file
* @throws HistoryException on error when accessing the history
*/
return getHistory(file, true);
}
/**
* Get the history for the specified file.
*
* @param file the file to get the history for
* @param withFiles whether or not the returned history should contain
* a list of files touched by each changeset (the file list may be skipped
* if false, but it doesn't have to)
* @return history for the file
* @throws HistoryException on error when accessing the history
*/
throws HistoryException {
.isRemoteScmSupported()))
{
} else {
}
}
return history;
}
/**
* Get a named revision of the specified file.
* @param parent The directory 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.
*/
{
}
return ret;
}
/**
* Does this directory contain files with source control information?
* @param file The name of the directory
* @return true if the files in this directory have associated revision
* history
*/
? false
}
/**
* Check if we can annotate the specified file.
*
* @param file the file to check
* @return <code>true</code> 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 in the
* specified directory.
*
* @param directory the directory whose files to check
* @return a map from file names to modification times for the files that
* the history cache has information about
*/
throws HistoryException {
}
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) {
} catch (IllegalAccessException iae) {
}
if (repository == null) {
// Not a repository, search it's sub-dirs
"Failed to get sub directories for '"
+ file.getAbsolutePath()
+ "', check access permissions.");
} else if (depth<=scanningDepth) {
}
}
} else {
try {
}
// @TODO: Search only for one type of repository - the one found here
"Failed to get sub directories for '"
+ 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) {
}
}
}
}
/**
* 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 {
}
}
}
/**
* 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) {
+ " in %s: Not implemented", type,
} catch (Exception e) {
}
} else {
+ " %s: Missing SCM dependencies?", type,
}
}
}
if (!useCache()) {
return;
}
if (repository.isWorking()) {
if (verbose) {
}
try {
} catch (Exception e) {
+ type + ")", e);
}
if (verbose) {
}
} else {
}
}
try {
} catch (Throwable t) {
}
}
try {
} catch (HistoryException he) {
"Failed to retrieve latest cached revision for %s",
continue;
}
public void run() {
}
});
}
while (!executor.isTerminated()) {
try {
// Wait forever
} catch (InterruptedException exp) {
"Received interrupt while waiting for executor to finish", exp);
}
}
// The cache has been populated. Now, optimize how it is stored on
// disk to enhance performance and save space.
try {
} catch (HistoryException he) {
"Failed optimizing the history cache database", he);
}
}
if (!useCache()) {
return;
}
}
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() {
if (!useCache()) {
return;
}
}
Repository r = getRepository(f);
if (r == null) {
f.getAbsolutePath());
}
}
return repos;
}
/**
* 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
* @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.
}
try {
} catch (IOException e) {
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) {
"Failed to instanciate internal repository data for "
} else {
}
} catch (InstantiationException ex) {
+ " for '" + i.getDirectoryName()
+ "', could not instantiate the repository.", ex);
} catch (IllegalAccessException iae) {
+ " for '" + i.getDirectoryName()
+ "', missing access rights.", iae);
}
}
repositories = nrep;
}
}
}