2024-12-31 04:39:27 +00:00
# Dart Process Handler
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
A Laravel-inspired process handling library for Dart that provides an elegant and powerful API for executing shell commands and managing processes.
2024-12-30 13:35:33 +00:00
## Features
2024-12-31 04:39:27 +00:00
- Fluent API for process configuration
- Synchronous and asynchronous execution
- Process timeouts and idle timeouts
- Working directory and environment variables
- Input/output handling and streaming
- Shell command support with pipes and redirects
- TTY mode support
- Comprehensive error handling
- Real-time output callbacks
- Process status tracking and management
2024-12-30 13:35:33 +00:00
## Installation
2024-12-31 04:39:27 +00:00
Add this to your package's `pubspec.yaml` file:
2024-12-30 13:35:33 +00:00
```yaml
dependencies:
platform_process: ^1.0.0
```
2024-12-31 04:39:27 +00:00
## Basic Usage
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Simple Command Execution
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
import 'package:platform_process/platform_process.dart';
void main() async {
final factory = Factory();
// Basic command execution
final result = await factory.command(['echo', 'Hello World']).run();
print('Output: ${result.output()}'); // Output: Hello World
print('Success: ${result.successful()}'); // Success: true
// Using string command (executed through shell)
final result2 = await factory.command('echo "Hello World"').run();
print('Output: ${result2.output()}'); // Output: Hello World
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Working Directory
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
// Execute command in specific directory
final result = await factory
.command(['ls', '-l'])
.withWorkingDirectory('/tmp')
.run();
print('Files in /tmp:');
print(result.output());
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Environment Variables
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
final result = await factory
.command(['printenv', 'MY_VAR'])
.withEnvironment({'MY_VAR': 'Hello from env!'})
.run();
print('Environment Value: ${result.output()}');
}
2024-12-30 13:35:33 +00:00
```
2024-12-31 04:39:27 +00:00
### Process Timeouts
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
try {
// Process timeout
await factory
.command(['sleep', '10'])
.withTimeout(5) // 5 second timeout
.run();
} on ProcessTimedOutException catch (e) {
print('Process timed out: ${e.message}');
}
try {
// Idle timeout (no output for specified duration)
await factory
.command(['tail', '-f', '/dev/null'])
.withIdleTimeout(5) // 5 second idle timeout
.run();
} on ProcessTimedOutException catch (e) {
print('Process idle timeout: ${e.message}');
}
}
```
### Standard Input
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
void main() async {
final factory = Factory();
// String input
final result1 = await factory
.command(['cat'])
.withInput('Hello from stdin!')
.run();
print('Input Echo: ${result1.output()}');
// Byte input
final result2 = await factory
.command(['cat'])
.withInput([72, 101, 108, 108, 111]) // "Hello" in bytes
.run();
print('Byte Input Echo: ${result2.output()}');
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Error Handling
```dart
void main() async {
final factory = Factory();
try {
await factory.command(['ls', 'nonexistent-file']).run();
} on ProcessFailedException catch (e) {
print('Command failed:');
print(' Exit code: ${e.result.exitCode}');
print(' Error output: ${e.result.errorOutput()}');
}
2024-12-30 13:35:33 +00:00
}
```
2024-12-31 04:39:27 +00:00
### Shell Commands with Pipes
```dart
void main() async {
final factory = Factory();
// Using pipes in shell command
final result = await factory
.command('echo "line1\nline2\nline3" | grep "line2"')
.run();
print('Grep Result: ${result.output()}');
// Multiple commands
final result2 = await factory
.command('cd /tmp & & ls -l | grep "log"')
.run();
print('Log files: ${result2.output()}');
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Asynchronous Execution with Output Callback
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
void main() async {
final factory = Factory();
// Start process asynchronously
final process = await factory
.command(['sh', '-c', 'for i in 1 2 3; do echo $i; sleep 1; done'])
.start((output) {
print('Realtime Output: $output');
});
// Wait for completion
final result = await process.wait();
print('Final Exit Code: ${result.exitCode}');
}
```
### Process Management
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
// Start long-running process
final process = await factory
.command(['sleep', '10'])
.start();
print('Process started with PID: ${process.pid}');
print('Is running: ${process.running()}');
// Kill the process
final killed = process.kill(); // Sends SIGTERM
print('Kill signal sent: $killed');
// Or with specific signal
process.kill(ProcessSignal.sigint); // Sends SIGINT
final result = await process.wait();
print('Process completed with exit code: ${result.exitCode}');
}
2024-12-30 13:35:33 +00:00
```
2024-12-31 04:39:27 +00:00
### Output Control
```dart
void main() async {
final factory = Factory();
// Disable output
final result = await factory
.command(['echo', 'test'])
.withoutOutput()
.run();
print('Output length: ${result.output().length}'); // Output length: 0
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### TTY Mode
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
void main() async {
final factory = Factory();
// Enable TTY mode for commands that require it
final result = await factory
.command(['ls', '--color=auto'])
.withTty()
.run();
print('Color Output: ${result.output()}');
}
2024-12-30 13:35:33 +00:00
```
2024-12-31 04:39:27 +00:00
## Advanced Usage
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Custom Process Configuration
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
void main() async {
final factory = Factory();
2024-12-30 13:35:33 +00:00
final result = await factory
2024-12-31 04:39:27 +00:00
.command(['my-script'])
.withWorkingDirectory('/path/to/scripts')
.withEnvironment({
'NODE_ENV': 'production',
'DEBUG': 'true'
})
.withTimeout(30)
.withIdleTimeout(5)
.withTty()
2024-12-30 13:35:33 +00:00
.run();
2024-12-31 04:39:27 +00:00
if (result.successful()) {
print('Script completed successfully');
print(result.output());
}
2024-12-30 13:35:33 +00:00
}
```
2024-12-31 04:39:27 +00:00
### Process Pool Management
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
void main() async {
final factory = Factory();
final processes = < InvokedProcess > [];
// Start multiple processes
for (var i = 0; i < 3 ; i + + ) {
final process = await factory
.command(['worker.sh', i.toString()])
.start();
processes.add(process);
}
// Wait for all processes to complete
for (var process in processes) {
final result = await process.wait();
print('Worker completed with exit code: ${result.exitCode}');
}
}
```
### Error Output Handling
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
try {
final result = await factory
.command(['some-command'])
.run();
print('Standard output:');
print(result.output());
print('Error output:');
print(result.errorOutput());
} on ProcessFailedException catch (e) {
print('Command failed with exit code: ${e.result.exitCode}');
print('Error details:');
print(e.result.errorOutput());
}
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
### Infinite Process Execution
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
void main() async {
final factory = Factory();
// Disable timeout for long-running processes
final process = await factory
.command(['tail', '-f', 'logfile.log'])
.forever() // Disables timeout
.start((output) {
print('New log entry: $output');
});
// Process will run until explicitly killed
await Future.delayed(Duration(minutes: 1));
process.kill();
2024-12-30 13:35:33 +00:00
}
```
2024-12-31 04:39:27 +00:00
## Error Handling
The library provides several exception types for different error scenarios:
### ProcessFailedException
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
Thrown when a process exits with a non-zero exit code:
2024-12-30 13:35:33 +00:00
```dart
2024-12-31 04:39:27 +00:00
try {
await factory.command(['nonexistent-command']).run();
} on ProcessFailedException catch (e) {
print('Command failed:');
print('Exit code: ${e.result.exitCode}');
print('Error output: ${e.result.errorOutput()}');
print('Standard output: ${e.result.output()}');
}
2024-12-30 13:35:33 +00:00
```
2024-12-31 04:39:27 +00:00
### ProcessTimedOutException
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
Thrown when a process exceeds its timeout or idle timeout:
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
```dart
try {
await factory
.command(['sleep', '10'])
.withTimeout(5)
.run();
} on ProcessTimedOutException catch (e) {
print('Process timed out:');
print('Message: ${e.message}');
if (e.result != null) {
print('Partial output: ${e.result?.output()}');
}
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
## Best Practices
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
1. **Always handle process failures:**
```dart
try {
await factory.command(['risky-command']).run();
} on ProcessFailedException catch (e) {
// Handle failure
} on ProcessTimedOutException catch (e) {
// Handle timeout
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
2. **Set appropriate timeouts:**
```dart
factory
.command(['long-running-task'])
.withTimeout(300) // Overall timeout
.withIdleTimeout(60) // Idle timeout
.run();
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
3. **Use output callbacks for long-running processes:**
```dart
await factory
.command(['lengthy-task'])
.start((output) {
// Process output in real-time
print('Progress: $output');
});
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
4. **Clean up resources:**
```dart
final process = await factory.command(['server']).start();
try {
// Do work
} finally {
process.kill(); // Ensure process is terminated
}
```
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
5. **Use shell mode appropriately:**
```dart
// For simple commands, use array form:
factory.command(['echo', 'hello']);
2024-12-30 13:35:33 +00:00
2024-12-31 04:39:27 +00:00
// For shell features (pipes, redirects), use string form:
factory.command('echo hello | grep "o"');
```
2024-12-30 13:35:33 +00:00
## Contributing
2024-12-31 04:39:27 +00:00
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
2024-12-30 13:35:33 +00:00
## License
2024-12-31 04:39:27 +00:00
This project is licensed under the MIT License - see the LICENSE file for details.