diff options
author | Xavier Ducrohet <xav@android.com> | 2010-06-14 17:10:56 -0700 |
---|---|---|
committer | Android Code Review <code-review@android.com> | 2010-06-14 17:10:56 -0700 |
commit | 543c2ee48b04e7bafb79db85c54c95eeec978952 (patch) | |
tree | 6f4c296e5474589d50961545f403e5e45743c2ac | |
parent | 29c807bf03310ef4852221cea6db2bcb5ad5d861 (diff) | |
parent | f5d5417652a05bce698fc3d7a1bed5a9ffa49002 (diff) | |
download | sdk-543c2ee48b04e7bafb79db85c54c95eeec978952.zip sdk-543c2ee48b04e7bafb79db85c54c95eeec978952.tar.gz sdk-543c2ee48b04e7bafb79db85c54c95eeec978952.tar.bz2 |
Merge "Saving ProjectProperties now keeps existing file and replaces values."
6 files changed, 205 insertions, 114 deletions
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java index 9ce3006..4ffbd0e 100644 --- a/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -926,7 +926,7 @@ public class Main { File skinFolder = avdManager.getSkinPath(skin, target); File skinHardwareFile = new File(skinFolder, AvdManager.HARDWARE_INI); if (skinHardwareFile.isFile()) { - skinHardwareConfig = SdkManager.parsePropertyFile( + skinHardwareConfig = ProjectProperties.parsePropertyFile( skinHardwareFile, mSdkLog); } break; diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index e70c8fe..36afc5b 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -83,12 +83,18 @@ public final class SdkConstants { /** hardware properties definition file */ public final static String FN_HARDWARE_INI = "hardware-properties.ini"; - /** project property file */ + /** project default property file */ public final static String FN_DEFAULT_PROPERTIES = "default.properties"; - /** export property file */ + /** project export property file */ public final static String FN_EXPORT_PROPERTIES = "export.properties"; + /** project local property file */ + public final static String FN_LOCAL_PROPERTIES = "local.properties"; + + /** project build property file */ + public final static String FN_BUILD_PROPERTIES = "build.properties"; + /** Skin layout file */ public final static String FN_SKIN_LAYOUT = "layout";//$NON-NLS-1$ diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java index 71fcee5..4249365 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java @@ -19,17 +19,13 @@ package com.android.sdklib; import com.android.prefs.AndroidLocation; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.AndroidVersion.AndroidVersionException; -import com.android.sdklib.io.FileWrapper; -import com.android.sdklib.io.IAbstractFile; -import com.android.sdklib.io.StreamException; +import com.android.sdklib.internal.project.ProjectProperties; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -60,8 +56,6 @@ public final class SdkManager { private final static String ADDON_REVISION = "revision"; private final static String ADDON_REVISION_OLD = "version"; - private final static Pattern PATTERN_PROP = Pattern.compile( - "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$"); private final static Pattern PATTERN_LIB_DATA = Pattern.compile( "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE); @@ -280,7 +274,7 @@ public final class SdkManager { File buildProp = new File(platform, SdkConstants.FN_BUILD_PROP); if (buildProp.isFile()) { - Map<String, String> map = parsePropertyFile(buildProp, log); + Map<String, String> map = ProjectProperties.parsePropertyFile(buildProp, log); if (map != null) { // look for some specific values in the map. @@ -328,7 +322,8 @@ public final class SdkManager { // platform rev number int revision = 1; File sourcePropFile = new File(platform, SdkConstants.FN_SOURCE_PROP); - Map<String, String> sourceProp = parsePropertyFile(sourcePropFile, log); + Map<String, String> sourceProp = ProjectProperties.parsePropertyFile(sourcePropFile, + log); if (sourceProp != null) { try { revision = Integer.parseInt(sourceProp.get("Pkg.Revision")); @@ -340,7 +335,7 @@ public final class SdkManager { // Ant properties File sdkPropFile = new File(platform, SdkConstants.FN_SDK_PROP); - Map<String, String> antProp = parsePropertyFile(sdkPropFile, log); + Map<String, String> antProp = ProjectProperties.parsePropertyFile(sdkPropFile, log); if (antProp != null) { map.putAll(antProp); } @@ -419,7 +414,8 @@ public final class SdkManager { File addOnManifest = new File(addon, SdkConstants.FN_MANIFEST_INI); if (addOnManifest.isFile()) { - Map<String, String> propertyMap = parsePropertyFile(addOnManifest, log); + Map<String, String> propertyMap = ProjectProperties.parsePropertyFile(addOnManifest, + log); if (propertyMap != null) { // look for some specific values in the map. @@ -609,76 +605,6 @@ public final class SdkManager { } - /** - * Parses a property file (using UTF-8 encoding) and returns a map of the content. - * <p/>If the file is not present, null is returned with no error messages sent to the log. - * - * @param propFile the property file to parse - * @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null. - * @return the map of (key,value) pairs, or null if the parsing failed. - * @deprecated Use {@link #parsePropertyFile(IAbstractFile, ISdkLog)} - */ - public static Map<String, String> parsePropertyFile(File propFile, ISdkLog log) { - IAbstractFile wrapper = new FileWrapper(propFile); - return parsePropertyFile(wrapper, log); - } - - /** - * Parses a property file (using UTF-8 encoding) and returns a map of the content. - * <p/>If the file is not present, null is returned with no error messages sent to the log. - * - * @param propFile the property file to parse - * @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null. - * @return the map of (key,value) pairs, or null if the parsing failed. - */ - public static Map<String, String> parsePropertyFile(IAbstractFile propFile, ISdkLog log) { - BufferedReader reader = null; - try { - reader = new BufferedReader(new InputStreamReader(propFile.getContents(), - SdkConstants.INI_CHARSET)); - - String line = null; - Map<String, String> map = new HashMap<String, String>(); - while ((line = reader.readLine()) != null) { - if (line.length() > 0 && line.charAt(0) != '#') { - - Matcher m = PATTERN_PROP.matcher(line); - if (m.matches()) { - map.put(m.group(1), m.group(2)); - } else { - log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax", - propFile.getOsLocation(), - line); - return null; - } - } - } - - return map; - } catch (FileNotFoundException e) { - // this should not happen since we usually test the file existence before - // calling the method. - // Return null below. - } catch (IOException e) { - log.warning("Error parsing '%1$s': %2$s.", - propFile.getOsLocation(), - e.getMessage()); - } catch (StreamException e) { - log.warning("Error parsing '%1$s': %2$s.", - propFile.getOsLocation(), - e.getMessage()); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // pass - } - } - } - - return null; - } /** * Parses the skin folder and builds the skin list. diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java index 35ce0b0..83dd7b0 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java @@ -23,6 +23,7 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkManager; import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus; +import com.android.sdklib.internal.project.ProjectProperties; import java.io.BufferedReader; import java.io.File; @@ -690,7 +691,7 @@ public final class AvdManager { File targetHardwareFile = new File(target.getLocation(), AvdManager.HARDWARE_INI); if (targetHardwareFile.isFile()) { - Map<String, String> targetHardwareConfig = SdkManager.parsePropertyFile( + Map<String, String> targetHardwareConfig = ProjectProperties.parsePropertyFile( targetHardwareFile, log); if (targetHardwareConfig != null) { finalHardwareValues.putAll(targetHardwareConfig); @@ -702,7 +703,7 @@ public final class AvdManager { File skinFolder = getSkinPath(skinName, target); File skinHardwareFile = new File(skinFolder, AvdManager.HARDWARE_INI); if (skinHardwareFile.isFile()) { - Map<String, String> skinHardwareConfig = SdkManager.parsePropertyFile( + Map<String, String> skinHardwareConfig = ProjectProperties.parsePropertyFile( skinHardwareFile, log); if (skinHardwareConfig != null) { finalHardwareValues.putAll(skinHardwareConfig); @@ -1140,7 +1141,7 @@ public final class AvdManager { * valid or not. */ private AvdInfo parseAvdInfo(File path, ISdkLog log) { - Map<String, String> map = SdkManager.parsePropertyFile(path, log); + Map<String, String> map = ProjectProperties.parsePropertyFile(path, log); String avdPath = map.get(AVD_INFO_PATH); String targetHash = map.get(AVD_INFO_TARGET); @@ -1162,7 +1163,7 @@ public final class AvdManager { if (!configIniFile.isFile()) { log.warning("Missing file '%1$s'.", configIniFile.getPath()); } else { - properties = SdkManager.parsePropertyFile(configIniFile, log); + properties = ProjectProperties.parsePropertyFile(configIniFile, log); } } diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java index 68fa817..dd465aa 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectProperties.java @@ -16,26 +16,40 @@ package com.android.sdklib.internal.project; +import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; -import com.android.sdklib.SdkManager; +import com.android.sdklib.io.FileWrapper; import com.android.sdklib.io.FolderWrapper; import com.android.sdklib.io.IAbstractFile; import com.android.sdklib.io.IAbstractFolder; import com.android.sdklib.io.StreamException; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * Class to load and save project properties for both ADT and Ant-based build. * */ public final class ProjectProperties { + private final static Pattern PATTERN_PROP = Pattern.compile( + "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$"); + /** The property name for the project target */ public final static String PROPERTY_TARGET = "target"; @@ -56,6 +70,7 @@ public final class ProjectProperties { public final static String PROPERTY_TESTED_PROJECT = "tested.project.dir"; public final static String PROPERTY_BUILD_SOURCE_DIR = "source.dir"; + public final static String PROPERTY_BUILD_OUT_DIR = "out.dir"; public final static String PROPERTY_PACKAGE = "package"; public final static String PROPERTY_VERSIONCODE = "versionCode"; @@ -64,22 +79,44 @@ public final class ProjectProperties { public final static String PROPERTY_KEY_ALIAS = "key.alias"; public static enum PropertyType { - BUILD("build.properties", BUILD_HEADER), - DEFAULT(SdkConstants.FN_DEFAULT_PROPERTIES, DEFAULT_HEADER), - LOCAL("local.properties", LOCAL_HEADER), - EXPORT("export.properties", EXPORT_HEADER); + BUILD(SdkConstants.FN_BUILD_PROPERTIES, BUILD_HEADER, new String[] { + PROPERTY_BUILD_SOURCE_DIR, PROPERTY_BUILD_OUT_DIR + }), + DEFAULT(SdkConstants.FN_DEFAULT_PROPERTIES, DEFAULT_HEADER, new String[] { + PROPERTY_TARGET, PROPERTY_LIBRARY, PROPERTY_LIB_REF, + PROPERTY_KEY_STORE, PROPERTY_KEY_ALIAS + }), + LOCAL(SdkConstants.FN_LOCAL_PROPERTIES, LOCAL_HEADER, new String[] { + PROPERTY_SDK + }), + EXPORT(SdkConstants.FN_EXPORT_PROPERTIES, EXPORT_HEADER, new String[] { + PROPERTY_PACKAGE, PROPERTY_VERSIONCODE, PROPERTY_PROJECTS, + PROPERTY_KEY_STORE, PROPERTY_KEY_ALIAS + }); private final String mFilename; private final String mHeader; + private final Set<String> mValidProps; - PropertyType(String filename, String header) { + PropertyType(String filename, String header, String[] validProps) { mFilename = filename; mHeader = header; + HashSet<String> s = new HashSet<String>(); + s.addAll(Arrays.asList(validProps)); + mValidProps = Collections.unmodifiableSet(s); } public String getFilename() { return mFilename; } + + /** + * Returns an unmodifyable {@link Set} of the known properties for that type of + * property file. + */ + public Set<String> getValidProps() { + return mValidProps; + } } private final static String LOCAL_HEADER = @@ -192,7 +229,7 @@ public final class ProjectProperties { if (projectFolder.exists()) { IAbstractFile propFile = projectFolder.getFile(type.mFilename); if (propFile.exists()) { - Map<String, String> map = SdkManager.parsePropertyFile(propFile, null /* log */); + Map<String, String> map = parsePropertyFile(propFile, null /* log */); if (map != null) { return new ProjectProperties(projectFolder, map, type); } @@ -222,7 +259,7 @@ public final class ProjectProperties { if (mProjectFolder.exists()) { IAbstractFile propFile = mProjectFolder.getFile(type.mFilename); if (propFile.exists()) { - Map<String, String> map = SdkManager.parsePropertyFile(propFile, null /* log */); + Map<String, String> map = parsePropertyFile(propFile, null /* log */); if (map != null) { for(Entry<String, String> entry : map.entrySet()) { String key = entry.getKey(); @@ -310,7 +347,7 @@ public final class ProjectProperties { if (mProjectFolder.exists()) { IAbstractFile propFile = mProjectFolder.getFile(mType.mFilename); if (propFile.exists()) { - Map<String, String> map = SdkManager.parsePropertyFile(propFile, null /* log */); + Map<String, String> map = parsePropertyFile(propFile, null /* log */); if (map != null) { mProperties.clear(); mProperties.putAll(map); @@ -327,29 +364,149 @@ public final class ProjectProperties { public synchronized void save() throws IOException, StreamException { IAbstractFile toSave = mProjectFolder.getFile(mType.mFilename); - OutputStreamWriter writer = new OutputStreamWriter(toSave.getOutputStream(), - SdkConstants.INI_CHARSET); + // write the whole file in a byte array before dumping it in the file. This + // This is so that if the file already existing + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStreamWriter writer = new OutputStreamWriter(baos, SdkConstants.INI_CHARSET); + + if (toSave.exists()) { + BufferedReader reader = new BufferedReader(new InputStreamReader(toSave.getContents(), + SdkConstants.INI_CHARSET)); + + String line = null; + while ((line = reader.readLine()) != null) { + // check if this is a line containing a property. + if (line.length() > 0 && line.charAt(0) != '#') { + + Matcher m = PATTERN_PROP.matcher(line); + if (m.matches()) { + String key = m.group(1); + String value = m.group(2); + // check if the property still exists. + if (mProperties.containsKey(key)) { + // put the new value. + value = mProperties.get(key); + } else { + // property doesn't exist. Check if it's a known property. + // if it's a known one, we'll remove it, otherwise, leave it untouched. + if (mType.getValidProps().contains(key)) { + value = null; + } + } - // write the header - writer.write(mType.mHeader); + // if the value is still valid, write it down. + if (value != null) { + value = value.replaceAll("\\\\", "\\\\\\\\"); + writer.write(String.format("%s=%s\n", key, value)); + } + } else { + // the line was wrong, let's just ignore it so that it's removed from the + // file. + } + } else { + // non-property line: just write the line in the output as-is. + writer.append(line).append('\n'); + } + } + } else { + // new file, just write it all + // write the header + writer.write(mType.mHeader); + + // write the properties. + for (Entry<String, String> entry : mProperties.entrySet()) { + String comment = COMMENT_MAP.get(entry.getKey()); + if (comment != null) { + writer.write(comment); + } + String value = entry.getValue(); + if (value != null) { + value = value.replaceAll("\\\\", "\\\\\\\\"); + writer.write(String.format("%s=%s\n", entry.getKey(), value)); + } + } + } + + writer.flush(); + + // now put the content in the file. + OutputStream filestream = toSave.getOutputStream(); + filestream.write(baos.toByteArray()); + filestream.flush(); + } - // write the properties. - for (Entry<String, String> entry : mProperties.entrySet()) { - String comment = COMMENT_MAP.get(entry.getKey()); - if (comment != null) { - writer.write(comment); + /** + * Parses a property file (using UTF-8 encoding) and returns a map of the content. + * <p/>If the file is not present, null is returned with no error messages sent to the log. + * + * @param propFile the property file to parse + * @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null. + * @return the map of (key,value) pairs, or null if the parsing failed. + * @deprecated Use {@link #parsePropertyFile(IAbstractFile, ISdkLog)} + */ + public static Map<String, String> parsePropertyFile(File propFile, ISdkLog log) { + IAbstractFile wrapper = new FileWrapper(propFile); + return parsePropertyFile(wrapper, log); + } + + /** + * Parses a property file (using UTF-8 encoding) and returns a map of the content. + * <p/>If the file is not present, null is returned with no error messages sent to the log. + * + * @param propFile the property file to parse + * @param log the ISdkLog object receiving warning/error from the parsing. Cannot be null. + * @return the map of (key,value) pairs, or null if the parsing failed. + */ + public static Map<String, String> parsePropertyFile(IAbstractFile propFile, ISdkLog log) { + BufferedReader reader = null; + try { + reader = new BufferedReader(new InputStreamReader(propFile.getContents(), + SdkConstants.INI_CHARSET)); + + String line = null; + Map<String, String> map = new HashMap<String, String>(); + while ((line = reader.readLine()) != null) { + if (line.length() > 0 && line.charAt(0) != '#') { + + Matcher m = PATTERN_PROP.matcher(line); + if (m.matches()) { + map.put(m.group(1), m.group(2)); + } else { + log.warning("Error parsing '%1$s': \"%2$s\" is not a valid syntax", + propFile.getOsLocation(), + line); + return null; + } + } } - String value = entry.getValue(); - if (value != null) { - value = value.replaceAll("\\\\", "\\\\\\\\"); - writer.write(String.format("%s=%s\n", entry.getKey(), value)); + + return map; + } catch (FileNotFoundException e) { + // this should not happen since we usually test the file existence before + // calling the method. + // Return null below. + } catch (IOException e) { + log.warning("Error parsing '%1$s': %2$s.", + propFile.getOsLocation(), + e.getMessage()); + } catch (StreamException e) { + log.warning("Error parsing '%1$s': %2$s.", + propFile.getOsLocation(), + e.getMessage()); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + // pass + } } } - // close the file to flush - writer.close(); + return null; } + /** * Private constructor. * <p/> diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java index e3724be..ff42b0b 100644 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java @@ -26,6 +26,7 @@ import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.HardwareProperties; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdklib.internal.avd.HardwareProperties.HardwareProperty; +import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdkuilib.internal.repository.icons.ImageFactory; import com.android.sdkuilib.ui.GridDialog; @@ -876,7 +877,7 @@ final class AvdCreationDialog extends GridDialog { if (target.isPlatform() == false) { File targetHardwareFile = new File(target.getLocation(), AvdManager.HARDWARE_INI); if (targetHardwareFile.isFile()) { - Map<String, String> targetHardwareConfig = SdkManager.parsePropertyFile( + Map<String, String> targetHardwareConfig = ProjectProperties.parsePropertyFile( targetHardwareFile, null /*log*/); if (targetHardwareConfig != null) { hardwareValues.putAll(targetHardwareConfig); @@ -887,7 +888,7 @@ final class AvdCreationDialog extends GridDialog { // from the skin File skinHardwareFile = new File(skin, AvdManager.HARDWARE_INI); if (skinHardwareFile.isFile()) { - Map<String, String> skinHardwareConfig = SdkManager.parsePropertyFile( + Map<String, String> skinHardwareConfig = ProjectProperties.parsePropertyFile( skinHardwareFile, null /*log*/); if (skinHardwareConfig != null) { hardwareValues.putAll(skinHardwareConfig); |