diff options
Diffstat (limited to 'src')
10 files changed, 290 insertions, 3 deletions
diff --git a/src/com/cyanogenmod/explorer/commands/ExecExecutable.java b/src/com/cyanogenmod/explorer/commands/ExecExecutable.java new file mode 100644 index 0000000..d743ace --- /dev/null +++ b/src/com/cyanogenmod/explorer/commands/ExecExecutable.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed 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 com.cyanogenmod.explorer.commands; + +/** + * An interface that represents an executable for execute a command + */ +public interface ExecExecutable extends AsyncResultExecutable { + + /** + * Method that returns the exit code of the executed program + * + * @return int The exit code + */ + public int getExitCode(); +} diff --git a/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java b/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java index 5a4f2f3..4e61f57 100644 --- a/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java +++ b/src/com/cyanogenmod/explorer/commands/ExecutableCreator.java @@ -158,6 +158,17 @@ public interface ExecutableCreator { EchoExecutable createEchoExecutable(String msg) throws CommandNotFoundException; /** + * Method that execute a command + * + * @param cmd The command to execute + * @param asyncResultListener The listener where to return partial results + * @return ExecExecutable A {@link ExecExecutable} executable implementation reference + * @throws CommandNotFoundException If the executable can't be created + */ + ExecExecutable createExecExecutable( + String cmd, AsyncResultListener asyncResultListener) throws CommandNotFoundException; + + /** * Method that creates an executable for make searches over the filesystem. * * @param directory The directory where to search diff --git a/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgram.java b/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgram.java index e765369..480f7f1 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgram.java +++ b/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgram.java @@ -31,12 +31,25 @@ import java.util.List; public abstract class AsyncResultProgram extends Program implements AsyncResultExecutable, AsyncResultProgramListener { + /** + * @hide + */ + static final Byte STDIN = new Byte((byte)0); + /** + * @hide + */ + static final Byte STDERR = new Byte((byte)1); + private final AsyncResultListener mAsyncResultListener; private AsyncResultProgramThread mWorkerThread; /** * @hide */ final List<String> mPartialData; + /** + * @hide + */ + final List<Byte> mPartialDataType; private final Object mSync = new Object(); /** * @hide @@ -79,6 +92,7 @@ public abstract class AsyncResultProgram super(id, prepare, args); this.mAsyncResultListener = asyncResultListener; this.mPartialData = Collections.synchronizedList(new ArrayList<String>()); + this.mPartialDataType = Collections.synchronizedList(new ArrayList<Byte>()); this.mTempBuffer = new StringBuffer(); this.mOnCancelListener = null; this.mCanceled = false; @@ -158,6 +172,35 @@ public abstract class AsyncResultProgram data = this.mTempBuffer.append(partialIn.substring(0, pos + 1)).toString(); } + this.mPartialDataType.add(STDIN); + this.mPartialData.add(data); + this.mTempBuffer = new StringBuffer(); + this.mSync.notify(); + } + } + + /** + * Method that parse the error result of a program invocation. + * + * @param partialErr A partial standard err buffer (incremental buffer) + * @hide + */ + public final void parsePartialErrResult(String partialErr) { + synchronized (this.mSync) { + String data = partialErr; + if (parseOnlyCompleteLines()) { + int pos = partialErr.lastIndexOf(FileHelper.NEWLINE); + if (pos == -1) { + //Save partial data + this.mTempBuffer.append(partialErr); + return; + } + + //Retrieve the data + data = this.mTempBuffer.append(partialErr.substring(0, pos + 1)).toString(); + } + + this.mPartialDataType.add(STDERR); this.mPartialData.add(data); this.mTempBuffer = new StringBuffer(); this.mSync.notify(); @@ -265,9 +308,14 @@ public abstract class AsyncResultProgram if (!this.mAlive) { return; } + Byte type = AsyncResultProgram.this.mPartialDataType.remove(0); String data = AsyncResultProgram.this.mPartialData.remove(0); try { - AsyncResultProgram.this.onParsePartialResult(data); + if (type.compareTo(STDIN) == 0) { + AsyncResultProgram.this.onParsePartialResult(data); + } else { + AsyncResultProgram.this.onParseErrorPartialResult(data); + } } catch (Throwable ex) { /**NON BLOCK**/ } diff --git a/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgramListener.java b/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgramListener.java index 9e4e058..dc57cfc 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgramListener.java +++ b/src/com/cyanogenmod/explorer/commands/shell/AsyncResultProgramListener.java @@ -40,4 +40,11 @@ public interface AsyncResultProgramListener { * @param partialIn A partial standard input buffer (incremental buffer) */ void onParsePartialResult(String partialIn); + + /** + * Method invoked when a parse of new error results are needed. + * + * @param partialErr A partial standard err buffer (incremental buffer) + */ + void onParseErrorPartialResult(String partialErr); } diff --git a/src/com/cyanogenmod/explorer/commands/shell/ExecCommand.java b/src/com/cyanogenmod/explorer/commands/shell/ExecCommand.java new file mode 100644 index 0000000..dff4c36 --- /dev/null +++ b/src/com/cyanogenmod/explorer/commands/shell/ExecCommand.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2012 The CyanogenMod Project + * + * Licensed 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 com.cyanogenmod.explorer.commands.shell; + +import com.cyanogenmod.explorer.commands.AsyncResultListener; +import com.cyanogenmod.explorer.commands.ExecExecutable; +import com.cyanogenmod.explorer.console.CommandNotFoundException; +import com.cyanogenmod.explorer.console.ExecutionException; +import com.cyanogenmod.explorer.console.InsufficientPermissionsException; + +/** + * A class for execute a command + * + * {@link "http://unixhelp.ed.ac.uk/CGI/man-cgi?sh"} + */ +public class ExecCommand extends AsyncResultProgram implements ExecExecutable { + + private static final String ID = "exec"; //$NON-NLS-1$ + + private int mExitCode; + + /** + * Constructor of <code>ExecCommand</code>. + * + * @param cmd The "absolute" directory to compute + * @param asyncResultListener The partial result listener + * @throws InvalidCommandDefinitionException If the command has an invalid definition + */ + public ExecCommand( + String cmd, AsyncResultListener asyncResultListener) + throws InvalidCommandDefinitionException { + super(ID, asyncResultListener, new String[]{cmd}); + } + + /** + * {@inheritDoc} + */ + @Override + public void onStartParsePartialResult() { + this.mExitCode = 0; + } + + /** + * {@inheritDoc} + */ + @Override + public void onEndParsePartialResult(boolean cancelled) {/** NON BLOCK **/} + + /** + * {@inheritDoc} + */ + @Override + public void onParsePartialResult(final String partialIn) { + //If a listener is defined, then send the partial result + if (partialIn != null && partialIn.length() > 0) { + if (getAsyncResultListener() != null) { + getAsyncResultListener().onPartialResult(partialIn); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onParseErrorPartialResult(String partialErr) { + //If a listener is defined, then send the partial result + if (partialErr != null && partialErr.length() > 0) { + if (getAsyncResultListener() != null) { + getAsyncResultListener().onPartialResult(partialErr); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public int getExitCode() { + return this.mExitCode; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isIgnoreShellStdErrCheck() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public void checkExitCode(int exitCode) + throws InsufficientPermissionsException, CommandNotFoundException, ExecutionException { + this.mExitCode = exitCode; + } +} diff --git a/src/com/cyanogenmod/explorer/commands/shell/FindCommand.java b/src/com/cyanogenmod/explorer/commands/shell/FindCommand.java index 7a2e3d0..11c237b 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/FindCommand.java +++ b/src/com/cyanogenmod/explorer/commands/shell/FindCommand.java @@ -193,6 +193,12 @@ public class FindCommand extends AsyncResultProgram implements FindExecutable { * {@inheritDoc} */ @Override + public void onParseErrorPartialResult(String partialErr) {/**NON BLOCK**/} + + /** + * {@inheritDoc} + */ + @Override public boolean isIgnoreShellStdErrCheck() { return true; } diff --git a/src/com/cyanogenmod/explorer/commands/shell/FolderUsageCommand.java b/src/com/cyanogenmod/explorer/commands/shell/FolderUsageCommand.java index b662c57..d2084c2 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/FolderUsageCommand.java +++ b/src/com/cyanogenmod/explorer/commands/shell/FolderUsageCommand.java @@ -46,7 +46,7 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag private static final String TAG = "FolderUsageCommand"; //$NON-NLS-1$ - private static final String ID_FOLDER_USAGE_DIRECTORY = "folderusage"; //$NON-NLS-1$ + private static final String ID = "folderusage"; //$NON-NLS-1$ private final String mDirectory; private FolderUsage mFolderUsage; @@ -62,7 +62,7 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag public FolderUsageCommand( String directory, AsyncResultListener asyncResultListener) throws InvalidCommandDefinitionException { - super(ID_FOLDER_USAGE_DIRECTORY, asyncResultListener, new String[]{directory}); + super(ID, asyncResultListener, new String[]{directory}); this.mFolderUsage = new FolderUsage(directory); this.mPartial = ""; //$NON-NLS-1$ this.mDirectory = directory; @@ -185,6 +185,12 @@ public class FolderUsageCommand extends AsyncResultProgram implements FolderUsag * {@inheritDoc} */ @Override + public void onParseErrorPartialResult(String partialErr) {/**NON BLOCK**/} + + /** + * {@inheritDoc} + */ + @Override public boolean isIgnoreShellStdErrCheck() { return true; } diff --git a/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java b/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java index 8e308e8..909f4bc 100644 --- a/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java +++ b/src/com/cyanogenmod/explorer/commands/shell/ShellExecutableCreator.java @@ -28,6 +28,7 @@ import com.cyanogenmod.explorer.commands.DeleteDirExecutable; import com.cyanogenmod.explorer.commands.DeleteFileExecutable; import com.cyanogenmod.explorer.commands.DiskUsageExecutable; import com.cyanogenmod.explorer.commands.EchoExecutable; +import com.cyanogenmod.explorer.commands.ExecExecutable; import com.cyanogenmod.explorer.commands.ExecutableCreator; import com.cyanogenmod.explorer.commands.FindExecutable; import com.cyanogenmod.explorer.commands.FolderUsageExecutable; @@ -224,6 +225,19 @@ public class ShellExecutableCreator implements ExecutableCreator { * {@inheritDoc} */ @Override + public ExecExecutable createExecExecutable( + String cmd, AsyncResultListener asyncResultListener) throws CommandNotFoundException { + try { + return new ExecCommand(cmd, asyncResultListener); + } catch (InvalidCommandDefinitionException icdEx) { + throw new CommandNotFoundException("ExecCommand", icdEx); //$NON-NLS-1$ + } + } + + /** + * {@inheritDoc} + */ + @Override public FindExecutable createFindExecutable( String directory, Query query, AsyncResultListener asyncResultListener) throws CommandNotFoundException { diff --git a/src/com/cyanogenmod/explorer/console/shell/ShellConsole.java b/src/com/cyanogenmod/explorer/console/shell/ShellConsole.java index 0f4c5e9..8e4b7e2 100644 --- a/src/com/cyanogenmod/explorer/console/shell/ShellConsole.java +++ b/src/com/cyanogenmod/explorer/console/shell/ShellConsole.java @@ -724,6 +724,15 @@ public abstract class ShellConsole extends Console { if (!ShellConsole.this.mCancelled) { ShellConsole.this.mSbErr.append((char)r); sb.append((char)r); + + //Notify asynchronous partial data + if (ShellConsole.this.mStarted && + ShellConsole.this.mActiveCommand != null && + ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) { + AsyncResultProgram program = + ((AsyncResultProgram)ShellConsole.this.mActiveCommand); + program.parsePartialErrResult(new String(new char[]{(char)r})); + } } //Has more data? Read with available as more as exists @@ -743,6 +752,14 @@ public abstract class ShellConsole extends Console { ShellConsole.this.mSbErr.append(s); sb.append(s); + //Notify asynchronous partial data + if (ShellConsole.this.mActiveCommand != null && + ShellConsole.this.mActiveCommand instanceof AsyncResultProgram) { + AsyncResultProgram program = + ((AsyncResultProgram)ShellConsole.this.mActiveCommand); + program.parsePartialErrResult(s); + } + //Wait for buffer to be filled try { Thread.sleep(50L); diff --git a/src/com/cyanogenmod/explorer/util/CommandHelper.java b/src/com/cyanogenmod/explorer/util/CommandHelper.java index f9793b8..4ea9dfa 100644 --- a/src/com/cyanogenmod/explorer/util/CommandHelper.java +++ b/src/com/cyanogenmod/explorer/util/CommandHelper.java @@ -31,6 +31,7 @@ import com.cyanogenmod.explorer.commands.DeleteDirExecutable; import com.cyanogenmod.explorer.commands.DeleteFileExecutable; import com.cyanogenmod.explorer.commands.DiskUsageExecutable; import com.cyanogenmod.explorer.commands.EchoExecutable; +import com.cyanogenmod.explorer.commands.ExecExecutable; import com.cyanogenmod.explorer.commands.Executable; import com.cyanogenmod.explorer.commands.FindExecutable; import com.cyanogenmod.explorer.commands.FolderUsageExecutable; @@ -734,6 +735,40 @@ public final class CommandHelper { } /** + * Method that executes a command. + * + * @param context The current context (needed if console == null) + * @param cmd The command to execute + * @param asyncResultListener The partial result listener + * @param console The console in which execute the program. + * <code>null</code> to attach to the default console + * @return AsyncResultProgram The command executed in background + * @throws FileNotFoundException If the initial directory not exists + * @throws IOException If initial directory can't not be checked + * @throws InvalidCommandDefinitionException If the command has an invalid definition + * @throws NoSuchFileOrDirectory If the file or directory was not found + * @throws ConsoleAllocException If the console can't be allocated + * @throws InsufficientPermissionsException If an operation requires elevated permissions + * @throws CommandNotFoundException If the command was not found + * @throws OperationTimeoutException If the operation exceeded the maximum time of wait + * @throws ExecutionException If the operation returns a invalid exit code + * @see AsyncResultExecutable + */ + public static AsyncResultExecutable exec( + Context context, String cmd, AsyncResultListener asyncResultListener, Console console) + throws FileNotFoundException, IOException, ConsoleAllocException, + NoSuchFileOrDirectory, InsufficientPermissionsException, + CommandNotFoundException, OperationTimeoutException, + ExecutionException, InvalidCommandDefinitionException { + Console c = ensureConsole(context, console); + ExecExecutable executable = + c.getExecutableFactory().newCreator(). + createExecExecutable(cmd, asyncResultListener); + execute(context, executable, c); + return executable; + } + + /** * Method that does a search in a directory tree seeking for some terms. * * @param context The current context (needed if console == null) |
