return true;
}
+// The default to use if no other ignore pattern is defined.
+const char * const gDefaultIgnoreAssets =
+ "!.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~";
+// The ignore pattern that can be passed via --ignore-assets in Main.cpp
+const char * gUserIgnoreAssets = NULL;
+
static bool isHidden(const char *root, const char *path)
{
- const char *ext = NULL;
- const char *type = NULL;
-
- // Skip all hidden files.
- if (path[0] == '.') {
- // Skip ., .. and .svn but don't chatter about it.
- if (strcmp(path, ".") == 0
- || strcmp(path, "..") == 0
- || strcmp(path, ".svn") == 0) {
- return true;
- }
- type = "hidden";
- } else if (path[0] == '_') {
- // skip directories starting with _ (don't chatter about it)
- String8 subdirName(root);
- subdirName.appendPath(path);
- if (getFileType(subdirName.string()) == kFileTypeDirectory) {
- return true;
- }
- } else if (strcmp(path, "CVS") == 0) {
- // Skip CVS but don't chatter about it.
- return true;
- } else if (strcasecmp(path, "thumbs.db") == 0
- || strcasecmp(path, "picasa.ini") == 0) {
- // Skip suspected image indexes files.
- type = "index";
- } else if (path[strlen(path)-1] == '~') {
- // Skip suspected emacs backup files.
- type = "backup";
- } else if ((ext = strrchr(path, '.')) != NULL && strcmp(ext, ".scc") == 0) {
- // Skip VisualSourceSafe files and don't chatter about it
+ // Patterns syntax:
+ // - Delimiter is :
+ // - Entry can start with the flag ! to avoid printing a warning
+ // about the file being ignored.
+ // - Entry can have the flag "<dir>" to match only directories
+ // or <file> to match only files. Default is to match both.
+ // - Entry can be a simplified glob "<prefix>*" or "*<suffix>"
+ // where prefix/suffix must have at least 1 character (so that
+ // we don't match a '*' catch-all pattern.)
+ // - The special filenames "." and ".." are always ignored.
+ // - Otherwise the full string is matched.
+ // - match is not case-sensitive.
+
+ if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0) {
return true;
- } else {
- // Let everything else through.
- return false;
}
- /* If we get this far, "type" should be set and the file
- * should be skipped.
- */
- String8 subdirName(root);
- subdirName.appendPath(path);
- fprintf(stderr, " (skipping %s %s '%s')\n", type,
- getFileType(subdirName.string())==kFileTypeDirectory ? "dir":"file",
- subdirName.string());
+ const char *delim = ":";
+ const char *p = gUserIgnoreAssets;
+ if (!p || !p[0]) {
+ p = getenv("ANDROID_AAPT_IGNORE");
+ }
+ if (!p || !p[0]) {
+ p = gDefaultIgnoreAssets;
+ }
+ char *patterns = strdup(p);
- return true;
+ bool ignore = false;
+ bool chatty = true;
+ char *matchedPattern = NULL;
+
+ String8 fullPath(root);
+ fullPath.appendPath(path);
+ FileType type = getFileType(fullPath);
+
+ int plen = strlen(path);
+
+ // Note: we don't have strtok_r under mingw.
+ for(char *token = strtok(patterns, delim);
+ !ignore && token != NULL;
+ token = strtok(NULL, delim)) {
+ chatty = token[0] != '!';
+ if (!chatty) token++; // skip !
+ if (strncasecmp(token, "<dir>" , 5) == 0) {
+ if (type != kFileTypeDirectory) continue;
+ token += 5;
+ }
+ if (strncasecmp(token, "<file>", 6) == 0) {
+ if (type != kFileTypeRegular) continue;
+ token += 6;
+ }
+
+ matchedPattern = token;
+ int n = strlen(token);
+
+ if (token[0] == '*') {
+ // Match *suffix
+ token++;
+ if (n <= plen) {
+ ignore = strncasecmp(token, path + plen - n, n) == 0;
+ }
+ } else if (n > 1 && token[n - 1] == '*') {
+ // Match prefix*
+ ignore = strncasecmp(token, path, n - 1) == 0;
+ } else {
+ ignore = strcasecmp(token, path) == 0;
+ }
+ }
+
+ if (ignore && chatty) {
+ fprintf(stderr, " (skipping %s '%s' due to ANDROID_AAPT_IGNORE pattern '%s')\n",
+ type == kFileTypeDirectory ? "dir" : "file",
+ path,
+ matchedPattern ? matchedPattern : "");
+ }
+
+ free(patterns);
+ return ignore;
}
// =========================================================================
mWantUTF16(false), mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
- mIsOverlayPackage(false),
mAutoAddOverlay(false), mGenDependencies(false),
mAssetSourceDir(NULL),
mCrunchedOutputDir(NULL), mProguardFile(NULL),
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
- bool getIsOverlayPackage() const { return mIsOverlayPackage; }
- void setIsOverlayPackage(bool val) { mIsOverlayPackage = val; }
bool getAutoAddOverlay() { return mAutoAddOverlay; }
void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
bool getGenDependencies() { return mGenDependencies; }
const char* mOutputAPKFile;
const char* mManifestPackageNameOverride;
const char* mInstrumentationPackageNameOverride;
- bool mIsOverlayPackage;
bool mAutoAddOverlay;
bool mGenDependencies;
const char* mAssetSourceDir;
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
- " [-o] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
"\n"
" Package the android resources. It will read assets and resources that are\n"
" -j specify a jar or zip file containing classes to include\n"
" -k junk path of file(s) added\n"
" -m make package directories under location specified by -J\n"
- " -o create overlay package (ie only resources; expects <overlay-package> in manifest)\n"
#if 0
" -p pseudolocalize the default configuration\n"
#endif
" --non-constant-id\n"
" Make the resources ID non constant. This is required to make an R java class\n"
" that does not contain the final value but is used to make reusable compiled\n"
- " libraries that need to access resources.\n");
+ " libraries that need to access resources.\n"
+ " --ignore-assets\n"
+ " Assets to be ignored. Default pattern is:\n"
+ " %s\n",
+ gDefaultIgnoreAssets);
}
/*
case 'm':
bundle.setMakePackageDirs(true);
break;
- case 'o':
- bundle.setIsOverlayPackage(true);
- break;
#if 0
case 'p':
bundle.setPseudolocalize(true);
bundle.setNonConstantId(true);
} else if (strcmp(cp, "-no-crunch") == 0) {
bundle.setUseCrunchCache(true);
- }else {
+ } else if (strcmp(cp, "-ignore-assets") == 0) {
+ argc--;
+ argv++;
+ if (!argc) {
+ fprintf(stderr, "ERROR: No argument supplied for '--ignore-assets' option\n");
+ wantUsage = true;
+ goto bail;
+ }
+ gUserIgnoreAssets = argv[0];
+ } else {
fprintf(stderr, "ERROR: Unknown option '-%s'\n", cp);
wantUsage = true;
goto bail;
const bool filterable = (typeName != mipmap16);
const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
+
+ // Until a non-NO_ENTRY value has been written for a resource,
+ // that resource is invalid; validResources[i] represents
+ // the item at t->getOrderedConfigs().itemAt(i).
+ Vector<bool> validResources;
+ validResources.insertAt(false, 0, N);
// First write the typeSpec chunk, containing information about
// each resource entry in this type.
if (amt < 0) {
return amt;
}
+ validResources.editItemAt(ei) = true;
} else {
index[ei] = htodl(ResTable_type::NO_ENTRY);
}
(((uint8_t*)data->editData()) + typeStart);
tHeader->header.size = htodl(data->getSize()-typeStart);
}
+
+ for (size_t i = 0; i < N; ++i) {
+ if (!validResources[i]) {
+ sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
+ fprintf(stderr, "warning: no entries written for %s/%s\n",
+ String8(typeName).string(), String8(c->getName()).string());
+ }
+ }
}
// Fill in the rest of the package information.
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
- if (mBundle->getIsOverlayPackage()) {
- p = new Package(package, 0x00);
- } else if (mIsAppPackage) {
+ if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n"
"Use -x to create extended resources.\n");