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.
|
# Add regular dependencies here.
|
||||||
dependencies:
|
dependencies:
|
||||||
# path: ^1.8.0
|
path: ^1.9.0
|
||||||
|
scope: ^4.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
lints: ^3.0.0
|
lints: ^3.0.0
|
||||||
|
|
Loading…
Reference in a new issue