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.adt.ndk.internal.discovery; 18 19 import com.android.ide.eclipse.adt.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 public IProject getProject() { 61 return mProject; 62 } 63 64 public IPath[] getIncludePaths() { 65 if (mNeedReindexing) { 66 // Call for a reindex 67 // TODO this is probably a bug. a new include path should trigger 68 // reindexing anyway, no? 69 // BTW, can't do this in the update since the indexer runs before 70 // this gets called 71 CCorePlugin.getIndexManager().reindex(CoreModel.getDefault().create(mProject)); 72 mNeedReindexing = false; 73 } 74 return mIncludePaths; 75 } 76 77 void setIncludePaths(List<String> pathStrings) { 78 mIncludePaths = new IPath[pathStrings.size()]; 79 int i = 0; 80 for (String path : pathStrings) 81 mIncludePaths[i++] = new Path(path); 82 mNeedReindexing = true; 83 } 84 85 public Map<String, String> getSymbols() { 86 if (mSymbols == null) 87 mSymbols = new HashMap<String, String>(); 88 return mSymbols; 89 } 90 91 void setSymbols(Map<String, String> symbols) { 92 this.mSymbols = symbols; 93 } 94 95 public IDiscoveredScannerInfoSerializable getSerializable() { 96 return null; 97 } 98 99 public void update(IProgressMonitor monitor) throws CoreException { 100 if (!needUpdating()) 101 return; 102 103 new NdkDiscoveryUpdater(this).runUpdate(monitor); 104 105 if (mIncludePaths != null && mSymbols != null) { 106 recordUpdate(); 107 save(); 108 } 109 } 110 111 private boolean needUpdating() { 112 if (mLastUpdate == IFile.NULL_STAMP) 113 return true; 114 return mProject.getFile(ANDROID_MK).getLocalTimeStamp() > mLastUpdate; //$NON-NLS-1$ 115 } 116 117 private void recordUpdate() { 118 mLastUpdate = mProject.getFile(ANDROID_MK).getLocalTimeStamp(); //$NON-NLS-1$ 119 } 120 121 public void delete() { 122 mLastUpdate = IFile.NULL_STAMP; 123 } 124 125 private File getInfoFile() { 126 File stateLoc = Activator.getDefault().getStateLocation().toFile(); 127 return new File(stateLoc, mProject.getName() + ".pathInfo"); //$NON-NLS-1$ 128 } 129 130 private void save() { 131 try { 132 File infoFile = getInfoFile(); 133 infoFile.getParentFile().mkdirs(); 134 PrintStream out = new PrintStream(infoFile); 135 136 // timestamp 137 out.print("t,"); //$NON-NLS-1$ 138 out.print(mLastUpdate); 139 out.println(); 140 141 for (IPath include : mIncludePaths) { 142 out.print("i,"); //$NON-NLS-1$ 143 out.print(include.toPortableString()); 144 out.println(); 145 } 146 147 for (Entry<String, String> symbol : mSymbols.entrySet()) { 148 out.print("d,"); //$NON-NLS-1$ 149 out.print(symbol.getKey()); 150 out.print(","); //$NON-NLS-1$ 151 out.print(symbol.getValue()); 152 out.println(); 153 } 154 155 out.close(); 156 } catch (IOException e) { 157 Activator.log(e); 158 } 159 160 } 161 162 private void load() { 163 try { 164 File infoFile = getInfoFile(); 165 if (!infoFile.exists()) 166 return; 167 168 long timestamp = IFile.NULL_STAMP; 169 List<IPath> includes = new ArrayList<IPath>(); 170 Map<String, String> defines = new HashMap<String, String>(); 171 172 BufferedReader reader = new BufferedReader(new FileReader(infoFile)); 173 for (String line = reader.readLine(); line != null; line = reader.readLine()) { 174 switch (line.charAt(0)) { 175 case 't': 176 timestamp = Long.valueOf(line.substring(2)); 177 break; 178 case 'i': 179 includes.add(Path.fromPortableString(line.substring(2))); 180 break; 181 case 'd': 182 int n = line.indexOf(',', 2); 183 if (n == -1) 184 defines.put(line.substring(2), ""); //$NON-NLS-1$ 185 else 186 defines.put(line.substring(2, n), line.substring(n + 1)); 187 break; 188 } 189 } 190 reader.close(); 191 192 mLastUpdate = timestamp; 193 mIncludePaths = includes.toArray(new IPath[includes.size()]); 194 mSymbols = defines; 195 } catch (IOException e) { 196 Activator.log(e); 197 } 198 } 199 } 200