/** * Looks through filtered drawables for files not of the target density and replaces them with * scaled versions. * * <p>Any drawables found by this step didn't have equivalents in the target density. If they are * of a higher density, we can replicate what Android does and downscale them at compile-time. */ private void scaleUnmatchedDrawables(ExecutionContext context) throws IOException, InterruptedException { ResourceFilters.Density targetDensity = ResourceFilters.Density.ORDERING.max(targetDensities); // Go over all the images that remain after filtering. Preconditions.checkNotNull(drawableFinder); Collection<Path> drawables = drawableFinder.findDrawables(inResDirToOutResDirMap.values(), filesystem); for (Path drawable : drawables) { if (drawable.toString().endsWith(".9.png")) { // Skip nine-patch for now. continue; } ResourceFilters.Qualifiers qualifiers = new ResourceFilters.Qualifiers(drawable); ResourceFilters.Density density = qualifiers.density; // If the image has a qualifier but it's not the right one. Preconditions.checkNotNull(targetDensities); if (!targetDensities.contains(density)) { // Replace density qualifier with target density using regular expression to match // the qualifier in the context of a path to a drawable. String fromDensity = (density == ResourceFilters.Density.NO_QUALIFIER ? "" : "-") + density.toString(); Path destination = Paths.get( MorePaths.pathWithUnixSeparators(drawable) .replaceFirst( "((?:^|/)drawable[^/]*)" + Pattern.quote(fromDensity) + "(-|$|/)", "$1-" + targetDensity + "$2")); double factor = targetDensity.value() / density.value(); if (factor >= 1.0) { // There is no point in up-scaling, or converting between drawable and drawable-mdpi. continue; } // Make sure destination folder exists and perform downscaling. filesystem.createParentDirs(destination); Preconditions.checkNotNull(imageScaler); imageScaler.scale(factor, drawable, destination, context); // Delete source file. filesystem.deleteFileAtPath(drawable); // Delete newly-empty directories to prevent missing resources errors in apkbuilder. Path parent = drawable.getParent(); if (filesystem.listFiles(parent).length == 0) { filesystem.deleteFileAtPath(parent); } } } }
@SuppressWarnings({"rawtypes", "unchecked"}) private TargetNode<?> createTargetNode( BuckEventBus eventBus, Cell cell, Path buildFile, BuildTarget target, Map<String, Object> rawNode, TargetNodeListener nodeListener) { BuildRuleType buildRuleType = parseBuildRuleTypeFromRawRule(cell, rawNode); // Because of the way that the parser works, we know this can never return null. Description<?> description = cell.getDescription(buildRuleType); if (target.isFlavored()) { if (description instanceof Flavored) { if (!((Flavored) description).hasFlavors(ImmutableSet.copyOf(target.getFlavors()))) { throw new HumanReadableException( "Unrecognized flavor in target %s while parsing %s%s.", target, UnflavoredBuildTarget.BUILD_TARGET_PREFIX, MorePaths.pathWithUnixSeparators( target.getBasePath().resolve(cell.getBuildFileName()))); } } else { LOG.warn( "Target %s (type %s) must implement the Flavored interface " + "before we can check if it supports flavors: %s", target.getUnflavoredBuildTarget(), buildRuleType, target.getFlavors()); throw new HumanReadableException( "Target %s (type %s) does not currently support flavors (tried %s)", target.getUnflavoredBuildTarget(), buildRuleType, target.getFlavors()); } } Cell targetCell = cell.getCell(target); BuildRuleFactoryParams factoryParams = new BuildRuleFactoryParams( targetCell.getFilesystem(), target.withoutCell(), new FilesystemBackedBuildFileTree(cell.getFilesystem(), cell.getBuildFileName()), targetCell.isEnforcingBuckPackageBoundaries()); Object constructorArg = description.createUnpopulatedConstructorArg(); try { ImmutableSet.Builder<BuildTarget> declaredDeps = ImmutableSet.builder(); ImmutableSet.Builder<BuildTargetPattern> visibilityPatterns = ImmutableSet.builder(); try (SimplePerfEvent.Scope scope = SimplePerfEvent.scope( eventBus, PerfEventId.of("MarshalledConstructorArg"), "target", target)) { marshaller.populate( targetCell.getCellRoots(), targetCell.getFilesystem(), factoryParams, constructorArg, declaredDeps, visibilityPatterns, rawNode); } try (SimplePerfEvent.Scope scope = SimplePerfEvent.scope(eventBus, PerfEventId.of("CreatedTargetNode"), "target", target)) { Hasher hasher = Hashing.sha1().newHasher(); hasher.putString(BuckVersion.getVersion(), UTF_8); JsonObjectHashing.hashJsonObject(hasher, rawNode); synchronized (this) { targetsCornucopia.put(target.getUnflavoredBuildTarget(), target); } TargetNode<?> node = new TargetNode( hasher.hash(), description, constructorArg, typeCoercerFactory, factoryParams, declaredDeps.build(), visibilityPatterns.build(), targetCell.getCellRoots()); nodeListener.onCreate(buildFile, node); return node; } } catch (NoSuchBuildTargetException | TargetNode.InvalidSourcePathInputException e) { throw new HumanReadableException(e); } catch (ConstructorArgMarshalException e) { throw new HumanReadableException("%s: %s", target, e.getMessage()); } catch (IOException e) { throw new HumanReadableException(e.getMessage(), e); } }
static OwnersReport buildOwnersReport( CommandRunnerParams params, ParserConfig parserConfig, BuildFileTree buildFileTree, Iterable<String> arguments, boolean guessForDeletedEnabled) throws IOException, InterruptedException, BuildFileParseException, BuildTargetException { final Path rootPath = params.getCell().getFilesystem().getRootPath(); Preconditions.checkState(rootPath.isAbsolute()); Map<Path, List<TargetNode<?>>> targetNodes = Maps.newHashMap(); OwnersReport report = OwnersReport.emptyReport(); for (Path filePath : getArgumentsAsPaths(rootPath, arguments)) { Optional<Path> basePath = buildFileTree.getBasePathOfAncestorTarget(filePath); if (!basePath.isPresent()) { report = report.updatedWith( new OwnersReport( ImmutableSetMultimap.<TargetNode<?>, Path>of(), /* inputWithNoOwners */ ImmutableSet.of(filePath), Sets.<String>newHashSet(), Sets.<String>newHashSet())); continue; } Path buckFile = basePath.get().resolve(parserConfig.getBuildFileName()); Preconditions.checkState(params.getCell().getFilesystem().exists(buckFile)); // Parse buck files and load target nodes. if (!targetNodes.containsKey(buckFile)) { try { targetNodes.put( buckFile, params .getParser() .getOrLoadTargetNodes( buckFile, parserConfig, params.getBuckEventBus(), params.getConsole(), params.getEnvironment())); } catch (BuildFileParseException | BuildTargetException e) { Path targetBasePath = MorePaths.relativize(rootPath, rootPath.resolve(basePath.get())); String targetBaseName = "//" + MorePaths.pathWithUnixSeparators(targetBasePath); params .getConsole() .getStdErr() .format("Could not parse build targets for %s", targetBaseName); throw e; } } for (TargetNode<?> targetNode : targetNodes.get(buckFile)) { report = report.updatedWith( generateOwnersReport( params, targetNode, ImmutableList.of(filePath.toString()), guessForDeletedEnabled)); } } return report; }