mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -92,8 +92,9 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
private static final String DEFAULT_LOGGER_CONFIG = "defaultLogConfig.xml";
|
||||
private volatile OSProcessHandler myProcessHandler;
|
||||
private final File mySystemDirectory;
|
||||
private volatile CompileServerClient myClient = new CompileServerClient();
|
||||
private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new SequentialTaskExecutor.AsyncTaskExecutor() {
|
||||
@Nullable
|
||||
private volatile CompileServerClient myClient;
|
||||
private final SequentialTaskExecutor myTaskExecutor = new SequentialTaskExecutor(new AsyncTaskExecutor() {
|
||||
public void submit(Runnable runnable) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(runnable);
|
||||
}
|
||||
@@ -102,6 +103,12 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
private static final int MAKE_TRIGGER_DELAY = 5 * 1000 /*5 seconds*/;
|
||||
private final Map<RequestFuture, Project> myAutomakeFutures = new HashMap<RequestFuture, Project>();
|
||||
private final CompileServerClasspathManager myClasspathManager = new CompileServerClasspathManager();
|
||||
private final AsyncTaskExecutor myAsyncExec = new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(runnable);
|
||||
}
|
||||
};
|
||||
|
||||
public CompileServerManager(final ProjectManager projectManager) {
|
||||
myProjectManager = projectManager;
|
||||
@@ -394,7 +401,8 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
}
|
||||
|
||||
final int port = NetUtils.findAvailableSocketPort();
|
||||
final Process process = launchServer(port);
|
||||
final long serverPingInterval = Registry.intValue("compiler.server.ping.interval", -1) * 1000L;
|
||||
final Process process = launchServer(port, serverPingInterval);
|
||||
|
||||
final OSProcessHandler processHandler = new OSProcessHandler(process, null) {
|
||||
protected boolean shouldDestroyProcessRecursively() {
|
||||
@@ -451,7 +459,7 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
throw new Exception("Server startup failed: " + startupMsg);
|
||||
}
|
||||
|
||||
CompileServerClient client = new CompileServerClient();
|
||||
CompileServerClient client = new CompileServerClient(serverPingInterval, myAsyncExec);
|
||||
boolean connected = false;
|
||||
try {
|
||||
connected = client.connect(NetUtils.getLocalHostString(), port);
|
||||
@@ -545,7 +553,7 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
// commandLine.add((launcherUsed? "-J" : "") + "-D" + CharsetToolkit.FILE_ENCODING_PROPERTY + "=" + CharsetToolkit.getDefaultSystemCharset().name());
|
||||
//}
|
||||
|
||||
private Process launchServer(final int port) throws ExecutionException {
|
||||
private Process launchServer(final int port, long pingInterval) throws ExecutionException {
|
||||
// validate tools.jar presence
|
||||
final JavaCompiler systemCompiler = ToolProvider.getSystemJavaCompiler();
|
||||
if (systemCompiler == null) {
|
||||
@@ -561,7 +569,10 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
cmdLine.addParameter("-XX:ReservedCodeCacheSize=64m");
|
||||
cmdLine.addParameter("-Xmx" + Registry.intValue("compiler.server.heap.size") + "m");
|
||||
cmdLine.addParameter("-Djava.awt.headless=true");
|
||||
//cmdLine.addParameter("-DuseJavaUtilZip");
|
||||
//noinspection ConstantConditions
|
||||
if (pingInterval > 0L) {
|
||||
cmdLine.addParameter("-D" + GlobalOptions.PING_INTERVAL_MS_OPTION + "=" + pingInterval);
|
||||
}
|
||||
final String additionalOptions = Registry.stringValue("compiler.server.vm.options");
|
||||
if (!StringUtil.isEmpty(additionalOptions)) {
|
||||
final StringTokenizer tokenizer = new StringTokenizer(additionalOptions, " ", false);
|
||||
|
||||
+25
-3
@@ -1414,13 +1414,35 @@ public class TranslatingCompilerFilesMonitor implements ApplicationComponent {
|
||||
private class MyVfsListener extends VirtualFileAdapter {
|
||||
public void propertyChanged(final VirtualFilePropertyEvent event) {
|
||||
if (VirtualFile.PROP_NAME.equals(event.getPropertyName())) {
|
||||
final VirtualFile file = event.getFile();
|
||||
final VirtualFile eventFile = event.getFile();
|
||||
final VirtualFile parent = event.getParent();
|
||||
if (parent != null) {
|
||||
final String oldName = (String)event.getOldValue();
|
||||
CompileServerManager.getInstance().notifyFilesDeleted(Collections.singleton(parent.getPath() + "/" + oldName));
|
||||
final String root = parent.getPath() + "/" + oldName;
|
||||
final Set<String> toMark;
|
||||
if (eventFile.isDirectory()) {
|
||||
toMark = new HashSet<String>();
|
||||
new Object() {
|
||||
void process(VirtualFile file, String filePath) {
|
||||
if (file.isDirectory()) {
|
||||
for (VirtualFile child : file.getChildren()) {
|
||||
process(child, filePath + "/" + child.getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
toMark.add(filePath);
|
||||
}
|
||||
}
|
||||
}.process(eventFile, root);
|
||||
}
|
||||
else {
|
||||
toMark = Collections.singleton(root);
|
||||
}
|
||||
if (!toMark.isEmpty()) {
|
||||
CompileServerManager.getInstance().notifyFilesDeleted(toMark);
|
||||
}
|
||||
}
|
||||
markDirtyIfSource(file, false);
|
||||
markDirtyIfSource(eventFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+15
-2
@@ -45,6 +45,8 @@ import com.intellij.openapi.wm.WindowManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.*;
|
||||
import com.intellij.psi.impl.PsiDiamondTypeUtil;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspCodeBlock;
|
||||
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
|
||||
import com.intellij.psi.impl.source.resolve.DefaultParameterTypeInferencePolicy;
|
||||
import com.intellij.psi.impl.source.tree.java.ReplaceExpressionUtil;
|
||||
import com.intellij.psi.util.PsiExpressionTrimRenderer;
|
||||
@@ -534,11 +536,11 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
supportProvider != null &&
|
||||
editor.getSettings().isVariableInplaceRenameEnabled() &&
|
||||
supportProvider.isInplaceIntroduceAvailable(expr, nameSuggestionContext) &&
|
||||
!ApplicationManager.getApplication().isUnitTestMode();
|
||||
!ApplicationManager.getApplication().isUnitTestMode() &&
|
||||
!isInJspHolderMethod(expr);
|
||||
final boolean inFinalContext = occurenceManager.isInFinalContext();
|
||||
final InputValidator validator = new InputValidator(this, project, anchorStatementIfAll, anchorStatement, occurenceManager);
|
||||
final TypeSelectorManagerImpl typeSelectorManager = new TypeSelectorManagerImpl(project, originalType, expr, occurrences);
|
||||
|
||||
final boolean[] wasSucceed = new boolean[]{true};
|
||||
final Pass<OccurrencesChooser.ReplaceChoice> callback = new Pass<OccurrencesChooser.ReplaceChoice>() {
|
||||
@Override
|
||||
@@ -599,6 +601,17 @@ public abstract class IntroduceVariableBase extends IntroduceHandlerBase {
|
||||
return wasSucceed[0];
|
||||
}
|
||||
|
||||
private static boolean isInJspHolderMethod(PsiExpression expr) {
|
||||
final PsiElement parent1 = expr.getParent();
|
||||
if (parent1 == null) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement parent2 = parent1.getParent();
|
||||
if (!(parent2 instanceof JspCodeBlock)) return false;
|
||||
final PsiElement parent3 = parent2.getParent();
|
||||
return parent3 instanceof JspHolderMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if write usages found
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.jetbrains.jps.api;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 2/28/12
|
||||
*/
|
||||
public interface AsyncTaskExecutor {
|
||||
AsyncTaskExecutor DEFAULT = new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
new Thread(runnable).start();
|
||||
}
|
||||
};
|
||||
|
||||
void submit(Runnable runnable);
|
||||
}
|
||||
@@ -10,6 +10,5 @@ public interface GlobalOptions {
|
||||
String USE_EXTERNAL_JAVAC_OPTION = "use.external.javac.process";
|
||||
String HOSTNAME_OPTION = "localhost.name";
|
||||
String VM_EXE_PATH_OPTION = "vm.executable.path";
|
||||
|
||||
long SERVER_PING_PERIOD = 2000L; // 2 sec
|
||||
String PING_INTERVAL_MS_OPTION = "server.ping.interval";
|
||||
}
|
||||
|
||||
@@ -31,10 +31,6 @@ public class SequentialTaskExecutor {
|
||||
}
|
||||
};
|
||||
|
||||
public interface AsyncTaskExecutor {
|
||||
void submit(Runnable runnable);
|
||||
}
|
||||
|
||||
public SequentialTaskExecutor(AsyncTaskExecutor executor) {
|
||||
myExecutor = executor;
|
||||
}
|
||||
|
||||
@@ -18,15 +18,17 @@ import java.util.concurrent.TimeUnit;
|
||||
public class CompileServerClient extends SimpleProtobufClient<JpsServerResponseHandler> {
|
||||
private static final ScheduledThreadPoolExecutor ourPingService = ConcurrencyUtil.newSingleScheduledThreadExecutor("Compile server ping thread", Thread.MIN_PRIORITY);
|
||||
private volatile ScheduledFuture<?> myPingFuture;
|
||||
private final long myServerPingInterval;
|
||||
|
||||
public CompileServerClient() {
|
||||
super(JpsRemoteProto.Message.getDefaultInstance(), new UUIDGetter() {
|
||||
public CompileServerClient(long serverPingInterval, final AsyncTaskExecutor asyncExec) {
|
||||
super(JpsRemoteProto.Message.getDefaultInstance(), asyncExec, new UUIDGetter() {
|
||||
@NotNull
|
||||
public UUID getSessionUUID(@NotNull MessageEvent e) {
|
||||
final JpsRemoteProto.Message message = (JpsRemoteProto.Message)e.getMessage();
|
||||
return ProtoUtil.fromProtoUUID(message.getSessionId());
|
||||
}
|
||||
});
|
||||
myServerPingInterval = serverPingInterval;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -89,15 +91,17 @@ public class CompileServerClient extends SimpleProtobufClient<JpsServerResponseH
|
||||
|
||||
@Override
|
||||
protected void onConnect() {
|
||||
myPingFuture = ourPingService.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final JpsRemoteProto.Message.Request ping = ProtoUtil.createPingRequest();
|
||||
if (isConnected()) {
|
||||
sendRequest(ping, null);
|
||||
if (myServerPingInterval > 0L) {
|
||||
myPingFuture = ourPingService.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final JpsRemoteProto.Message.Request ping = ProtoUtil.createPingRequest();
|
||||
if (isConnected()) {
|
||||
sendRequest(ping, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, GlobalOptions.SERVER_PING_PERIOD, GlobalOptions.SERVER_PING_PERIOD, TimeUnit.MILLISECONDS);
|
||||
}, myServerPingInterval, myServerPingInterval, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.jboss.netty.channel.ChannelStateEvent;
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jboss.netty.channel.SimpleChannelHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.AsyncTaskExecutor;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -21,10 +22,12 @@ final class ProtobufClientMessageHandler<T extends ProtobufResponseHandler> exte
|
||||
@NotNull
|
||||
private final UUIDGetter myUuidGetter;
|
||||
private final SimpleProtobufClient myClient;
|
||||
private final AsyncTaskExecutor myAsyncExec;
|
||||
|
||||
public ProtobufClientMessageHandler(@NotNull UUIDGetter uuidGetter, SimpleProtobufClient client) {
|
||||
public ProtobufClientMessageHandler(@NotNull UUIDGetter uuidGetter, SimpleProtobufClient client, AsyncTaskExecutor asyncExec) {
|
||||
myUuidGetter = uuidGetter;
|
||||
myClient = client;
|
||||
myAsyncExec = asyncExec;
|
||||
}
|
||||
|
||||
public final void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
@@ -89,7 +92,12 @@ final class ProtobufClientMessageHandler<T extends ProtobufResponseHandler> exte
|
||||
}
|
||||
finally {
|
||||
// make sure the client is in disconnected state
|
||||
myClient.scheduleDisconnect();
|
||||
myAsyncExec.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
myClient.disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.api.AsyncTaskExecutor;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
@@ -36,8 +37,8 @@ public class SimpleProtobufClient<T extends ProtobufResponseHandler> {
|
||||
protected ChannelFuture myConnectFuture;
|
||||
private final ProtobufClientMessageHandler<T> myMessageHandler;
|
||||
|
||||
public SimpleProtobufClient(final MessageLite msgDefaultInstance, final UUIDGetter uuidGetter) {
|
||||
myMessageHandler = new ProtobufClientMessageHandler<T>(uuidGetter, this);
|
||||
public SimpleProtobufClient(final MessageLite msgDefaultInstance, final AsyncTaskExecutor asyncExec, final UUIDGetter uuidGetter) {
|
||||
myMessageHandler = new ProtobufClientMessageHandler<T>(uuidGetter, this, asyncExec);
|
||||
myChannelFactory = new NioClientSocketChannelFactory(ourExecutor, ourExecutor, 1);
|
||||
myPipelineFactory = new ChannelPipelineFactory() {
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
@@ -105,15 +106,6 @@ public class SimpleProtobufClient<T extends ProtobufResponseHandler> {
|
||||
protected void onDisconnect() {
|
||||
}
|
||||
|
||||
public final void scheduleDisconnect() {
|
||||
ourExecutor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
disconnect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public final void disconnect() {
|
||||
if (myState.compareAndSet(State.CONNECTED, State.DISCONNECTING)) {
|
||||
try {
|
||||
@@ -154,23 +146,31 @@ public class SimpleProtobufClient<T extends ProtobufResponseHandler> {
|
||||
public final RequestFuture<T> sendMessage(final UUID messageId, MessageLite message, @Nullable final T responseHandler, @Nullable final RequestFuture.CancelAction<T> cancelAction) {
|
||||
final RequestFuture<T> requestFuture = new RequestFuture<T>(responseHandler, messageId, cancelAction);
|
||||
myMessageHandler.registerFuture(messageId, requestFuture);
|
||||
final ChannelFuture channelFuture = Channels.write(myConnectFuture.getChannel(), message);
|
||||
channelFuture.addListener(new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (!future.isSuccess()) {
|
||||
try {
|
||||
myMessageHandler.removeFuture(messageId);
|
||||
if (responseHandler != null) {
|
||||
responseHandler.sessionTerminated();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
requestFuture.setDone();
|
||||
final Channel channel = myConnectFuture.getChannel();
|
||||
if (channel.isConnected()) {
|
||||
Channels.write(channel, message).addListener(new ChannelFutureListener() {
|
||||
public void operationComplete(ChannelFuture future) throws Exception {
|
||||
if (!future.isSuccess()) {
|
||||
notifyTerminated(messageId, requestFuture, responseHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
notifyTerminated(messageId, requestFuture, responseHandler);
|
||||
}
|
||||
return requestFuture;
|
||||
}
|
||||
|
||||
private void notifyTerminated(UUID messageId, RequestFuture<T> requestFuture, @Nullable T responseHandler) {
|
||||
try {
|
||||
myMessageHandler.removeFuture(messageId);
|
||||
if (responseHandler != null) {
|
||||
responseHandler.sessionTerminated();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
requestFuture.setDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,11 +170,11 @@ public class IncProjectBuilder {
|
||||
runTasks(context, myBuilderRegistry.getBeforeTasks());
|
||||
|
||||
context.setCompilingTests(false);
|
||||
context.processMessage(new ProgressMessage("Building production sources"));
|
||||
context.processMessage(new ProgressMessage("Checking production sources"));
|
||||
buildChunks(context, myProductionChunks);
|
||||
|
||||
context.setCompilingTests(true);
|
||||
context.processMessage(new ProgressMessage("Building test sources"));
|
||||
context.processMessage(new ProgressMessage("Checking test sources"));
|
||||
buildChunks(context, myTestChunks);
|
||||
|
||||
context.processMessage(new ProgressMessage("Building project"));
|
||||
@@ -290,10 +290,12 @@ public class IncProjectBuilder {
|
||||
if (context.isMake()) {
|
||||
// cleanup outputs
|
||||
final Set<String> allChunkRemovedSources = new HashSet<String>();
|
||||
final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap();
|
||||
|
||||
for (Module module : chunk.getModules()) {
|
||||
final Collection<String> deletedPaths = myProjectDescriptor.fsState.getDeletedPaths(module, context.isCompilingTests());
|
||||
if (deletedPaths.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
allChunkRemovedSources.addAll(deletedPaths);
|
||||
|
||||
final String moduleName = module.getName().toLowerCase(Locale.US);
|
||||
@@ -304,29 +306,31 @@ public class IncProjectBuilder {
|
||||
// deleting outputs corresponding to non-existing source
|
||||
final Collection<String> outputs = sourceToOutputStorage.getState(deletedSource);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
if (outputs.size() > 0) {
|
||||
final String[] buffer = new String[outputs.size()];
|
||||
int i = 0;
|
||||
for (final String o : outputs) {
|
||||
buffer[i++] = o;
|
||||
}
|
||||
Arrays.sort(buffer);
|
||||
LOG.info("Cleaning output files:");
|
||||
for(final String o : buffer) {
|
||||
LOG.info(o);
|
||||
}
|
||||
LOG.info("End of files");
|
||||
}
|
||||
}
|
||||
|
||||
if (outputs != null) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
if (outputs.size() > 0) {
|
||||
final String[] buffer = new String[outputs.size()];
|
||||
int i = 0;
|
||||
for (final String o : outputs) {
|
||||
buffer[i++] = o;
|
||||
}
|
||||
Arrays.sort(buffer);
|
||||
LOG.info("Cleaning output files:");
|
||||
for(final String o : buffer) {
|
||||
LOG.info(o);
|
||||
}
|
||||
LOG.info("End of files");
|
||||
}
|
||||
}
|
||||
|
||||
for (String output : outputs) {
|
||||
FileUtil.delete(new File(output));
|
||||
}
|
||||
sourceToOutputStorage.remove(deletedSource);
|
||||
}
|
||||
|
||||
// check if deleted source was associated with a form
|
||||
final SourceToFormMapping sourceToFormMap = context.getDataManager().getSourceToFormMap();
|
||||
final String formPath = sourceToFormMap.getState(deletedSource);
|
||||
if (formPath != null) {
|
||||
final File formFile = new File(formPath);
|
||||
|
||||
@@ -92,6 +92,7 @@ public abstract class AbstractStateStorage<Key, T> {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T getState(Key key) throws IOException {
|
||||
synchronized (myDataLock) {
|
||||
return myMap.get(key);
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import com.intellij.util.io.IOUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
@@ -46,6 +47,7 @@ public final class SourceToOutputMapping extends AbstractStateStorage<String, Co
|
||||
super.remove(FileUtil.toSystemIndependentName(srcPath));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Collection<String> getState(@NotNull String srcPath) throws IOException {
|
||||
return super.getState(FileUtil.toSystemIndependentName(srcPath));
|
||||
|
||||
@@ -2,21 +2,31 @@ package org.jetbrains.jps.javac;
|
||||
|
||||
import org.jboss.netty.channel.MessageEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.AsyncTaskExecutor;
|
||||
import org.jetbrains.jps.api.RequestFuture;
|
||||
import org.jetbrains.jps.client.SimpleProtobufClient;
|
||||
import org.jetbrains.jps.client.UUIDGetter;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: 1/22/12
|
||||
*/
|
||||
public class JavacServerClient extends SimpleProtobufClient<JavacServerResponseHandler>{
|
||||
private static final ExecutorService ourExecutors = Executors.newCachedThreadPool();
|
||||
private static final AsyncTaskExecutor ASYNC_EXEC = new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
ourExecutors.submit(runnable);
|
||||
}
|
||||
};
|
||||
|
||||
public JavacServerClient() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), new UUIDGetter() {
|
||||
super(JavacRemoteProto.Message.getDefaultInstance(), ASYNC_EXEC, new UUIDGetter() {
|
||||
@NotNull
|
||||
public UUID getSessionUUID(@NotNull MessageEvent e) {
|
||||
final JavacRemoteProto.Message message = (JavacRemoteProto.Message)e.getMessage();
|
||||
|
||||
@@ -38,6 +38,7 @@ public class Server {
|
||||
public static final String SERVER_SUCCESS_START_MESSAGE = "Compile Server started successfully. Listening on port: ";
|
||||
public static final String SERVER_ERROR_START_MESSAGE = "Error starting Compile Server: ";
|
||||
private static final String LOG_FILE_NAME = "log.xml";
|
||||
private static final long PING_INTERVAL = Long.parseLong(System.getProperty(GlobalOptions.PING_INTERVAL_MS_OPTION, "-1"));
|
||||
|
||||
private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("compile-server");
|
||||
private final ChannelFactory myChannelFactory;
|
||||
@@ -45,6 +46,7 @@ public class Server {
|
||||
private final ExecutorService myBuildsExecutor;
|
||||
private volatile long myLastPingTime = -1L;
|
||||
private final ScheduledExecutorService myScheduler;
|
||||
private final ServerMessageHandler myMessageHandler;
|
||||
|
||||
public Server(File systemDir) {
|
||||
Paths.getInstance().setSystemRoot(systemDir);
|
||||
@@ -53,7 +55,7 @@ public class Server {
|
||||
myBuildsExecutor = Executors.newFixedThreadPool(MAX_SIMULTANEOUS_BUILD_SESSIONS);
|
||||
myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1);
|
||||
final ChannelRegistrar channelRegistrar = new ChannelRegistrar();
|
||||
final ServerMessageHandler messageHandler = new ServerMessageHandler(myBuildsExecutor, this);
|
||||
myMessageHandler = new ServerMessageHandler(myBuildsExecutor, this);
|
||||
myPipelineFactory = new ChannelPipelineFactory() {
|
||||
public ChannelPipeline getPipeline() throws Exception {
|
||||
return Channels.pipeline(
|
||||
@@ -62,7 +64,7 @@ public class Server {
|
||||
new ProtobufDecoder(JpsRemoteProto.Message.getDefaultInstance()),
|
||||
new ProtobufVarint32LengthFieldPrepender(),
|
||||
new ProtobufEncoder(),
|
||||
messageHandler
|
||||
myMessageHandler
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -76,11 +78,14 @@ public class Server {
|
||||
final Channel serverChannel = bootstrap.bind(new InetSocketAddress(listenPort));
|
||||
myAllOpenChannels.add(serverChannel);
|
||||
|
||||
startIdleMonitor();
|
||||
startActivityMonitor();
|
||||
}
|
||||
|
||||
private void startIdleMonitor() {
|
||||
final long allowedIdlePeriod = 2 * GlobalOptions.SERVER_PING_PERIOD;
|
||||
private void startActivityMonitor() {
|
||||
if (PING_INTERVAL <= 0L) {
|
||||
return;
|
||||
}
|
||||
final long allowedIdlePeriod = 2 * PING_INTERVAL;
|
||||
myScheduler.scheduleAtFixedRate(new Runnable() {
|
||||
private long myStartTime;
|
||||
@Override
|
||||
@@ -90,16 +95,16 @@ public class Server {
|
||||
if (lastPing > 0L) {
|
||||
final long elapsed = now - lastPing;
|
||||
if (elapsed > allowedIdlePeriod) {
|
||||
doStop();
|
||||
doStop(elapsed);
|
||||
}
|
||||
}
|
||||
else {
|
||||
final long start = myStartTime;
|
||||
if (start > 0) {
|
||||
final long elapsed = now - start;
|
||||
if (elapsed > 5 * GlobalOptions.SERVER_PING_PERIOD) {
|
||||
if (elapsed > 5 * PING_INTERVAL) {
|
||||
// no pings received since start
|
||||
doStop();
|
||||
doStop(elapsed);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -108,12 +113,15 @@ public class Server {
|
||||
}
|
||||
}
|
||||
|
||||
private void doStop() {
|
||||
try {
|
||||
stop();
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
private void doStop(long elapsedTime) {
|
||||
if (!myMessageHandler.hasRunningBuilds()) {
|
||||
try {
|
||||
System.out.println("Stopping compile server; reason: no pings from client received in " + elapsedTime + " ms");
|
||||
stop();
|
||||
}
|
||||
finally {
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, allowedIdlePeriod, allowedIdlePeriod, TimeUnit.MILLISECONDS);
|
||||
|
||||
@@ -36,6 +36,7 @@ class ServerMessageHandler extends SimpleChannelHandler {
|
||||
}
|
||||
|
||||
public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
myServer.pingReceived();
|
||||
final JpsRemoteProto.Message message = (JpsRemoteProto.Message)e.getMessage();
|
||||
final UUID sessionId = ProtoUtil.fromProtoUUID(message.getSessionId());
|
||||
|
||||
@@ -86,7 +87,6 @@ class ServerMessageHandler extends SimpleChannelHandler {
|
||||
break;
|
||||
|
||||
case SHUTDOWN_COMMAND :
|
||||
// todo pay attention to policy
|
||||
myBuildsExecutor.submit(new Runnable() {
|
||||
public void run() {
|
||||
final List<RunnableFuture> futures = new ArrayList<RunnableFuture>();
|
||||
@@ -139,7 +139,6 @@ class ServerMessageHandler extends SimpleChannelHandler {
|
||||
reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createCommandCompletedEvent(null));
|
||||
break;
|
||||
case PING:
|
||||
myServer.pingReceived();
|
||||
reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createCommandCompletedEvent(null));
|
||||
default:
|
||||
reply = ProtoUtil.toMessage(sessionId, ProtoUtil.createFailure("Unknown request: " + message));
|
||||
@@ -213,7 +212,7 @@ class ServerMessageHandler extends SimpleChannelHandler {
|
||||
synchronized (myTaskExecutors) {
|
||||
SequentialTaskExecutor executor = myTaskExecutors.get(projectId);
|
||||
if (executor == null) {
|
||||
executor = new SequentialTaskExecutor(new SequentialTaskExecutor.AsyncTaskExecutor() {
|
||||
executor = new SequentialTaskExecutor(new AsyncTaskExecutor() {
|
||||
@Override
|
||||
public void submit(Runnable runnable) {
|
||||
myBuildsExecutor.submit(runnable);
|
||||
@@ -226,12 +225,14 @@ class ServerMessageHandler extends SimpleChannelHandler {
|
||||
}
|
||||
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
|
||||
if (this == ctx.getPipeline().getLast()) {
|
||||
LOG.error(e);
|
||||
}
|
||||
LOG.error(e);
|
||||
ctx.sendUpstream(e);
|
||||
}
|
||||
|
||||
public boolean hasRunningBuilds() {
|
||||
return !myBuildsInProgress.isEmpty();
|
||||
}
|
||||
|
||||
private class CompilationTask implements Runnable, CanceledStatus {
|
||||
|
||||
private final UUID mySessionId;
|
||||
|
||||
@@ -260,8 +260,10 @@ public class Mappings {
|
||||
|
||||
private abstract class PostPass {
|
||||
boolean myPerformed = false;
|
||||
|
||||
abstract void perform();
|
||||
void run () {
|
||||
|
||||
void run() {
|
||||
if (!myPerformed) {
|
||||
myPerformed = true;
|
||||
perform();
|
||||
@@ -1605,7 +1607,7 @@ public class Mappings {
|
||||
}
|
||||
}
|
||||
|
||||
if (delta.isDifferentiated() && false) {
|
||||
if (delta.isDifferentiated()) {
|
||||
for (DependencyContext.S c : delta.getChangedClasses()) {
|
||||
myClassToSubclasses.remove(c);
|
||||
|
||||
@@ -1767,9 +1769,9 @@ public class Mappings {
|
||||
|
||||
@Override
|
||||
public void registerImports(final String className, final Collection<String> imports, Collection<String> staticImports) {
|
||||
for (String s: staticImports) {
|
||||
for (String s : staticImports) {
|
||||
int i = s.length() - 1;
|
||||
for (; s.charAt(i) != '.'; i--);
|
||||
for (; s.charAt(i) != '.'; i--) ;
|
||||
imports.add(s.substring(0, i));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.jetbrains.jps.idea;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.Module;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nik
|
||||
*/
|
||||
public abstract class AdditionalRootsProviderService {
|
||||
@NotNull
|
||||
public List<String> getAdditionalSourceRoots(@NotNull Module module) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getAdditionalTestSourceRoots(@NotNull Module module) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ public class IdeaProjectLoader {
|
||||
private Map<String, String> pathVariables
|
||||
private ProjectMacroExpander projectMacroExpander
|
||||
private ProjectLoadingErrorReporter errorReporter
|
||||
private static final OwnServiceLoader<AdditionalRootsProviderService> rootsProviderLoader = OwnServiceLoader.load(AdditionalRootsProviderService.class)
|
||||
|
||||
public static String guessHome(Script script) {
|
||||
File home = new File(script["gant.file"].substring("file:".length()))
|
||||
@@ -508,6 +509,15 @@ public class IdeaProjectLoader {
|
||||
currentModule.languageLevel = convertLanguageLevel(languageLevel)
|
||||
}
|
||||
|
||||
rootsProviderLoader.each {AdditionalRootsProviderService service ->
|
||||
def sourceRoots = service.getAdditionalSourceRoots(currentModule)
|
||||
def testSourceRoots = service.getAdditionalTestSourceRoots(currentModule)
|
||||
currentModule.sourceRoots.addAll(sourceRoots)
|
||||
currentModule.testRoots.addAll(testSourceRoots)
|
||||
if (!sourceRoots.isEmpty() || !testSourceRoots.isEmpty()) {
|
||||
srcFolderExists = true
|
||||
}
|
||||
}
|
||||
if (srcFolderExists) {
|
||||
if (componentTag."@inherit-compiler-output" == "true") {
|
||||
if (projectOutputPath == null) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.intellij.psi.search.scope;
|
||||
import com.intellij.openapi.roots.ProjectFileIndex;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.ProjectScope;
|
||||
import com.intellij.psi.search.scope.packageSet.AbstractPackageSet;
|
||||
import com.intellij.psi.search.scope.packageSet.NamedScope;
|
||||
import com.intellij.psi.search.scope.packageSet.NamedScopesHolder;
|
||||
@@ -37,8 +38,7 @@ public class NonProjectFilesScope extends NamedScope {
|
||||
super(NAME, new AbstractPackageSet("NonProject") {
|
||||
public boolean contains(VirtualFile file, NamedScopesHolder holder) {
|
||||
if (file == null) return true;
|
||||
final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(holder.getProject()).getFileIndex();
|
||||
return !(holder.getProject().isInitialized() && !fileIndex.isIgnored(file) && fileIndex.getContentRootForFile(file) != null);
|
||||
return !ProjectScope.getProjectScope(holder.getProject()).contains(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ public class OptimizeImportsAction extends AnAction {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
includeSubdirectories = processDirectory = false;
|
||||
}
|
||||
else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG) {
|
||||
else if (!EditorSettingsExternalizable.getInstance().getOptions().SHOW_OPIMIZE_IMPORTS_DIALOG && file != null) {
|
||||
includeSubdirectories = processDirectory = false;
|
||||
}
|
||||
else {
|
||||
|
||||
+4
@@ -16,6 +16,7 @@
|
||||
package com.intellij.codeInsight.editorActions.enter;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.lang.LanguageFormatting;
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
@@ -122,6 +123,9 @@ public class BaseIndentEnterHandler extends EnterHandlerDelegateAdapter {
|
||||
return Result.Stop;
|
||||
}
|
||||
|
||||
if (LanguageFormatting.INSTANCE.forLanguage(myLanguage) != null) {
|
||||
return Result.Continue;
|
||||
}
|
||||
EditorModificationUtil.insertStringAtCaret(editor, "\n" + lineIndent);
|
||||
editor.getCaretModel().moveToLogicalPosition(new LogicalPosition(lineNumber + 1, lineIndent.length()));
|
||||
return Result.Stop;
|
||||
|
||||
+11
-1
@@ -96,7 +96,17 @@ public class ConfigurationSettingsEditorWrapper extends SettingsEditor<RunnerAnd
|
||||
}
|
||||
}
|
||||
|
||||
myStepsPanel.setLayout(new GridLayout((stepsRows.size() + 1) / 2, 1, UIUtil.DEFAULT_HGAP, UIUtil.DEFAULT_VGAP));
|
||||
int maxStepRowWidth = 0;
|
||||
for (StepBeforeLaunchRow stepRow : stepsRows) {
|
||||
maxStepRowWidth = Math.max(maxStepRowWidth, stepRow.getPreferredSize().width);
|
||||
}
|
||||
if (maxStepRowWidth * 3 < getComponent().getPreferredSize().width || maxStepRowWidth < 200) {
|
||||
myStepsPanel.setLayout(new GridLayout(0, 3, UIUtil.DEFAULT_HGAP, UIUtil.DEFAULT_VGAP));
|
||||
} else if (maxStepRowWidth * 2 < getComponent().getPreferredSize().width || maxStepRowWidth < 300) {
|
||||
myStepsPanel.setLayout(new GridLayout(0, 2, UIUtil.DEFAULT_HGAP, UIUtil.DEFAULT_VGAP));
|
||||
} else {
|
||||
myStepsPanel.setLayout(new GridLayout(0, 1, UIUtil.DEFAULT_HGAP, UIUtil.DEFAULT_VGAP));
|
||||
}
|
||||
for (StepBeforeLaunchRow stepRow : stepsRows) {
|
||||
myStepsPanel.add(stepRow);
|
||||
}
|
||||
|
||||
@@ -142,6 +142,7 @@ public abstract class DialogWrapper {
|
||||
};
|
||||
private List<JBOptionButton> myOptionsButtons = new ArrayList<JBOptionButton>();
|
||||
private int myCurrentOptionsButtonIndex = -1;
|
||||
private boolean myResizeInProgress = false;
|
||||
|
||||
protected String getDoNotShowMessage() {
|
||||
return CommonBundle.message("dialog.options.do.not.show");
|
||||
@@ -167,6 +168,14 @@ public abstract class DialogWrapper {
|
||||
*/
|
||||
protected DialogWrapper(Project project, boolean canBeParent) {
|
||||
myPeer = createPeer(project, canBeParent);
|
||||
myPeer.getWindow().addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentResized(ComponentEvent e) {
|
||||
if (!myResizeInProgress) {
|
||||
myActualSize = myPeer.getSize();
|
||||
}
|
||||
}
|
||||
});
|
||||
createDefaultActions();
|
||||
}
|
||||
|
||||
@@ -1611,8 +1620,10 @@ public abstract class DialogWrapper {
|
||||
|
||||
private void resizeWithAnimation(final Dimension size) {
|
||||
//todo[kb]: fix this PITA
|
||||
myResizeInProgress = true;
|
||||
if (!Registry.is("enable.animation.on.dialogs")) {
|
||||
setSize(size.width, size.height);
|
||||
myResizeInProgress = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1637,6 +1648,7 @@ public abstract class DialogWrapper {
|
||||
if (myErrorText.shouldBeVisible()) {
|
||||
myErrorText.setVisible(true);
|
||||
}
|
||||
myResizeInProgress = false;
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshQueue;
|
||||
import com.intellij.openapi.vfs.newvfs.RefreshSession;
|
||||
import com.intellij.util.Alarm;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.beans.PropertyChangeEvent;
|
||||
@@ -48,6 +49,7 @@ public class SaveAndSyncHandler implements ApplicationComponent {
|
||||
|
||||
private final AtomicInteger myBlockSaveOnFrameDeactivationCount = new AtomicInteger();
|
||||
private final AtomicInteger myBlockSyncOnFrameActivationCount = new AtomicInteger();
|
||||
private final Alarm myRefreshDelayAlarm = new Alarm(Alarm.ThreadToUse.SWING_THREAD);
|
||||
|
||||
public static SaveAndSyncHandler getInstance(){
|
||||
return ApplicationManager.getApplication().getComponent(SaveAndSyncHandler.class);
|
||||
@@ -157,7 +159,8 @@ public class SaveAndSyncHandler implements ApplicationComponent {
|
||||
}
|
||||
|
||||
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
myRefreshDelayAlarm.cancelAllRequests();
|
||||
myRefreshDelayAlarm.addRequest(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (canSyncOrSave()) {
|
||||
@@ -166,7 +169,7 @@ public class SaveAndSyncHandler implements ApplicationComponent {
|
||||
|
||||
maybeRefresh(ModalityState.NON_MODAL);
|
||||
}
|
||||
}, ModalityState.NON_MODAL);
|
||||
}, 300, ModalityState.NON_MODAL);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("exit: synchronize()");
|
||||
@@ -213,4 +216,4 @@ public class SaveAndSyncHandler implements ApplicationComponent {
|
||||
public void unblockSyncOnFrameActivation() {
|
||||
myBlockSyncOnFrameActivationCount.decrementAndGet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,7 @@ import com.intellij.ide.presentation.VirtualFilePresentation;
|
||||
import com.intellij.ide.util.PropertiesComponent;
|
||||
import com.intellij.openapi.actionSystem.DataProvider;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.application.AccessToken;
|
||||
import com.intellij.openapi.application.WriteAction;
|
||||
import com.intellij.openapi.application.ex.ApplicationManagerEx;
|
||||
import com.intellij.openapi.diff.DiffRequest;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
|
||||
@@ -275,15 +274,14 @@ public class VirtualFileDiffElement extends DiffElement<VirtualFile> {
|
||||
}
|
||||
|
||||
if (!docsToSave.isEmpty()) {
|
||||
AccessToken token = WriteAction.start();
|
||||
try {
|
||||
for (Document document : docsToSave) {
|
||||
manager.saveDocument(document);
|
||||
ApplicationManagerEx.getApplicationEx().runEdtSafeAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Document document : docsToSave) {
|
||||
manager.saveDocument(document);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
token.finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!FileWatcher.getInstance().isWatched(virtualFile)) {
|
||||
((NewVirtualFile)virtualFile).markDirtyRecursively();
|
||||
|
||||
+21
-2
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.diff.impl.highlighting;
|
||||
|
||||
import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.diff.DiffContent;
|
||||
import com.intellij.openapi.diff.impl.ContentChangeListener;
|
||||
@@ -24,7 +25,9 @@ import com.intellij.openapi.diff.impl.DiffVersionComponent;
|
||||
import com.intellij.openapi.diff.impl.util.ContentDocumentListener;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.editor.EditorFactory;
|
||||
import com.intellij.openapi.editor.ex.DocumentEx;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.editor.impl.EditorImpl;
|
||||
import com.intellij.openapi.fileEditor.FileEditor;
|
||||
import com.intellij.openapi.fileEditor.FileEditorProvider;
|
||||
import com.intellij.openapi.fileEditor.TextEditor;
|
||||
@@ -65,11 +68,11 @@ class EditorPlaceHolder extends DiffMarkup implements DiffVersionComponent {
|
||||
}
|
||||
|
||||
public void setContent(final DiffContent content) {
|
||||
runRegisteredDisposables();
|
||||
myContent = content;
|
||||
if (myContent != null) {
|
||||
Document document = myContent.getDocument();
|
||||
final Document document = myContent.getDocument();
|
||||
if (myContent.isBinary() || document == null || myContent.getContentType() instanceof UIBasedFileType) {
|
||||
runRegisteredDisposables();
|
||||
final VirtualFile file = myContent.getFile();
|
||||
if (file != null) {
|
||||
final FileEditorProvider[] providers = FileEditorProviderManager.getInstance().getProviders(getProject(), file);
|
||||
@@ -93,6 +96,22 @@ class EditorPlaceHolder extends DiffMarkup implements DiffVersionComponent {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (myEditor != null) {
|
||||
final DocumentEx doc = ((EditorImpl)myEditor).getDocument();
|
||||
if (doc != null) {
|
||||
final boolean wasWriteable = doc.isWritable();
|
||||
doc.setReadOnly(false);
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
doc.setText(document.getText());
|
||||
}
|
||||
});
|
||||
doc.setReadOnly(! wasWriteable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
runRegisteredDisposables();
|
||||
final EditorFactory editorFactory = EditorFactory.getInstance();
|
||||
myEditor = DiffUtil.createEditor(document, getProject(), false);
|
||||
addDisposable(new Disposable() {
|
||||
|
||||
+8
-15
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.openapi.fileEditor.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.ide.ui.UISettings;
|
||||
import com.intellij.openapi.actionSystem.KeyboardShortcut;
|
||||
import com.intellij.openapi.actionSystem.Shortcut;
|
||||
@@ -65,8 +66,8 @@ import java.util.List;
|
||||
*/
|
||||
public class EditorsSplitters extends JPanel {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.fileEditor.impl.EditorsSplitters");
|
||||
|
||||
private EditorWindow myCurrentWindow;
|
||||
private VirtualFile myCurrentFile;
|
||||
private final FileEditorManagerImpl myManager;
|
||||
private Element mySplittersElement; // temporarily used during initialization
|
||||
int myInsideChange = 0;
|
||||
@@ -97,7 +98,6 @@ public class EditorsSplitters extends JPanel {
|
||||
removeAll();
|
||||
myWindows.clear();
|
||||
setCurrentWindow(null);
|
||||
myCurrentFile = null;
|
||||
repaint (); // revalidate doesn't repaint correctly after "Close All"
|
||||
}
|
||||
|
||||
@@ -151,13 +151,12 @@ public class EditorsSplitters extends JPanel {
|
||||
}
|
||||
|
||||
if (showEmptyText()) {
|
||||
final boolean darkerColors = UIUtil.isUnderAquaLookAndFeel() || UIUtil.isUnderGTKLookAndFeel();
|
||||
UIUtil.applyRenderingHints(g);
|
||||
g.setColor(darkerColors ? Gray._100 : Color.DARK_GRAY);
|
||||
g.setColor(Gray._100);
|
||||
g.setFont(UIUtil.getLabelFont().deriveFont(18f));
|
||||
|
||||
final UIUtil.TextPainter painter = new UIUtil.TextPainter(1.4f);
|
||||
painter.appendLine("No files are open").underlined(darkerColors ? Gray._150 : Color.DARK_GRAY);
|
||||
final UIUtil.TextPainter painter = new UIUtil.TextPainter().withShadow(true).withLineSpacing(1.4f);
|
||||
painter.appendLine("No files are open").underlined(Gray._150);
|
||||
|
||||
if (!isProjectViewVisible()) {
|
||||
painter.appendLine("Open Project View with " + KeymapUtil.getShortcutText(new KeyboardShortcut(
|
||||
@@ -325,8 +324,7 @@ public class EditorsSplitters extends JPanel {
|
||||
window = findWindowWith(panel);
|
||||
LOG.assertTrue(window != null);
|
||||
}
|
||||
//noinspection unchecked
|
||||
final List<Element> children = new ArrayList<Element>(leaf.getChildren("file"));
|
||||
@SuppressWarnings("unchecked") final List<Element> children = Lists.newArrayList(leaf.getChildren("file"));
|
||||
VirtualFile currentFile = null;
|
||||
|
||||
if (UISettings.getInstance().ACTIVATE_RIGHT_EDITOR_ON_CLOSE) {
|
||||
@@ -506,7 +504,7 @@ public class EditorsSplitters extends JPanel {
|
||||
return myInsideChange > 0;
|
||||
}
|
||||
|
||||
private void setCurrentWindow(final EditorWindow currentWindow) {
|
||||
private void setCurrentWindow(@Nullable final EditorWindow currentWindow) {
|
||||
myCurrentWindow = currentWindow;
|
||||
}
|
||||
|
||||
@@ -785,16 +783,11 @@ public class EditorsSplitters extends JPanel {
|
||||
private final class MyFocusWatcher extends FocusWatcher {
|
||||
protected void focusedComponentChanged(final Component component, final AWTEvent cause) {
|
||||
EditorWindow newWindow = null;
|
||||
VirtualFile newFile = null;
|
||||
|
||||
if (component != null) {
|
||||
newWindow = findWindowWith(component);
|
||||
if (newWindow != null) {
|
||||
newFile = newWindow.getSelectedFile();
|
||||
}
|
||||
}
|
||||
|
||||
myCurrentFile = newFile;
|
||||
setCurrentWindow(newWindow);
|
||||
setCurrentWindow(newWindow, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* 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.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.search.PsiSearchHelper;
|
||||
import com.intellij.psi.search.TodoItem;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 2/28/12
|
||||
* Time: 6:06 PM
|
||||
*/
|
||||
public class TodoForBaseRevision extends TodoForRanges {
|
||||
private final Getter<Object> myGetter;
|
||||
private final Consumer<Object> mySaver;
|
||||
|
||||
public TodoForBaseRevision(Project project,
|
||||
List<TextRange> ranges,
|
||||
int additionalOffset,
|
||||
String name,
|
||||
String text,
|
||||
boolean revision, FileType type, final Getter<Object> cacheGetter,
|
||||
final Consumer<Object> cacheSaver) {
|
||||
super(project, ranges, additionalOffset, name, text, revision, type);
|
||||
myGetter = cacheGetter;
|
||||
mySaver = cacheSaver;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TodoItem[] getTodoItems() {
|
||||
final TodoItem[] items = (TodoItem[])myGetter.get();
|
||||
if (items != null) return items;
|
||||
final TodoItem[] todoItems = getTodoForText(PsiSearchHelper.SERVICE.getInstance(myProject));
|
||||
if (todoItems != null) {
|
||||
mySaver.consume(todoItems);
|
||||
}
|
||||
return todoItems;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* 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.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiFileFactory;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.search.PsiSearchHelper;
|
||||
import com.intellij.psi.search.TodoItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created with IntelliJ IDEA.
|
||||
* User: Irina.Chernushina
|
||||
* Date: 2/28/12
|
||||
* Time: 4:48 PM
|
||||
*/
|
||||
public class TodoForExistingFile extends TodoForRanges {
|
||||
private final VirtualFile myFile;
|
||||
|
||||
public TodoForExistingFile(Project project,
|
||||
List<TextRange> ranges,
|
||||
int additionalOffset,
|
||||
String name,
|
||||
String text,
|
||||
boolean revision, FileType type, VirtualFile file) {
|
||||
super(project, ranges, additionalOffset, name, text, revision, type);
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
protected TodoItem[] getTodoItems() {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<TodoItem[]>() {
|
||||
@Override
|
||||
public TodoItem[] compute() {
|
||||
final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(myProject);
|
||||
|
||||
PsiFile psiFile = myFile == null ? null : PsiManager.getInstance(myProject).findFile(myFile);
|
||||
if (psiFile != null) {
|
||||
return helper.findTodoItems(psiFile);
|
||||
}
|
||||
|
||||
return getTodoForText(helper);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -41,36 +41,32 @@ import java.util.List;
|
||||
* Date: 9/9/11
|
||||
* Time: 9:55 AM
|
||||
*/
|
||||
public class TodoForRanges {
|
||||
private final Project myProject;
|
||||
private final String myFileName;
|
||||
private final String myText;
|
||||
private final boolean myOldRevision;
|
||||
public abstract class TodoForRanges {
|
||||
protected final Project myProject;
|
||||
private final List<TextRange> myRanges;
|
||||
private final FileType myFileType;
|
||||
private final int myAdditionalOffset;
|
||||
protected final String myFileName;
|
||||
protected final String myText;
|
||||
protected final boolean myOldRevision;
|
||||
protected final FileType myFileType;
|
||||
|
||||
public TodoForRanges(final Project project, final String fileName, final String text, final boolean oldRevision,
|
||||
final List<TextRange> ranges, FileType fileType, int additionalOffset) {
|
||||
protected TodoForRanges(final Project project,
|
||||
final List<TextRange> ranges,
|
||||
int additionalOffset,
|
||||
String name,
|
||||
String text,
|
||||
boolean revision, FileType type) {
|
||||
myProject = project;
|
||||
myFileName = fileName;
|
||||
myText = text;
|
||||
myOldRevision = oldRevision;
|
||||
myRanges = ranges;
|
||||
myFileType = fileType;
|
||||
myAdditionalOffset = additionalOffset;
|
||||
myFileName = name;
|
||||
myText = text;
|
||||
myOldRevision = revision;
|
||||
myFileType = type;
|
||||
}
|
||||
|
||||
public List<Pair<TextRange, TextAttributes>> execute() {
|
||||
final TodoItem[] todoItems = ApplicationManager.getApplication().runReadAction(new Computable<TodoItem[]>() {
|
||||
@Override
|
||||
public TodoItem[] compute() {
|
||||
final PsiFile psiFile = PsiFileFactory.getInstance(myProject).createFileFromText((myOldRevision ? "old" : "") + myFileName, myFileType, myText);
|
||||
|
||||
final PsiSearchHelper helper = PsiSearchHelper.SERVICE.getInstance(myProject);
|
||||
return helper.findTodoItemsLight(psiFile);
|
||||
}
|
||||
});
|
||||
final TodoItem[] todoItems = getTodoItems();
|
||||
|
||||
final StepIntersection<TodoItem, TextRange> stepIntersection =
|
||||
new StepIntersection<TodoItem, TextRange>(new Convertor<TodoItem, TextRange>() {
|
||||
@@ -105,4 +101,16 @@ public class TodoForRanges {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract TodoItem[] getTodoItems();
|
||||
|
||||
protected TodoItem[] getTodoForText(PsiSearchHelper helper) {
|
||||
final PsiFile psiFile = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
|
||||
@Override
|
||||
public PsiFile compute() {
|
||||
return PsiFileFactory.getInstance(myProject).createFileFromText((myOldRevision ? "old" : "") + myFileName, myFileType, myText);
|
||||
}
|
||||
});
|
||||
return helper.findTodoItemsLight(psiFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,6 +145,9 @@ compiler.server.use.memory.temp.cache.description=Store temporary data in memory
|
||||
compiler.server.use.external.javac.process=true
|
||||
compiler.server.use.external.javac.process.description=Run javac compiler in external process (allows to run compile server with smaller heap size)
|
||||
|
||||
compiler.server.ping.interval=5
|
||||
compiler.server.ping.interval.description=Interval in seconds between ping requests the IDE periodically sends to server. If server does not receive pings for some time, it shuts down. Specify -1 to disable this feature.
|
||||
|
||||
compiler.server.debug.port=-1
|
||||
#compiler.server.javac.debug.port=-1
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
<action id="CIDR.CreateXcodeProject">
|
||||
<keyboard-shortcut first-keystroke="shift meta N" />
|
||||
</action>
|
||||
<action id="CloseProject">
|
||||
<keyboard-shortcut first-keystroke="meta W" />
|
||||
<action id="CloseContent">
|
||||
<keyboard-shortcut first-keystroke="meta W"/>
|
||||
</action>
|
||||
<action id="CodeCompletion">
|
||||
<keyboard-shortcut first-keystroke="control SPACE" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -19,10 +19,7 @@ import com.intellij.openapi.Disposable;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.ui.ColorUtil;
|
||||
import com.intellij.ui.Gray;
|
||||
import com.intellij.ui.PanelWithAnchor;
|
||||
import com.intellij.ui.SideBorder;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PairFunction;
|
||||
import com.intellij.util.Processor;
|
||||
@@ -2308,25 +2305,48 @@ public class UIUtil {
|
||||
|
||||
public static class TextPainter {
|
||||
private List<Pair<String, LineInfo>> myLines = new ArrayList<Pair<String, LineInfo>>();
|
||||
private boolean myDrawMacShadow;
|
||||
private Color myMacShadowColor;
|
||||
private boolean myDrawShadow;
|
||||
private Color myShadowColor;
|
||||
private float myLineSpacing;
|
||||
|
||||
|
||||
public TextPainter() {
|
||||
this(true, Gray._220, 1.0f);
|
||||
myDrawShadow = isUnderAquaLookAndFeel();
|
||||
myShadowColor = Gray._220;
|
||||
myLineSpacing = 1.0f;
|
||||
}
|
||||
|
||||
/** @deprecated use {@linkplain #withLineSpacing(float)} (to remove in IDEA 12) */
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public TextPainter(final float lineSpacing) {
|
||||
this(true, Gray._220, lineSpacing);
|
||||
myDrawShadow = isUnderAquaLookAndFeel();
|
||||
myShadowColor = Gray._220;
|
||||
myLineSpacing = lineSpacing;
|
||||
}
|
||||
|
||||
public TextPainter(final boolean drawMacShadow, final Color shadowColor, final float lineSpacing) {
|
||||
myDrawMacShadow = drawMacShadow;
|
||||
myMacShadowColor = shadowColor;
|
||||
/** @deprecated use {@linkplain #withShadow(boolean, java.awt.Color)} and {@linkplain #withLineSpacing(float)} (to remove in IDEA 12) */
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public TextPainter(final boolean drawShadow, final Color shadowColor, final float lineSpacing) {
|
||||
myDrawShadow = drawShadow;
|
||||
myShadowColor = shadowColor;
|
||||
myLineSpacing = lineSpacing;
|
||||
}
|
||||
|
||||
public TextPainter withShadow(final boolean drawShadow) {
|
||||
myDrawShadow = drawShadow;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextPainter withShadow(final boolean drawShadow, final Color shadowColor) {
|
||||
myDrawShadow = drawShadow;
|
||||
myShadowColor = shadowColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextPainter withLineSpacing(final float lineSpacing) {
|
||||
myLineSpacing = lineSpacing;
|
||||
return this;
|
||||
}
|
||||
|
||||
public TextPainter appendLine(final String text) {
|
||||
if (text == null || text.length() == 0) return this;
|
||||
myLines.add(Pair.create(text, new LineInfo()));
|
||||
@@ -2432,9 +2452,9 @@ public class UIUtil {
|
||||
xOffset = x + (maxWidth[0] - fm.stringWidth(pair.getFirst())) / 2;
|
||||
}
|
||||
|
||||
if (myDrawMacShadow && UIUtil.isUnderAquaLookAndFeel()) {
|
||||
if (myDrawShadow) {
|
||||
final Color oldColor = g.getColor();
|
||||
g.setColor(myMacShadowColor);
|
||||
g.setColor(myShadowColor);
|
||||
|
||||
if (info.withBullet) {
|
||||
g.drawString(info.bulletChar + " ", x - fm.stringWidth(" " + info.bulletChar), yOffset[0] + 1);
|
||||
@@ -2462,9 +2482,9 @@ public class UIUtil {
|
||||
g.setColor(c);
|
||||
}
|
||||
|
||||
if (myDrawMacShadow && UIUtil.isUnderAquaLookAndFeel()) {
|
||||
if (myDrawShadow) {
|
||||
c = g.getColor();
|
||||
g.setColor(myMacShadowColor);
|
||||
g.setColor(myShadowColor);
|
||||
g.drawLine(x - maxBulletWidth[0] - 10, yOffset[0] + fm.getDescent() + 1, x + maxWidth[0] + 10, yOffset[0] + fm.getDescent() + 1);
|
||||
g.setColor(c);
|
||||
}
|
||||
@@ -2533,23 +2553,30 @@ public class UIUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void mergeComponentsWithAnchor(PanelWithAnchor c1, PanelWithAnchor c2) {
|
||||
if (c1 == null || c2 == null) return;
|
||||
|
||||
if (c1.getAnchor() == null) {
|
||||
c1.setAnchor(c2.getAnchor());
|
||||
} else {
|
||||
if (c2.getAnchor() == null) {
|
||||
c2.setAnchor(c1.getAnchor());
|
||||
} else {
|
||||
JComponent anchor = c1.getAnchor().getPreferredSize().getWidth() > c2.getAnchor().getPreferredSize().getWidth() ?
|
||||
c1.getAnchor() : c2.getAnchor();
|
||||
c2.setAnchor(anchor);
|
||||
c1.setAnchor(anchor);
|
||||
}
|
||||
}
|
||||
@Nullable
|
||||
public static JComponent mergeComponentsWithAnchor(PanelWithAnchor...panels) {
|
||||
return mergeComponentsWithAnchor(Arrays.asList(panels));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JComponent mergeComponentsWithAnchor(Collection<? extends PanelWithAnchor> panels) {
|
||||
JComponent tempAnchor = null;
|
||||
int maxWidth = 0;
|
||||
for (PanelWithAnchor panel : panels) {
|
||||
if (panel == null) continue;
|
||||
if (panel.getAnchor() == null) continue;
|
||||
if (maxWidth < panel.getAnchor().getPreferredSize().width) {
|
||||
maxWidth = panel.getAnchor().getPreferredSize().width;
|
||||
tempAnchor = panel.getAnchor();
|
||||
}
|
||||
}
|
||||
for (PanelWithAnchor panel : panels) {
|
||||
if (panel == null) continue;
|
||||
panel.setAnchor(tempAnchor);
|
||||
}
|
||||
return tempAnchor;
|
||||
}
|
||||
|
||||
public static void setNotOpaqueRecursively(@NotNull Component component) {
|
||||
if (!isUnderAquaLookAndFeel()) return;
|
||||
|
||||
|
||||
@@ -46,14 +46,14 @@ public abstract class VcsDirtyScopeManager {
|
||||
*
|
||||
* @param file the file for which the status update is requested.
|
||||
*/
|
||||
public abstract void fileDirty(VirtualFile file);
|
||||
public abstract void fileDirty(@NotNull VirtualFile file);
|
||||
|
||||
/**
|
||||
* Requests an asynchronous file status update for the specified file path. Must be called from a read action.
|
||||
*
|
||||
* @param file the file path for which the status update is requested.
|
||||
*/
|
||||
public abstract void fileDirty(FilePath file);
|
||||
public abstract void fileDirty(@NotNull FilePath file);
|
||||
|
||||
/**
|
||||
* Requests an asynchronous file status update for all files under the specified directory.
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package com.intellij.openapi.vcs.impl;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.Throwable2Computable;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
@@ -48,12 +49,14 @@ public class ContentRevisionCache {
|
||||
private final Object myLock;
|
||||
private final SLRUMap<Key, byte[]> myCache;
|
||||
private final SLRUMap<CurrentKey, VcsRevisionNumber> myCurrentRevisionsCache;
|
||||
private final SLRUMap<Pair<FilePath, VcsRevisionNumber>, Object> myCustom;
|
||||
private long myCounter;
|
||||
|
||||
public ContentRevisionCache() {
|
||||
myLock = new Object();
|
||||
myCache = new SLRUMap<Key, byte[]>(100, 50);
|
||||
myCurrentRevisionsCache = new SLRUMap<CurrentKey, VcsRevisionNumber>(200, 50);
|
||||
myCustom = new SLRUMap<Pair<FilePath, VcsRevisionNumber>, Object>(30,30);
|
||||
myCounter = 0;
|
||||
}
|
||||
|
||||
@@ -73,6 +76,19 @@ public class ContentRevisionCache {
|
||||
}
|
||||
}
|
||||
|
||||
public void putCustom(FilePath path, VcsRevisionNumber number, final Object o) {
|
||||
synchronized (myLock) {
|
||||
myCustom.put(new Pair<FilePath, VcsRevisionNumber>(path, number), o);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object getCustom(FilePath path, VcsRevisionNumber number) {
|
||||
synchronized (myLock) {
|
||||
return myCustom.get(new Pair<FilePath, VcsRevisionNumber>(path, number));
|
||||
}
|
||||
}
|
||||
|
||||
public void clearAllCurrent() {
|
||||
synchronized (myLock) {
|
||||
++ myCounter;
|
||||
@@ -220,6 +236,10 @@ public class ContentRevisionCache {
|
||||
Pair<VcsRevisionNumber, byte[]> loaded;
|
||||
while (true) {
|
||||
currentRevision = putIntoCurrentCache(cache, path, vcsKey, loader);
|
||||
final byte[] cachedCurrent = cache.getBytes(path, currentRevision, vcsKey, UniqueType.REPOSITORY_CONTENT);
|
||||
if (cachedCurrent != null) {
|
||||
return new Pair<VcsRevisionNumber, byte[]>(currentRevision, cachedCurrent);
|
||||
}
|
||||
loaded = loader.get();
|
||||
if (loaded.getFirst().equals(currentRevision)) break;
|
||||
}
|
||||
|
||||
@@ -32,22 +32,15 @@ import java.util.List;
|
||||
* @author yole
|
||||
*/
|
||||
public abstract class VcsBackgroundTask<T> extends Task.ConditionalModal {
|
||||
@NotNull private final PerformInBackgroundOption myBackgroundOption;
|
||||
private final Collection<T> myItems;
|
||||
private final List<VcsException> myExceptions = new ArrayList<VcsException>();
|
||||
|
||||
public VcsBackgroundTask(final Project project, @NotNull final String title, @NotNull final PerformInBackgroundOption backgroundOption,
|
||||
final Collection<T> itemsToProcess) {
|
||||
super(project, title, false, backgroundOption);
|
||||
myBackgroundOption = backgroundOption;
|
||||
myItems = itemsToProcess;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PerformInBackgroundOption getBackgroundOption() {
|
||||
return myBackgroundOption;
|
||||
}
|
||||
|
||||
public void run(@NotNull ProgressIndicator indicator) {
|
||||
for(T item: myItems) {
|
||||
try {
|
||||
|
||||
+4
-3
@@ -81,14 +81,15 @@ public class FragmentedDiffRequestFromChange {
|
||||
final FileStatus fs = change.getFileStatus();
|
||||
fragmentedContent.setIsAddition(FileStatus.ADDED.equals(fs));
|
||||
fragmentedContent.setOneSide(FileStatus.ADDED.equals(fs) || FileStatus.DELETED.equals(fs));
|
||||
final PreparedFragmentedContent preparedFragmentedContent = new PreparedFragmentedContent(myProject, fragmentedContent,
|
||||
filePath.getName(), filePath.getFileType());
|
||||
VirtualFile file = filePath.getVirtualFile();
|
||||
if (file == null) {
|
||||
filePath.hardRefresh();
|
||||
file = filePath.getVirtualFile();
|
||||
}
|
||||
preparedFragmentedContent.setVirtualFile(file);
|
||||
final PreparedFragmentedContent preparedFragmentedContent = new PreparedFragmentedContent(myProject, fragmentedContent,
|
||||
filePath.getName(), filePath.getFileType(),
|
||||
change.getBeforeRevision() == null ? null : change.getBeforeRevision().getRevisionNumber(),
|
||||
change.getAfterRevision() == null ? null : change.getAfterRevision().getRevisionNumber(), filePath, file);
|
||||
return preparedFragmentedContent;
|
||||
}
|
||||
|
||||
|
||||
+35
-9
@@ -24,11 +24,18 @@ import com.intellij.openapi.editor.markup.TextAttributes;
|
||||
import com.intellij.openapi.fileTypes.FileType;
|
||||
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Getter;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsConfiguration;
|
||||
import com.intellij.openapi.vcs.history.VcsRevisionNumber;
|
||||
import com.intellij.openapi.vcs.impl.ContentRevisionCache;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.BeforeAfter;
|
||||
import com.intellij.util.Consumer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -60,14 +67,25 @@ public class PreparedFragmentedContent {
|
||||
private final FragmentedContent myFragmentedContent;
|
||||
private final String myFileName;
|
||||
private final FileType myFileType;
|
||||
private final VcsRevisionNumber myBeforeNumber;
|
||||
private final VcsRevisionNumber myAfterNumber;
|
||||
private VirtualFile myFile;
|
||||
private FilePath myFilePath;
|
||||
|
||||
public PreparedFragmentedContent(final Project project, final FragmentedContent fragmentedContent, final String fileName,
|
||||
final FileType fileType) {
|
||||
final FileType fileType,
|
||||
VcsRevisionNumber beforeNumber,
|
||||
VcsRevisionNumber afterNumber,
|
||||
FilePath path,
|
||||
VirtualFile file) {
|
||||
myFile = file;
|
||||
myProject = project;
|
||||
myFragmentedContent = fragmentedContent;
|
||||
myFileName = fileName;
|
||||
myFileType = fileType;
|
||||
myBeforeNumber = beforeNumber;
|
||||
myAfterNumber = afterNumber;
|
||||
myFilePath = path;
|
||||
oldConvertor = new LineNumberConvertor();
|
||||
newConvertor = new LineNumberConvertor();
|
||||
sbOld = new StringBuilder();
|
||||
@@ -301,18 +319,26 @@ public class PreparedFragmentedContent {
|
||||
}
|
||||
|
||||
private void setTodoHighlighting(final Document oldDocument, final Document document) {
|
||||
final List<Pair<TextRange,TextAttributes>> beforeTodoRanges = new TodoForRanges(myProject, myFileName, oldDocument.getText(), true,
|
||||
getBeforeFragments(), myFileType, 1).execute();
|
||||
final List<Pair<TextRange, TextAttributes>> afterTodoRanges = new TodoForRanges(myProject, myFileName, document.getText(), false,
|
||||
getAfterFragments(), myFileType, 1).execute();
|
||||
final ContentRevisionCache cache = ProjectLevelVcsManager.getInstance(myProject).getContentRevisionCache();
|
||||
final List<Pair<TextRange,TextAttributes>> beforeTodoRanges = myBeforeNumber == null ? Collections.<Pair<TextRange,TextAttributes>>emptyList() :
|
||||
new TodoForBaseRevision(myProject, getBeforeFragments(), 1, myFileName, oldDocument.getText(), true, myFileType, new Getter<Object>() {
|
||||
@Override
|
||||
public Object get() {
|
||||
return cache.getCustom(myFilePath, myBeforeNumber);
|
||||
}
|
||||
}, new Consumer<Object>() {
|
||||
@Override
|
||||
public void consume(Object items) {
|
||||
cache.putCustom(myFilePath, myBeforeNumber, items);
|
||||
}
|
||||
}).execute();
|
||||
|
||||
final List<Pair<TextRange, TextAttributes>> afterTodoRanges = new TodoForExistingFile(myProject, getAfterFragments(), 1,
|
||||
myFileName, document.getText(), false, myFileType, myFile).execute();
|
||||
setBeforeTodoRanges(beforeTodoRanges);
|
||||
setAfterTodoRanges(afterTodoRanges);
|
||||
}
|
||||
|
||||
public void setVirtualFile(VirtualFile file) {
|
||||
myFile = file;
|
||||
}
|
||||
|
||||
public VirtualFile getFile() {
|
||||
return myFile;
|
||||
}
|
||||
|
||||
+2
-2
@@ -252,7 +252,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
public void fileDirty(final VirtualFile file) {
|
||||
public void fileDirty(@NotNull final VirtualFile file) {
|
||||
try {
|
||||
final AbstractVcs vcs = myGuess.getVcsForDirty(file);
|
||||
if (vcs == null) return;
|
||||
@@ -269,7 +269,7 @@ public class VcsDirtyScopeManagerImpl extends VcsDirtyScopeManager implements Pr
|
||||
}
|
||||
}
|
||||
|
||||
public void fileDirty(final FilePath file) {
|
||||
public void fileDirty(@NotNull final FilePath file) {
|
||||
try {
|
||||
final AbstractVcs vcs = myGuess.getVcsForDirty(file);
|
||||
if (vcs == null) return;
|
||||
|
||||
+2
-2
@@ -54,11 +54,11 @@ class VcsDirtyScopeManagerProxy extends VcsDirtyScopeManager {
|
||||
myFiles.clear();
|
||||
}
|
||||
|
||||
public void fileDirty(final VirtualFile file) {
|
||||
public void fileDirty(@NotNull final VirtualFile file) {
|
||||
myVFiles.add(file);
|
||||
}
|
||||
|
||||
public void fileDirty(final FilePath file) {
|
||||
public void fileDirty(@NotNull final FilePath file) {
|
||||
myFiles.add(file);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.intellij.openapi.vcs.FilePath;
|
||||
import com.intellij.openapi.vcs.impl.ProjectLevelVcsManagerImpl;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class VcsGuess {
|
||||
@@ -41,7 +42,7 @@ public class VcsGuess {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AbstractVcs getVcsForDirty(final VirtualFile file) {
|
||||
public AbstractVcs getVcsForDirty(@NotNull final VirtualFile file) {
|
||||
if (!file.isInLocalFileSystem()) {
|
||||
return null;
|
||||
}
|
||||
@@ -56,7 +57,7 @@ public class VcsGuess {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AbstractVcs getVcsForDirty(final FilePath filePath) {
|
||||
public AbstractVcs getVcsForDirty(@NotNull final FilePath filePath) {
|
||||
if (filePath.isNonLocal()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
+6
-4
@@ -16,13 +16,15 @@
|
||||
package com.intellij.openapi.vcs.changes.actions;
|
||||
|
||||
import com.intellij.idea.ActionsBundle;
|
||||
import com.intellij.openapi.actionSystem.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.PlatformDataKeys;
|
||||
import com.intellij.openapi.project.DumbAware;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.IconLoader;
|
||||
import com.intellij.openapi.vcs.FileStatus;
|
||||
import com.intellij.openapi.vcs.ProjectLevelVcsManager;
|
||||
import com.intellij.openapi.vcs.VcsBundle;
|
||||
import com.intellij.openapi.vcs.VcsDataKeys;
|
||||
import com.intellij.openapi.vcs.changes.*;
|
||||
import com.intellij.openapi.vcs.changes.ui.ChangeListChooser;
|
||||
@@ -135,7 +137,7 @@ public class MoveChangesToAnotherListAction extends AnAction implements DumbAwar
|
||||
final ChangeListManagerImpl listManager = ChangeListManagerImpl.getInstanceImpl(project);
|
||||
final List<LocalChangeList> lists = listManager.getChangeLists();
|
||||
ChangeListChooser chooser = new ChangeListChooser(project, getPreferredLists(lists, changes, true), guessPreferredList(lists, changes),
|
||||
VcsBundle.message("changes.changelist.chooser.title"), null);
|
||||
ActionsBundle.message("action.ChangesView.Move.text"), null);
|
||||
chooser.show();
|
||||
LocalChangeList resultList = chooser.getSelectedList();
|
||||
if (resultList != null) {
|
||||
|
||||
+13
-7
@@ -25,6 +25,7 @@ import com.intellij.openapi.vcs.changes.ChangeListManager;
|
||||
import com.intellij.openapi.vcs.changes.LocalChangeList;
|
||||
import com.intellij.openapi.vcs.changes.committed.CommittedChangeListRenderer;
|
||||
import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer;
|
||||
import com.intellij.ui.CollectionComboBoxModel;
|
||||
import com.intellij.ui.HtmlListCellRenderer;
|
||||
import com.intellij.ui.SimpleTextAttributes;
|
||||
import com.intellij.util.Consumer;
|
||||
@@ -36,12 +37,20 @@ import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.util.Collection;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
public class ChangeListChooserPanel extends JPanel {
|
||||
private static final Comparator<ChangeList> CHANGE_LIST_COMPARATOR = new Comparator<ChangeList>() {
|
||||
@Override
|
||||
public int compare(ChangeList o1, ChangeList o2) {
|
||||
return o1.getName().compareToIgnoreCase(o2.getName());
|
||||
}
|
||||
};
|
||||
|
||||
private JPanel myPanel;
|
||||
private JRadioButton myRbExisting;
|
||||
private JRadioButton myRbNew;
|
||||
@@ -94,12 +103,9 @@ public class ChangeListChooserPanel extends JPanel {
|
||||
}
|
||||
|
||||
public void setChangeLists(Collection<? extends ChangeList> changeLists) {
|
||||
final DefaultComboBoxModel model = new DefaultComboBoxModel();
|
||||
for (ChangeList list : changeLists) {
|
||||
model.addElement(list);
|
||||
}
|
||||
|
||||
myExistingListsCombo.setModel(model);
|
||||
List<ChangeList> list = new ArrayList<ChangeList>(changeLists);
|
||||
Collections.sort(list, CHANGE_LIST_COMPARATOR);
|
||||
myExistingListsCombo.setModel(new CollectionComboBoxModel(list, null));
|
||||
}
|
||||
|
||||
public void setDefaultName(String name) {
|
||||
|
||||
+1
-1
@@ -166,7 +166,7 @@ public class ChangesViewContentManager extends AbstractProjectComponent implemen
|
||||
}
|
||||
|
||||
public boolean isToolwindowVisible() {
|
||||
return myToolWindow.isVisible();
|
||||
return ! myToolWindow.isDisposed() && myToolWindow.isVisible();
|
||||
}
|
||||
|
||||
public void projectClosed() {
|
||||
|
||||
@@ -70,6 +70,18 @@ public abstract class XDebuggerEvaluator {
|
||||
evaluate(expression, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start evaluating expression.
|
||||
*
|
||||
* called from evaluation dialog
|
||||
* @param expression expression to evaluate
|
||||
* @param callback used to notify that the expression has been evaluated or an error occurs
|
||||
* @param mode code fragment or expression
|
||||
*/
|
||||
public void evaluate(@NotNull String expression, XEvaluationCallback callback, @Nullable XSourcePosition expressionPosition, @Nullable EvaluationMode mode) {
|
||||
evaluate(expression, callback, expressionPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated override {@link #evaluate(String, XEvaluationCallback, com.intellij.xdebugger.XSourcePosition)} instead
|
||||
*/
|
||||
|
||||
+1
-1
@@ -182,7 +182,7 @@ public class XDebuggerEvaluationDialog extends DialogWrapper {
|
||||
final XDebuggerEditorBase inputEditor = myInputComponent.getInputEditor();
|
||||
inputEditor.saveTextInHistory();
|
||||
String expression = inputEditor.getText();
|
||||
myEvaluator.evaluate(expression, evaluationCallback, null);
|
||||
myEvaluator.evaluate(expression, evaluationCallback, null, inputEditor.getMode());
|
||||
}
|
||||
|
||||
public JComponent getPreferredFocusedComponent() {
|
||||
|
||||
@@ -52,6 +52,10 @@ public abstract class XDebuggerEditorBase {
|
||||
mySourcePosition = sourcePosition;
|
||||
}
|
||||
|
||||
public EvaluationMode getMode() {
|
||||
return myMode;
|
||||
}
|
||||
|
||||
public abstract JComponent getComponent();
|
||||
|
||||
protected abstract void doSetText(String text);
|
||||
|
||||
@@ -13,4 +13,6 @@ android.jps.errors.package.not.specified=Package is not specified in AndroidMani
|
||||
android.jps.progress.library.packaging=Packaging Android libraries for module {0}
|
||||
android.jps.errors.main.content.root.not.found=Cannot find main content root for module {0}
|
||||
android.jps.progress.proguard=Executing ProGuard for module {0}
|
||||
android.jps.progress.res.caching=Caching resources for module {0}
|
||||
android.jps.progress.res.caching=Caching resources for module {0}
|
||||
android.jps.progress.packaging=Packaging {0}
|
||||
android.jps.progress.packaging.resources=Packaging resources for module {0}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.storage.ValidityState;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidApkBuilderConfigState implements ValidityState {
|
||||
private final String myOutputApkPath;
|
||||
private final String myCustomKeystorePath;
|
||||
|
||||
public AndroidApkBuilderConfigState(@NotNull String outputApkPath, @NotNull String customKeystorePath) {
|
||||
myOutputApkPath = outputApkPath;
|
||||
myCustomKeystorePath = customKeystorePath;
|
||||
}
|
||||
|
||||
public AndroidApkBuilderConfigState(DataInput in) throws IOException {
|
||||
myOutputApkPath = in.readUTF();
|
||||
myCustomKeystorePath = in.readUTF();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsTo(ValidityState otherState) {
|
||||
if (!(otherState instanceof AndroidApkBuilderConfigState)) {
|
||||
return false;
|
||||
}
|
||||
final AndroidApkBuilderConfigState apkBuilderConfigState = (AndroidApkBuilderConfigState)otherState;
|
||||
return apkBuilderConfigState.myOutputApkPath.equals(myOutputApkPath) &&
|
||||
apkBuilderConfigState.myCustomKeystorePath.equals(myCustomKeystorePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out) throws IOException {
|
||||
out.writeUTF(myOutputApkPath);
|
||||
out.writeUTF(myCustomKeystorePath);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.storage.AbstractStateStorage;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidApkBuilderConfigStateStorage extends AbstractStateStorage<String, AndroidApkBuilderConfigState> {
|
||||
public AndroidApkBuilderConfigStateStorage(@NotNull File dataStorageRoot, @NotNull String storageName) throws IOException {
|
||||
super(getStorageFile(dataStorageRoot, storageName), new EnumeratorStringDescriptor(), new MyDataExternalizer());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getStorageFile(@NotNull File dataStorageRoot, @NotNull String storageName) {
|
||||
return new File(new File(new File(dataStorageRoot, AndroidJpsUtil.ANDROID_STORAGE_DIR), storageName), storageName);
|
||||
}
|
||||
|
||||
private static class MyDataExternalizer implements DataExternalizer<AndroidApkBuilderConfigState> {
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out, AndroidApkBuilderConfigState value) throws IOException {
|
||||
value.save(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidApkBuilderConfigState read(DataInput in) throws IOException {
|
||||
return new AndroidApkBuilderConfigState(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,6 @@ public class AndroidBuilderService extends BuilderService {
|
||||
@Override
|
||||
public List<? extends ProjectLevelBuilder> createProjectLevelBuilders() {
|
||||
return Arrays.asList(new AndroidDexBuilder(),
|
||||
new AndroidResourcePackagingBuilder());
|
||||
new AndroidPackagingBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.storage.ValidityState;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class AndroidClassesAndJarsState implements ValidityState {
|
||||
private Map<String, Long> myFiles;
|
||||
|
||||
public AndroidClassesAndJarsState(@NotNull Collection<String> roots) {
|
||||
myFiles = new HashMap<String, Long>();
|
||||
|
||||
for (String rootPath : roots) {
|
||||
AndroidJpsUtil.processClassFilesAndJarsRecursively(rootPath, new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
myFiles.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public AndroidClassesAndJarsState(@NotNull DataInput in) throws IOException {
|
||||
myFiles = new HashMap<String, Long>();
|
||||
int size = in.readInt();
|
||||
|
||||
while (size-- > 0) {
|
||||
final String path = in.readUTF();
|
||||
final long timestamp = in.readLong();
|
||||
myFiles.put(path, timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equalsTo(ValidityState otherState) {
|
||||
return otherState instanceof AndroidClassesAndJarsState
|
||||
&& myFiles.equals(((AndroidClassesAndJarsState)otherState).myFiles);
|
||||
}
|
||||
|
||||
public void save(DataOutput out) throws IOException {
|
||||
out.writeInt(myFiles.size());
|
||||
|
||||
for (String path : myFiles.keySet()) {
|
||||
out.writeUTF(path);
|
||||
out.writeLong(myFiles.get(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.intellij.util.io.DataExternalizer;
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.incremental.storage.AbstractStateStorage;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidClassesAndJarsStateStorage extends AbstractStateStorage<String, AndroidClassesAndJarsState> {
|
||||
|
||||
@NonNls private static final String CLASSES_AND_JARS_STORAGE = "classes_and_jars";
|
||||
|
||||
public AndroidClassesAndJarsStateStorage(@NotNull File dataStorageRoot, @NotNull String suffix) throws IOException {
|
||||
super(getStorageFile(dataStorageRoot, suffix), new EnumeratorStringDescriptor(), new MyDataExternalizer());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getStorageFile(@NotNull File dataStorageRoot, @NotNull String suffix) {
|
||||
return new File(new File(new File(dataStorageRoot, AndroidJpsUtil.ANDROID_STORAGE_DIR), CLASSES_AND_JARS_STORAGE + suffix),
|
||||
CLASSES_AND_JARS_STORAGE);
|
||||
}
|
||||
|
||||
private static class MyDataExternalizer implements DataExternalizer<AndroidClassesAndJarsState> {
|
||||
|
||||
@Override
|
||||
public void save(DataOutput out, AndroidClassesAndJarsState value) throws IOException {
|
||||
value.save(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AndroidClassesAndJarsState read(DataInput in) throws IOException {
|
||||
return new AndroidClassesAndJarsState(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,11 +55,12 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
private static void doBuild(CompileContext context) throws IOException, ProjectBuildException {
|
||||
final File root = context.getDataManager().getDataStorageRoot();
|
||||
|
||||
AndroidClassesAndJarsStateStorage dexStateStorage = null;
|
||||
AndroidClassesAndJarsStateStorage proguardStateStorage = null;
|
||||
AndroidFileSetStorage dexStateStorage = null;
|
||||
AndroidFileSetStorage proguardStateStorage = null;
|
||||
try {
|
||||
dexStateStorage = new AndroidClassesAndJarsStateStorage(root, "_dex");
|
||||
proguardStateStorage = new AndroidClassesAndJarsStateStorage(root, "_proguard");
|
||||
dexStateStorage = new AndroidFileSetStorage(root, "dex");
|
||||
proguardStateStorage = new AndroidFileSetStorage(root, "proguard");
|
||||
|
||||
if (!doDexBuild(context, dexStateStorage, proguardStateStorage)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
@@ -75,8 +76,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
}
|
||||
|
||||
private static boolean doDexBuild(@NotNull CompileContext context,
|
||||
@NotNull AndroidClassesAndJarsStateStorage dexStateStorage,
|
||||
@NotNull AndroidClassesAndJarsStateStorage proguardStateStorage) {
|
||||
@NotNull AndroidFileSetStorage dexStateStorage,
|
||||
@NotNull AndroidFileSetStorage proguardStateStorage) {
|
||||
boolean success = true;
|
||||
|
||||
for (Module module : context.getProject().getModules().values()) {
|
||||
@@ -145,10 +146,10 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
}
|
||||
}
|
||||
}
|
||||
final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(fileSet);
|
||||
final AndroidFileSetState newState = new AndroidFileSetState(fileSet, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true);
|
||||
|
||||
if (context.isMake()) {
|
||||
final AndroidClassesAndJarsState oldState = dexStateStorage.getState(module.getName());
|
||||
final AndroidFileSetState oldState = dexStateStorage.getState(module.getName());
|
||||
if (oldState != null && oldState.equalsTo(newState)) {
|
||||
continue;
|
||||
}
|
||||
@@ -192,11 +193,11 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
return "Android Dex Builder";
|
||||
}
|
||||
|
||||
public static boolean runDex(@NotNull AndroidSdk sdk,
|
||||
@NotNull IAndroidTarget target,
|
||||
@NotNull String outputDir,
|
||||
@NotNull String[] compileTargets,
|
||||
@NotNull CompileContext context) throws IOException {
|
||||
private static boolean runDex(@NotNull AndroidSdk sdk,
|
||||
@NotNull IAndroidTarget target,
|
||||
@NotNull String outputDir,
|
||||
@NotNull String[] compileTargets,
|
||||
@NotNull CompileContext context) throws IOException {
|
||||
@SuppressWarnings("deprecation")
|
||||
final String dxJarPath = FileUtil.toSystemDependentName(target.getPath(IAndroidTarget.DX_JAR));
|
||||
|
||||
@@ -254,7 +255,7 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
@NotNull CompileContext context,
|
||||
@NotNull String outputJarPath,
|
||||
@NotNull String proguardCfgPath,
|
||||
@NotNull AndroidClassesAndJarsStateStorage proguardStateStorage) throws IOException {
|
||||
@NotNull AndroidFileSetStorage proguardStateStorage) throws IOException {
|
||||
final Module module = facet.getModule();
|
||||
|
||||
final File proguardCfgFile = new File(proguardCfgPath);
|
||||
@@ -294,8 +295,8 @@ public class AndroidDexBuilder extends ProjectLevelBuilder {
|
||||
allFiles.addAll(libClassFilesDirs);
|
||||
allFiles.addAll(externalJars);
|
||||
|
||||
final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(allFiles);
|
||||
final AndroidClassesAndJarsState oldState = proguardStateStorage.getState(module.getName());
|
||||
final AndroidFileSetState newState = new AndroidFileSetState(allFiles, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true);
|
||||
final AndroidFileSetState oldState = proguardStateStorage.getState(module.getName());
|
||||
if (context.getTimestampStorage().getStamp(proguardCfgFile) == proguardCfgFile.lastModified() &&
|
||||
newState.equalsTo(oldState)) {
|
||||
return true;
|
||||
|
||||
@@ -23,6 +23,10 @@ class AndroidFacet extends Facet {
|
||||
boolean useCustomManifestForCompilation;
|
||||
boolean packTestCode;
|
||||
|
||||
String apkRelativePath;
|
||||
String customDebugKeyStorePath;
|
||||
String nativeLibsFolderRelativePath;
|
||||
|
||||
AndroidFacet(Module module, String name) {
|
||||
this.module = module
|
||||
this.name = name;
|
||||
@@ -54,6 +58,11 @@ class AndroidFacet extends Facet {
|
||||
return manifestFile != null ? manifestFile.getCanonicalFile() : null;
|
||||
}
|
||||
|
||||
File getNativeLibsDir() throws IOException {
|
||||
def nativeLibsFolder = findFileByRelativeModulePath(nativeLibsFolderRelativePath, false);
|
||||
return nativeLibsFolder != null ? nativeLibsFolder.getCanonicalFile() : null;
|
||||
}
|
||||
|
||||
private File findFileByRelativeModulePath(String relativePath, boolean lookInContentRoot) {
|
||||
if (module.basePath != null) {
|
||||
def absPath = FileUtil.toSystemIndependentName(module.basePath + relativePath)
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.jps.MacroExpander
|
||||
import org.jetbrains.jps.Module
|
||||
import org.jetbrains.jps.idea.Facet
|
||||
import org.jetbrains.jps.idea.FacetTypeService
|
||||
import org.jetbrains.jps.idea.IdeaProjectLoadingUtil
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
@@ -49,6 +50,16 @@ class AndroidFacetType extends FacetTypeService {
|
||||
break
|
||||
case "ASSETS_FOLDER_RELATIVE_PATH":
|
||||
facet.assetsFolderRelativePath = value
|
||||
break
|
||||
case "APK_PATH":
|
||||
facet.apkRelativePath = value
|
||||
break
|
||||
case "CUSTOM_DEBUG_KEYSTORE_PATH":
|
||||
facet.customDebugKeyStorePath = IdeaProjectLoadingUtil.pathFromUrl(value)
|
||||
break
|
||||
case "LIBS_FOLDER_RELATIVE_PATH":
|
||||
facet.nativeLibsFolderRelativePath = value
|
||||
break
|
||||
}
|
||||
}
|
||||
return facet;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
@@ -19,21 +20,29 @@ import java.util.Map;
|
||||
public class AndroidFileSetState implements ValidityState {
|
||||
private final Map<String, Long> myTimestamps;
|
||||
|
||||
public AndroidFileSetState(@NotNull Collection<String> roots) {
|
||||
public AndroidFileSetState(@NotNull Collection<String> roots, @NotNull final Condition<File> filter, boolean recursively) {
|
||||
myTimestamps = new HashMap<String, Long>();
|
||||
|
||||
for (String resourceDir : roots) {
|
||||
FileUtil.processFilesRecursively(new File(resourceDir), new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (String rootPath : roots) {
|
||||
final File root = new File(rootPath);
|
||||
|
||||
if (recursively) {
|
||||
FileUtil.processFilesRecursively(root, new Processor<File>() {
|
||||
@Override
|
||||
public boolean process(File file) {
|
||||
if (filter.value(file)) {
|
||||
myTimestamps.put(FileUtil.toSystemIndependentName(file.getPath()), file.lastModified());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (filter.value(root)) {
|
||||
myTimestamps.put(FileUtil.toSystemIndependentName(root.getPath()), root.lastModified());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public AndroidFileSetState(DataInput in) throws IOException {
|
||||
final int resourcesCount = in.readInt();
|
||||
myTimestamps = new HashMap<String, Long>(resourcesCount);
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.jetbrains.jps.android;
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.android.sdklib.SdkManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
@@ -34,9 +35,18 @@ import java.util.regex.Matcher;
|
||||
*/
|
||||
class AndroidJpsUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.android.AndroidJpsUtil");
|
||||
|
||||
@NonNls public static final String ANDROID_STORAGE_DIR = "android";
|
||||
@NonNls private static final String RESOURCE_CACHE_STORAGE = "res-cache";
|
||||
|
||||
public static final Condition<File> CLASSES_AND_JARS_FILTER = new Condition<File>() {
|
||||
@Override
|
||||
public boolean value(File file) {
|
||||
final String ext = FileUtil.getExtension(file.getName());
|
||||
return "jar".equals(ext) || "class".equals(ext);
|
||||
}
|
||||
};
|
||||
|
||||
private AndroidJpsUtil() {
|
||||
}
|
||||
|
||||
@@ -106,6 +116,19 @@ class AndroidJpsUtil {
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static List<String> toPaths(@NotNull Collection<File> files) {
|
||||
if (files.size() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final List<String> result = new ArrayList<String>(files.size());
|
||||
for (File file : files) {
|
||||
result.add(file.getPath());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static File getOutputDirectoryForPackagedFiles(@NotNull ProjectPaths paths, @NotNull Module module) {
|
||||
// todo: return build directory for mavenized modules to place .dex and .apk files into target dir (not target/classes)
|
||||
@@ -150,6 +173,7 @@ class AndroidJpsUtil {
|
||||
}
|
||||
|
||||
if (libraries != null) {
|
||||
// todo: do not include provided libs there
|
||||
for (ClasspathItem item : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE, exportedLibrariesOnly)) {
|
||||
if (item instanceof Library && !(item instanceof Sdk)) {
|
||||
for (String filePath : item.getClasspathRoots(ClasspathKind.PRODUCTION_COMPILE)) {
|
||||
@@ -180,7 +204,7 @@ class AndroidJpsUtil {
|
||||
if (depLibrary) {
|
||||
final File packagedClassesJar = new File(depClassDir, AndroidCommonUtils.CLASSES_JAR_FILE_NAME);
|
||||
|
||||
if (packagedClassesJar.isDirectory()) {
|
||||
if (packagedClassesJar.isFile()) {
|
||||
outputDirs.add(packagedClassesJar.getPath());
|
||||
}
|
||||
}
|
||||
@@ -402,4 +426,72 @@ class AndroidJpsUtil {
|
||||
final File androidStorage = new File(context.getDataManager().getDataStorageRoot(), ANDROID_STORAGE_DIR);
|
||||
return new File(new File(androidStorage, RESOURCE_CACHE_STORAGE), module.getName());
|
||||
}
|
||||
|
||||
private static void fillSourceRoots(@NotNull Module module, @NotNull Set<Module> visited, @NotNull Set<File> result)
|
||||
throws IOException {
|
||||
visited.add(module);
|
||||
final AndroidFacet facet = getFacet(module);
|
||||
File resDir = null;
|
||||
File resDirForCompilation = null;
|
||||
|
||||
if (facet != null) {
|
||||
resDir = facet.getResourceDir();
|
||||
resDirForCompilation = facet.getResourceDirForCompilation();
|
||||
}
|
||||
|
||||
for (String sourceRootPath : module.getSourceRoots()) {
|
||||
final File sourceRoot = new File(sourceRootPath).getCanonicalFile();
|
||||
|
||||
if (!sourceRoot.equals(resDir) && !sourceRoot.equals(resDirForCompilation)) {
|
||||
result.add(sourceRoot);
|
||||
}
|
||||
}
|
||||
|
||||
if (facet != null && facet.isPackTestCode()) {
|
||||
for (String testRootPath : module.getTestRoots()) {
|
||||
final File testRoot = new File(testRootPath).getCanonicalFile();
|
||||
|
||||
if (!testRoot.equals(resDir) && !testRoot.equals(resDirForCompilation)) {
|
||||
result.add(testRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) {
|
||||
if (classpathItem instanceof Module) {
|
||||
final Module depModule = (Module)classpathItem;
|
||||
|
||||
if (!visited.contains(depModule)) {
|
||||
fillSourceRoots(depModule, visited, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException {
|
||||
Set<File> result = new HashSet<File>();
|
||||
fillSourceRoots(module, new HashSet<Module>(), result);
|
||||
return result.toArray(new File[result.size()]);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getApkPath(@NotNull AndroidFacet facet, @NotNull File outputDirForPackagedArtifacts) {
|
||||
final String apkRelativePath = facet.getApkRelativePath();
|
||||
final Module module = facet.getModule();
|
||||
|
||||
if (apkRelativePath.length() == 0) {
|
||||
return new File(outputDirForPackagedArtifacts, getApkName(module)).getPath();
|
||||
}
|
||||
final String moduleDirPath = module.getBasePath();
|
||||
|
||||
return moduleDirPath != null
|
||||
? FileUtil.toSystemDependentName(moduleDirPath + apkRelativePath)
|
||||
: null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getApkName(@NotNull Module module) {
|
||||
return module.getName() + ".apk";
|
||||
}
|
||||
}
|
||||
|
||||
+3
-4
@@ -45,8 +45,7 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder {
|
||||
|
||||
private static ModuleLevelBuilder.ExitCode doBuild(CompileContext context, ModuleChunk chunk) throws IOException {
|
||||
boolean success = true;
|
||||
final AndroidClassesAndJarsStateStorage storage =
|
||||
new AndroidClassesAndJarsStateStorage(context.getDataManager().getDataStorageRoot(), "_libs");
|
||||
final AndroidFileSetStorage storage = new AndroidFileSetStorage(context.getDataManager().getDataStorageRoot(), "libs_packaging");
|
||||
|
||||
try {
|
||||
for (Module module : chunk.getModules()) {
|
||||
@@ -73,8 +72,8 @@ public class AndroidLibraryPackagingBuilder extends ModuleLevelBuilder {
|
||||
final Set<String> subdirs = new HashSet<String>();
|
||||
AndroidJpsUtil.addSubdirectories(classesDir, subdirs);
|
||||
|
||||
final AndroidClassesAndJarsState newState = new AndroidClassesAndJarsState(subdirs);
|
||||
final AndroidClassesAndJarsState oldState = storage.getState(module.getName());
|
||||
final AndroidFileSetState newState = new AndroidFileSetState(subdirs, AndroidJpsUtil.CLASSES_AND_JARS_FILTER, true);
|
||||
final AndroidFileSetState oldState = storage.getState(module.getName());
|
||||
|
||||
if (oldState != null && oldState.equalsTo(newState)) {
|
||||
continue;
|
||||
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.android.compiler.tools.AndroidApkBuilder;
|
||||
import org.jetbrains.android.compiler.tools.AndroidApt;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidCompilerMessageKind;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.CompilerExcludes;
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.Project;
|
||||
import org.jetbrains.jps.ProjectPaths;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
import org.jetbrains.jps.incremental.ProjectLevelBuilder;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidPackagingBuilder extends ProjectLevelBuilder {
|
||||
@NonNls private static final String BUILDER_NAME = "android-packager";
|
||||
@NonNls private static final String RELEASE_SUFFIX = ".release";
|
||||
@NonNls private static final String UNSIGNED_SUFFIX = ".unsigned";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return BUILDER_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Android Packaging Builder";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(CompileContext context) throws ProjectBuildException {
|
||||
if (!AndroidJpsUtil.containsAndroidFacet(context.getProject()) || AndroidJpsUtil.isLightBuild(context)) {
|
||||
return;
|
||||
}
|
||||
final Collection<Module> modules = context.getProject().getModules().values();
|
||||
final Map<Module, AndroidFileSetState> resourcesStates = new HashMap<Module, AndroidFileSetState>();
|
||||
final Map<Module, AndroidFileSetState> assetsStates = new HashMap<Module, AndroidFileSetState>();
|
||||
|
||||
try {
|
||||
fillStates(modules, resourcesStates, assetsStates);
|
||||
|
||||
if (!doCaching(context, modules, resourcesStates)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
|
||||
if (!doResourcePackaging(context, modules, resourcesStates, assetsStates)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
|
||||
if (!doPackaging(context, modules)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
}
|
||||
catch (ProjectBuildException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
AndroidJpsUtil.handleException(context, e, BUILDER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void fillStates(@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> resourcesStates,
|
||||
@NotNull Map<Module, AndroidFileSetState> assetsStates) throws IOException {
|
||||
for (Module module : modules) {
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
|
||||
if (facet != null) {
|
||||
final File resourceDir = facet.getResourceDir();
|
||||
final List<String> resourceDirs = resourceDir != null
|
||||
? Arrays.asList(resourceDir.getPath())
|
||||
: Collections.<String>emptyList();
|
||||
resourcesStates.put(module, new AndroidFileSetState(resourceDirs, Condition.TRUE, true));
|
||||
|
||||
final File assetsDir = facet.getAssetsDir();
|
||||
final List<String> assetDirs = assetsDir != null
|
||||
? Arrays.asList(assetsDir.getPath())
|
||||
: Collections.<String>emptyList();
|
||||
assetsStates.put(module, new AndroidFileSetState(assetDirs, Condition.TRUE, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doCaching(@NotNull CompileContext context,
|
||||
@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> module2state) throws IOException {
|
||||
boolean success = true;
|
||||
final File dataStorageRoot = context.getDataManager().getDataStorageRoot();
|
||||
final AndroidFileSetStorage storage = new AndroidFileSetStorage(dataStorageRoot, "resource_caching");
|
||||
|
||||
try {
|
||||
for (Module module : modules) {
|
||||
final AndroidFileSetState state = module2state.get(module);
|
||||
|
||||
try {
|
||||
if (!runPngCaching(context, module, storage, state)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
storage.close();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean runPngCaching(@NotNull CompileContext context,
|
||||
@NotNull Module module,
|
||||
@NotNull AndroidFileSetStorage storage,
|
||||
@Nullable AndroidFileSetState state)
|
||||
throws IOException {
|
||||
final AndroidFileSetState savedState = storage.getState(module.getName());
|
||||
if (context.isMake() && savedState != null && savedState.equalsTo(state)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
if (facet == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO,
|
||||
AndroidJpsBundle.message("android.jps.progress.res.caching", module.getName())));
|
||||
|
||||
final File resourceDir = AndroidJpsUtil.getResourceDirForCompilationPath(facet);
|
||||
if (resourceDir == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Pair<AndroidSdk, IAndroidTarget> pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final File resCacheDir = AndroidJpsUtil.getResourcesCacheDir(context, module);
|
||||
|
||||
if (!resCacheDir.exists()) {
|
||||
if (!resCacheDir.mkdirs()) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
|
||||
"Cannot create directory " + resCacheDir.getPath()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final IAndroidTarget target = pair.second;
|
||||
|
||||
final Map<AndroidCompilerMessageKind, List<String>> messages =
|
||||
AndroidApt.crunch(target, Collections.singletonList(resourceDir.getPath()), resCacheDir.getPath());
|
||||
|
||||
AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME);
|
||||
|
||||
final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty();
|
||||
storage.update(module.getName(), success ? state : null);
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean doResourcePackaging(@NotNull CompileContext context,
|
||||
@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> resourcesStates,
|
||||
@NotNull Map<Module, AndroidFileSetState> assetsStates) throws IOException {
|
||||
boolean success = true;
|
||||
|
||||
final File dataStorageRoot = context.getDataManager().getDataStorageRoot();
|
||||
final boolean releaseBuild = AndroidJpsUtil.isReleaseBuild(context);
|
||||
AndroidFileSetStorage resourcesStorage = null;
|
||||
AndroidFileSetStorage assetsStorage = null;
|
||||
|
||||
try {
|
||||
final String resourcesStorageName = releaseBuild ? "resources_packaging_release" : "resources_packaging_dev";
|
||||
resourcesStorage = new AndroidFileSetStorage(dataStorageRoot, resourcesStorageName);
|
||||
|
||||
final String assetsStorageName = releaseBuild ? "assets_packaging_release" : "assets_packaging_dev";
|
||||
assetsStorage = new AndroidFileSetStorage(dataStorageRoot, assetsStorageName);
|
||||
|
||||
for (Module module : modules) {
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
if (facet == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean updateState = true;
|
||||
|
||||
if (!facet.isLibrary() &&
|
||||
!(context.isMake() &&
|
||||
checkUpToDate(module, resourcesStates, resourcesStorage) &&
|
||||
checkUpToDate(module, assetsStates, assetsStorage))) {
|
||||
|
||||
updateState = packageResources(facet, context);
|
||||
|
||||
if (!updateState) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
resourcesStorage.update(module.getName(), updateState ? resourcesStates.get(module) : null);
|
||||
assetsStorage.update(module.getName(), updateState ? assetsStates.get(module) : null);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (resourcesStorage != null) {
|
||||
resourcesStorage.close();
|
||||
}
|
||||
|
||||
if (assetsStorage != null) {
|
||||
assetsStorage.close();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean doPackaging(@NotNull CompileContext context, @NotNull Collection<Module> modules) throws IOException {
|
||||
final boolean release = AndroidJpsUtil.isReleaseBuild(context);
|
||||
final File dataStorageRoot = context.getDataManager().getDataStorageRoot();
|
||||
|
||||
boolean success = true;
|
||||
|
||||
AndroidFileSetStorage apkFileSetStorage = null;
|
||||
AndroidApkBuilderConfigStateStorage apkBuilderConfigStateStorage = null;
|
||||
try {
|
||||
final String apkFileSetStorageName = "apk_builder_file_set" + (release ? "_release" : "_dev");
|
||||
apkFileSetStorage = new AndroidFileSetStorage(dataStorageRoot, apkFileSetStorageName);
|
||||
|
||||
final String apkBuilderStateStorageName = "apk_builder_config" + (release ? "_release" : "_dev");
|
||||
apkBuilderConfigStateStorage = new AndroidApkBuilderConfigStateStorage(dataStorageRoot, apkBuilderStateStorageName);
|
||||
|
||||
for (Module module : modules) {
|
||||
try {
|
||||
if (!doPackagingForModule(context, module, apkFileSetStorage, apkBuilderConfigStateStorage, release)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (apkFileSetStorage != null) {
|
||||
apkFileSetStorage.close();
|
||||
}
|
||||
|
||||
if (apkBuilderConfigStateStorage != null) {
|
||||
apkBuilderConfigStateStorage.close();
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean doPackagingForModule(@NotNull CompileContext context,
|
||||
@NotNull Module module,
|
||||
@NotNull AndroidFileSetStorage apkFileSetStorage,
|
||||
@NotNull AndroidApkBuilderConfigStateStorage apkBuilderConfigStateStorage,
|
||||
boolean release) throws IOException {
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
if (facet == null || facet.isLibrary()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final String[] sourceRoots = AndroidJpsUtil.toPaths(AndroidJpsUtil.getSourceRootsForModuleAndDependencies(module));
|
||||
final ProjectPaths paths = context.getProjectPaths();
|
||||
|
||||
final File outputDir = AndroidJpsUtil.getOutputDirectoryForPackagedFiles(paths, module);
|
||||
if (outputDir == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle
|
||||
.message("android.jps.errors.output.dir.not.specified", module.getName())));
|
||||
return false;
|
||||
}
|
||||
|
||||
final Pair<AndroidSdk, IAndroidTarget> pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Set<String> externalJarsSet = AndroidJpsUtil.getExternalLibraries(paths, module);
|
||||
final File resPackage = getPackagedResourcesFile(module, outputDir);
|
||||
|
||||
final File classesDexFile = new File(outputDir.getPath(), AndroidCommonUtils.CLASSES_FILE_NAME);
|
||||
|
||||
final String sdkPath = pair.getFirst().getSdkPath();
|
||||
final String outputPath = AndroidJpsUtil.getApkPath(facet, outputDir);
|
||||
if (outputPath == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
|
||||
"Cannot compute output path for file " + AndroidJpsUtil.getApkName(module)));
|
||||
return false;
|
||||
}
|
||||
final String customKeyStorePath = FileUtil.toSystemDependentName(facet.getCustomDebugKeyStorePath());
|
||||
final String[] nativeLibDirs = collectNativeLibsFolders(facet);
|
||||
|
||||
final String resPackagePath = release ? resPackage.getPath() + RELEASE_SUFFIX : resPackage.getPath();
|
||||
final String outputApkPath = release ? outputPath + UNSIGNED_SUFFIX : outputPath;
|
||||
final String classesDexFilePath = classesDexFile.getPath();
|
||||
final String[] externalJars = ArrayUtil.toStringArray(externalJarsSet);
|
||||
|
||||
final AndroidFileSetState currentFileSetState =
|
||||
buildCurrentApkBuilderState(context.getProject(), resPackagePath, classesDexFilePath, nativeLibDirs,
|
||||
sourceRoots, externalJars, release);
|
||||
|
||||
final AndroidApkBuilderConfigState currentApkBuilderConfigState =
|
||||
new AndroidApkBuilderConfigState(outputApkPath, customKeyStorePath);
|
||||
|
||||
final AndroidFileSetState savedApkFileSetState = apkFileSetStorage.getState(module.getName());
|
||||
final AndroidApkBuilderConfigState savedApkBuilderConfigState = apkBuilderConfigStateStorage.getState(module.getName());
|
||||
|
||||
if (context.isMake() &&
|
||||
currentFileSetState.equalsTo(savedApkFileSetState) &&
|
||||
currentApkBuilderConfigState.equalsTo(savedApkBuilderConfigState)) {
|
||||
return true;
|
||||
}
|
||||
context
|
||||
.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.packaging", AndroidJpsUtil.getApkName(module))));
|
||||
|
||||
final Map<AndroidCompilerMessageKind, List<String>> messages = AndroidApkBuilder
|
||||
.execute(resPackagePath, classesDexFilePath, sourceRoots, externalJars, nativeLibDirs, outputApkPath,
|
||||
release, sdkPath, customKeyStorePath, new MyExcludedSourcesFilter(context.getProject()));
|
||||
|
||||
AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME);
|
||||
final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty();
|
||||
|
||||
apkFileSetStorage.update(module.getName(), success ? currentFileSetState : null);
|
||||
apkBuilderConfigStateStorage.update(module.getName(), success ? currentApkBuilderConfigState : null);
|
||||
return success;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static AndroidFileSetState buildCurrentApkBuilderState(@NotNull Project project,
|
||||
@NotNull String resPackagePath,
|
||||
@NotNull String classesDexFilePath,
|
||||
@NotNull String[] nativeLibDirs,
|
||||
@NotNull String[] sourceRoots,
|
||||
@NotNull String[] externalJars,
|
||||
boolean release) {
|
||||
final List<String> roots = new ArrayList<String>();
|
||||
roots.add(resPackagePath);
|
||||
roots.add(classesDexFilePath);
|
||||
roots.addAll(Arrays.asList(externalJars));
|
||||
|
||||
for (String sourceRootPath : sourceRoots) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
AndroidApkBuilder.collectStandardSourceFolderResources(new File(sourceRootPath), files, new MyExcludedSourcesFilter(project));
|
||||
roots.addAll(AndroidJpsUtil.toPaths(files));
|
||||
}
|
||||
|
||||
for (String nativeLibDir : nativeLibDirs) {
|
||||
final List<File> files = new ArrayList<File>();
|
||||
AndroidApkBuilder.collectNativeLibraries(new File(nativeLibDir), files, !release);
|
||||
roots.addAll(AndroidJpsUtil.toPaths(files));
|
||||
}
|
||||
|
||||
return new AndroidFileSetState(roots, Condition.TRUE, false);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String[] collectNativeLibsFolders(@NotNull AndroidFacet facet) throws IOException {
|
||||
final List<String> result = new ArrayList<String>();
|
||||
final File libsDir = facet.getNativeLibsDir();
|
||||
|
||||
if (libsDir != null) {
|
||||
result.add(libsDir.getPath());
|
||||
}
|
||||
|
||||
for (AndroidFacet depFacet : AndroidJpsUtil.getAllDependentAndroidLibraries(facet.getModule())) {
|
||||
final File depLibsDir = depFacet.getNativeLibsDir();
|
||||
if (depLibsDir != null) {
|
||||
result.add(depLibsDir.getPath());
|
||||
}
|
||||
}
|
||||
return ArrayUtil.toStringArray(result);
|
||||
}
|
||||
|
||||
private static boolean checkUpToDate(@NotNull Module module,
|
||||
@NotNull Map<Module, AndroidFileSetState> module2state,
|
||||
@NotNull AndroidFileSetStorage storage) throws IOException {
|
||||
final AndroidFileSetState moduleState = module2state.get(module);
|
||||
final AndroidFileSetState savedState = storage.getState(module.getName());
|
||||
if (savedState == null || !savedState.equalsTo(moduleState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AndroidFacet libFacet : AndroidJpsUtil.getAllDependentAndroidLibraries(module)) {
|
||||
final Module libModule = libFacet.getModule();
|
||||
final AndroidFileSetState currentLibState = module2state.get(libModule);
|
||||
final AndroidFileSetState savedLibState = storage.getState(libModule.getName());
|
||||
|
||||
if (savedLibState == null || !savedLibState.equalsTo(currentLibState)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean packageResources(@NotNull AndroidFacet facet, @NotNull CompileContext context) {
|
||||
final Module module = facet.getModule();
|
||||
|
||||
try {
|
||||
context.processMessage(new ProgressMessage(AndroidJpsBundle.message("android.jps.progress.packaging.resources", module.getName())));
|
||||
|
||||
final File manifestFile = AndroidJpsUtil.getManifestFileForCompilationPath(facet);
|
||||
if (manifestFile == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
|
||||
AndroidJpsBundle.message("android.jps.errors.manifest.not.found", module.getName())));
|
||||
return false;
|
||||
}
|
||||
final File assetsDir = facet.getAssetsDir();
|
||||
|
||||
final File outputDir = AndroidJpsUtil.getOutputDirectoryForPackagedFiles(context.getProjectPaths(), module);
|
||||
if (outputDir == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle
|
||||
.message("android.jps.errors.output.dir.not.specified", module.getName())));
|
||||
return false;
|
||||
}
|
||||
|
||||
final Pair<AndroidSdk, IAndroidTarget> pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
final IAndroidTarget target = pair.getSecond();
|
||||
|
||||
final String outputFilePath = getPackagedResourcesFile(module, outputDir).getPath();
|
||||
final String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null;
|
||||
final String[] resourceDirPaths = AndroidJpsUtil.collectResourceDirsForCompilation(facet, true, context);
|
||||
|
||||
return doPackageResources(context, manifestFile, target, resourceDirPaths, assetsDirPath, outputFilePath,
|
||||
AndroidJpsUtil.isReleaseBuild(context));
|
||||
}
|
||||
catch (IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doPackageResources(@NotNull final CompileContext context,
|
||||
@NotNull File manifestFile,
|
||||
@NotNull IAndroidTarget target,
|
||||
@NotNull String[] resourceDirPaths,
|
||||
@Nullable String assetsDirPath,
|
||||
@NotNull String outputFilePath,
|
||||
boolean releasePackage) {
|
||||
try {
|
||||
final String outputPath = releasePackage
|
||||
? outputFilePath + RELEASE_SUFFIX
|
||||
: outputFilePath;
|
||||
final Map<AndroidCompilerMessageKind, List<String>> messages = AndroidApt
|
||||
.packageResources(target, -1, manifestFile.getPath(), resourceDirPaths, assetsDirPath, outputPath, null, !releasePackage, 0);
|
||||
|
||||
AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME);
|
||||
return messages.get(AndroidCompilerMessageKind.ERROR).size() == 0;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static File getPackagedResourcesFile(@NotNull Module module, @NotNull File outputDir) {
|
||||
return new File(outputDir.getPath(), module.getName() + ".apk.res");
|
||||
}
|
||||
|
||||
private static class MyExcludedSourcesFilter implements Condition<File> {
|
||||
private final CompilerExcludes myExcludes;
|
||||
|
||||
public MyExcludedSourcesFilter(@NotNull Project project) {
|
||||
myExcludes = project.getCompilerConfiguration().getExcludes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(File file) {
|
||||
return !myExcludes.isExcluded(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
-322
@@ -1,322 +0,0 @@
|
||||
package org.jetbrains.jps.android;
|
||||
|
||||
import com.android.sdklib.IAndroidTarget;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.android.compiler.tools.AndroidApt;
|
||||
import org.jetbrains.android.util.AndroidCompilerMessageKind;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.incremental.CompileContext;
|
||||
import org.jetbrains.jps.incremental.ProjectBuildException;
|
||||
import org.jetbrains.jps.incremental.ProjectLevelBuilder;
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage;
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage;
|
||||
import org.jetbrains.jps.incremental.messages.ProgressMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidResourcePackagingBuilder extends ProjectLevelBuilder {
|
||||
@NonNls private static final String BUILDER_NAME = "android-packager";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return BUILDER_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Android Packaging Builder";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build(CompileContext context) throws ProjectBuildException {
|
||||
if (!AndroidJpsUtil.containsAndroidFacet(context.getProject()) || AndroidJpsUtil.isLightBuild(context)) {
|
||||
return;
|
||||
}
|
||||
final Collection<Module> modules = context.getProject().getModules().values();
|
||||
final Map<Module, AndroidFileSetState> resourcesStates = new HashMap<Module, AndroidFileSetState>();
|
||||
final Map<Module, AndroidFileSetState> assetsStates = new HashMap<Module, AndroidFileSetState>();
|
||||
|
||||
try {
|
||||
fillStates(modules, resourcesStates, assetsStates);
|
||||
|
||||
if (!doCaching(context, modules, resourcesStates)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
|
||||
if (!doPackaging(context, modules, resourcesStates, assetsStates)) {
|
||||
throw new ProjectBuildException();
|
||||
}
|
||||
}
|
||||
catch (ProjectBuildException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
AndroidJpsUtil.handleException(context, e, BUILDER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private static void fillStates(@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> resourcesStates,
|
||||
@NotNull Map<Module, AndroidFileSetState> assetsStates) throws IOException {
|
||||
for (Module module : modules) {
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
|
||||
if (facet != null) {
|
||||
final File resourceDir = facet.getResourceDir();
|
||||
final List<String> resourceDirs = resourceDir != null
|
||||
? Arrays.asList(resourceDir.getPath())
|
||||
: Collections.<String>emptyList();
|
||||
resourcesStates.put(module, new AndroidFileSetState(resourceDirs));
|
||||
|
||||
final File assetsDir = facet.getAssetsDir();
|
||||
final List<String> assetDirs = assetsDir != null
|
||||
? Arrays.asList(assetsDir.getPath())
|
||||
: Collections.<String>emptyList();
|
||||
assetsStates.put(module, new AndroidFileSetState(assetDirs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doCaching(@NotNull CompileContext context,
|
||||
@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> module2state) throws IOException {
|
||||
boolean success = true;
|
||||
final File dataStorageRoot = context.getDataManager().getDataStorageRoot();
|
||||
final AndroidFileSetStorage storage = new AndroidFileSetStorage(dataStorageRoot, "resource_caching");
|
||||
|
||||
try {
|
||||
for (Module module : modules) {
|
||||
final AndroidFileSetState state = module2state.get(module);
|
||||
|
||||
try {
|
||||
if (!runPngCaching(context, module, storage, state)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
storage.close();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean runPngCaching(@NotNull CompileContext context,
|
||||
@NotNull Module module,
|
||||
@NotNull AndroidFileSetStorage storage,
|
||||
@Nullable AndroidFileSetState state)
|
||||
throws IOException {
|
||||
final AndroidFileSetState savedState = storage.getState(module.getName());
|
||||
if (savedState != null && savedState.equalsTo(state)) {
|
||||
return true;
|
||||
}
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.INFO,
|
||||
AndroidJpsBundle.message("android.jps.progress.res.caching", module.getName())));
|
||||
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
if (facet == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final File resourceDir = AndroidJpsUtil.getResourceDirForCompilationPath(facet);
|
||||
if (resourceDir == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final Pair<AndroidSdk, IAndroidTarget> pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final File resCacheDir = AndroidJpsUtil.getResourcesCacheDir(context, module);
|
||||
|
||||
if (!resCacheDir.exists()) {
|
||||
if (!resCacheDir.mkdirs()) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
|
||||
"Cannot create directory " + resCacheDir.getPath()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final IAndroidTarget target = pair.second;
|
||||
|
||||
final Map<AndroidCompilerMessageKind, List<String>> messages =
|
||||
AndroidApt.crunch(target, Collections.singletonList(resourceDir.getPath()), resCacheDir.getPath());
|
||||
|
||||
AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME);
|
||||
|
||||
final boolean success = messages.get(AndroidCompilerMessageKind.ERROR).isEmpty();
|
||||
storage.update(module.getName(), success ? state : null);
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean doPackaging(@NotNull CompileContext context,
|
||||
@NotNull Collection<Module> modules,
|
||||
@NotNull Map<Module, AndroidFileSetState> resourcesStates,
|
||||
@NotNull Map<Module, AndroidFileSetState> assetsStates) throws IOException {
|
||||
boolean success = true;
|
||||
|
||||
final File dataStorageRoot = context.getDataManager().getDataStorageRoot();
|
||||
AndroidFileSetStorage devResourcesStorage = null;
|
||||
AndroidFileSetStorage releaseResourcesStorage = null;
|
||||
AndroidFileSetStorage devAssetsStorage = null;
|
||||
AndroidFileSetStorage releaseAssetsStorage = null;
|
||||
|
||||
try {
|
||||
devResourcesStorage = new AndroidFileSetStorage(dataStorageRoot, "resources_packaging_dev");
|
||||
releaseResourcesStorage = new AndroidFileSetStorage(dataStorageRoot, "resources_packaging_release");
|
||||
|
||||
devAssetsStorage = new AndroidFileSetStorage(dataStorageRoot, "assets_packaging_dev");
|
||||
releaseAssetsStorage = new AndroidFileSetStorage(dataStorageRoot, "assets_packaging_release");
|
||||
|
||||
for (Module module : modules) {
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
if (facet == null || facet.isLibrary()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!packageResources(facet, context, devResourcesStorage, devAssetsStorage, releaseResourcesStorage, releaseAssetsStorage,
|
||||
resourcesStates, assetsStates)) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (devResourcesStorage != null) {
|
||||
devResourcesStorage.close();
|
||||
}
|
||||
if (releaseResourcesStorage != null) {
|
||||
releaseResourcesStorage.close();
|
||||
}
|
||||
if (devAssetsStorage != null) {
|
||||
devAssetsStorage.close();
|
||||
}
|
||||
if (releaseAssetsStorage != null) {
|
||||
releaseAssetsStorage.close();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private static boolean checkUpToDate(@NotNull Module module,
|
||||
@NotNull Map<Module, AndroidFileSetState> module2state,
|
||||
@NotNull AndroidFileSetStorage storage) throws IOException {
|
||||
final AndroidFileSetState moduleState = module2state.get(module);
|
||||
final AndroidFileSetState savedState = storage.getState(module.getName());
|
||||
if (savedState == null || !savedState.equalsTo(moduleState)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (AndroidFacet libFacet : AndroidJpsUtil.getAllDependentAndroidLibraries(module)) {
|
||||
final Module libModule = libFacet.getModule();
|
||||
final AndroidFileSetState currentLibState = module2state.get(libModule);
|
||||
final AndroidFileSetState savedLibState = storage.getState(libModule.getName());
|
||||
|
||||
if (savedLibState == null || !savedLibState.equalsTo(currentLibState)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean packageResources(@NotNull AndroidFacet facet,
|
||||
@NotNull CompileContext context,
|
||||
@NotNull AndroidFileSetStorage devResourcesStorage,
|
||||
@NotNull AndroidFileSetStorage devAssetsStorage,
|
||||
@NotNull AndroidFileSetStorage releaseResourcesStorage,
|
||||
@NotNull AndroidFileSetStorage releaseAssetsStorage,
|
||||
@NotNull Map<Module, AndroidFileSetState> resourcesStates,
|
||||
@NotNull Map<Module, AndroidFileSetState> assetsStates) {
|
||||
final Module module = facet.getModule();
|
||||
|
||||
final boolean releaseBuild = AndroidJpsUtil.isReleaseBuild(context);
|
||||
final AndroidFileSetStorage resourcesStorage = releaseBuild ? releaseResourcesStorage : devResourcesStorage;
|
||||
final AndroidFileSetStorage assetsStorage = releaseBuild ? releaseAssetsStorage : devAssetsStorage;
|
||||
|
||||
try {
|
||||
if (checkUpToDate(module, resourcesStates, resourcesStorage) &&
|
||||
checkUpToDate(module, assetsStates, assetsStorage)) {
|
||||
return true;
|
||||
}
|
||||
context.processMessage(new ProgressMessage("Packaging resources for module " + module.getName()));
|
||||
|
||||
final File manifestFile = AndroidJpsUtil.getManifestFileForCompilationPath(facet);
|
||||
if (manifestFile == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR,
|
||||
AndroidJpsBundle.message("android.jps.errors.manifest.not.found", module.getName())));
|
||||
return false;
|
||||
}
|
||||
final File assetsDir = facet.getAssetsDir();
|
||||
|
||||
final File outputDir = AndroidJpsUtil.getOutputDirectoryForPackagedFiles(context.getProjectPaths(), module);
|
||||
if (outputDir == null) {
|
||||
context.processMessage(new CompilerMessage(BUILDER_NAME, BuildMessage.Kind.ERROR, AndroidJpsBundle
|
||||
.message("android.jps.errors.output.dir.not.specified", module.getName())));
|
||||
return false;
|
||||
}
|
||||
|
||||
final Pair<AndroidSdk, IAndroidTarget> pair = AndroidJpsUtil.getAndroidPlatform(module, context, BUILDER_NAME);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
final IAndroidTarget target = pair.getSecond();
|
||||
|
||||
final String outputFilePath = getOutputFile(module, outputDir).getPath();
|
||||
final String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null;
|
||||
final String[] resourceDirPaths = AndroidJpsUtil.collectResourceDirsForCompilation(facet, true, context);
|
||||
|
||||
if (!doPackageResources(context, manifestFile, target, resourceDirPaths, assetsDirPath, outputFilePath, releaseBuild)) {
|
||||
resourcesStorage.update(module.getName(), null);
|
||||
assetsStorage.update(module.getName(), null);
|
||||
return false;
|
||||
}
|
||||
resourcesStorage.update(module.getName(), resourcesStates.get(module));
|
||||
assetsStorage.update(module.getName(), assetsStates.get(module));
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean doPackageResources(@NotNull final CompileContext context,
|
||||
@NotNull File manifestFile,
|
||||
@NotNull IAndroidTarget target,
|
||||
@NotNull String[] resourceDirPaths,
|
||||
@Nullable String assetsDirPath,
|
||||
@NotNull String outputFilePath,
|
||||
boolean releasePackage) {
|
||||
try {
|
||||
final String outputPath = releasePackage
|
||||
? outputFilePath + ".release"
|
||||
: outputFilePath;
|
||||
final Map<AndroidCompilerMessageKind, List<String>> messages = AndroidApt
|
||||
.packageResources(target, -1, manifestFile.getPath(), resourceDirPaths, assetsDirPath, outputPath, null, !releasePackage, 0);
|
||||
|
||||
AndroidJpsUtil.addMessages(context, messages, BUILDER_NAME);
|
||||
return messages.get(AndroidCompilerMessageKind.ERROR).size() == 0;
|
||||
}
|
||||
catch (final IOException e) {
|
||||
AndroidJpsUtil.reportExceptionError(context, null, e, BUILDER_NAME);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
static File getOutputFile(@NotNull Module module, @NotNull File outputDir) {
|
||||
return new File(outputDir.getPath(), module.getName() + ".apk.res");
|
||||
}
|
||||
}
|
||||
+1
-41
@@ -18,8 +18,6 @@ import org.jetbrains.android.util.ValueResourcesFileParser;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.ClasspathItem;
|
||||
import org.jetbrains.jps.ClasspathKind;
|
||||
import org.jetbrains.jps.Module;
|
||||
import org.jetbrains.jps.ModuleChunk;
|
||||
import org.jetbrains.jps.incremental.*;
|
||||
@@ -153,7 +151,7 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
|
||||
final IAndroidTarget target = moduleData.getAndroidTarget();
|
||||
|
||||
try {
|
||||
final File[] sourceRoots = getSourceRootsForModuleAndDependencies(module);
|
||||
final File[] sourceRoots = AndroidJpsUtil.getSourceRootsForModuleAndDependencies(module);
|
||||
final String[] sourceRootPaths = AndroidJpsUtil.toPaths(sourceRoots);
|
||||
final String packageName = computePackageForFile(context, file);
|
||||
|
||||
@@ -569,44 +567,6 @@ public class AndroidSourceGeneratingBuilder extends ModuleLevelBuilder {
|
||||
return FileUtil.toSystemIndependentName(relPath).replace('/', '.');
|
||||
}
|
||||
|
||||
private static void fillSourceRoots(@NotNull Module module, @NotNull Set<Module> visited, @NotNull Set<File> result)
|
||||
throws IOException {
|
||||
visited.add(module);
|
||||
final AndroidFacet facet = AndroidJpsUtil.getFacet(module);
|
||||
File resDir = null;
|
||||
File resDirForCompilation = null;
|
||||
|
||||
if (facet != null) {
|
||||
resDir = facet.getResourceDir();
|
||||
resDirForCompilation = facet.getResourceDirForCompilation();
|
||||
}
|
||||
|
||||
for (String sourceRootPath : module.getSourceRoots()) {
|
||||
final File sourceRoot = new File(sourceRootPath).getCanonicalFile();
|
||||
|
||||
if (!sourceRoot.equals(resDir) && !sourceRoot.equals(resDirForCompilation)) {
|
||||
result.add(sourceRoot);
|
||||
}
|
||||
}
|
||||
|
||||
for (ClasspathItem classpathItem : module.getClasspath(ClasspathKind.PRODUCTION_COMPILE)) {
|
||||
if (classpathItem instanceof Module) {
|
||||
final Module depModule = (Module)classpathItem;
|
||||
|
||||
if (!visited.contains(depModule)) {
|
||||
fillSourceRoots(depModule, visited, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static File[] getSourceRootsForModuleAndDependencies(@NotNull Module module) throws IOException {
|
||||
Set<File> result = new HashSet<File>();
|
||||
fillSourceRoots(module, new HashSet<Module>(), result);
|
||||
return result.toArray(new File[result.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Android Source Generating Builder";
|
||||
|
||||
@@ -139,7 +139,6 @@ avd.not.valid.error=AVD {0} is not valid
|
||||
avd.not.compatible.error=Build target of AVD {0} is not compatible with your build target
|
||||
avd.cannot.be.loaded.error=Cannot load virtual devices
|
||||
navigate.to.android.resource.action=Navigate to Android resource definition
|
||||
android.debug.certificate.expired.error=Debug certificate expired on {0}. Cannot regenerate it, please delete file \"{1}\" manually.
|
||||
android.identifier.expected={0} is not an identifier
|
||||
android.directory.cannot.be.found.error="{0}" directory cannot be found
|
||||
create.run.configuration.question=Do you want to create run configuration for module {0}?
|
||||
|
||||
@@ -14,11 +14,15 @@
|
||||
<CLASSES>
|
||||
<root url="jar://$MODULE_DIR$/../lib/sdklib.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/common.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/jarutils.jar!/" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/androidprefs.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES>
|
||||
<root url="jar://$MODULE_DIR$/../lib/src/sdklib_src.zip!/src" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/src/common_src.zip!/src" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/src/jarutils.zip!/src" />
|
||||
<root url="jar://$MODULE_DIR$/../lib/src/androidprefs_src.zip!/src" />
|
||||
</SOURCES>
|
||||
</library>
|
||||
</orderEntry>
|
||||
|
||||
+97
-128
@@ -20,25 +20,15 @@ import com.android.jarutils.JavaResourceFilter;
|
||||
import com.android.jarutils.SignedJarBuilder;
|
||||
import com.android.prefs.AndroidLocation;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.intellij.ide.highlighter.ArchiveFileType;
|
||||
import com.intellij.openapi.compiler.CompilerManager;
|
||||
import com.intellij.openapi.compiler.CompilerMessageCategory;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.text.DateFormatUtil;
|
||||
import org.jetbrains.android.compiler.AndroidCompileUtil;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidCompilerMessageKind;
|
||||
import org.jetbrains.android.util.AndroidExecutionUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -54,7 +44,7 @@ import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static com.intellij.openapi.compiler.CompilerMessageCategory.*;
|
||||
import static org.jetbrains.android.util.AndroidCompilerMessageKind.*;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
@@ -68,7 +58,7 @@ public class AndroidApkBuilder {
|
||||
private AndroidApkBuilder() {
|
||||
}
|
||||
|
||||
private static Map<CompilerMessageCategory, List<String>> filterUsingKeystoreMessages(Map<CompilerMessageCategory, List<String>> messages) {
|
||||
private static Map<AndroidCompilerMessageKind, List<String>> filterUsingKeystoreMessages(Map<AndroidCompilerMessageKind, List<String>> messages) {
|
||||
List<String> infoMessages = messages.get(INFORMATION);
|
||||
if (infoMessages == null) {
|
||||
infoMessages = new ArrayList<String>();
|
||||
@@ -118,48 +108,49 @@ public class AndroidApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<CompilerMessageCategory, List<String>> execute(Project project,
|
||||
@NotNull String resPackagePath,
|
||||
@NotNull String dexPath,
|
||||
@NotNull VirtualFile[] sourceRoots,
|
||||
@NotNull String[] externalJars,
|
||||
@NotNull VirtualFile[] nativeLibsFolders,
|
||||
@NotNull String finalApk,
|
||||
boolean unsigned,
|
||||
@NotNull String sdkPath,
|
||||
@Nullable String customKeystorePath) throws IOException {
|
||||
public static Map<AndroidCompilerMessageKind, List<String>> execute(@NotNull String resPackagePath,
|
||||
@NotNull String dexPath,
|
||||
@NotNull String[] sourceRoots,
|
||||
@NotNull String[] externalJars,
|
||||
@NotNull String[] nativeLibsFolders,
|
||||
@NotNull String finalApk,
|
||||
boolean unsigned,
|
||||
@NotNull String sdkPath,
|
||||
@Nullable String customKeystorePath,
|
||||
@NotNull Condition<File> resourceFilter) throws IOException {
|
||||
if (unsigned) {
|
||||
return filterUsingKeystoreMessages(
|
||||
finalPackage(project, dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, resPackagePath, customKeystorePath, false));
|
||||
finalPackage(dexPath, sourceRoots, externalJars, nativeLibsFolders, finalApk, resPackagePath, customKeystorePath, false,
|
||||
resourceFilter));
|
||||
}
|
||||
|
||||
final Map<CompilerMessageCategory, List<String>> map = new HashMap<CompilerMessageCategory, List<String>>();
|
||||
final String zipAlignPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_ZIPALIGN);
|
||||
final Map<AndroidCompilerMessageKind, List<String>> map = new HashMap<AndroidCompilerMessageKind, List<String>>();
|
||||
final String zipAlignPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.FN_ZIPALIGN);
|
||||
boolean withAlignment = new File(zipAlignPath).exists();
|
||||
String unalignedApk = finalApk + UNALIGNED_SUFFIX;
|
||||
|
||||
Map<CompilerMessageCategory, List<String>> map2 = filterUsingKeystoreMessages(
|
||||
finalPackage(project, dexPath, sourceRoots, externalJars, nativeLibsFolders, withAlignment ? unalignedApk : finalApk, resPackagePath,
|
||||
customKeystorePath, true));
|
||||
Map<AndroidCompilerMessageKind, List<String>> map2 = filterUsingKeystoreMessages(
|
||||
finalPackage(dexPath, sourceRoots, externalJars, nativeLibsFolders, withAlignment ? unalignedApk : finalApk, resPackagePath,
|
||||
customKeystorePath, true, resourceFilter));
|
||||
map.putAll(map2);
|
||||
|
||||
if (withAlignment && map.get(ERROR).size() == 0) {
|
||||
map2 = AndroidCompileUtil.execute(zipAlignPath, "-f", "4", unalignedApk, finalApk);
|
||||
map2 = AndroidExecutionUtil.doExecute(zipAlignPath, "-f", "4", unalignedApk, finalApk);
|
||||
map.putAll(map2);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private static Map<CompilerMessageCategory, List<String>> finalPackage(Project project,
|
||||
@NotNull String dexPath,
|
||||
@NotNull VirtualFile[] sourceRoots,
|
||||
@NotNull String[] externalJars,
|
||||
@NotNull VirtualFile[] nativeLibsFolders,
|
||||
@NotNull String outputApk,
|
||||
@NotNull String apkPath,
|
||||
@Nullable String customKeystorePath,
|
||||
boolean signed) {
|
||||
final Map<CompilerMessageCategory, List<String>> result = new HashMap<CompilerMessageCategory, List<String>>();
|
||||
private static Map<AndroidCompilerMessageKind, List<String>> finalPackage(@NotNull String dexPath,
|
||||
@NotNull String[] sourceRoots,
|
||||
@NotNull String[] externalJars,
|
||||
@NotNull String[] nativeLibsFolders,
|
||||
@NotNull String outputApk,
|
||||
@NotNull String apkPath,
|
||||
@Nullable String customKeystorePath,
|
||||
boolean signed,
|
||||
@NotNull Condition<File> resourceFilter) {
|
||||
final Map<AndroidCompilerMessageKind, List<String>> result = new HashMap<AndroidCompilerMessageKind, List<String>>();
|
||||
result.put(ERROR, new ArrayList<String>());
|
||||
result.put(INFORMATION, new ArrayList<String>());
|
||||
result.put(WARNING, new ArrayList<String>());
|
||||
@@ -187,35 +178,36 @@ public class AndroidApkBuilder {
|
||||
|
||||
if (certificate != null && certificate.getNotAfter().compareTo(new Date()) < 0) {
|
||||
String date = DateFormatUtil.formatPrettyDateTime(certificate.getNotAfter());
|
||||
result.get(ERROR).add(AndroidBundle.message("android.debug.certificate.expired.error", date, keyStoreOsPath));
|
||||
result.get(ERROR).add(
|
||||
("Debug certificate expired on " + date + ". Cannot regenerate it, please delete file \"" + keyStoreOsPath + "\" manually."));
|
||||
return result;
|
||||
}
|
||||
|
||||
PrivateKey key = provider.getDebugKey();
|
||||
|
||||
if (key == null) {
|
||||
result.get(ERROR).add(AndroidBundle.message("android.cannot.create.new.key.error"));
|
||||
result.get(ERROR).add("Cannot create new key or keystore");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (!new File(apkPath).exists()) {
|
||||
result.get(CompilerMessageCategory.ERROR).add("File " + apkPath + " not found. Try to rebuild project");
|
||||
result.get(ERROR).add("File " + apkPath + " not found. Try to rebuild project");
|
||||
return result;
|
||||
}
|
||||
|
||||
File dexEntryFile = new File(dexPath);
|
||||
if (!dexEntryFile.exists()) {
|
||||
result.get(CompilerMessageCategory.ERROR).add("File " + dexEntryFile.getPath() + " not found. Try to rebuild project");
|
||||
result.get(ERROR).add("File " + dexEntryFile.getPath() + " not found. Try to rebuild project");
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String externalJar : externalJars) {
|
||||
if (new File(externalJar).isDirectory()) {
|
||||
result.get(CompilerMessageCategory.ERROR).add(externalJar + " is directory. Directory libraries are not supported");
|
||||
result.get(ERROR).add(externalJar + " is directory. Directory libraries are not supported");
|
||||
}
|
||||
}
|
||||
|
||||
if (result.get(CompilerMessageCategory.ERROR).size() > 0) {
|
||||
if (result.get(ERROR).size() > 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -233,9 +225,10 @@ public class AndroidApkBuilder {
|
||||
builder.writeFile(dexEntryFile, AndroidCommonUtils.CLASSES_FILE_NAME);
|
||||
|
||||
final HashSet<String> added = new HashSet<String>();
|
||||
for (VirtualFile sourceRoot : sourceRoots) {
|
||||
final HashSet<VirtualFile> sourceFolderResources = new HashSet<VirtualFile>();
|
||||
collectStandardSourceFolderResources(sourceRoot, new HashSet<VirtualFile>(), sourceFolderResources, project);
|
||||
for (String sourceRootPath : sourceRoots) {
|
||||
final HashSet<File> sourceFolderResources = new HashSet<File>();
|
||||
final File sourceRoot = new File(sourceRootPath);
|
||||
collectStandardSourceFolderResources(sourceRoot, sourceFolderResources, resourceFilter);
|
||||
writeStandardSourceFolderResources(sourceFolderResources, sourceRoot, builder, added);
|
||||
}
|
||||
|
||||
@@ -246,7 +239,7 @@ public class AndroidApkBuilder {
|
||||
}
|
||||
|
||||
for (String duplicate : duplicates) {
|
||||
result.get(CompilerMessageCategory.WARNING).add("Duplicate entry " + duplicate + ". The file won't be added");
|
||||
result.get(WARNING).add("Duplicate entry " + duplicate + ". The file won't be added");
|
||||
}
|
||||
|
||||
MyResourceFilter filter = new MyResourceFilter(duplicates);
|
||||
@@ -262,9 +255,14 @@ public class AndroidApkBuilder {
|
||||
}
|
||||
|
||||
final HashSet<String> nativeLibs = new HashSet<String>();
|
||||
for (VirtualFile nativeLibsFolder : nativeLibsFolders) {
|
||||
for (VirtualFile child : nativeLibsFolder.getChildren()) {
|
||||
writeNativeLibraries(builder, nativeLibsFolder, child, signed, nativeLibs);
|
||||
for (String nativeLibsFolderPath : nativeLibsFolders) {
|
||||
final File nativeLibsFolder = new File(nativeLibsFolderPath);
|
||||
final File[] children = nativeLibsFolder.listFiles();
|
||||
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
writeNativeLibraries(builder, nativeLibsFolder, child, signed, nativeLibs);
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.close();
|
||||
@@ -305,7 +303,7 @@ public class AndroidApkBuilder {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static DebugKeyProvider createDebugKeyProvider(final Map<CompilerMessageCategory, List<String>> result, String path) throws
|
||||
private static DebugKeyProvider createDebugKeyProvider(final Map<AndroidCompilerMessageKind, List<String>> result, String path) throws
|
||||
KeyStoreException,
|
||||
NoSuchAlgorithmException,
|
||||
CertificateException,
|
||||
@@ -326,18 +324,20 @@ public class AndroidApkBuilder {
|
||||
}
|
||||
|
||||
private static void writeNativeLibraries(SignedJarBuilder builder,
|
||||
VirtualFile nativeLibsFolder,
|
||||
VirtualFile child,
|
||||
File nativeLibsFolder,
|
||||
File child,
|
||||
boolean debugBuild,
|
||||
Set<String> added)
|
||||
throws IOException {
|
||||
ArrayList<VirtualFile> list = new ArrayList<VirtualFile>();
|
||||
ArrayList<File> list = new ArrayList<File>();
|
||||
collectNativeLibraries(child, list, debugBuild);
|
||||
for (VirtualFile file : list) {
|
||||
String relativePath = VfsUtilCore.getRelativePath(file, nativeLibsFolder, File.separatorChar);
|
||||
|
||||
for (File file : list) {
|
||||
final String relativePath = FileUtil.getRelativePath(nativeLibsFolder, file);
|
||||
String path = FileUtil.toSystemIndependentName(SdkConstants.FD_APK_NATIVE_LIBS + File.separator + relativePath);
|
||||
|
||||
if (added.add(path)) {
|
||||
builder.writeFile(toIoFile(file), path);
|
||||
builder.writeFile(file, path);
|
||||
LOG.info("Native lib file added to APK: " + file.getPath());
|
||||
}
|
||||
else {
|
||||
@@ -346,104 +346,73 @@ public class AndroidApkBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<CompilerMessageCategory, List<String>> addExceptionMessage(Exception e,
|
||||
Map<CompilerMessageCategory, List<String>> result) {
|
||||
private static Map<AndroidCompilerMessageKind, List<String>> addExceptionMessage(Exception e,
|
||||
Map<AndroidCompilerMessageKind, List<String>> result) {
|
||||
LOG.info(e);
|
||||
String simpleExceptionName = e.getClass().getCanonicalName();
|
||||
result.get(ERROR).add(simpleExceptionName + ": " + e.getMessage());
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void collectNativeLibraries(@NotNull VirtualFile file, @NotNull List<VirtualFile> result, boolean debugBuild) {
|
||||
public static void collectNativeLibraries(@NotNull File file, @NotNull List<File> result, boolean debugBuild) {
|
||||
if (!file.isDirectory()) {
|
||||
String ext = file.getExtension();
|
||||
String ext = FileUtil.getExtension(file.getName());
|
||||
|
||||
// some users store jars and *.so libs in the same directory. Do not pack JARs to APK's "lib" folder!
|
||||
if (EXT_NATIVE_LIB.equalsIgnoreCase(ext) ||
|
||||
(debugBuild && !(file.getFileType() instanceof ArchiveFileType))) {
|
||||
(debugBuild && !("jar".equals(ext)))) {
|
||||
result.add(file);
|
||||
}
|
||||
}
|
||||
else if (JavaResourceFilter.checkFolderForPackaging(file.getName())) {
|
||||
for (VirtualFile child : file.getChildren()) {
|
||||
collectNativeLibraries(child, result, debugBuild);
|
||||
final File[] children = file.listFiles();
|
||||
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
collectNativeLibraries(child, result, debugBuild);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectStandardSourceFolderResources(VirtualFile sourceFolder,
|
||||
Set<VirtualFile> visited,
|
||||
Set<VirtualFile> result,
|
||||
@Nullable Project project) {
|
||||
visited.add(sourceFolder);
|
||||
|
||||
for (VirtualFile child : sourceFolder.getChildren()) {
|
||||
if (child.exists()) {
|
||||
if (child.isDirectory()) {
|
||||
if (!visited.contains(child) &&
|
||||
JavaResourceFilter.checkFolderForPackaging(child.getName()) && !isExcludedFromCompilation(child, project)) {
|
||||
collectStandardSourceFolderResources(child, visited, result, project);
|
||||
public static void collectStandardSourceFolderResources(@NotNull File sourceFolder,
|
||||
@NotNull Collection<File> result,
|
||||
@NotNull Condition<File> filter) {
|
||||
final File[] children = sourceFolder.listFiles();
|
||||
|
||||
if (children != null) {
|
||||
for (File child : children) {
|
||||
if (child.exists()) {
|
||||
if (child.isDirectory()) {
|
||||
if (JavaResourceFilter.checkFolderForPackaging(child.getName()) && filter.value(child)) {
|
||||
collectStandardSourceFolderResources(child, result, filter);
|
||||
}
|
||||
}
|
||||
else if (checkFileForPackaging(child) && filter.value(child)) {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
else if (checkFileForPackaging(child) && !isExcludedFromCompilation(child, project)) {
|
||||
result.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isExcludedFromCompilation(VirtualFile child, @Nullable Project project) {
|
||||
final CompilerManager compilerManager = project != null ? CompilerManager.getInstance(project) : null;
|
||||
|
||||
if (compilerManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compilerManager.isExcludedFromCompilation(child)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Module module = ModuleUtil.findModuleForFile(child, project);
|
||||
if (module == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AndroidFacet facet = AndroidFacet.getInstance(module);
|
||||
if (facet == null || !facet.getConfiguration().LIBRARY_PROJECT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform();
|
||||
if (platform == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// we exclude sources of library modules automatically for tools r7 or previous
|
||||
return platform.getSdkData().getPlatformToolsRevision() > 7;
|
||||
}
|
||||
|
||||
private static void writeStandardSourceFolderResources(Collection<VirtualFile> resources,
|
||||
VirtualFile sourceRoot,
|
||||
private static void writeStandardSourceFolderResources(Collection<File> resources,
|
||||
File sourceRoot,
|
||||
SignedJarBuilder jarBuilder,
|
||||
Set<String> added) throws IOException {
|
||||
for (VirtualFile child : resources) {
|
||||
final String relativePath = FileUtil.toSystemIndependentName(VfsUtilCore.getRelativePath(child, sourceRoot, File.separatorChar));
|
||||
if (!added.contains(relativePath)) {
|
||||
File file = toIoFile(child);
|
||||
jarBuilder.writeFile(file, FileUtil.toSystemIndependentName(relativePath));
|
||||
for (File child : resources) {
|
||||
final String relativePath = FileUtil.getRelativePath(sourceRoot, child);
|
||||
if (relativePath != null && !added.contains(relativePath)) {
|
||||
jarBuilder.writeFile(child, FileUtil.toSystemIndependentName(relativePath));
|
||||
added.add(relativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static File toIoFile(VirtualFile child) {
|
||||
return new File(FileUtil.toSystemDependentName(child.getPath())).getAbsoluteFile();
|
||||
}
|
||||
|
||||
private static boolean checkFileForPackaging(VirtualFile file) {
|
||||
String fileName = file.getNameWithoutExtension();
|
||||
private static boolean checkFileForPackaging(File file) {
|
||||
String fileName = FileUtil.getNameWithoutExtension(file);
|
||||
if (fileName.length() > 0) {
|
||||
return JavaResourceFilter.checkFileForPackaging(fileName, file.getExtension());
|
||||
return JavaResourceFilter.checkFileForPackaging(fileName, FileUtil.getExtension(file.getName()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -343,4 +343,8 @@ public class AndroidCommonUtils {
|
||||
|
||||
return FileUtil.toSystemDependentName(inputJar.getPath());
|
||||
}
|
||||
|
||||
public static String toolPath(@NotNull String toolFileName) {
|
||||
return SdkConstants.OS_SDK_TOOLS_FOLDER + toolFileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,6 +205,14 @@
|
||||
<compileServer.plugin jar-path="common.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../community/plugins/android/lib/common.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../plugins/android/lib/common.jar"/>
|
||||
|
||||
<compileServer.plugin jar-path="jarutils.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../community/plugins/android/lib/jarutils.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../plugins/android/lib/jarutils.jar"/>
|
||||
|
||||
<compileServer.plugin jar-path="androidprefs.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../community/plugins/android/lib/androidprefs.jar"/>
|
||||
<compileServer.plugin jar-path="../../../../../plugins/android/lib/androidprefs.jar"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
|
||||
@@ -20,8 +20,8 @@ import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.ExecutionStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -47,7 +47,7 @@ public class RunAndroidAvdManagerAction extends AndroidRunSdkToolAction {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String toolPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName());
|
||||
final String toolPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName());
|
||||
GeneralCommandLine commandLine = new GeneralCommandLine();
|
||||
commandLine.setExePath(toolPath);
|
||||
commandLine.addParameter("avd");
|
||||
|
||||
@@ -20,8 +20,8 @@ import com.intellij.execution.ExecutionException;
|
||||
import com.intellij.execution.configurations.GeneralCommandLine;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.ExecutionStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -43,7 +43,7 @@ public class RunAndroidSdkManagerAction extends AndroidRunSdkToolAction {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String toolPath = sdkPath + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName());
|
||||
final String toolPath = sdkPath + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName());
|
||||
GeneralCommandLine commandLine = new GeneralCommandLine();
|
||||
commandLine.setExePath(toolPath);
|
||||
commandLine.addParameter("sdk");
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.module.ModuleUtil;
|
||||
import com.intellij.openapi.project.DumbService;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.*;
|
||||
@@ -769,4 +770,39 @@ public class AndroidCompileUtil {
|
||||
if (compilerOutput == null) return null;
|
||||
return new File(compilerOutput.getPath(), getApkName(module)).getPath();
|
||||
}
|
||||
|
||||
public static boolean isExcludedFromCompilation(@NotNull File file, @Nullable Project project) {
|
||||
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file);
|
||||
return vFile != null && isExcludedFromCompilation(vFile, project);
|
||||
}
|
||||
|
||||
public static boolean isExcludedFromCompilation(VirtualFile child, @Nullable Project project) {
|
||||
final CompilerManager compilerManager = project != null ? CompilerManager.getInstance(project) : null;
|
||||
|
||||
if (compilerManager == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!compilerManager.isExcludedFromCompilation(child)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Module module = ModuleUtil.findModuleForFile(child, project);
|
||||
if (module == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AndroidFacet facet = AndroidFacet.getInstance(module);
|
||||
if (facet == null || !facet.getConfiguration().LIBRARY_PROJECT) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AndroidPlatform platform = facet.getConfiguration().getAndroidPlatform();
|
||||
if (platform == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// we exclude sources of library modules automatically for tools r7 or previous
|
||||
return platform.getSdkData().getPlatformToolsRevision() > 7;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.compiler.*;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.module.ModuleManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.DependencyScope;
|
||||
import com.intellij.openapi.roots.ModuleOrderEntry;
|
||||
import com.intellij.openapi.roots.ModuleRootManager;
|
||||
@@ -233,9 +234,15 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
? item.getFinalPath() + UNSIGNED_SUFFIX
|
||||
: item.getFinalPath();
|
||||
|
||||
final Map<CompilerMessageCategory, List<String>> messages = AndroidApkBuilder
|
||||
.execute(context.getProject(), resPackagePath, item.getClassesDexPath(), item.getSourceRoots(), externalLibPaths, item.getNativeLibsFolders(),
|
||||
finalPath, unsigned, item.mySdkPath, item.getCustomKeystorePath());
|
||||
final String[] sourceRoots = AndroidCompileUtil.toOsPaths(item.getSourceRoots());
|
||||
final String[] nativeLibsFolders = AndroidCompileUtil.toOsPaths(item.getNativeLibsFolders());
|
||||
final Project project = context.getProject();
|
||||
|
||||
final Map<CompilerMessageCategory, List<String>> messages = AndroidCompileUtil.toCompilerMessageCategoryKeys(
|
||||
AndroidApkBuilder.execute(resPackagePath, item.getClassesDexPath(), sourceRoots, externalLibPaths,
|
||||
nativeLibsFolders, finalPath, unsigned, item.mySdkPath, item.getCustomKeystorePath(),
|
||||
new ExcludedSourcesFilter(project)));
|
||||
|
||||
AndroidCompileUtil.addMessages(context, messages);
|
||||
}
|
||||
catch (final IOException e) {
|
||||
@@ -296,7 +303,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
private final boolean myGenerateUnsigendApk;
|
||||
private final Module myModule;
|
||||
private boolean myReleaseBuild;
|
||||
|
||||
|
||||
private final String myCustomKeystorePath;
|
||||
|
||||
private AptPackagingItem(String sdkPath,
|
||||
@@ -375,8 +382,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
|
||||
@Nullable
|
||||
public ValidityState getValidityState() {
|
||||
return new MyValidityState(myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsigendApk, myReleaseBuild,
|
||||
mySourceRoots, myExternalLibraries, myNativeLibsFolders, myCustomKeystorePath);
|
||||
return new MyValidityState(myModule.getProject(), myResPackagePath, myClassesDexPath, myFinalPath, myGenerateUnsigendApk,
|
||||
myReleaseBuild, mySourceRoots, myExternalLibraries, myNativeLibsFolders, myCustomKeystorePath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +407,8 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
myCustomKeystorePath = CompilerIOUtil.readString(is);
|
||||
}
|
||||
|
||||
MyValidityState(String resPackagePath,
|
||||
MyValidityState(Project project,
|
||||
String resPackagePath,
|
||||
String classesDexPath,
|
||||
String apkPath,
|
||||
boolean generateUnsignedApk,
|
||||
@@ -416,25 +424,26 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
myReleaseBuild = releaseBuild;
|
||||
myCustomKeystorePath = customKeystorePath != null ? customKeystorePath : "";
|
||||
|
||||
final HashSet<VirtualFile> resourcesFromSourceRoot = new HashSet<VirtualFile>();
|
||||
final HashSet<File> resourcesFromSourceRoot = new HashSet<File>();
|
||||
for (VirtualFile sourceRoot : sourceRoots) {
|
||||
AndroidApkBuilder.collectStandardSourceFolderResources(sourceRoot, new HashSet<VirtualFile>(), resourcesFromSourceRoot, null);
|
||||
AndroidApkBuilder.collectStandardSourceFolderResources(new File(sourceRoot.getPath()), resourcesFromSourceRoot,
|
||||
new ExcludedSourcesFilter(project));
|
||||
}
|
||||
for (VirtualFile resource : resourcesFromSourceRoot) {
|
||||
myResourceTimestamps.put(resource.getPath(), resource.getTimeStamp());
|
||||
for (File resource : resourcesFromSourceRoot) {
|
||||
myResourceTimestamps.put(FileUtil.toSystemIndependentName(resource.getPath()), resource.lastModified());
|
||||
}
|
||||
|
||||
for (VirtualFile externalLib : externalLibs) {
|
||||
myResourceTimestamps.put(externalLib.getPath(), externalLib.getTimeStamp());
|
||||
}
|
||||
ArrayList<VirtualFile> nativeLibs = new ArrayList<VirtualFile>();
|
||||
ArrayList<File> nativeLibs = new ArrayList<File>();
|
||||
for (VirtualFile nativeLibFolder : nativeLibFolders) {
|
||||
for (VirtualFile child : nativeLibFolder.getChildren()) {
|
||||
AndroidApkBuilder.collectNativeLibraries(child, nativeLibs, !releaseBuild);
|
||||
AndroidApkBuilder.collectNativeLibraries(new File(child.getPath()), nativeLibs, !releaseBuild);
|
||||
}
|
||||
}
|
||||
for (VirtualFile nativeLib : nativeLibs) {
|
||||
myResourceTimestamps.put(nativeLib.getPath(), nativeLib.getTimeStamp());
|
||||
for (File nativeLib : nativeLibs) {
|
||||
myResourceTimestamps.put(FileUtil.toSystemIndependentName(nativeLib.getPath()), nativeLib.lastModified());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -447,7 +456,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler {
|
||||
return mvs.myGenerateUnsignedApk == myGenerateUnsignedApk &&
|
||||
mvs.myReleaseBuild == myReleaseBuild &&
|
||||
mvs.myResourceTimestamps.equals(myResourceTimestamps) &&
|
||||
mvs.myApkPath.equals(myApkPath) &&
|
||||
mvs.myApkPath.equals(myApkPath) &&
|
||||
mvs.myCustomKeystorePath.equals(myCustomKeystorePath);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.jetbrains.android.compiler;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class ExcludedSourcesFilter implements Condition<File> {
|
||||
private final Project myProject;
|
||||
|
||||
public ExcludedSourcesFilter(@NotNull Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean value(File file) {
|
||||
return !AndroidCompileUtil.isExcludedFromCompilation(file, myProject);
|
||||
}
|
||||
}
|
||||
@@ -51,8 +51,8 @@ import org.jetbrains.android.compiler.AndroidProguardCompiler;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.facet.AndroidRootUtil;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.SaveFileListener;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -196,7 +196,7 @@ class ApkStep extends ExportSignedPackageWizardStep {
|
||||
AndroidPlatform platform = myWizard.getFacet().getConfiguration().getAndroidPlatform();
|
||||
assert platform != null;
|
||||
String sdkPath = platform.getSdkData().getLocation();
|
||||
String zipAlignPath = sdkPath + File.separatorChar + AndroidSdkUtils.toolPath(SdkConstants.FN_ZIPALIGN);
|
||||
String zipAlignPath = sdkPath + File.separatorChar + AndroidCommonUtils.toolPath(SdkConstants.FN_ZIPALIGN);
|
||||
File zipalign = new File(zipAlignPath);
|
||||
final boolean runZipAlign = zipalign.isFile();
|
||||
File destFile = null;
|
||||
|
||||
@@ -81,6 +81,7 @@ import org.jetbrains.android.resourceManagers.ResourceManager;
|
||||
import org.jetbrains.android.resourceManagers.SystemResourceManager;
|
||||
import org.jetbrains.android.sdk.*;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.ResourceEntry;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -392,7 +393,8 @@ public class AndroidFacet extends Facet<AndroidFacetConfiguration> {
|
||||
public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @Nullable ProcessHandler handler) {
|
||||
AndroidPlatform platform = getConfiguration().getAndroidPlatform();
|
||||
if (platform != null) {
|
||||
final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_EMULATOR);
|
||||
final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidCommonUtils
|
||||
.toolPath(SdkConstants.FN_EMULATOR);
|
||||
final GeneralCommandLine commandLine = new GeneralCommandLine();
|
||||
commandLine.setExePath(FileUtil.toSystemDependentName(emulatorPath));
|
||||
if (avdName != null) {
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.jetbrains.android.run.testing.AndroidTestRunConfigurationType;
|
||||
import org.jetbrains.android.sdk.AndroidPlatform;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -218,7 +219,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder {
|
||||
IAndroidTarget target = platform.getTarget();
|
||||
|
||||
final String androidToolPath =
|
||||
platform.getSdkData().getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.androidCmdName());
|
||||
platform.getSdkData().getLocation() + File.separator + AndroidCommonUtils.toolPath(SdkConstants.androidCmdName());
|
||||
|
||||
if (!new File(androidToolPath).exists()) {
|
||||
return false;
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.sdk.AndroidSdkData;
|
||||
import org.jetbrains.android.sdk.AndroidSdkUtils;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidCommonUtils;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.BooleanCellRenderer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -71,7 +72,7 @@ public class AvdChooser extends DialogWrapper {
|
||||
AndroidSdkData sdkData = facet.getConfiguration().getAndroidSdk();
|
||||
if (sdkData == null) return null;
|
||||
String androidCmd = SdkConstants.androidCmdName();
|
||||
return sdkData.getLocation() + File.separator + AndroidSdkUtils.toolPath(androidCmd);
|
||||
return sdkData.getLocation() + File.separator + AndroidCommonUtils.toolPath(androidCmd);
|
||||
}
|
||||
|
||||
public AvdChooser(@NotNull final Project project,
|
||||
|
||||
@@ -300,7 +300,7 @@ public class AndroidSdkData {
|
||||
private String getAdbPath() {
|
||||
String path = getLocation() + File.separator + SdkConstants.OS_SDK_PLATFORM_TOOLS_FOLDER + SdkConstants.FN_ADB;
|
||||
if (!new File(path).exists()) {
|
||||
return getLocation() + File.separator + AndroidSdkUtils.toolPath(SdkConstants.FN_ADB);
|
||||
return getLocation() + File.separator + AndroidCommonUtils.toolPath(SdkConstants.FN_ADB);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -423,10 +423,6 @@ public class AndroidSdkUtils {
|
||||
};
|
||||
}
|
||||
|
||||
public static String toolPath(@NotNull String toolFileName) {
|
||||
return SdkConstants.OS_SDK_TOOLS_FOLDER + toolFileName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Sdk findAppropriateAndroidPlatform(@NotNull IAndroidTarget target, @NotNull AndroidSdkData sdkData) {
|
||||
for (Sdk library : ProjectJdkTable.getInstance().getAllJdks()) {
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Features:
|
||||
- Groovy support
|
||||
+7
-6
@@ -37,6 +37,7 @@ import com.intellij.openapi.vcs.versionBrowser.CommittedChangeList;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.AsynchConsumer;
|
||||
import com.intellij.util.Consumer;
|
||||
import gnu.trove.TObjectLongHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.netbeans.lib.cvsclient.admin.Entry;
|
||||
@@ -73,8 +74,8 @@ public class CvsCommittedChangesProvider implements CachingCommittedChangesProvi
|
||||
}
|
||||
|
||||
private static class MyZipper extends VcsCommittedListsZipperAdapter {
|
||||
private long lastNumber = 0;
|
||||
private final Map<CommittedChangeListKey, Long> numberCache = new HashMap();
|
||||
private long lastNumber = 1;
|
||||
private final TObjectLongHashMap<CommittedChangeListKey> numberCache = new TObjectLongHashMap<CommittedChangeListKey>();
|
||||
|
||||
private MyZipper() {
|
||||
super(new GroupCreator() {
|
||||
@@ -98,12 +99,12 @@ public class CvsCommittedChangesProvider implements CachingCommittedChangesProvi
|
||||
final long time = list.getCommitDate().getTime();
|
||||
final Long roundedTime = Long.valueOf(time - (time % CvsChangeList.SUITABLE_DIFF));
|
||||
final CommittedChangeListKey key = new CommittedChangeListKey(list.getCommitterName(), roundedTime, list.getComment());
|
||||
final Long number = numberCache.get(key);
|
||||
if (number == null) {
|
||||
numberCache.put(key, Long.valueOf(lastNumber));
|
||||
final long number = numberCache.get(key);
|
||||
if (number == 0) {
|
||||
numberCache.put(key, lastNumber);
|
||||
return lastNumber++;
|
||||
}
|
||||
return number.longValue();
|
||||
return number;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -384,7 +384,8 @@ public class CompleteReferenceExpression {
|
||||
}
|
||||
|
||||
GroovyResolveResult result = (GroovyResolveResult)o;
|
||||
if (!result.isStaticsOK() || !result.isAccessible()) return;
|
||||
if (!result.isStaticsOK()) return;
|
||||
if (!result.isAccessible() && myParameters.getInvocationCount() < 2) return;
|
||||
if (mySkipPackages && result.getElement() instanceof PsiPackage) return;
|
||||
|
||||
PsiElement element = result.getElement();
|
||||
|
||||
@@ -115,6 +115,13 @@ public abstract class MvcFramework {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isInteractiveConsoleSupport(@NotNull Module module) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void runInteractiveConsole(@NotNull Module module) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public abstract void upgradeFramework(@NotNull Module module);
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="VM options:"/>
|
||||
<text value="&VM options:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="b107f" class="javax.swing.JLabel" binding="myModuleLabel">
|
||||
@@ -66,7 +66,7 @@
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Module:"/>
|
||||
<text value="&Module:"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="cf36f" class="javax.swing.JComboBox" binding="myModuleBox">
|
||||
|
||||
@@ -54,15 +54,49 @@ public class MvcRunTargetDialog extends DialogWrapper {
|
||||
private ComboBox myTargetField;
|
||||
private Module myModule;
|
||||
|
||||
public MvcRunTargetDialog(@NotNull Module module, MvcFramework framework) {
|
||||
private final MvcFramework myFramework;
|
||||
|
||||
private Action myInteractiveRunAction;
|
||||
|
||||
public MvcRunTargetDialog(@NotNull Module module, @NotNull MvcFramework framework) {
|
||||
super(module.getProject(), true);
|
||||
myModule = module;
|
||||
myFramework = framework;
|
||||
setTitle("Run " + framework.getDisplayName() + " target");
|
||||
setUpDialog();
|
||||
setModal(true);
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Action[] createLeftSideActions() {
|
||||
boolean hasOneSupportedModule = false;
|
||||
for (Module module : ModuleManager.getInstance(myModule.getProject()).getModules()) {
|
||||
if (module == myModule || myFramework.hasSupport(module)) {
|
||||
if (myFramework.isInteractiveConsoleSupport(module)) {
|
||||
hasOneSupportedModule = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOneSupportedModule) {
|
||||
myInteractiveRunAction = new DialogWrapperAction("&Run Interactive Console") {
|
||||
@Override
|
||||
protected void doAction(ActionEvent e) {
|
||||
myFramework.runInteractiveConsole(getSelectedModule());
|
||||
doCancelAction();
|
||||
}
|
||||
};
|
||||
|
||||
myInteractiveRunAction.setEnabled(myFramework.isInteractiveConsoleSupport(myModule));
|
||||
|
||||
return new Action[]{myInteractiveRunAction};
|
||||
}
|
||||
|
||||
return new Action[0];
|
||||
}
|
||||
|
||||
private void setUpDialog() {
|
||||
myTargetLabel.setLabelFor(myTargetField);
|
||||
myTargetField.setFocusable(true);
|
||||
@@ -72,7 +106,7 @@ public class MvcRunTargetDialog extends DialogWrapper {
|
||||
|
||||
List<Module> mvcModules = new ArrayList<Module>();
|
||||
for (Module module : ModuleManager.getInstance(myModule.getProject()).getModules()) {
|
||||
if (module == myModule || MvcFramework.getInstance(module) != null) {
|
||||
if (module == myModule || myFramework.hasSupport(module)) {
|
||||
mvcModules.add(module);
|
||||
}
|
||||
}
|
||||
@@ -85,6 +119,9 @@ public class MvcRunTargetDialog extends DialogWrapper {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
myModule = (Module)myModuleBox.getSelectedItem();
|
||||
if (myInteractiveRunAction != null) {
|
||||
myInteractiveRunAction.setEnabled(myFramework.isInteractiveConsoleSupport(myModule));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+11
@@ -1172,4 +1172,15 @@ class Base {
|
||||
new Base().@prefixField<caret>''')
|
||||
}
|
||||
|
||||
public void testPrivateFieldOnSecondInvocation() {
|
||||
myFixture.configureByText('_a.groovy', '''\
|
||||
class Base {
|
||||
private int field1
|
||||
}
|
||||
|
||||
new Base().fie<caret>x''')
|
||||
myFixture.complete(CompletionType.BASIC, 2)
|
||||
assert myFixture.lookupElementStrings == ['field1']
|
||||
}
|
||||
|
||||
}
|
||||
@@ -168,7 +168,7 @@ public class SvnDiffProvider implements DiffProvider, DiffMixin {
|
||||
LOG.info("No SVN status returned for " + file.getPath());
|
||||
return defaultResult();
|
||||
}
|
||||
return createResult(info.getRevision(), true, false);
|
||||
return createResult(info.getCommittedRevision(), true, false);
|
||||
}
|
||||
final boolean exists = ! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteContentsStatus()) &&
|
||||
! SVNStatusType.STATUS_DELETED.equals(svnStatus.getRemoteNodeStatus());
|
||||
|
||||
+2
-1
@@ -83,7 +83,8 @@ public class SvnCommandLineUpdateClient extends SvnSvnkitUpdateClient {
|
||||
new CommandLineAuthenticator(myProject, new CommandLineAuthenticator.AuthenticationRequiringCommand() {
|
||||
@Override
|
||||
public void run(File configDir) throws SVNException {
|
||||
final File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath());
|
||||
File base = myCommonAncestor == null ? paths[0] : new File(myCommonAncestor.getPath());
|
||||
base = base.isDirectory() ? base : base.getParentFile();
|
||||
final SvnLineCommand command = new SvnLineCommand(myProject, base, SvnCommandName.up);
|
||||
if (revision != null && ! SVNRevision.UNDEFINED.equals(revision) && ! SVNRevision.WORKING.equals(revision)) {
|
||||
command.addParameters("-r", revision.toString());
|
||||
|
||||
@@ -137,7 +137,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto
|
||||
@NotNull List<VcsFileRevision> revisions,
|
||||
@NotNull FilePath filePath,
|
||||
VcsRevisionNumber currentRevision) {
|
||||
return new MyHistorySession(revisions, filePath, aBoolean, currentRevision);
|
||||
return new MyHistorySession(revisions, filePath, aBoolean, currentRevision, false);
|
||||
}
|
||||
|
||||
class MyHistorySession extends VcsAbstractHistorySession {
|
||||
@@ -145,11 +145,13 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto
|
||||
private final boolean mySupports15;
|
||||
|
||||
private MyHistorySession(final List<VcsFileRevision> revisions, final FilePath committedPath, final boolean supports15,
|
||||
@Nullable final VcsRevisionNumber currentRevision) {
|
||||
@Nullable final VcsRevisionNumber currentRevision, boolean skipRefreshOnStart) {
|
||||
super(revisions, currentRevision);
|
||||
myCommittedPath = committedPath;
|
||||
mySupports15 = supports15;
|
||||
shouldBeRefreshed();
|
||||
if (! skipRefreshOnStart) {
|
||||
shouldBeRefreshed();
|
||||
}
|
||||
}
|
||||
|
||||
public HistoryAsTreeProvider getHistoryAsTreeProvider() {
|
||||
@@ -161,7 +163,23 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto
|
||||
if (myCommittedPath == null) {
|
||||
return null;
|
||||
}
|
||||
return getCurrentRevision(myCommittedPath);
|
||||
if (myCommittedPath.isNonLocal()) {
|
||||
// technically, it does not make sense, since there's no "current" revision for non-local history (if look how it's used)
|
||||
// but ok, lets keep it for now
|
||||
return new SvnRevisionNumber(SVNRevision.HEAD);
|
||||
}
|
||||
try {
|
||||
SVNWCClient wcClient = myVcs.createWCClient();
|
||||
SVNInfo info = wcClient.doInfo(new File(myCommittedPath.getPath()), SVNRevision.UNDEFINED);
|
||||
if (info != null) {
|
||||
return new SvnRevisionNumber(info.getCommittedRevision());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (SVNException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public FilePath getCommittedPath() {
|
||||
@@ -179,7 +197,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto
|
||||
|
||||
@Override
|
||||
public VcsHistorySession copy() {
|
||||
return new MyHistorySession(getRevisionList(), myCommittedPath, mySupports15, getCurrentRevisionNumber());
|
||||
return new MyHistorySession(getRevisionList(), myCommittedPath, mySupports15, getCurrentRevisionNumber(), true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +230,7 @@ public class SvnHistoryProvider implements VcsHistoryProvider, VcsCacheableHisto
|
||||
logLoader.initSupports15();
|
||||
|
||||
final MyHistorySession historySession =
|
||||
new MyHistorySession(Collections.<VcsFileRevision>emptyList(), committedPath, Boolean.TRUE.equals(logLoader.mySupport15), null);
|
||||
new MyHistorySession(Collections.<VcsFileRevision>emptyList(), committedPath, Boolean.TRUE.equals(logLoader.mySupport15), null, false);
|
||||
|
||||
final Ref<Boolean> sessionReported = new Ref<Boolean>();
|
||||
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
|
||||
|
||||
@@ -44,4 +44,6 @@ public abstract class LocalTask extends Task {
|
||||
public boolean isDefault() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract void setAssociatedChangelistId(String associatedChangelistId);
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ public class ActivateTaskDialog extends DialogWrapper {
|
||||
}
|
||||
}
|
||||
}
|
||||
myMarkAsInProgressBox.setSelected(myMarkAsInProgress && isMarkAsInProgressApplicable());
|
||||
myMarkAsInProgressBox.setSelected(myMarkAsInProgress);
|
||||
|
||||
// refresh change lists
|
||||
ChangeListManager changeListManager = ChangeListManager.getInstance(myProject);
|
||||
|
||||
@@ -19,8 +19,8 @@ package com.intellij.tasks.actions;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.Presentation;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.tasks.LocalTask;
|
||||
import com.intellij.tasks.TaskManager;
|
||||
import com.intellij.tasks.Task;
|
||||
import com.intellij.tasks.impl.TaskManagerImpl;
|
||||
import com.intellij.tasks.impl.TaskUtil;
|
||||
|
||||
@@ -34,7 +34,7 @@ public class CreateChangelistAction extends BaseTaskAction {
|
||||
TaskManager manager = getTaskManager(event);
|
||||
Presentation presentation = event.getPresentation();
|
||||
|
||||
if (manager == null || !manager.getOpenChangelists(manager.getActiveTask()).isEmpty()) {
|
||||
if (manager == null || !manager.isVcsEnabled() || !manager.getOpenChangelists(manager.getActiveTask()).isEmpty()) {
|
||||
presentation.setText(getTemplatePresentation().getText());
|
||||
presentation.setEnabled(false);
|
||||
} else {
|
||||
@@ -45,8 +45,8 @@ public class CreateChangelistAction extends BaseTaskAction {
|
||||
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
Task activeTask = getActiveTask(e);
|
||||
String name = Messages.showInputDialog(getProject(e), "Changelist name:", "Create changelist", null, TaskUtil.getChangeListName(activeTask), null);
|
||||
LocalTask activeTask = getActiveTask(e);
|
||||
String name = Messages.showInputDialog(getProject(e), "Changelist name:", "Create Changelist", null, TaskUtil.getChangeListName(activeTask), null);
|
||||
if (name != null) {
|
||||
TaskManagerImpl manager = (TaskManagerImpl)getTaskManager(e);
|
||||
assert manager != null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.tasks.Task;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -153,7 +154,7 @@ public class WorkingContextManager {
|
||||
private boolean loadContext(String zipPostfix, String entryName) {
|
||||
try {
|
||||
JBZipFile archive = getTasksArchive(zipPostfix);
|
||||
JBZipEntry entry = archive.getEntry(entryName.startsWith("/") ? entryName : "/" + entryName);
|
||||
JBZipEntry entry = archive.getEntry(StringUtil.startsWithChar(entryName, '/') ? entryName : "/" + entryName);
|
||||
if (entry != null) {
|
||||
byte[] bytes = entry.getData();
|
||||
Document document = JDOMUtil.loadDocument(new String(bytes));
|
||||
|
||||
@@ -196,6 +196,7 @@ public class LocalTaskImpl extends LocalTask {
|
||||
myChangeLists = changeLists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAssociatedChangelistId(String associatedChangelistId) {
|
||||
myAssociatedChangelistId = associatedChangelistId;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe
|
||||
}
|
||||
myContextManager.restoreContext(origin);
|
||||
|
||||
final Task task = doActivate(origin, true);
|
||||
final LocalTask task = doActivate(origin, true);
|
||||
|
||||
if (isVcsEnabled()) {
|
||||
List<ChangeListInfo> changeLists = getOpenChangelists(task);
|
||||
@@ -340,17 +340,18 @@ public class TaskManagerImpl extends TaskManager implements ProjectComponent, Pe
|
||||
myActiveTask.setUpdated(new Date());
|
||||
}
|
||||
|
||||
public void createChangeList(Task task, String name) {
|
||||
public void createChangeList(LocalTask task, String name) {
|
||||
String comment = TaskUtil.getChangeListComment(this, task);
|
||||
createChangeList(task, name, comment);
|
||||
}
|
||||
|
||||
public void createChangeList(Task task, String name, String comment) {
|
||||
public void createChangeList(LocalTask task, String name, String comment) {
|
||||
LocalChangeList changeList = myChangeListManager.findChangeList(name);
|
||||
if (changeList == null) {
|
||||
changeList = myChangeListManager.addChangeList(name, comment);
|
||||
}
|
||||
myChangeListManager.setDefaultChangeList(changeList);
|
||||
task.setAssociatedChangelistId(changeList.getId());
|
||||
getOpenChangelists(task).add(new ChangeListInfo(changeList));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user