Exemple #1
0
async def find_changed_owners(request: ChangedRequest) -> ChangedAddresses:
    owners = await Get(Owners, OwnersRequest(request.sources))
    if request.dependees == DependeesOption.NONE:
        return ChangedAddresses(owners)
    dependees_with_roots = await Get(
        Dependees,
        DependeesRequest(
            owners, transitive=request.dependees == DependeesOption.TRANSITIVE, include_roots=True,
        ),
    )
    return ChangedAddresses(dependees_with_roots)
Exemple #2
0
async def find_changed_owners(request: ChangedRequest,
                              specs_filter: SpecsFilter) -> ChangedAddresses:
    no_dependees = request.dependees == DependeesOption.NONE
    owners = await Get(
        Owners,
        OwnersRequest(
            request.sources,
            # If `--changed-dependees` is used, we cannot eagerly filter out root targets. We
            # need to first find their dependees, and only then should we filter. See
            # https://github.com/pantsbuild/pants/issues/15544
            filter_by_global_options=no_dependees,
        ),
    )
    if no_dependees:
        return ChangedAddresses(owners)

    # See https://github.com/pantsbuild/pants/issues/15313. We filter out target generators because
    # they are not useful as aliases for their generated targets in the context of
    # `--changed-since`. Including them makes it look like all sibling targets from the same
    # target generator have also changed.
    #
    # However, we also must be careful to preserve if target generators are direct owners, which
    # happens when a generated file is deleted.
    owner_target_generators = FrozenOrderedSet(
        addr.maybe_convert_to_target_generator() for addr in owners
        if addr.is_generated_target)
    dependees = await Get(
        Dependees,
        DependeesRequest(
            owners,
            transitive=request.dependees == DependeesOption.TRANSITIVE,
            include_roots=False,
        ),
    )
    result = FrozenOrderedSet(owners) | (dependees - owner_target_generators)
    if specs_filter.is_specified:
        # Finally, we must now filter out the result to only include what matches our tags, as the
        # last step of https://github.com/pantsbuild/pants/issues/15544.
        #
        # Note that we use `UnexpandedTargets` rather than `Targets` or `FilteredTargets` so that
        # we preserve target generators.
        result_as_tgts = await Get(UnexpandedTargets, Addresses(result))
        result = FrozenOrderedSet(tgt.address for tgt in result_as_tgts
                                  if specs_filter.matches(tgt))

    return ChangedAddresses(result)
Exemple #3
0
async def py_constraints(
    addresses: Addresses,
    console: Console,
    py_constraints_subsystem: PyConstraintsSubsystem,
    python_setup: PythonSetup,
    registered_target_types: RegisteredTargetTypes,
    union_membership: UnionMembership,
) -> PyConstraintsGoal:
    if py_constraints_subsystem.summary:
        if addresses:
            console.print_stderr(
                "The `py-constraints --summary` goal does not take file/target arguments. Run "
                "`help py-constraints` for more details."
            )
            return PyConstraintsGoal(exit_code=1)

        with_generated_targets, without_generated_targets = await MultiGet(
            Get(Targets, AddressSpecs([DescendantAddresses("")])),
            Get(UnexpandedTargets, AddressSpecs([DescendantAddresses("")])),
        )
        all_python_targets = sorted(
            {
                t
                for t in (*with_generated_targets, *without_generated_targets)
                if t.has_field(InterpreterConstraintsField)
            },
            key=lambda tgt: cast(Address, tgt.address),
        )

        constraints_per_tgt = [
            InterpreterConstraints.create_from_targets([tgt], python_setup)
            for tgt in all_python_targets
        ]

        transitive_targets_per_tgt = await MultiGet(
            Get(TransitiveTargets, TransitiveTargetsRequest([tgt.address]))
            for tgt in all_python_targets
        )
        transitive_constraints_per_tgt = [
            InterpreterConstraints.create_from_targets(transitive_targets.closure, python_setup)
            for transitive_targets in transitive_targets_per_tgt
        ]

        dependees_per_root = await MultiGet(
            Get(Dependees, DependeesRequest([tgt.address], transitive=True, include_roots=False))
            for tgt in all_python_targets
        )

        data = [
            {
                "Target": tgt.address.spec,
                "Constraints": str(constraints),
                "Transitive Constraints": str(transitive_constraints),
                "# Dependencies": len(transitive_targets.dependencies),
                "# Dependees": len(dependees),
            }
            for tgt, constraints, transitive_constraints, transitive_targets, dependees in zip(
                all_python_targets,
                constraints_per_tgt,
                transitive_constraints_per_tgt,
                transitive_targets_per_tgt,
                dependees_per_root,
            )
        ]

        with py_constraints_subsystem.output_sink(console) as stdout:
            writer = csv.DictWriter(
                stdout,
                fieldnames=[
                    "Target",
                    "Constraints",
                    "Transitive Constraints",
                    "# Dependencies",
                    "# Dependees",
                ],
            )
            writer.writeheader()
            for entry in data:
                writer.writerow(entry)

        return PyConstraintsGoal(exit_code=0)

    transitive_targets = await Get(TransitiveTargets, TransitiveTargetsRequest(addresses))
    final_constraints = InterpreterConstraints.create_from_targets(
        transitive_targets.closure, python_setup
    )

    if not final_constraints:
        target_types_with_constraints = sorted(
            tgt_type.alias
            for tgt_type in registered_target_types.types
            if tgt_type.class_has_field(InterpreterConstraintsField, union_membership)
        )
        logger.warning(
            "No Python files/targets matched for the `py-constraints` goal. All target types with "
            f"Python interpreter constraints: {', '.join(target_types_with_constraints)}"
        )
        return PyConstraintsGoal(exit_code=0)

    constraints_to_addresses = defaultdict(set)
    for tgt in transitive_targets.closure:
        constraints = InterpreterConstraints.create_from_targets([tgt], python_setup)
        if not constraints:
            continue
        constraints_to_addresses[constraints].add(tgt.address)

    with py_constraints_subsystem.output(console) as output_stdout:
        output_stdout(f"Final merged constraints: {final_constraints}\n")
        if len(addresses) > 1:
            merged_constraints_warning = (
                "(These are the constraints used if you were to depend on all of the input "
                "files/targets together, even though they may end up never being used together in "
                "the real world. Consider using a more precise query or running "
                "`./pants py-constraints --summary`.)\n"
            )
            output_stdout(indent(fill(merged_constraints_warning, 80), "  "))

        for constraint, addrs in sorted(constraints_to_addresses.items()):
            output_stdout(f"\n{constraint}\n")
            for addr in sorted(addrs):
                output_stdout(f"  {addr}\n")

    return PyConstraintsGoal(exit_code=0)