1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.ndk.internal.discovery; 18 19 import com.android.ide.eclipse.ndk.internal.Activator; 20 21 import org.eclipse.cdt.core.CCorePlugin; 22 import org.eclipse.cdt.core.model.CoreModel; 23 import org.eclipse.cdt.make.core.scannerconfig.IDiscoveredPathManager.IDiscoveredPathInfo; 24 import org.eclipse.cdt.make.core.scannerconfig.IDiscoveredPathManager.IDiscoveredScannerInfoSerializable; 25 import org.eclipse.core.resources.IFile; 26 import org.eclipse.core.resources.IProject; 27 import org.eclipse.core.runtime.CoreException; 28 import org.eclipse.core.runtime.IPath; 29 import org.eclipse.core.runtime.IProgressMonitor; 30 import org.eclipse.core.runtime.Path; 31 32 import java.io.BufferedReader; 33 import java.io.File; 34 import java.io.FileReader; 35 import java.io.IOException; 36 import java.io.PrintStream; 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.Map.Entry; 42 43 public class NdkDiscoveredPathInfo implements IDiscoveredPathInfo { 44 45 private final IProject mProject; 46 private long mLastUpdate = IFile.NULL_STAMP; 47 private IPath[] mIncludePaths; 48 private Map<String, String> mSymbols; 49 private boolean mNeedReindexing = false; 50 private static final IPath ANDROID_MK = new Path("jni/Android.mk"); 51 52 // Keys for preferences 53 public static final String LAST_UPDATE = "lastUpdate"; //$NON-NLS-1$ 54 55 public NdkDiscoveredPathInfo(IProject project) { 56 this.mProject = project; 57 load(); 58 } 59 60 @Override 61 public IProject getProject() { 62 return mProject; 63 } 64 65 @Override 66 public IPath[] getIncludePaths() { 67 if (mNeedReindexing) { 68 // Call for a reindex 69 // TODO this is probably a bug. a new include path should trigger 70 // reindexing anyway, no? 71 // BTW, can't do this in the update since the indexer runs before 72 // this gets called 73 CCorePlugin.getIndexManager().reindex(CoreModel.getDefault().create(mProject)); 74 mNeedReindexing = false; 75 } 76 return mIncludePaths; 77 } 78 79 void setIncludePaths(List<String> pathStrings) { 80 mIncludePaths = new IPath[pathStrings.size()]; 81 int i = 0; 82 for (String path : pathStrings) 83 mIncludePaths[i++] = new Path(path); 84 mNeedReindexing = true; 85 } 86 87 @Override 88 public Map<String, String> getSymbols() { 89 if (mSymbols == null) 90 mSymbols = new HashMap<String, String>(); 91 return mSymbols; 92 } 93 94 void setSymbols(Map<String, String> symbols) { 95 this.mSymbols = symbols; 96 } 97 98 @Override 99 public IDiscoveredScannerInfoSerializable getSerializable() { 100 return null; 101 } 102 103 public void update(IProgressMonitor monitor) throws CoreException { 104 if (!needUpdating()) 105 return; 106 107 new NdkDiscoveryUpdater(this).runUpdate(monitor); 108 109 if (mIncludePaths != null && mSymbols != null) { 110 recordUpdate(); 111 save(); 112 } 113 } 114 115 private boolean needUpdating() { 116 if (mLastUpdate == IFile.NULL_STAMP) 117 return true; 118 return mProject.getFile(ANDROID_MK).getLocalTimeStamp() > mLastUpdate; 119 } 120 121 private void recordUpdate() { 122 mLastUpdate = mProject.getFile(ANDROID_MK).getLocalTimeStamp(); 123 } 124 125 public void delete() { 126 mLastUpdate = IFile.NULL_STAMP; 127 } 128 129 private File getInfoFile() { 130 File stateLoc = Activator.getDefault().getStateLocation().toFile(); 131 return new File(stateLoc, mProject.getName() + ".pathInfo"); //$NON-NLS-1$ 132 } 133 134 private void save() { 135 try { 136 File infoFile = getInfoFile(); 137 infoFile.getParentFile().mkdirs(); 138 PrintStream out = new PrintStream(infoFile); 139 140 // timestamp 141 out.print("t,"); //$NON-NLS-1$ 142 out.print(mLastUpdate); 143 out.println(); 144 145 for (IPath include : mIncludePaths) { 146 out.print("i,"); //$NON-NLS-1$ 147 out.print(include.toPortableString()); 148 out.println(); 149 } 150 151 for (Entry<String, String> symbol : mSymbols.entrySet()) { 152 out.print("d,"); //$NON-NLS-1$ 153 out.print(symbol.getKey()); 154 out.print(","); //$NON-NLS-1$ 155 out.print(symbol.getValue()); 156 out.println(); 157 } 158 159 out.close(); 160 } catch (IOException e) { 161 Activator.log(e); 162 } 163 164 } 165 166 private void load() { 167 try { 168 File infoFile = getInfoFile(); 169 if (!infoFile.exists()) 170 return; 171 172 long timestamp = IFile.NULL_STAMP; 173 List<IPath> includes = new ArrayList<IPath>(); 174 Map<String, String> defines = new HashMap<String, String>(); 175 176 BufferedReader reader = new BufferedReader(new FileReader(infoFile)); 177 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 178 switch (line.charAt(0)) { 179 case 't': 180 timestamp = Long.valueOf(line.substring(2)); 181 break; 182 case 'i': 183 includes.add(Path.fromPortableString(line.substring(2))); 184 break; 185 case 'd': 186 int n = line.indexOf(',', 2); 187 if (n == -1) 188 defines.put(line.substring(2), ""); //$NON-NLS-1$ 189 else 190 defines.put(line.substring(2, n), line.substring(n + 1)); 191 break; 192 } 193 } 194 reader.close(); 195 196 mLastUpdate = timestamp; 197 mIncludePaths = includes.toArray(new IPath[includes.size()]); 198 mSymbols = defines; 199 } catch (IOException e) { 200 Activator.log(e); 201 } 202 } 203 } 204