Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relax dcou dep. in order-crates-for-publishing.py #32432

Merged
merged 3 commits into from
Jul 13, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion ci/order-crates-for-publishing.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,59 @@ def load_metadata():
return json.loads(subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE).communicate()[0])

# Consider a situation where a crate now wants to use already existing
# developing-oriented library code for their integration tests and benchmarks,
# like creating malformed data or omitting signature verifications. Ideally,
# the code should have been guarded under the special feature
# `dev-context-only-utils` to avoid accidental misuse for production code path.
#
# In this case, the feature needs to be defined then activated for the crate
# itself. To that end, the crate actually needs to depend on itself as a
# dev-dependency with `dev-context-only-utils` activated, so that the feature
# is conditionally activated only for integration tests and benchmarks. In this
# way, other crates won't see the feature activated even if they normal-depend
# on the crate.
#
# This self-referencing dev-dependency can be thought of a variant of
# dev-dependency cycles and it's well supported by cargo. The only exception is
# when publishing. In general, cyclic dev-dependency doesn't work nicely with
# publishing: https://github.com/rust-lang/cargo/issues/4242 .
#
# However, there's a work around supported by cargo. Namely, it will ignore and
# strip these cyclic dev-dependencies when publishing, if explicit version
# isn't specified: https://github.com/rust-lang/cargo/pull/7333 (Released in
# rust 1.40.0: https://releases.rs/docs/1.40.0/#cargo )
#
# This script follows the same safe discarding logic to exclude these
# special-cased dev dependencies from its `dependency_graph` and further
# processing.
def is_self_dev_dep_with_dev_context_only_utils(package, dependency):
no_explicit_version = '*'

is_special_cased = False
if (dependency['kind'] == 'dev' and
dependency['name'] == package['name'] and
'dev-context-only-utils' in dependency['features'] and
'path' in dependency):
if dependency['req'] == no_explicit_version:
is_special_cased = True
else:
# it's likely `{ workspace = true, ... }` is used, which implicitly pulls the
# version in...
sys.exit(
'Error: wrong dev-context-only-utils circular dependency. try: ' +
'{} = {{ path = ".", features = {} }}\n'
.format(dependency['name'], json.dumps(dependency['features']))
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we collect the crates that fail this check and print them at the end instead of early-returning? spare someone the demoralizing check-fail-fix cycles 😉

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

phew, you rightfully spotted my laziness: 44e6513


return is_special_cased

def should_add(package, dependency):
is_related_to_solana = dependency['name'].startswith('solana')
return (
is_related_to_solana and not is_self_dev_dep_with_dev_context_only_utils(package, dependency)
)

def get_packages():
metadata = load_metadata()

Expand All @@ -30,7 +83,7 @@ def get_packages():
dependency_graph = dict()
for pkg in metadata['packages']:
manifest_path[pkg['name']] = pkg['manifest_path'];
dependency_graph[pkg['name']] = [x['name'] for x in pkg['dependencies'] if x['name'].startswith('solana')];
dependency_graph[pkg['name']] = [x['name'] for x in pkg['dependencies'] if should_add(pkg, x)];

# Check for direct circular dependencies
circular_dependencies = set()
Expand Down