Seth Ladd
Seth Ladd

Reputation: 120749

How do I get the directory of the current script, in Dart?

I want to know what the script's directory is. I have a command-line Dart script.

Upvotes: 19

Views: 9097

Answers (4)

jamesdlin
jamesdlin

Reputation: 90155

Another (albeit hacky) way to determine the path to the current .dart file is to extract the path from the stack trace.

Unlike Platform.script.path, this should work with unit tests:

import 'package:stack_trace/stack_trace.dart' as stacktrace;

/// Returns an absolute path to the caller's `.dart` file.
String currentDartFilePath() => stacktrace.Frame.caller(1).uri.toFilePath();

/// Returns a path to the caller's `.dart` file, relative to the package root.
String currentPackageRelativePath() => stacktrace.Frame.caller(1).library;

Note that stacktrace.Frame.caller(1) returns the stack frame of the caller, so the code above expects that you call currentDartFilePath() currentPackageRelativePath() and not use stacktrace.Frame.caller(1).uri.toFilePath() or stacktrace.Frame.caller(1).library directly.

If you want just the directory, you then can perform typical path manipulation operations on the results.

Upvotes: 2

Brett Sutton
Brett Sutton

Reputation: 4584

Using Platform.script.path doesn't work in all circumstances.

If your script is compiled or running as a unit test you won't get the expected results.

This is from the dcli project (https://pub.dev/packages/dcli)

If you are using dcli you can call:

// absolute path including the script name
DartScript.self.pathToScript;

or

// just the absolute path to the script's directory
DartScript.self.pathToScriptDirectory;

This code works if the script is run via dart <scriptname.dart>, if you compile the script or if you script is a unit test.

Here is the internal implementation.

static String get _pathToCurrentScript {
    if (_current == null) {
      final script = Platform.script;

      String _pathToScript;
      if (script.isScheme('file')) {
        _pathToScript = Platform.script.toFilePath();

        if (_isCompiled) {
          _pathToScript = Platform.resolvedExecutable;
        }
      } else {
        /// when running in a unit test we can end up with a 'data' scheme
        if (script.isScheme('data')) {
          final start = script.path.indexOf('file:');
          final end = script.path.lastIndexOf('.dart');
          final fileUri = script.path.substring(start, end + 5);

          /// now parse the remaining uri to a path.
          _pathToScript = Uri.parse(fileUri).toFilePath();
        }
      }

      return _pathToScript;
    } else {
      return _current.pathToScript;
    }
  }

  static bool get _isCompiled =>
      basename(Platform.resolvedExecutable) ==
      basename(Platform.script.path);

Upvotes: 5

Dan Field
Dan Field

Reputation: 21661

If you're doing this for a console based app (e.g. in a unit test) and intend to use the output to open a file for reading or writing, it's more helpful to use Platform.script.path:

import "package:path/path.dart" show dirname, join;
import 'dart:io' show Platform;

main() {
  print(join(dirname(Platform.script.path), 'test_data_file.dat'));
}

The result of that command can be used with a File object and be opened/read (e.g. if you have a unit test that needs to read/compare sample data, or a console program that needs to open a file relative to the current script for some other reason).

Upvotes: 18

Seth Ladd
Seth Ladd

Reputation: 120749

The easiest way to find the script's directory is to use the path package.

import "package:path/path.dart" show dirname;
import 'dart:io' show Platform;

main() {
  print(dirname(Platform.script.toString()));
}

Put the path package into your pubspec.yaml:

dependencies:
  path: any

And be sure to run pub get to download and link the path package.

Upvotes: 9

Related Questions