private void runBuild(final MessageHandler msgHandler, CanceledStatus cs) throws Throwable { final File dataStorageRoot = Utils.getDataStorageRoot(myProjectPath); if (dataStorageRoot == null) { msgHandler.processMessage( new CompilerMessage( "build", BuildMessage.Kind.ERROR, "Cannot determine build data storage root for project " + myProjectPath)); return; } if (!dataStorageRoot.exists()) { // invoked the very first time for this project. Force full rebuild myBuildType = BuildType.PROJECT_REBUILD; } final DataInputStream fsStateStream = createFSDataStream(dataStorageRoot); if (fsStateStream != null) { // optimization: check whether we can skip the build final boolean hasWorkToDoWithModules = fsStateStream.readBoolean(); if (myBuildType == BuildType.MAKE && !hasWorkToDoWithModules && scopeContainsModulesOnly(myBuildRunner.getScopes()) && !containsChanges(myInitialFSDelta)) { updateFsStateOnDisk(dataStorageRoot, fsStateStream, myInitialFSDelta.getOrdinal()); return; } } final BuildFSState fsState = new BuildFSState(false); try { final ProjectDescriptor pd = myBuildRunner.load(msgHandler, dataStorageRoot, fsState); myProjectDescriptor = pd; if (fsStateStream != null) { try { try { fsState.load(fsStateStream, pd.getModel(), pd.getBuildRootIndex()); applyFSEvent(pd, myInitialFSDelta); } finally { fsStateStream.close(); } } catch (Throwable e) { LOG.error(e); fsState.clearAll(); } } myLastEventOrdinal = myInitialFSDelta != null ? myInitialFSDelta.getOrdinal() : 0L; // free memory myInitialFSDelta = null; // ensure events from controller are processed after FSState initialization myEventsProcessor.startProcessing(); myBuildRunner.runBuild(pd, cs, myConstantSearch, msgHandler, myBuildType); } finally { saveData(fsState, dataStorageRoot); } }
@Nullable private DataInputStream createFSDataStream(File dataStorageRoot) { if (myInitialFSDelta == null) { // this will force FS rescan return null; } try { final File file = new File(dataStorageRoot, FS_STATE_FILE); final InputStream fs = new FileInputStream(file); byte[] bytes; try { bytes = FileUtil.loadBytes(fs, (int) file.length()); } finally { fs.close(); } final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); final int version = in.readInt(); if (version != FSState.VERSION) { return null; } final long savedOrdinal = in.readLong(); if (savedOrdinal + 1L != myInitialFSDelta.getOrdinal()) { return null; } return in; } catch (FileNotFoundException ignored) { } catch (Throwable e) { LOG.error(e); } return null; }
private void applyFSEvent( ProjectDescriptor pd, @Nullable CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) throws IOException { if (event == null) { return; } final Timestamps timestamps = pd.timestamps.getStorage(); for (String deleted : event.getDeletedPathsList()) { final File file = new File(deleted); Collection<BuildRootDescriptor> descriptor = pd.getBuildRootIndex().findAllParentDescriptors(file, null, null); if (!descriptor.isEmpty()) { if (Utils.IS_TEST_MODE) { LOG.info("Applying deleted path from fs event: " + file.getPath()); } for (BuildRootDescriptor rootDescriptor : descriptor) { pd.fsState.registerDeleted(rootDescriptor.getTarget(), file, timestamps); } } else if (Utils.IS_TEST_MODE) { LOG.info("Skipping deleted path: " + file.getPath()); } } for (String changed : event.getChangedPathsList()) { final File file = new File(changed); Collection<BuildRootDescriptor> descriptors = pd.getBuildRootIndex().findAllParentDescriptors(file, null, null); if (!descriptors.isEmpty()) { if (Utils.IS_TEST_MODE) { LOG.info("Applying dirty path from fs event: " + file.getPath()); } for (BuildRootDescriptor descriptor : descriptors) { pd.fsState.markDirty(null, file, descriptor, timestamps); } } else if (Utils.IS_TEST_MODE) { LOG.info("Skipping dirty path: " + file.getPath()); } } }
private static boolean containsChanges( CmdlineRemoteProto.Message.ControllerMessage.FSEvent event) { return event.getChangedPathsCount() != 0 || event.getDeletedPathsCount() != 0; }