Skip to content

Commit

Permalink
Don't follow links when copying paths
Browse files Browse the repository at this point in the history
The original intent of this method was to copy links as links, not to
deeply copy the content of linked directories. This was never tested and
the original implementation did not have this behavior.

Change behavior in place without a major version change since the new
behavior is what was intended. Add a test that both the sync and async
implementation copies links as links.
  • Loading branch information
natebosch committed Jan 15, 2025
1 parent 5cdad88 commit c935f21
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 3 deletions.
5 changes: 5 additions & 0 deletions pkgs/io/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 1.1.0

* Copy links as links instead of deeply copying the content for all links in
`copyPath` and `copyPathSync`.

## 1.0.5

* Require Dart 3.4.
Expand Down
6 changes: 4 additions & 2 deletions pkgs/io/lib/src/copy_path.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ Future<void> copyPath(String from, String to) async {
return;
}
await Directory(to).create(recursive: true);
await for (final file in Directory(from).list(recursive: true)) {
await for (final file
in Directory(from).list(recursive: true, followLinks: false)) {
final copyTo = p.join(to, p.relative(file.path, from: from));
if (file is Directory) {
await Directory(copyTo).create(recursive: true);
Expand All @@ -56,7 +57,8 @@ void copyPathSync(String from, String to) {
return;
}
Directory(to).createSync(recursive: true);
for (final file in Directory(from).listSync(recursive: true)) {
for (final file
in Directory(from).listSync(recursive: true, followLinks: false)) {
final copyTo = p.join(to, p.relative(file.path, from: from));
if (file is Directory) {
Directory(copyTo).createSync(recursive: true);
Expand Down
2 changes: 1 addition & 1 deletion pkgs/io/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: io
description: >-
Utilities for the Dart VM Runtime including support for ANSI colors, file
copying, and standard exit code values.
version: 1.0.5
version: 1.1.0-wip
repository: https://github.com/dart-lang/tools/tree/main/pkgs/io

environment:
Expand Down
32 changes: 32 additions & 0 deletions pkgs/io/test/copy_path_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
@TestOn('vm')
library;

import 'dart:io';

import 'package:io/io.dart';
import 'package:path/path.dart' as p;
import 'package:test/test.dart';
Expand Down Expand Up @@ -33,6 +35,36 @@ void main() {
throwsArgumentError,
);
});

test('links are preserved in async copy', () async {
await _create();
const linkTarget = 'link_target';
final targetPath = p.join(d.sandbox, linkTarget);
const linkSource = 'link_source';
await d.dir(linkTarget).create();
await Link(p.join(d.sandbox, _parentDir, linkSource)).create(targetPath);

await copyPath(p.join(d.sandbox, _parentDir), p.join(d.sandbox, _copyDir));

final expectedLink = Link(p.join(d.sandbox, _copyDir, linkSource));
expect(await expectedLink.exists(), isTrue);
expect(await expectedLink.target(), targetPath);
});

test('links are preserved in sync copy', () async {
await _create();
const linkTarget = 'link_target';
final targetPath = p.join(d.sandbox, linkTarget);
const linkSource = 'link_source';
await d.dir(linkTarget).create();
await Link(p.join(d.sandbox, _parentDir, linkSource)).create(targetPath);

copyPathSync(p.join(d.sandbox, _parentDir), p.join(d.sandbox, _copyDir));

final expectedLink = Link(p.join(d.sandbox, _copyDir, linkSource));
expect(await expectedLink.exists(), isTrue);
expect(await expectedLink.target(), targetPath);
});
}

const _parentDir = 'parent';
Expand Down

0 comments on commit c935f21

Please sign in to comment.