add(dcli): refactoring from dcli_common
This commit is contained in:
parent
46c43388e2
commit
59e30aa9be
5 changed files with 223 additions and 1 deletions
21
packages/console/lib/common.dart
Normal file
21
packages/console/lib/common.dart
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* This file is part of the Protevus Platform.
|
||||
*
|
||||
* (C) Protevus <developers@protevus.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/// This library file exports common utility functions and controllers used in the Protevus Console package.
|
||||
///
|
||||
/// It includes:
|
||||
/// - Functionality for determining paths, exported from 'determine_paths.dart'
|
||||
/// - A unit test controller, exported from 'unit_test_controller.dart'
|
||||
///
|
||||
/// These exports allow other parts of the application to easily access and use
|
||||
/// these common utilities without needing to import them individually.
|
||||
library;
|
||||
|
||||
export 'package:protevus_console/src/common/determine_paths.dart';
|
||||
export 'package:protevus_console/src/common/unit_test_controller.dart';
|
144
packages/console/lib/src/common/determine_paths.dart
Normal file
144
packages/console/lib/src/common/determine_paths.dart
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* This file is part of the Protevus Platform.
|
||||
*
|
||||
* (C) Protevus <developers@protevus.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path/path.dart';
|
||||
|
||||
/// Determines the paths for source and backup directories based on the given parameters.
|
||||
///
|
||||
/// [path] is the relative or absolute path to the
|
||||
/// file that we are going to backup. If [path] is
|
||||
/// relative then it is relative to [workingDirectory].
|
||||
/// [backupDir] is the temporary directory that we
|
||||
/// are going to backup [path] to.
|
||||
///
|
||||
/// We use the following directory structure for the backup
|
||||
/// relative/<path to [path]>
|
||||
/// absolute/<path to [path]>
|
||||
///
|
||||
/// On Windows to accomodate drive letters we need a slightly
|
||||
/// different directory structure
|
||||
/// relative/<path to [path]>
|
||||
/// absolute/<XDrive>/<path to [path]>
|
||||
///
|
||||
/// Where 'X' is the drive letter that [path] is located on.
|
||||
///
|
||||
Paths determinePaths({
|
||||
required String path,
|
||||
required String workingDirectory,
|
||||
required String backupDir,
|
||||
}) {
|
||||
late final String sourcePath;
|
||||
late final String backupPath;
|
||||
|
||||
/// we use two different directories for relative and absolute
|
||||
/// paths otherwise we can't differentiate when it comes time
|
||||
/// to restore.
|
||||
if (isRelative(path)) {
|
||||
backupPath = normalize(absolute(join(backupDir, 'relative', path)));
|
||||
sourcePath = join(workingDirectory, path);
|
||||
} else {
|
||||
sourcePath = normalize(absolute(path));
|
||||
final translatedPath =
|
||||
translateAbsolutePath(path, workingDirectory: workingDirectory);
|
||||
backupPath = join(backupDir, 'absolute', _stripRootPrefix(translatedPath));
|
||||
}
|
||||
|
||||
return Paths(sourcePath, backupPath);
|
||||
}
|
||||
|
||||
/// Represents a pair of paths for source and backup files.
|
||||
///
|
||||
/// This class is used to store and manage the paths for a source file
|
||||
/// and its corresponding backup file.
|
||||
///
|
||||
/// [sourcePath] is the path to the original source file.
|
||||
/// [backupPath] is the path where the backup of the source file will be stored.
|
||||
class Paths {
|
||||
Paths(this.sourcePath, this.backupPath);
|
||||
|
||||
String sourcePath;
|
||||
String backupPath;
|
||||
}
|
||||
|
||||
/// Removes the root prefix (/ or \) from an absolute path
|
||||
/// If there is no root prefix the original [absolutePath]
|
||||
/// is returned untouched.
|
||||
///
|
||||
/// If the [absolutePath] only contains the root prefix
|
||||
/// then a blank string is returned
|
||||
///
|
||||
/// /hellow -> hellow
|
||||
/// hellow -> hellow
|
||||
/// / ->
|
||||
///
|
||||
String? _stripRootPrefix(String absolutePath) {
|
||||
if (absolutePath.startsWith(r'\') || absolutePath.startsWith('/')) {
|
||||
if (absolutePath.length > 1) {
|
||||
return absolutePath.substring(1);
|
||||
} else {
|
||||
// the path only contained the root prefix and nothing else.
|
||||
return '';
|
||||
}
|
||||
}
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
/// Translates an absolute path to a standardized format, primarily for Windows systems.
|
||||
///
|
||||
/// C:/abc -> /CDrive/abc
|
||||
/// C:\abc -> /CDrive\abc
|
||||
/// \\\abc -> \abc
|
||||
/// \\abc -> abc
|
||||
///
|
||||
/// The [context] is only used for unit testing so
|
||||
/// we can fake the platform separator.
|
||||
String translateAbsolutePath(
|
||||
String absolutePath, {
|
||||
String? workingDirectory,
|
||||
p.Context? context,
|
||||
}) {
|
||||
final windowsStyle = context != null && context.style == Style.windows;
|
||||
if (!windowsStyle && !Platform.isWindows) {
|
||||
return absolutePath;
|
||||
}
|
||||
|
||||
context ??= p.context;
|
||||
|
||||
// ignore: parameter_assignments
|
||||
workingDirectory ??= Directory.current.path;
|
||||
|
||||
final parts = context.split(absolutePath);
|
||||
if (parts[0].contains(':')) {
|
||||
final index = parts[0].indexOf(':');
|
||||
|
||||
final drive = parts[0][index - 1].toUpperCase();
|
||||
return context.joinAll(['\\${drive}Drive', ...parts.sublist(1)]);
|
||||
}
|
||||
|
||||
if (parts[0].startsWith(r'\\')) {
|
||||
final uncparts = parts[0].split(r'\\');
|
||||
return context.joinAll([r'\UNC', ...uncparts.sublist(1)]);
|
||||
}
|
||||
|
||||
if (absolutePath.startsWith(r'\') || absolutePath.startsWith('/')) {
|
||||
String drive;
|
||||
if (workingDirectory.contains(':')) {
|
||||
drive = workingDirectory[0].toUpperCase();
|
||||
} else {
|
||||
drive = Directory.current.path[0].toUpperCase();
|
||||
}
|
||||
return context.joinAll(['\\${drive}Drive', ...parts.sublist(1)]);
|
||||
}
|
||||
|
||||
/// probably not an absolute path
|
||||
/// so just pass back what we were handed.
|
||||
return absolutePath;
|
||||
}
|
56
packages/console/lib/src/common/unit_test_controller.dart
Normal file
56
packages/console/lib/src/common/unit_test_controller.dart
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* This file is part of the Protevus Platform.
|
||||
*
|
||||
* (C) Protevus <developers@protevus.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import 'package:scope/scope.dart';
|
||||
|
||||
/// A utility class for managing unit test behavior in DCli.
|
||||
///
|
||||
/// This class provides static members to control and detect when code is running
|
||||
/// within a unit test environment. It uses the `scope` package to manage a boolean
|
||||
/// flag indicating whether the current execution context is a unit test.
|
||||
class UnitTestController {
|
||||
/// A ScopeKey used to indicate whether the current execution is within a unit test.
|
||||
///
|
||||
/// This key is injected when running a unit test, allowing DCli code to be
|
||||
/// 'unit test' aware and modify its behavior to be unit test friendly.
|
||||
/// The default value is false, indicating that by default, the code is not
|
||||
/// running in a unit test environment.
|
||||
///
|
||||
/// Usage:
|
||||
/// - When set to true, it signals that the code is running within a unit test.
|
||||
/// - DCli functions can check this key to adjust their behavior accordingly.
|
||||
static final unitTestingKey =
|
||||
ScopeKey<bool>.withDefault(false, 'Running in a unit test');
|
||||
|
||||
/// Executes the provided action within a unit test context.
|
||||
///
|
||||
/// This method creates a new [Scope] where the [unitTestingKey] is set to true,
|
||||
/// indicating that the code is running within a unit test environment. It then
|
||||
/// executes the provided [action] within this scope.
|
||||
///
|
||||
/// Certain DCli functions modify their behavior when run within a unit test.
|
||||
/// They rely on this scope to determine if they are in a unit test environment.
|
||||
///
|
||||
/// Usage:
|
||||
/// ```dart
|
||||
/// await UnitTestController.withUnitTest(() {
|
||||
/// // Your unit test code here
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// Parameters:
|
||||
/// - action: A void function that contains the code to be executed within the unit test context.
|
||||
///
|
||||
/// Returns:
|
||||
/// A [Future] that completes when the action has finished executing.
|
||||
static Future<void> withUnitTest(void Function() action) async {
|
||||
final scope = Scope()..value(unitTestingKey, true);
|
||||
await scope.run(() async => action());
|
||||
}
|
||||
}
|
|
@ -10,7 +10,8 @@ environment:
|
|||
|
||||
# Add regular dependencies here.
|
||||
dependencies:
|
||||
# path: ^1.8.0
|
||||
path: ^1.9.0
|
||||
scope: ^4.1.0
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^3.0.0
|
||||
|
|
Loading…
Reference in a new issue