forked from qt-creator/qt-creator
ClearCase: Fix checking if a directory is managed
Now both dynamic and snapshot views are supported under both Unix/Linux and Windows. The implementation is based on "cleartool pwv" which gets the working view. Change-Id: I0d21d2c84fae4a641a3bac8b1087cfeffb89c447 Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Knut Petter Svendsen <knutpett@pvv.org>
This commit is contained in:
committed by
Eike Ziller
parent
bedc477943
commit
c222a4f623
@@ -118,7 +118,6 @@ static const char CMD_ID_UPDATEINDEX[] = "ClearCase.UpdateIndex";
|
|||||||
static const char CMD_ID_UPDATE_VIEW[] = "ClearCase.UpdateView";
|
static const char CMD_ID_UPDATE_VIEW[] = "ClearCase.UpdateView";
|
||||||
static const char CMD_ID_CHECKIN_ALL[] = "ClearCase.CheckInAll";
|
static const char CMD_ID_CHECKIN_ALL[] = "ClearCase.CheckInAll";
|
||||||
static const char CMD_ID_STATUS[] = "ClearCase.Status";
|
static const char CMD_ID_STATUS[] = "ClearCase.Status";
|
||||||
static const char *CLEARCASE_ROOT_FILES[] = { "view.dat", ".view.dat" };
|
|
||||||
|
|
||||||
static const VcsBase::VcsBaseEditorParameters editorParameters[] = {
|
static const VcsBase::VcsBaseEditorParameters editorParameters[] = {
|
||||||
{
|
{
|
||||||
@@ -219,58 +218,141 @@ bool ClearCasePlugin::isCheckInEditorOpen() const
|
|||||||
return !m_checkInMessageFileName.isEmpty();
|
return !m_checkInMessageFileName.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString ccFindRepositoryForDirectory(const QString &dirS)
|
/// Files in this directories are under ClearCase control
|
||||||
|
QStringList ClearCasePlugin::getVobList() const
|
||||||
{
|
{
|
||||||
const QString home = QDir::homePath();
|
QStringList args(QLatin1String("lsvob"));
|
||||||
|
args << QLatin1String("-s");
|
||||||
|
const ClearCaseResponse response =
|
||||||
|
runCleartool(currentState().topLevel(), args, m_settings.timeOutMS(), SilentRun);
|
||||||
|
|
||||||
QDir directory(dirS);
|
return response.stdOut.split(QLatin1Char('\n'), QString::SkipEmptyParts);
|
||||||
do {
|
}
|
||||||
const QString absDirPath = directory.absolutePath();
|
|
||||||
if (directory.isRoot() || absDirPath == home)
|
/// Get the drive letter of a path
|
||||||
break;
|
/// Necessary since QDir(directory).rootPath() returns C:/ in all cases
|
||||||
|
QString ClearCasePlugin::getDriveLetterOfPath(const QString &directory)
|
||||||
|
{
|
||||||
|
// cdUp until we get just the drive letter
|
||||||
|
QDir dir(directory);
|
||||||
|
while (dir.cdUp())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
return dir.path();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Check if the directory is managed by ClearCase.
|
||||||
|
///
|
||||||
|
/// There are 6 cases to consider for accessing ClearCase views:
|
||||||
|
///
|
||||||
|
/// 1) Windows: dynamic view under M:\<view_tag> (working dir view)
|
||||||
|
/// 2) Windows: dynamic view under Z:\ (similar to unix "set view" by using "subst" or "net use")
|
||||||
|
/// 3) Windows: snapshot view
|
||||||
|
/// 4) Unix: dynamic view under /view/<view_tag> (working dir view)
|
||||||
|
/// 5) Unix: dynamic view which are set view (transparent access in a shell process)
|
||||||
|
/// 6) Unix: snapshot view
|
||||||
|
///
|
||||||
|
/// Note: the drive letters M: and Z: can be chosen by the user. /view is the "view-root"
|
||||||
|
/// directory and is not configurable, while VOB names and mount points are configurable
|
||||||
|
/// by the ClearCase admin.
|
||||||
|
///
|
||||||
|
/// Note: All cases except #5 have a root directory, i.e., all files reside under a directory.
|
||||||
|
/// For #5 files are "mounted" and access is transparent (e.g., under /vobs).
|
||||||
|
///
|
||||||
|
/// For a view named "myview" and a VOB named "vobA" topLevels would be:
|
||||||
|
/// 1) M:/myview/vobA
|
||||||
|
/// 2) Z:/vobA
|
||||||
|
/// 3) c:/snapshots/myview/vobA
|
||||||
|
/// 4) /view/myview/vobs/vobA
|
||||||
|
/// 5) /vobs/vobA/
|
||||||
|
/// 6) /home/<username>/snapshots/myview/vobs/vobA
|
||||||
|
///
|
||||||
|
/// Note: The VOB directory is used as toplevel although the directory one up could have been
|
||||||
|
/// used on cases execpt 5. For case 5 it would have been /, which we don't want.
|
||||||
|
///
|
||||||
|
/// "cleartool pwv" returns the values for "set view" and "working directory view", also for
|
||||||
|
/// snapshot views.
|
||||||
|
///
|
||||||
|
/// \returns The ClearCase topLevel/VOB directory for this directory
|
||||||
|
QString ClearCasePlugin::ccManagesDirectory(const QString &directory) const
|
||||||
|
{
|
||||||
|
QStringList args(QLatin1String("pwv"));
|
||||||
|
const ClearCaseResponse response =
|
||||||
|
runCleartool(directory, args, m_settings.timeOutMS(), SilentRun);
|
||||||
|
|
||||||
|
if (response.error)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
const QStringList result = response.stdOut.split(QLatin1Char('\n'), QString::SkipEmptyParts);
|
||||||
|
if (result.size() != 2)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
const QByteArray workingDirPattern("Working directory view: ");
|
||||||
|
if (!result[0].startsWith(QLatin1String(workingDirPattern)))
|
||||||
|
return QString();
|
||||||
|
const QString workingDirectoryView = result[0].mid(workingDirPattern.size());
|
||||||
|
|
||||||
|
const QByteArray setViewDirPattern("Set view: ");
|
||||||
|
if (!result[1].startsWith(QLatin1String(setViewDirPattern)))
|
||||||
|
return QString();
|
||||||
|
const QString setView = result[1].mid(setViewDirPattern.size());
|
||||||
|
|
||||||
|
const QString none(QLatin1String("** NONE **"));
|
||||||
|
QString rootDir;
|
||||||
|
if (setView != none || workingDirectoryView != none)
|
||||||
|
rootDir = ccViewRoot(directory);
|
||||||
|
else
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
// Check if the directory is inside one of the known VOBs.
|
||||||
|
static QStringList vobs;
|
||||||
|
if (vobs.empty())
|
||||||
|
vobs = getVobList();
|
||||||
|
|
||||||
|
foreach (const QString &relativeVobDir, vobs) {
|
||||||
|
const QString vobPath = QDir::cleanPath(rootDir + QDir::fromNativeSeparators(relativeVobDir));
|
||||||
|
const bool isManaged = Utils::FileName::fromString(directory).isChildOf(Utils::FileName::fromString(vobPath));
|
||||||
|
if (isManaged)
|
||||||
|
return vobPath;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint i = 0; i < sizeof(CLEARCASE_ROOT_FILES) / sizeof(*CLEARCASE_ROOT_FILES); ++i)
|
|
||||||
if (QFileInfo(directory, QLatin1String(CLEARCASE_ROOT_FILES[i])).isFile())
|
|
||||||
return absDirPath;
|
|
||||||
} while (directory.cdUp());
|
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find the root path of a clearcase view. Precondition: This is a clearcase managed dir
|
||||||
|
QString ClearCasePlugin::ccViewRoot(const QString &directory) const
|
||||||
|
{
|
||||||
|
QStringList args(QLatin1String("pwv"));
|
||||||
|
args << QLatin1String("-root");
|
||||||
|
const ClearCaseResponse response =
|
||||||
|
runCleartool(directory, args, m_settings.timeOutMS(), SilentRun);
|
||||||
|
|
||||||
|
QString root = response.stdOut.trimmed();
|
||||||
|
|
||||||
|
if (root.isEmpty()) {
|
||||||
|
if (Utils::HostOsInfo::isWindowsHost())
|
||||||
|
root = getDriveLetterOfPath(directory);
|
||||||
|
else
|
||||||
|
root = QLatin1String("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
return QDir::fromNativeSeparators(root);
|
||||||
|
}
|
||||||
|
|
||||||
/*! Find top level for view that contains \a directory
|
/*! Find top level for view that contains \a directory
|
||||||
*
|
*
|
||||||
* - Snapshot view has one of CLEARCASE_ROOT_FILES (view.dat or .view.dat) in its top dir
|
* Handles both dynamic views and snapshot views.
|
||||||
* - Dynamic view can either be
|
|
||||||
* - M:/view_name,
|
|
||||||
* - or mapped to a drive letter, like Z:/
|
|
||||||
* (drive letters are just examples)
|
|
||||||
*/
|
*/
|
||||||
QString ClearCasePlugin::findTopLevel(const QString &directory) const
|
QString ClearCasePlugin::findTopLevel(const QString &directory) const
|
||||||
{
|
{
|
||||||
|
// Do not check again if we've already tested that the dir is managed,
|
||||||
|
// or if it is a child of a managed dir (top level).
|
||||||
if ((directory == m_topLevel) ||
|
if ((directory == m_topLevel) ||
|
||||||
Utils::FileName::fromString(directory).isChildOf(Utils::FileName::fromString(m_topLevel)))
|
Utils::FileName::fromString(directory).isChildOf(Utils::FileName::fromString(m_topLevel)))
|
||||||
return m_topLevel;
|
return m_topLevel;
|
||||||
|
|
||||||
// Snapshot view
|
return ccManagesDirectory(directory);
|
||||||
QString topLevel =
|
|
||||||
ccFindRepositoryForDirectory(directory);
|
|
||||||
if (!topLevel.isEmpty() || !clearCaseControl()->isConfigured())
|
|
||||||
return topLevel;
|
|
||||||
|
|
||||||
// Dynamic view
|
|
||||||
if (ccGetView(directory).isDynamic) {
|
|
||||||
QDir dir(directory);
|
|
||||||
// Go up to one level before root
|
|
||||||
QDir outer = dir;
|
|
||||||
outer.cdUp();
|
|
||||||
while (outer.cdUp())
|
|
||||||
dir.cdUp();
|
|
||||||
topLevel = dir.path(); // M:/View_Name
|
|
||||||
dir.cdUp(); // Z:/ (dynamic view with assigned letter)
|
|
||||||
if (!ccGetView(dir.path()).name.isEmpty())
|
|
||||||
topLevel = dir.path();
|
|
||||||
}
|
|
||||||
|
|
||||||
return topLevel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VcsBase::VcsBaseSubmitEditorParameters submitParameters = {
|
static const VcsBase::VcsBaseSubmitEditorParameters submitParameters = {
|
||||||
@@ -555,14 +637,15 @@ QString ClearCasePlugin::ccGetPredecessor(const QString &version) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Get a list of paths to active VOBs.
|
//! Get a list of paths to active VOBs.
|
||||||
//! Paths are relative to topLevel
|
//! Paths are relative to viewRoot
|
||||||
QStringList ClearCasePlugin::ccGetActiveVobs() const
|
QStringList ClearCasePlugin::ccGetActiveVobs() const
|
||||||
{
|
{
|
||||||
QStringList res;
|
QStringList res;
|
||||||
QStringList args(QLatin1String("lsvob"));
|
QStringList args(QLatin1String("lsvob"));
|
||||||
const QString topLevel = currentState().topLevel();
|
const QString theViewRoot = viewRoot();
|
||||||
|
|
||||||
const ClearCaseResponse response =
|
const ClearCaseResponse response =
|
||||||
runCleartool(topLevel, args, m_settings.timeOutMS(), SilentRun);
|
runCleartool(theViewRoot, args, m_settings.timeOutMS(), SilentRun);
|
||||||
if (response.error)
|
if (response.error)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
@@ -570,10 +653,11 @@ QStringList ClearCasePlugin::ccGetActiveVobs() const
|
|||||||
// * /path/to/vob /path/to/vob/storage.vbs <and some text omitted here>
|
// * /path/to/vob /path/to/vob/storage.vbs <and some text omitted here>
|
||||||
// format of output windows:
|
// format of output windows:
|
||||||
// * \vob \\share\path\to\vob\storage.vbs <and some text omitted here>
|
// * \vob \\share\path\to\vob\storage.vbs <and some text omitted here>
|
||||||
QString prefix = topLevel;
|
QString prefix = theViewRoot;
|
||||||
if (!prefix.endsWith(QLatin1Char('/')))
|
if (!prefix.endsWith(QLatin1Char('/')))
|
||||||
prefix += QLatin1Char('/');
|
prefix += QLatin1Char('/');
|
||||||
|
|
||||||
|
const QDir theViewRootDir(theViewRoot);
|
||||||
foreach (const QString &line, response.stdOut.split(QLatin1Char('\n'), QString::SkipEmptyParts)) {
|
foreach (const QString &line, response.stdOut.split(QLatin1Char('\n'), QString::SkipEmptyParts)) {
|
||||||
const bool isActive = line.at(0) == QLatin1Char('*');
|
const bool isActive = line.at(0) == QLatin1Char('*');
|
||||||
if (!isActive)
|
if (!isActive)
|
||||||
@@ -581,7 +665,7 @@ QStringList ClearCasePlugin::ccGetActiveVobs() const
|
|||||||
|
|
||||||
const QString dir =
|
const QString dir =
|
||||||
QDir::fromNativeSeparators(line.mid(3, line.indexOf(QLatin1Char(' '), 3) - 3));
|
QDir::fromNativeSeparators(line.mid(3, line.indexOf(QLatin1Char(' '), 3) - 3));
|
||||||
const QString relativeDir = QDir(topLevel).relativeFilePath(dir);
|
const QString relativeDir = theViewRootDir.relativeFilePath(dir);
|
||||||
|
|
||||||
// Snapshot views does not necessarily have all active VOBs loaded, so we'll have to
|
// Snapshot views does not necessarily have all active VOBs loaded, so we'll have to
|
||||||
// check if the dirs exists as well. Else the command will work, but the output will
|
// check if the dirs exists as well. Else the command will work, but the output will
|
||||||
@@ -628,11 +712,11 @@ void ClearCasePlugin::updateStatusActions()
|
|||||||
FileStatus fileStatus = FileStatus::Unknown;
|
FileStatus fileStatus = FileStatus::Unknown;
|
||||||
bool hasFile = currentState().hasFile();
|
bool hasFile = currentState().hasFile();
|
||||||
if (hasFile) {
|
if (hasFile) {
|
||||||
QString fileName = currentState().relativeCurrentFile();
|
QString absoluteFileName = currentState().currentFile();
|
||||||
fileStatus = m_statusMap->value(fileName, FileStatus(FileStatus::Unknown));
|
fileStatus = m_statusMap->value(absoluteFileName, FileStatus(FileStatus::Unknown));
|
||||||
|
|
||||||
if (ClearCase::Constants::debug)
|
if (ClearCase::Constants::debug)
|
||||||
qDebug() << Q_FUNC_INFO << fileName << ", status = " << fileStatus.status;
|
qDebug() << Q_FUNC_INFO << absoluteFileName << ", status = " << fileStatus.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_checkOutAction->setEnabled(hasFile && (fileStatus.status & (FileStatus::CheckedIn | FileStatus::Hijacked)));
|
m_checkOutAction->setEnabled(hasFile && (fileStatus.status & (FileStatus::CheckedIn | FileStatus::Hijacked)));
|
||||||
@@ -686,10 +770,12 @@ void ClearCasePlugin::addCurrentFile()
|
|||||||
vcsAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
|
vcsAdd(state.currentFileTopLevel(), state.relativeCurrentFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the FileStatus of file given in absolute path
|
||||||
void ClearCasePlugin::setStatus(const QString &file, FileStatus::Status status, bool update)
|
void ClearCasePlugin::setStatus(const QString &file, FileStatus::Status status, bool update)
|
||||||
{
|
{
|
||||||
m_statusMap->insert(file, FileStatus(status, QFileInfo(currentState().topLevel(), file).permissions()));
|
m_statusMap->insert(file, FileStatus(status, QFileInfo(file).permissions()));
|
||||||
if (update && (currentState().relativeCurrentFile() == file))
|
|
||||||
|
if (update && currentState().currentFile() == file)
|
||||||
QMetaObject::invokeMethod(this, "updateStatusActions");
|
QMetaObject::invokeMethod(this, "updateStatusActions");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -738,9 +824,11 @@ bool ClearCasePlugin::vcsUndoCheckOut(const QString &workingDir, const QString &
|
|||||||
ShowStdOutInLogWindow | FullySynchronously);
|
ShowStdOutInLogWindow | FullySynchronously);
|
||||||
|
|
||||||
if (!response.error) {
|
if (!response.error) {
|
||||||
|
const QString absPath = workingDir + QLatin1Char('/') + fileName;
|
||||||
|
|
||||||
if (!m_settings.disableIndexer)
|
if (!m_settings.disableIndexer)
|
||||||
setStatus(fileName, FileStatus::CheckedIn);
|
setStatus(absPath, FileStatus::CheckedIn);
|
||||||
clearCaseControl()->emitFilesChanged(QStringList(fileName));
|
clearCaseControl()->emitFilesChanged(QStringList(absPath));
|
||||||
}
|
}
|
||||||
return !response.error;
|
return !response.error;
|
||||||
}
|
}
|
||||||
@@ -767,8 +855,10 @@ bool ClearCasePlugin::vcsUndoHijack(const QString &workingDir, const QString &fi
|
|||||||
const ClearCaseResponse response =
|
const ClearCaseResponse response =
|
||||||
runCleartool(workingDir, args, m_settings.timeOutMS(),
|
runCleartool(workingDir, args, m_settings.timeOutMS(),
|
||||||
ShowStdOutInLogWindow | FullySynchronously);
|
ShowStdOutInLogWindow | FullySynchronously);
|
||||||
if (!response.error && !m_settings.disableIndexer)
|
if (!response.error && !m_settings.disableIndexer) {
|
||||||
setStatus(fileName, FileStatus::CheckedIn);
|
const QString absPath = workingDir + QLatin1Char('/') + fileName;
|
||||||
|
setStatus(absPath, FileStatus::CheckedIn);
|
||||||
|
}
|
||||||
return !response.error;
|
return !response.error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -819,8 +909,9 @@ void ClearCasePlugin::ccDiffWithPred(const QString &workingDir, const QStringLis
|
|||||||
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VcsBase::VcsBaseEditorWidget::getCodec(source);
|
QTextCodec *codec = source.isEmpty() ? static_cast<QTextCodec *>(0) : VcsBase::VcsBaseEditorWidget::getCodec(source);
|
||||||
|
|
||||||
if ((m_settings.diffType == GraphicalDiff) && (files.count() == 1)) {
|
if ((m_settings.diffType == GraphicalDiff) && (files.count() == 1)) {
|
||||||
QString file = files.first();
|
const QString file = files.first();
|
||||||
if (m_statusMap->value(file).status == FileStatus::Hijacked)
|
const QString absFilePath = workingDir + QLatin1Char('/') + file;
|
||||||
|
if (m_statusMap->value(absFilePath).status == FileStatus::Hijacked)
|
||||||
diffGraphical(ccGetFileVersion(workingDir, file), file);
|
diffGraphical(ccGetFileVersion(workingDir, file), file);
|
||||||
else
|
else
|
||||||
diffGraphical(file);
|
diffGraphical(file);
|
||||||
@@ -833,7 +924,8 @@ void ClearCasePlugin::ccDiffWithPred(const QString &workingDir, const QStringLis
|
|||||||
}
|
}
|
||||||
QString result;
|
QString result;
|
||||||
foreach (const QString &file, files) {
|
foreach (const QString &file, files) {
|
||||||
if (m_statusMap->value(QDir::fromNativeSeparators(file)).status == FileStatus::Hijacked)
|
const QString absFilePath = workingDir + QLatin1Char('/') + file;
|
||||||
|
if (m_statusMap->value(QDir::fromNativeSeparators(absFilePath)).status == FileStatus::Hijacked)
|
||||||
result += diffExternal(ccGetFileVersion(workingDir, file), file);
|
result += diffExternal(ccGetFileVersion(workingDir, file), file);
|
||||||
else
|
else
|
||||||
result += diffExternal(file);
|
result += diffExternal(file);
|
||||||
@@ -1370,14 +1462,14 @@ bool ClearCasePlugin::vcsOpen(const QString &workingDir, const QString &fileName
|
|||||||
CheckOutDialog coDialog(title, m_viewData.isUcm);
|
CheckOutDialog coDialog(title, m_viewData.isUcm);
|
||||||
|
|
||||||
if (!m_settings.disableIndexer &&
|
if (!m_settings.disableIndexer &&
|
||||||
(fi.isWritable() || m_statusMap->value(relFile).status == FileStatus::Unknown))
|
(fi.isWritable() || m_statusMap->value(absPath).status == FileStatus::Unknown))
|
||||||
QtConcurrent::run(&sync, topLevel, QStringList(relFile)).waitForFinished();
|
QtConcurrent::run(&sync, QStringList(absPath)).waitForFinished();
|
||||||
if (m_statusMap->value(relFile).status == FileStatus::CheckedOut) {
|
if (m_statusMap->value(absPath).status == FileStatus::CheckedOut) {
|
||||||
QMessageBox::information(0, tr("ClearCase Checkout"), tr("File is already checked out."));
|
QMessageBox::information(0, tr("ClearCase Checkout"), tr("File is already checked out."));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Only snapshot views can have hijacked files
|
// Only snapshot views can have hijacked files
|
||||||
bool isHijacked = (!m_viewData.isDynamic && (m_statusMap->value(relFile).status & FileStatus::Hijacked));
|
bool isHijacked = (!m_viewData.isDynamic && (m_statusMap->value(absPath).status & FileStatus::Hijacked));
|
||||||
if (!isHijacked)
|
if (!isHijacked)
|
||||||
coDialog.hideHijack();
|
coDialog.hideHijack();
|
||||||
if (coDialog.exec() == QDialog::Accepted) {
|
if (coDialog.exec() == QDialog::Accepted) {
|
||||||
@@ -1440,8 +1532,10 @@ bool ClearCasePlugin::vcsOpen(const QString &workingDir, const QString &fileName
|
|||||||
QFile::rename(absPath + QLatin1String(".hijack"), absPath);
|
QFile::rename(absPath + QLatin1String(".hijack"), absPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((!response.error || response.stdOut.contains(QLatin1String("already checked out"))) && !m_settings.disableIndexer)
|
if ((!response.error || response.stdOut.contains(QLatin1String("already checked out")))
|
||||||
setStatus(relFile, FileStatus::CheckedOut);
|
&& !m_settings.disableIndexer) {
|
||||||
|
setStatus(absPath, FileStatus::CheckedOut);
|
||||||
|
}
|
||||||
return !response.error;
|
return !response.error;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -1501,8 +1595,11 @@ bool ClearCasePlugin::vcsCheckIn(const QString &messageFile, const QStringList &
|
|||||||
int offset = checkedIn.indexIn(response.stdOut);
|
int offset = checkedIn.indexIn(response.stdOut);
|
||||||
while (offset != -1) {
|
while (offset != -1) {
|
||||||
QString file = checkedIn.cap(1);
|
QString file = checkedIn.cap(1);
|
||||||
|
QFileInfo fi(m_checkInView, file);
|
||||||
|
QString absPath = fi.absoluteFilePath();
|
||||||
|
|
||||||
if (!m_settings.disableIndexer)
|
if (!m_settings.disableIndexer)
|
||||||
setStatus(QDir::fromNativeSeparators(file), FileStatus::CheckedIn);
|
setStatus(QDir::fromNativeSeparators(absPath), FileStatus::CheckedIn);
|
||||||
clearCaseControl()->emitFilesChanged(files);
|
clearCaseControl()->emitFilesChanged(files);
|
||||||
anySucceeded = true;
|
anySucceeded = true;
|
||||||
offset = checkedIn.indexIn(response.stdOut, offset + 12);
|
offset = checkedIn.indexIn(response.stdOut, offset + 12);
|
||||||
@@ -1639,7 +1736,9 @@ QString ClearCasePlugin::vcsGetRepositoryURL(const QString & /*directory*/)
|
|||||||
return currentState().topLevel();
|
return currentState().topLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearCase has "view.dat" file in the root directory it manages for snapshot views.
|
///
|
||||||
|
/// Check if the directory is managed under ClearCase control.
|
||||||
|
///
|
||||||
bool ClearCasePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
|
bool ClearCasePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
|
||||||
{
|
{
|
||||||
QString topLevelFound = findTopLevel(directory);
|
QString topLevelFound = findTopLevel(directory);
|
||||||
@@ -1770,6 +1869,7 @@ ViewData ClearCasePlugin::ccGetView(const QString &workingDir) const
|
|||||||
res.isDynamic = !data.isEmpty() && (data.at(0) == QLatin1Char('*'));
|
res.isDynamic = !data.isEmpty() && (data.at(0) == QLatin1Char('*'));
|
||||||
res.name = data.mid(2, data.indexOf(QLatin1Char(' '), 2) - 2);
|
res.name = data.mid(2, data.indexOf(QLatin1Char(' '), 2) - 2);
|
||||||
res.isUcm = ccCheckUcm(res.name, workingDir);
|
res.isUcm = ccCheckUcm(res.name, workingDir);
|
||||||
|
res.root = ccViewRoot(workingDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -1829,7 +1929,7 @@ void ClearCasePlugin::updateIndex()
|
|||||||
return;
|
return;
|
||||||
m_checkInAllAction->setEnabled(false);
|
m_checkInAllAction->setEnabled(false);
|
||||||
m_statusMap->clear();
|
m_statusMap->clear();
|
||||||
QFuture<void> result = QtConcurrent::run(&sync, currentState().topLevel(),
|
QFuture<void> result = QtConcurrent::run(&sync,
|
||||||
project->files(ProjectExplorer::Project::ExcludeGeneratedFiles));
|
project->files(ProjectExplorer::Project::ExcludeGeneratedFiles));
|
||||||
if (!m_settings.disableIndexer)
|
if (!m_settings.disableIndexer)
|
||||||
Core::ICore::progressManager()->addTask(result, tr("CC Indexing"),
|
Core::ICore::progressManager()->addTask(result, tr("CC Indexing"),
|
||||||
@@ -1969,7 +2069,7 @@ void ClearCasePlugin::syncSlot()
|
|||||||
QString topLevel = state.topLevel();
|
QString topLevel = state.topLevel();
|
||||||
if (topLevel != state.currentProjectTopLevel())
|
if (topLevel != state.currentProjectTopLevel())
|
||||||
return;
|
return;
|
||||||
QtConcurrent::run(&sync, topLevel, QStringList());
|
QtConcurrent::run(&sync, QStringList());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCasePlugin::closing()
|
void ClearCasePlugin::closing()
|
||||||
@@ -1979,12 +2079,12 @@ void ClearCasePlugin::closing()
|
|||||||
disconnect(Core::ICore::mainWindow(), SIGNAL(windowActivated()), this, SLOT(syncSlot()));
|
disconnect(Core::ICore::mainWindow(), SIGNAL(windowActivated()), this, SLOT(syncSlot()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCasePlugin::sync(QFutureInterface<void> &future, QString topLevel, QStringList files)
|
void ClearCasePlugin::sync(QFutureInterface<void> &future, QStringList files)
|
||||||
{
|
{
|
||||||
ClearCasePlugin *plugin = ClearCasePlugin::instance();
|
ClearCasePlugin *plugin = ClearCasePlugin::instance();
|
||||||
ClearCaseSync ccSync(plugin, plugin->m_statusMap);
|
ClearCaseSync ccSync(plugin, plugin->m_statusMap);
|
||||||
connect(&ccSync, SIGNAL(updateStreamAndView()), plugin, SLOT(updateStreamAndView()));
|
connect(&ccSync, SIGNAL(updateStreamAndView()), plugin, SLOT(updateStreamAndView()));
|
||||||
ccSync.run(future, topLevel, files);
|
ccSync.run(future, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ public:
|
|||||||
QString name;
|
QString name;
|
||||||
bool isDynamic;
|
bool isDynamic;
|
||||||
bool isUcm;
|
bool isUcm;
|
||||||
|
QString root;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ClearCasePlugin : public VcsBase::VcsBasePlugin
|
class ClearCasePlugin : public VcsBase::VcsBasePlugin
|
||||||
@@ -156,6 +157,7 @@ public:
|
|||||||
const QString &fileName, const QString &file2 = QString());
|
const QString &fileName, const QString &file2 = QString());
|
||||||
FileStatus vcsStatus(const QString &file) const;
|
FileStatus vcsStatus(const QString &file) const;
|
||||||
QString currentView() const { return m_viewData.name; }
|
QString currentView() const { return m_viewData.name; }
|
||||||
|
QString viewRoot() const { return m_viewData.root; }
|
||||||
void refreshActivities();
|
void refreshActivities();
|
||||||
inline bool isUcm() const { return m_viewData.isUcm; }
|
inline bool isUcm() const { return m_viewData.isUcm; }
|
||||||
inline bool isDynamic() const { return m_viewData.isDynamic; }
|
inline bool isDynamic() const { return m_viewData.isDynamic; }
|
||||||
@@ -207,6 +209,9 @@ protected:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
inline bool isCheckInEditorOpen() const;
|
inline bool isCheckInEditorOpen() const;
|
||||||
|
QStringList getVobList() const;
|
||||||
|
QString ccManagesDirectory(const QString &directory) const;
|
||||||
|
QString ccViewRoot(const QString &directory) const;
|
||||||
QString findTopLevel(const QString &directory) const;
|
QString findTopLevel(const QString &directory) const;
|
||||||
Core::IEditor *showOutputInEditor(const QString& title, const QString &output,
|
Core::IEditor *showOutputInEditor(const QString& title, const QString &output,
|
||||||
int editorType, const QString &source,
|
int editorType, const QString &source,
|
||||||
@@ -215,7 +220,7 @@ private:
|
|||||||
ClearCaseResponse runCleartool(const QString &workingDir,
|
ClearCaseResponse runCleartool(const QString &workingDir,
|
||||||
const QStringList &arguments, int timeOut,
|
const QStringList &arguments, int timeOut,
|
||||||
unsigned flags, QTextCodec *outputCodec = 0) const;
|
unsigned flags, QTextCodec *outputCodec = 0) const;
|
||||||
static void sync(QFutureInterface<void> &future, QString topLevel, QStringList files);
|
static void sync(QFutureInterface<void> &future, QStringList files);
|
||||||
|
|
||||||
void history(const QString &workingDir,
|
void history(const QString &workingDir,
|
||||||
const QStringList &file = QStringList(),
|
const QStringList &file = QStringList(),
|
||||||
@@ -234,6 +239,7 @@ private:
|
|||||||
static void rmdir(const QString &path);
|
static void rmdir(const QString &path);
|
||||||
QString runExtDiff(const QString &workingDir, const QStringList &arguments,
|
QString runExtDiff(const QString &workingDir, const QStringList &arguments,
|
||||||
int timeOut, QTextCodec *outputCodec = 0);
|
int timeOut, QTextCodec *outputCodec = 0);
|
||||||
|
static QString getDriveLetterOfPath(const QString &directory);
|
||||||
|
|
||||||
ClearCaseSettings m_settings;
|
ClearCaseSettings m_settings;
|
||||||
|
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ ClearCaseSync::ClearCaseSync(ClearCasePlugin *plugin, QSharedPointer<StatusMap>
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel, QStringList &files)
|
void ClearCaseSync::run(QFutureInterface<void> &future, QStringList &files)
|
||||||
{
|
{
|
||||||
ClearCaseSettings settings = m_plugin->settings();
|
ClearCaseSettings settings = m_plugin->settings();
|
||||||
const QString program = settings.ccBinaryPath;
|
const QString program = settings.ccBinaryPath;
|
||||||
@@ -66,8 +66,9 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
if (settings.disableIndexer)
|
if (settings.disableIndexer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QDir topLevelDir(topLevel);
|
|
||||||
const bool isDynamic = m_plugin->isDynamic();
|
const bool isDynamic = m_plugin->isDynamic();
|
||||||
|
const QString viewRoot = m_plugin->viewRoot();
|
||||||
|
const QDir viewRootDir(viewRoot);
|
||||||
|
|
||||||
QStringList args(QLatin1String("ls"));
|
QStringList args(QLatin1String("ls"));
|
||||||
if (hot) {
|
if (hot) {
|
||||||
@@ -75,7 +76,7 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
// (might have become checked out)
|
// (might have become checked out)
|
||||||
const StatusMap::Iterator send = m_statusMap->end();
|
const StatusMap::Iterator send = m_statusMap->end();
|
||||||
for (StatusMap::Iterator it = m_statusMap->begin(); it != send; ++it) {
|
for (StatusMap::Iterator it = m_statusMap->begin(); it != send; ++it) {
|
||||||
const QFileInfo fi(topLevel, it.key());
|
const QFileInfo fi(viewRoot, it.key());
|
||||||
const bool permChanged = it.value().permissions != fi.permissions();
|
const bool permChanged = it.value().permissions != fi.permissions();
|
||||||
if (permChanged || it.value().status == FileStatus::Hijacked) {
|
if (permChanged || it.value().status == FileStatus::Hijacked) {
|
||||||
files.append(it.key());
|
files.append(it.key());
|
||||||
@@ -90,11 +91,11 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
} else {
|
} else {
|
||||||
foreach (const QString &file, files) {
|
foreach (const QString &file, files) {
|
||||||
if (isDynamic) { // assume a read only file is checked in
|
if (isDynamic) { // assume a read only file is checked in
|
||||||
const QFileInfo fi(topLevelDir, file);
|
const QFileInfo fi(viewRootDir, file);
|
||||||
if (!fi.isWritable())
|
if (!fi.isWritable())
|
||||||
m_plugin->setStatus(topLevelDir.relativeFilePath(file), FileStatus::CheckedIn, false);
|
m_plugin->setStatus(fi.absoluteFilePath(), FileStatus::CheckedIn, false);
|
||||||
} else {
|
} else {
|
||||||
m_plugin->setStatus(topLevelDir.relativeFilePath(file), FileStatus::Unknown, false);
|
m_plugin->setStatus(viewRootDir.absoluteFilePath(file), FileStatus::Unknown, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args << QLatin1String("-recurse");
|
args << QLatin1String("-recurse");
|
||||||
@@ -112,7 +113,7 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
// (we don't want it to become green)
|
// (we don't want it to become green)
|
||||||
future.setProgressRange(0, total + 1);
|
future.setProgressRange(0, total + 1);
|
||||||
QProcess process;
|
QProcess process;
|
||||||
process.setWorkingDirectory(topLevel);
|
process.setWorkingDirectory(viewRoot);
|
||||||
|
|
||||||
process.start(program, args);
|
process.start(program, args);
|
||||||
if (!process.waitForStarted())
|
if (!process.waitForStarted())
|
||||||
@@ -130,21 +131,24 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
if (atatpos != -1) { // probably managed file
|
if (atatpos != -1) { // probably managed file
|
||||||
// find first whitespace. anything before that is not interesting
|
// find first whitespace. anything before that is not interesting
|
||||||
const int wspos = buffer.indexOf(QRegExp(QLatin1String("\\s")));
|
const int wspos = buffer.indexOf(QRegExp(QLatin1String("\\s")));
|
||||||
const QString relFile = topLevelDir.relativeFilePath(QDir::fromNativeSeparators(buffer.left(atatpos)));
|
const QString absFile =
|
||||||
|
viewRootDir.absoluteFilePath(
|
||||||
|
QDir::fromNativeSeparators(buffer.left(atatpos)));
|
||||||
|
|
||||||
QString ccState;
|
QString ccState;
|
||||||
const QRegExp reState(QLatin1String("^\\s*\\[[^\\]]*\\]")); // [hijacked]; [loaded but missing]
|
const QRegExp reState(QLatin1String("^\\s*\\[[^\\]]*\\]")); // [hijacked]; [loaded but missing]
|
||||||
if (reState.indexIn(buffer, wspos + 1, QRegExp::CaretAtOffset) != -1) {
|
if (reState.indexIn(buffer, wspos + 1, QRegExp::CaretAtOffset) != -1) {
|
||||||
ccState = reState.cap();
|
ccState = reState.cap();
|
||||||
if (ccState.indexOf(QLatin1String("hijacked")) != -1)
|
if (ccState.indexOf(QLatin1String("hijacked")) != -1)
|
||||||
m_plugin->setStatus(relFile, FileStatus::Hijacked, true);
|
m_plugin->setStatus(absFile, FileStatus::Hijacked, true);
|
||||||
else if (ccState.indexOf(QLatin1String("loaded but missing")) != -1)
|
else if (ccState.indexOf(QLatin1String("loaded but missing")) != -1)
|
||||||
m_plugin->setStatus(relFile, FileStatus::Missing, false);
|
m_plugin->setStatus(absFile, FileStatus::Missing, false);
|
||||||
}
|
}
|
||||||
else if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1)
|
else if (buffer.lastIndexOf(QLatin1String("CHECKEDOUT"), wspos) != -1)
|
||||||
m_plugin->setStatus(relFile, FileStatus::CheckedOut, true);
|
m_plugin->setStatus(absFile, FileStatus::CheckedOut, true);
|
||||||
// don't care about checked-in files not listed in project
|
// don't care about checked-in files not listed in project
|
||||||
else if (m_statusMap->contains(relFile))
|
else if (m_statusMap->contains(absFile))
|
||||||
m_plugin->setStatus(relFile, FileStatus::CheckedIn, true);
|
m_plugin->setStatus(absFile, FileStatus::CheckedIn, true);
|
||||||
}
|
}
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
future.setProgressValue(qMin(total, ++processed));
|
future.setProgressValue(qMin(total, ++processed));
|
||||||
@@ -154,9 +158,9 @@ void ClearCaseSync::run(QFutureInterface<void> &future, const QString &topLevel,
|
|||||||
|
|
||||||
if (!future.isCanceled()) {
|
if (!future.isCanceled()) {
|
||||||
foreach (const QString &file, files) {
|
foreach (const QString &file, files) {
|
||||||
const QString relFile = topLevelDir.relativeFilePath(file);
|
QString absFile = QFileInfo(file).absoluteFilePath();
|
||||||
if (m_statusMap->value(relFile).status == FileStatus::Unknown)
|
if (!m_statusMap->contains(absFile))
|
||||||
m_plugin->setStatus(relFile, FileStatus::NotManaged, false);
|
m_plugin->setStatus(absFile, FileStatus::NotManaged, false);
|
||||||
}
|
}
|
||||||
future.setProgressValue(total + 1);
|
future.setProgressValue(total + 1);
|
||||||
if (!hot) {
|
if (!hot) {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class ClearCaseSync : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ClearCaseSync(ClearCasePlugin *plugin, QSharedPointer<StatusMap> statusMap);
|
explicit ClearCaseSync(ClearCasePlugin *plugin, QSharedPointer<StatusMap> statusMap);
|
||||||
void run(QFutureInterface<void> &future, const QString &topLevel, QStringList &files);
|
void run(QFutureInterface<void> &future, QStringList &files);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateStreamAndView();
|
void updateStreamAndView();
|
||||||
|
|||||||
Reference in New Issue
Block a user