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

[io] copyPath/copyPathSync: expose parameter followLinks #1267

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

gmpassos
Copy link

Directory.listSync only returns Link entries if followLinks: false is passed.

copyPath needs a followLinks parameter to configure the call of Directory.listSync and allow the copy of Link entries, as expected by line else if (file is Link) {


  • [✅ ] I’ve reviewed the contributor guide and applied the relevant portions to this PR.

@gmpassos
Copy link
Author

FYI: @natebosch

@natebosch
Copy link
Member

@jakemac53 I think uses are unlike to break if we change the default behavior. We already have a default behavior for recursive with no override. Do you think it would make sense to assume followLinks: true too?

Copy link

github-actions bot commented Jan 14, 2025

PR Health

Breaking changes ✔️
Package Change Current Version New Version Needed Version Looking good?
io Non-Breaking 1.0.5 1.1.0-wip 1.1.0 ✔️
Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

Coverage ✔️
File Coverage
pkgs/io/lib/src/copy_path.dart 💚 100 % ⬆️ 18 %

This check for test coverage is informational (issues shown here will not fail the PR).

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbols
License Headers ✔️
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/bazel_worker/benchmark/benchmark.dart
pkgs/bazel_worker/example/client.dart
pkgs/bazel_worker/example/worker.dart
pkgs/benchmark_harness/integration_test/perf_benchmark_test.dart
pkgs/boolean_selector/example/example.dart
pkgs/clock/lib/clock.dart
pkgs/clock/lib/src/clock.dart
pkgs/clock/lib/src/default.dart
pkgs/clock/lib/src/stopwatch.dart
pkgs/clock/lib/src/utils.dart
pkgs/clock/test/clock_test.dart
pkgs/clock/test/default_test.dart
pkgs/clock/test/stopwatch_test.dart
pkgs/clock/test/utils.dart
pkgs/html/example/main.dart
pkgs/html/lib/dom.dart
pkgs/html/lib/dom_parsing.dart
pkgs/html/lib/html_escape.dart
pkgs/html/lib/parser.dart
pkgs/html/lib/src/constants.dart
pkgs/html/lib/src/encoding_parser.dart
pkgs/html/lib/src/html_input_stream.dart
pkgs/html/lib/src/list_proxy.dart
pkgs/html/lib/src/query_selector.dart
pkgs/html/lib/src/token.dart
pkgs/html/lib/src/tokenizer.dart
pkgs/html/lib/src/treebuilder.dart
pkgs/html/lib/src/utils.dart
pkgs/html/test/dom_test.dart
pkgs/html/test/parser_feature_test.dart
pkgs/html/test/parser_test.dart
pkgs/html/test/query_selector_test.dart
pkgs/html/test/selectors/level1_baseline_test.dart
pkgs/html/test/selectors/level1_lib.dart
pkgs/html/test/selectors/selectors.dart
pkgs/html/test/support.dart
pkgs/html/test/tokenizer_test.dart
pkgs/pubspec_parse/test/git_uri_test.dart
pkgs/stack_trace/example/example.dart
pkgs/watcher/test/custom_watcher_factory_test.dart
pkgs/yaml_edit/example/example.dart

@gmpassos
Copy link
Author

gmpassos commented Jan 14, 2025

@jakemac53 I think uses are unlike to break if we change the default behavior. We already have a default behavior for recursive with no override. Do you think it would make sense to assume followLinks: true too?

The current behavior is followLinks: true due to Directory.list default value for followLinks:
https://api.dart.dev/dart-io/Directory/list.html

I vote to keep the current behavior as the default since this is a core function and could be used by multiple third-party projects that might not catch any changes in this behavior in their tests, as it's not a common thing to test.

The main purpose is to add an extra option for those who really want to change the behavior.

Copy link
Contributor

@jakemac53 jakemac53 left a comment

Choose a reason for hiding this comment

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

This looks fine to me

@natebosch
Copy link
Member

After a discussion with a few folks I do think it'll be easier to change the default behavior than to add an argument for this. I'm pretty confident it's the behavior we'd want as default, and omitting the argument will save on testing surface area. I'll open up another PR shortly to do that change.

@jakemac53
Copy link
Contributor

After a discussion with a few folks I do think it'll be easier to change the default behavior than to add an argument for this. I'm pretty confident it's the behavior we'd want as default, and omitting the argument will save on testing surface area. I'll open up another PR shortly to do that change.

I am not quite understanding why we want to change behavior here? Why do we want to diverge from what dart:io does by default?

@jakemac53
Copy link
Contributor

jakemac53 commented Jan 15, 2025

I guess the question really here is do you actually copy the (recursive) file contents the links point to or do you copy the links themselves?

Today we copy the file contents because by default links are followed.

Both seem useful depending on the application - I would probably consider the deep copy to be the "safest" option. You are expecting a copy here and not a pointer (link). If you don't do the deep copy, and the thing the link points to changes, your "copy" actually changes too because all you copied was the pointer.

@gmpassos
Copy link
Author

gmpassos commented Jan 15, 2025

I'm pretty confident it's the behavior we'd want as default.

IMHO, you shouldn't change this behavior after 8 years.

omitting the argument will save on testing surface area. I'll open up another PR shortly to do that change.

To avoid testing on the Dart SDK, you could potentially break many third-party tests. Personally, I can't agree with that.

Without the followLinks parameter, depending on the default behavior leads to the following limitations:

  • Solutions that aim to copy a tree of files without copying links will be unable to use copyPath.
  • Solutions that require a local copy with links, to avoid file duplication, will be unable to use copyPath.

@natebosch
Copy link
Member

I guess the question really here is do you actually copy the (recursive) file contents the links point to or do you copy the links themselves?

The intention at the time was that the links would be copied. That's also the behavior that makes the most sense to me, and is what I'd do if I was implementing this today - either being the default if there was a reason to make this optional, or more likely make it the only implementation.

I am not quite understanding why we want to change behavior here?

Primarily:

  • Reduce the amount of testing surface area. If we were strict about testing, it would cut the surface in half, but in practice it's a smaller savings to avoid the extra boolean argument.
  • Provide what appears to be the intended behavior to whatever internal use cases need it without them needing to migrate.

@natebosch
Copy link
Member

See #1972 for the alternative.

@natebosch
Copy link
Member

natebosch commented Jan 15, 2025

what I'd do if I was implementing this today - either being the default if there was a reason to make this optional, or more likely make it the only implementation.

Thinking about it more, if both behaviors were necessary I think I'd still push back against the boolean argument. They feel enough like different operations to me that I'd argue for separating deepCopyLinkedContent which could replace links in place, from copyPath which would always treat links as links. The former could be useful separately.

@gmpassos
Copy link
Author

deepCopyLinkedContent

I vote for bool deepCopyLinkedContent = true, as it preserves the old behavior while also enabling the new (originally intended) behavior.

@natebosch
Copy link
Member

I vote for bool deepCopyLinkedContent = true, as it preserves the old behavior while also enabling the new (originally intended) behavior.

I mean that I'd write an entirely separate method deepCopyLinkedContent(String path) {...}. I don't think a boolean argument with any name is the best API design.

@gmpassos
Copy link
Author

I mean that I'd write an entirely separate method deepCopyLinkedContent(String path) {...}.

Well, it's an alternative, but you are still changing the behavior of copyPath. You will need to check all the internal tools that use it to ensure that nothing breaks.

@natebosch
Copy link
Member

@jakemac53 I think the followLinks naming is a bit too tied to the implementation. WDYT about the new name and doc? Also, can you take a look at the added tests?

File(p.join(d.sandbox, _copyDir, linkSource, linkContent));
expect(await expectedDir.exists(), isTrue);
expect(await expectedFile.exists(), isTrue);

Copy link
Author

Choose a reason for hiding this comment

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

Check for the copied content before overwrite it.

File(p.join(d.sandbox, _copyDir, linkSource, linkContent));
expect(await expectedDir.exists(), isTrue);
expect(await expectedFile.exists(), isTrue);

Copy link
Author

Choose a reason for hiding this comment

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

Same check here, before content overwrite.

@gmpassos
Copy link
Author

I prefer the parameter name deepCopyLinks, as it is more intuitive. followLinks requires documentation to clarify its actual behavior. followLinks only exists because of the Directory.list parameter, and this shouldn't dictate the copyPath signature.

I have made two comments in the test code.

@kevmoo kevmoo changed the title copyPath/copyPathSync: expose parameter followLinks [io] copyPath/copyPathSync: expose parameter followLinks Jan 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants