Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.netbeans.modules.mercurial.commands.StatusCommand Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.modules.mercurial.commands;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.modules.mercurial.FileInformation;
import org.netbeans.modules.mercurial.FileStatus;
import org.netbeans.modules.mercurial.HgException;
import org.netbeans.modules.mercurial.Mercurial;
import org.netbeans.modules.mercurial.OutputLogger;
import org.netbeans.modules.mercurial.ui.log.HgLogMessage.HgRevision;
import org.netbeans.modules.mercurial.util.HgCommand;
import org.netbeans.modules.mercurial.util.HgUtils;
import org.openide.util.NbBundle;
import org.openide.util.Parameters;
import org.openide.util.Utilities;
/**
*
* @author Ondrej Vrabec
*/
@NbBundle.Messages({
"MSG_NO_REPOSITORY_ERR=Mercurial repository could not be found"
})
public final class StatusCommand extends HgCommand> {
private final File repository;
private List output;
private String statusFlags;
private String revisionFrom;
private String revisionTo;
private final List files;
private static final Logger LOG = Logger.getLogger(StatusCommand.class.getName());
private static final String HG_STATUS_FLAG_INTERESTING_CMD = "-mardu"; // NOI18N
private static final String HG_STATUS_FLAG_COPIES = "C"; // NOI18N
private static final char HG_STATUS_CODE_MODIFIED = 'M' + ' '; // NOI18N // STATUS_VERSIONED_MODIFIEDLOCALLY
private static final char HG_STATUS_CODE_ADDED = 'A' + ' '; // NOI18N // STATUS_VERSIONED_ADDEDLOCALLY
private static final char HG_STATUS_CODE_REMOVED = 'R' + ' '; // NOI18N // STATUS_VERSIONED_REMOVEDLOCALLY - still tracked, hg update will recover, hg commit
private static final char HG_STATUS_CODE_CLEAN = 'C' + ' '; // NOI18N // STATUS_VERSIONED_UPTODATE
private static final char HG_STATUS_CODE_DELETED = '!' + ' '; // NOI18N // STATUS_VERSIONED_DELETEDLOCALLY - still tracked, hg update will recover, hg commit no effect
private static final char HG_STATUS_CODE_NOTTRACKED = '?' + ' '; // NOI18N // STATUS_NOTVERSIONED_NEWLOCALLY - not tracked
private static final char HG_STATUS_CODE_IGNORED = 'I' + ' '; // NOI18N // STATUS_NOTVERSIONED_EXCLUDE - not shown by default
private static final char HG_STATUS_CODE_CONFLICT = 'U' + ' '; // NOI18N // STATUS_VERSIONED_CONFLICT - TODO when Hg status supports conflict markers
private static final char HG_STATUS_CODE_ABORT = 'a' + 'b'; // NOI18N
private boolean detectCopies;
private boolean detectConflicts;
public StatusCommand (File repository, List files) {
Parameters.notNull("repository", repository);
Parameters.notNull("files", files);
this.repository = repository;
this.files = files;
this.statusFlags = HG_STATUS_FLAG_INTERESTING_CMD;
this.detectConflicts = true;
}
/**
* Creates a status command for only files of interest to us in a given directory in a repository
* that is modified, locally added, locally removed, locally deleted, locally new and ignored.
*
* @param File repository of the mercurial repository's root directory
* @param files files or directories of interest
* @param detectCopies if set to true then the command takes longer and returns also original files for renames and copies
*/
public static StatusCommand create (File repository, List files, boolean detectCopies) {
return new StatusCommand(repository, files)
.setStatusFlags(HG_STATUS_FLAG_INTERESTING_CMD)
.setDetectCopies(detectCopies);
}
public StatusCommand setRevisionFrom (String revisionFrom) {
this.revisionFrom = revisionFrom;
return this;
}
public StatusCommand setRevisionTo (String revisionTo) {
this.revisionTo = revisionTo;
return this;
}
public StatusCommand setDetectCopies (boolean detectCopies) {
this.detectCopies = detectCopies;
return this;
}
/**
* Instruct the status command to also detect conflicts. The default
* value is false
so you need to call this method only if
* you actually want not to detect conflicts and make the command a bit
* faster.
*
* @param detectConflicts detect conflicts or not
*/
public StatusCommand setDetectConflicts (boolean detectConflicts) {
this.detectConflicts = detectConflicts;
return this;
}
private StatusCommand setStatusFlags (String statusFlags) {
this.statusFlags = statusFlags;
return this;
}
@Override
public Map call () throws HgException {
long startTime = 0;
if (LOG.isLoggable(Level.FINER)) {
LOG.log(Level.FINER, "getStatusWithFlags: starting for {0}", files); //NOI18N
startTime = System.currentTimeMillis();
}
try {
return runInternal();
} finally {
if (LOG.isLoggable(Level.FINER)) {
LOG.log(Level.FINER, "getStatusWithFlags for {0} lasted {1}", new Object[]{files, System.currentTimeMillis() - startTime}); //NOI18N
}
}
}
private Map runInternal () throws HgException {
CommandParameters args = new CommandParameters(HgCommand.HG_STATUS_CMD);
String flags = this.statusFlags;
if (detectCopies) {
flags = flags + HG_STATUS_FLAG_COPIES;
}
args.add(flags)
.addRepositoryLocation(repository.getAbsolutePath())
.add(HgCommand.HG_OPT_CWD_CMD)
.add(repository.getAbsolutePath());
List command = args.toCommand();
List> attributeGroups = HgCommand.splitAttributes(repository, command, files, true);
boolean workDirStatus = true;
boolean skipMidChanges = false;
if (revisionFrom != null) {
command.add(HgCommand.HG_FLAG_REV_CMD);
if (revisionTo == null || HgRevision.CURRENT.getRevisionNumber().equals(revisionTo)) {
skipMidChanges = !HgRevision.BASE.getRevisionNumber().equals(revisionFrom);
command.add(revisionFrom);
} else {
skipMidChanges = true;
command.add(revisionFrom + ":" + revisionTo); //NOI18N
workDirStatus = false;
}
}
List commandOutput = new ArrayList();
List changedPaths = skipMidChanges ? new ArrayList() : null;
for (List attributes : attributeGroups) {
if (changedPaths != null) {
changedPaths.addAll(HgCommand.getListOfChangedFiles(repository, attributes, revisionFrom, revisionTo));
}
List finalCommand = new ArrayList(command);
finalCommand.addAll(attributes);
List list = exec(finalCommand);
if (!list.isEmpty() && HgCommand.isErrorNoRepository(list.get(0))) {
OutputLogger logger = OutputLogger.getLogger(repository);
try {
handleError(finalCommand, list, Bundle.MSG_NO_REPOSITORY_ERR(), logger);
} finally {
logger.closeLog();
}
} else if (detectConflicts && workDirStatus && HgUtils.hasResolveCommand(Mercurial.getInstance().getVersion())) {
try {
List unresolved = HgCommand.getUnresolvedFiles(repository, attributes);
list.addAll(unresolved);
} catch (HgException ex) {
//
}
}
commandOutput.addAll(list);
}
Map infos = processStatusResult(commandOutput, repository, flags, changedPaths);
if (LOG.isLoggable(Level.FINE)) {
if (commandOutput.size() < 10) {
LOG.log(Level.FINE, "getStatusWithFlags(): repository path: {0} status flags: {1} status list {2}", // NOI18N
new Object[] {repository.getAbsolutePath(), flags, commandOutput} );
} else {
LOG.log(Level.FINE, "getStatusWithFlags(): repository path: {0} status flags: {1} status list has {2} elements", // NOI18N
new Object[] {repository.getAbsolutePath(), flags, commandOutput.size()} );
}
}
return infos;
}
private static Map processStatusResult (List commandOutput, File repository,
String statusFlags, List changedPaths) {
Map repositoryFiles = new HashMap(commandOutput.size());
File file = null;
FileInformation prev_info = null;
String repositoryPath = repository.getAbsolutePath();
for (String statusLine : commandOutput) {
if (statusLine.isEmpty()) {
continue;
}
FileInformation info = getFileInformationFromStatusLine(statusLine);
LOG.log(Level.FINE, "getStatusWithFlags(): status line {0} info {1}", new Object[]{statusLine, info}); // NOI18N
if (statusLine.length() > 0) {
if (statusLine.charAt(0) == ' ') {
// Locally Added but Copied
if (file != null) {
File original = getFileFromStatusLine(statusLine, repository);
prev_info = new FileInformation(prev_info.getStatus(),
new FileStatus(file, original), false);
LOG.log(Level.FINE, "getStatusWithFlags(): prev_info {0} filePath {1}", new Object[]{prev_info, file}); // NOI18N
} else {
LOG.log(Level.FINE, "getStatusWithFlags(): repository path: {0} status flags: {1} status line {2} filepath == nullfor prev_info ", new Object[]{repository.getAbsolutePath(), statusFlags, statusLine}); // NOI18N
}
continue;
} else {
if (file != null) {
repositoryFiles.put(file, prev_info);
}
}
}
if(info.getStatus() == FileInformation.STATUS_NOTVERSIONED_NOTMANAGED
|| info.getStatus() == FileInformation.STATUS_UNKNOWN) continue;
if (changedPaths == null || (info.getStatus() & FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY) == 0
|| changedPaths.contains(getRelativePathFromStatusLine(statusLine, repositoryPath))) {
file = getFileFromStatusLine(statusLine, repository);
} else {
// uninteresting file, changed in the middle of revision range and back again
// e.g. line added and then removed again
file = null;
continue;
}
// Handle Conflict Status
// TODO: remove this if Hg status supports Conflict marker
if (existsConflictFile(file.getAbsolutePath())) {
info = new FileInformation(FileInformation.STATUS_VERSIONED_CONFLICT, null, false);
LOG.log(Level.FINE, "getStatusWithFlags(): CONFLICT repository path: {0} status flags: {1} status line {2} CONFLICT {3}", new Object[]{repository.getAbsolutePath(), statusFlags, statusLine, file + HgCommand.HG_STR_CONFLICT_EXT}); // NOI18N
}
prev_info = info;
}
if (prev_info != null) {
repositoryFiles.put(file, prev_info);
}
return repositoryFiles;
}
private static File getFileFromStatusLine (String statusLine, File repository) {
File file;
String repositoryPath = repository.getAbsolutePath();
String path = getRelativePathFromStatusLine(statusLine, repositoryPath);
if(Utilities.isWindows() && path.startsWith(repositoryPath)) {
file = new File(path); // prevent bogus paths (C:\tmp\hg\C:\tmp\hg\whatever) - see issue #139500
} else {
file = new File(repository, path);
}
return file;
}
/**
* Gets file information for a given hg status output status line
*/
private static FileInformation getFileInformationFromStatusLine(String status){
FileInformation info = null;
if (status == null || (status.length() == 0)) return new FileInformation(FileInformation.STATUS_VERSIONED_UPTODATE, null, false);
char c0 = status.charAt(0);
char c1 = status.charAt(1);
switch(c0 + c1) {
case HG_STATUS_CODE_MODIFIED:
info = new FileInformation(FileInformation.STATUS_VERSIONED_MODIFIEDLOCALLY,null, false);
break;
case HG_STATUS_CODE_ADDED:
info = new FileInformation(FileInformation.STATUS_VERSIONED_ADDEDLOCALLY,null, false);
break;
case HG_STATUS_CODE_REMOVED:
info = new FileInformation(FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY,null, false);
break;
case HG_STATUS_CODE_CLEAN:
info = new FileInformation(FileInformation.STATUS_VERSIONED_UPTODATE,null, false);
break;
case HG_STATUS_CODE_DELETED:
info = new FileInformation(FileInformation.STATUS_VERSIONED_DELETEDLOCALLY,null, false);
break;
case HG_STATUS_CODE_IGNORED:
info = new FileInformation(FileInformation.STATUS_NOTVERSIONED_EXCLUDED,null, false);
break;
case HG_STATUS_CODE_NOTTRACKED:
info = new FileInformation(FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY,null, false);
break;
// Leave this here for whenever Hg status suports conflict markers
case HG_STATUS_CODE_CONFLICT:
info = new FileInformation(FileInformation.STATUS_VERSIONED_CONFLICT,null, false);
break;
case HG_STATUS_CODE_ABORT:
info = new FileInformation(FileInformation.STATUS_NOTVERSIONED_NOTMANAGED,null, false);
break;
default:
info = new FileInformation(FileInformation.STATUS_UNKNOWN,null, false);
break;
}
return info;
}
private static String getRelativePathFromStatusLine (String statusLine, String repositoryPath) {
String path = statusLine.substring(2);
if (Utilities.isWindows() && path.startsWith(repositoryPath)) {
path = path.substring(repositoryPath.length() + 1);
}
return path;
}
public List getOutput () {
return output;
}
}