/*******************************************************************************
* Copyright (c) 2012 Arapiki Solutions Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* "Peter Smith <psmith@arapiki.com>" - initial API and
* implementation and/or initial documentation
*******************************************************************************/
package com.buildml.main.commands;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import com.buildml.main.CliUtils;
import com.buildml.main.ICliCommand;
import com.buildml.model.IActionMgr;
import com.buildml.model.IBuildStore;
import com.buildml.model.IFileMgr;
import com.buildml.model.undo.MultiUndoOp;
import com.buildml.refactor.CanNotRefactorException;
import com.buildml.refactor.IImportRefactorer;
import com.buildml.refactor.imports.ImportRefactorer;
import com.buildml.utils.errors.ErrorCode;
/**
* BuildML CLI Command class that implements the "rm-file" command.
*
* @author "Peter Smith <psmith@arapiki.com>"
*/
public class CliCommandRmFile implements ICliCommand {
/*=====================================================================================*
* FIELDS/TYPES
*=====================================================================================*/
/** Set if we should force removal of the file, and its generating actions. */
private boolean optionForceRm = false;
/** Set if we want to delete directory content recursively */
private boolean optionRecursive = false;
/*=====================================================================================*
* PUBLIC METHODS
*=====================================================================================*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#getLongDescription()
*/
@Override
public String getLongDescription() {
return CliUtils.genLocalizedMessage("#include commands/rm-file.txt");
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#getName()
*/
@Override
public String getName() {
return "rm-file";
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#getOptions()
*/
@Override
public Options getOptions() {
Options opts = new Options();
/* add the --force-rm-actions option */
Option deleteActionsOpt = new Option("f", "force-rm-file", false,
"Force removal of this path, even if it's in use.");
opts.addOption(deleteActionsOpt);
/* add the --recursive option */
Option deleteRecursiveOpt = new Option("r", "recursive", false,
"Delete sub-tree recursively.");
opts.addOption(deleteRecursiveOpt);
return opts;
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#getParameterDescription()
*/
@Override
public String getParameterDescription() {
return "[-r] [-f] <path>";
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#getShortDescription()
*/
@Override
public String getShortDescription() {
return "Delete a file (and associated action) from the build system.";
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#processOptions(org.apache.commons.cli.CommandLine)
*/
@Override
public void processOptions(IBuildStore buildStore, CommandLine cmdLine) {
optionForceRm = cmdLine.hasOption("force-rm-file");
optionRecursive = cmdLine.hasOption("recursive");
}
/*-------------------------------------------------------------------------------------*/
/* (non-Javadoc)
* @see com.buildml.main.ICliCommand#invoke(com.buildml.model.BuildStore, java.lang.String[])
*/
@Override
public void invoke(IBuildStore buildStore, String buildStorePath, String[] args) {
CliUtils.validateArgs(getName(), args, 1, 1, "You must specify a single path name.");
IFileMgr fileMgr = buildStore.getFileMgr();
IActionMgr actionMgr = buildStore.getActionMgr();
String pathName = args[0];
int pathId = fileMgr.getPath(pathName);
/* is the path valid, if so, set the root */
if (pathId != ErrorCode.BAD_PATH) {
IImportRefactorer refactor = new ImportRefactorer(buildStore);
try {
MultiUndoOp multiOp = new MultiUndoOp();
if (optionRecursive) {
refactor.deletePathTree(multiOp, pathId, optionForceRm, optionForceRm);
} else {
refactor.deletePath(multiOp, pathId, optionForceRm, optionForceRm);
}
multiOp.redo();
/*
* Handle the array of possible error cases.
*/
} catch (CanNotRefactorException e) {
String msg = "Failed to delete file: " + pathName + ". ";
switch (e.getCauseCode()) {
/* The path is currently used as input to one or more actions */
case PATH_IN_USE:
msg += "The path is in use by the following actions:\n";
msg = appendActions(actionMgr, msg, e.getCauseIDs());
break;
/* The path is still being generated by an action */
case PATH_IS_GENERATED:
msg += "This path is generated by the following action (or actions):\n";
msg = appendActions(actionMgr, msg, e.getCauseIDs());
msg += "\nUse the -f flag to force deletion of this action.\n";
break;
/* The action is still in use because a generated file is needed */
case ACTION_IN_USE:
msg += "The action that generates this file also generates additional files " +
"that are in use by other actions. The files are:\n";
msg = appendPaths(fileMgr, msg, e.getCauseIDs());
break;
/* The action is not atomic, so this operation can not proceed */
case ACTION_NOT_ATOMIC:
msg += "The action that generates this file is not atomic. Can't delete it:\n";
msg = appendActions(actionMgr, msg, e.getCauseIDs());
break;
/** Couldn't delete a directory, since it's not empty */
case DIRECTORY_NOT_EMPTY:
msg += "This directory can't be deleted because it's not empty.";
break;
default:
msg += "Unrecognized error: " + e.getCauseCode();
break;
}
CliUtils.reportErrorAndExit(msg);
}
}
/* the path we're trying to delete is invalid */
else {
CliUtils.reportErrorAndExit("Invalid path: " + pathName + ".");
}
}
/*=====================================================================================*
* PRIVATE METHODS
*=====================================================================================*/
/**
* Given a list of action IDs, append the command output of each action onto the
* existing error message. This is a helper message for display errors.
*
* @param actionMgr The ActionMgr that owns the actions.
* @param msg The error message so far (we'll append to this).
* @param actions An array of action IDs.
* @return The original "msg" parameter, which the action summaries appended to it.
*/
private String appendActions(IActionMgr actionMgr, String msg, Integer[] actions) {
for (int actionId : actions) {
msg += "\n" + actionMgr.getSlotValue(actionId, IActionMgr.COMMAND_SLOT_ID) + "\n";
}
return msg;
}
/*-------------------------------------------------------------------------------------*/
/**
* Given a list of path IDs, append each path name onto the existing error message.
* This is a helper message for display errors.
*
* @param fileMgr The FileMgr that owns the paths.
* @param msg The error message so far (we'll append to this).
* @param paths An array of path IDs.
* @return The original "msg" parameter, which the path names appended to it.
*/
private String appendPaths(IFileMgr fileMgr, String msg, Integer[] paths) {
for (int pathId : paths) {
msg += "\n " + fileMgr.getPathName(pathId) + "\n";
}
return msg;
}
/*-------------------------------------------------------------------------------------*/
}