AAPT2: Parse artifact names from template.
Add a helper method to convert a templated artifact name to file name
based on the values present in an Artifact struct. The Artifact
validates that all required template paramters are present.
Test: Unit tests
Change-Id: Id97ff606bb41c72a31c2d769104966be9cbca1a0
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index 0b6743c..d051120 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -29,6 +29,7 @@
#include "Diagnostics.h"
#include "io/File.h"
#include "io/FileSystem.h"
+#include "util/Maybe.h"
#include "util/Util.h"
#include "xml/XmlActionExecutor.h"
#include "xml/XmlDom.h"
@@ -109,6 +110,61 @@
return kAbiToStringMap.find(abi)->second;
}
+/**
+ * Attempts to replace the placeholder in the name string with the provided value. Returns true on
+ * success, or false if the either the placeholder is not found in the name, or the value is not
+ * present and the placeholder was.
+ */
+static bool ReplacePlaceholder(const std::string& placeholder, const Maybe<std::string>& value,
+ std::string* name, IDiagnostics* diag) {
+ size_t offset = name->find(placeholder);
+ if (value) {
+ if (offset == std::string::npos) {
+ diag->Error(DiagMessage() << "Missing placeholder for artifact: " << placeholder);
+ return false;
+ }
+ name->replace(offset, placeholder.length(), value.value());
+ return true;
+ }
+
+ // Make sure the placeholder was not present if the desired value was not present.
+ bool result = (offset == std::string::npos);
+ if (!result) {
+ diag->Error(DiagMessage() << "Placeholder present but no value for artifact: " << placeholder);
+ }
+ return result;
+}
+
+Maybe<std::string> Artifact::ToArtifactName(const std::string& format, IDiagnostics* diag) const {
+ std::string result = format;
+
+ if (!ReplacePlaceholder("{abi}", abi_group, &result, diag)) {
+ return {};
+ }
+
+ if (!ReplacePlaceholder("{density}", screen_density_group, &result, diag)) {
+ return {};
+ }
+
+ if (!ReplacePlaceholder("{locale}", locale_group, &result, diag)) {
+ return {};
+ }
+
+ if (!ReplacePlaceholder("{sdk}", android_sdk_group, &result, diag)) {
+ return {};
+ }
+
+ if (!ReplacePlaceholder("{feature}", device_feature_group, &result, diag)) {
+ return {};
+ }
+
+ if (!ReplacePlaceholder("{gl}", gl_texture_group, &result, diag)) {
+ return {};
+ }
+
+ return result;
+}
+
} // namespace configuration
/** Returns a ConfigurationParser for the file located at the provided path. */
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 3fae5dd..28c355e 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -20,8 +20,9 @@
#include <string>
#include <unordered_map>
#include <vector>
-#include <ConfigDescription.h>
+#include "ConfigDescription.h"
+#include "Diagnostics.h"
#include "util/Maybe.h"
namespace aapt {
@@ -48,6 +49,9 @@
Maybe<std::string> device_feature_group;
/** If present, uses the OpenGL texture group with this name. */
Maybe<std::string> gl_texture_group;
+
+ /** Convert an artifact name template into a name string based on configuration contents. */
+ Maybe<std::string> ToArtifactName(const std::string& format, IDiagnostics* diag) const;
};
/** Enumeration of currently supported ABIs. */
@@ -212,4 +216,4 @@
} // namespace aapt
-#endif //AAPT2_CONFIGURATION_H
+#endif // AAPT2_CONFIGURATION_H
diff --git a/tools/aapt2/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index a4fa134..fb71e98 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -32,6 +32,7 @@
using android::ResTable_config;
using configuration::Abi;
using configuration::AndroidSdk;
+using configuration::Artifact;
using configuration::PostProcessingConfiguration;
using configuration::DeviceFeature;
using configuration::GlTexture;
@@ -417,5 +418,55 @@
ASSERT_THAT(out, ElementsAre(low_latency, pro));
}
+TEST(ArtifactTest, Simple) {
+ StdErrDiagnostics diag;
+ Artifact x86;
+ x86.abi_group = {"x86"};
+
+ auto x86_result = x86.ToArtifactName("something.{abi}.apk", &diag);
+ ASSERT_TRUE(x86_result);
+ EXPECT_EQ(x86_result.value(), "something.x86.apk");
+
+ Artifact arm;
+ arm.abi_group = {"armeabi-v7a"};
+
+ auto arm_result = arm.ToArtifactName("app.{abi}.apk", &diag);
+ ASSERT_TRUE(arm_result);
+ EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
+}
+
+TEST(ArtifactTest, Complex) {
+ StdErrDiagnostics diag;
+ Artifact artifact;
+ artifact.abi_group = {"mips64"};
+ artifact.screen_density_group = {"ldpi"};
+ artifact.device_feature_group = {"df1"};
+ artifact.gl_texture_group = {"glx1"};
+ artifact.locale_group = {"en-AU"};
+ artifact.android_sdk_group = {"26"};
+
+ auto result =
+ artifact.ToArtifactName("app.{density}_{locale}_{feature}_{gl}.sdk{sdk}.{abi}.apk", &diag);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk");
+}
+
+TEST(ArtifactTest, Missing) {
+ StdErrDiagnostics diag;
+ Artifact x86;
+ x86.abi_group = {"x86"};
+
+ EXPECT_FALSE(x86.ToArtifactName("something.{density}.apk", &diag));
+ EXPECT_FALSE(x86.ToArtifactName("something.apk", &diag));
+}
+
+TEST(ArtifactTest, Empty) {
+ StdErrDiagnostics diag;
+ Artifact artifact;
+
+ EXPECT_FALSE(artifact.ToArtifactName("something.{density}.apk", &diag));
+ EXPECT_TRUE(artifact.ToArtifactName("something.apk", &diag));
+}
+
} // namespace
} // namespace aapt