زیادہ تر ڈویلپر اپنے دن کا ایک اہم حصہ ٹرمینل میں گزارتے ہیں۔ وہ چلاتے ہیں flutter buildدھکا gitپیکیج مینجمنٹ dart pubکمانڈ لائن سے اپنی پائپ لائن کو ٹیون کریں۔ یہ تمام ٹولز CLI یا کمانڈ لائن انٹرفیس ہیں۔ یہ ایک ایسا پروگرام ہے جو ٹرمینل میں موجود ہے اور ٹیکسٹ کمانڈز کا جواب دیتا ہے۔
لیکن زیادہ تر ڈویلپرز نے کبھی نہیں بنایا۔
یہ ایک ضائع ہونے والا موقع ہے۔ CLI ٹولز سب سے زیادہ عملی ٹولز میں سے ایک ہیں جو ایک ڈویلپر پیش کر سکتا ہے۔ یہ دہرائے جانے والے ورک فلو کو خودکار بناتا ہے، ٹیموں میں عمل کو معیاری بناتا ہے، اور ایک بار شائع ہونے کے بعد، ایک ٹھوس نمونہ بن جاتا ہے جسے ڈویلپر کمیونٹی دریافت، انسٹال اور استعمال کر سکتی ہے۔
اس ہینڈ بک میں، ہم مکمل طور پر تقسیم شدہ ڈارٹ CLI ٹول بنانے کا عمل شروع کرتے ہیں۔ آئیے بنیادی باتوں کے ساتھ شروع کریں: CLI کیسے کام کرتا ہے، ڈارٹ ٹرمینل ان پٹ کو کیسے حاصل کرتا ہے اور اس پر کارروائی کرتا ہے، اور کلیدی نحو کے بارے میں جو آپ کو جاننے کی ضرورت ہے۔ اس کے بعد ہم تین بتدریج زیادہ پیچیدہ CLIs بناتے ہیں، جو بنیادی باتوں سے شروع ہوتے ہیں اور اصل API درخواست کے ایگزیکیوٹر کے ساتھ ختم ہوتے ہیں۔ آخر میں، ہم تقسیم کے تمام دستیاب راستوں کا احاطہ کریں گے۔ pub.dev مرتب شدہ بائنریز، ہومبریو ٹیبز، ڈوکر، اور مقامی ٹیم ایکٹیویشن کے لیے استعمال کیا جاتا ہے۔
گائیڈ کے اختتام تک، آپ دونوں کو سمجھ جائیں گے کہ ڈارٹ میں CLI ٹولز کیسے بنائے جائیں اور انہیں دوسرے ڈویلپرز کو عملی استعمال کے لیے کیسے دستیاب کیا جائے۔
انڈیکس
شرطیں
شروع کرنے سے پہلے، آپ کے پاس ہونا ضروری ہے:
-
ڈارٹ SDK انسٹال کریں (
dart --versionٹرمینل میں کام کرنا چاہئے) -
ڈارٹ نحو کا بنیادی علم
-
ٹرمینل اور چلانے کے احکامات کے ساتھ آرام
-
pub.dev اکاؤنٹ (پبلشنگ سیکشن کے لیے)
-
GitHub اکاؤنٹ (بائنری ڈسٹری بیوشن سیکشن کے لیے)
CLI کیا ہے اور میں اسے کیوں بناؤں؟
CLI (یا کمانڈ لائن انٹرفیس) ایک ایسا پروگرام ہے جو گرافیکل انٹرفیس میں بٹنوں اور اسکرینوں کے بجائے ٹرمینل میں ٹیکسٹ کمانڈز کے ذریعے مکمل طور پر انٹرایکٹو ہوتا ہے۔
ایک ڈویلپر کے طور پر، بہت سے ٹولز جو آپ پہلے ہی استعمال کرتے ہیں وہ CLI ٹولز ہیں۔
flutter build apk
git commit -m "fix: auth flow"
dart pub get
npm install
پھڑپھڑانا، گٹ، ڈارٹ، این پی ایم – تمام CLIs۔ آپ پہلے سے ہی روزانہ CLI صارف ہیں۔ یہ مضمون CLI بلڈر بننے کے طریقہ کے بارے میں ہے۔
ایک ڈویلپر کے طور پر، CLI ٹول بنانے کی تین زبردست وجوہات ہیں۔
-
دہرائے جانے والے کاموں کو خودکار بنائیں: جو بھی چیز آپ ہفتے میں دو بار سے زیادہ داخل کرتے ہیں وہ آٹومیشن کے لیے اہل ہے۔ سی ایل آئی سات قدمی دستی عمل کو ایک واحد کمانڈ میں بدل دیتا ہے: بوائلر پلیٹ فولڈر کا ڈھانچہ بنانا، حکموں کی ترتیب کو چلانا، فائلوں کو سہاروں میں ڈھالنا، اور پہلے سے تعمیر شدہ ماحول کی تصدیق کرنا۔
-
ٹیم ورک فلو کو معیاری بنائیں: README کے بجائے جو کہتا ہے کہ "ان کمانڈز کو اس ترتیب سے چلائیں”، ایک کمانڈ دیں جو ہر چیز کو مستقل طور پر، ہر بار، انسانی غلطی یا گمشدہ اقدامات کے بغیر کرے۔
-
ٹولز بنائیں اور شائع کریں۔ شائع شدہ ڈارٹ سی ایل آئی پیکجز ٹھوس نمونے ہیں۔ یہ pub.dev پر نظر آتا ہے، دوسرے ڈویلپرز کے ذریعہ انسٹال اور استعمال کیا جاتا ہے، اور انجینئرنگ کی حقیقی گہرائی کو اس طرح بتاتا ہے جس طرح پورٹ فولیو یا ریزیوم نہیں کر سکتا۔
CLI تجزیہ
کوڈ کی ایک لائن لکھنے سے پہلے CLI کمانڈز کی ساخت کو سمجھنا مفید ہے۔ تمام احکامات ایک مستقل پیٹرن کی پیروی کرتے ہیں۔
tool [subcommand] [arguments] [options/flags]
اگر ہم ایک حقیقی مثال کا تجزیہ کریں تو وہ اس طرح ہے:
flutter build apk --release --obfuscate
│ │ │ │
tool sub arg flags
-
سامان – پروگرام خود (
flutter،dart،git) -
ذیلی کمانڈ – تم کیا کر رہے ہو (
build،run،pub) -
عنصر – وہ اعتراض جس پر عمل کیا جاتا ہے (
apk،main.dartفائل کا نام) -
جھنڈے اور اختیارات – ترمیم کرنے والے جو رویے کو تبدیل کرتے ہیں۔
اختیارات کی دو قسمیں ہیں:
--release # Boolean flag — either present or absent
--output=build/app # Key-value option — name and a value
-v # Short flag — single hyphen, single character
یہ وہ ڈھانچہ ہے جس کی CLI کو پیروی کرنی چاہیے۔ کوڈ لکھنے سے پہلے اس کو سمجھنے کا مطلب یہ ہے کہ غلطی سے ساخت کو پیچیدہ کرنے کے بجائے جان بوجھ کر ہدایات تیار کریں۔
ڈارٹ کو ٹرمینل ان پٹ کیسے ملتا ہے۔
ڈارٹ میں، ٹول کے نام کے بعد صارف جو کچھ بھی ٹائپ کرتا ہے اس کے ذریعے پروگرام کو منتقل کیا جاتا ہے: main فنکشن:
void main(List args) {
print(args);
}
چلائیں:
dart run bin/mytool.dart hello world --name=Seyi
# [hello, world, --name=Seyi]
کہ List یہ صرف تاروں کی فہرست ہے۔ صارف کی طرف سے درج کردہ ہر لفظ یا جھنڈا اس فہرست کا ایک عنصر بن جاتا ہے۔ باقی سب کچھ جو آپ CLI ذیلی کمانڈز، جھنڈوں اور توثیق کے اوپر بناتے ہیں بالآخر اس فہرست پر کارروائی کرے گی۔
ڈارٹ کے بنیادی CLI تصورات
تصورات کا ایک بنیادی مجموعہ ہے جسے ہر CLI ڈویلپر کو کچھ بھی بنانے سے پہلے سمجھنا چاہیے۔ یہ عمارت کے بلاکس ہیں جن پر باقی سب کچھ ٹکی ہوئی ہے۔
stdout، stderr، اور stdin
زیادہ تر ڈویلپر استعمال کرتے ہیں۔ print() CLI کی تعمیر شروع کرتے وقت تمام آؤٹ پٹ کے لیے۔ یہ تربیت کے لیے کام کرتا ہے، لیکن پیداوار میں غلط ہے۔
ٹرمینل پروگرام میں دو الگ آؤٹ پٹ اسٹریمز ہیں:
-
stdout– صارفین کے لیے عمومی پیداوار -
stderr– تشخیصی پیغامات اور خرابی کی پیداوار ناکامی کی نشاندہی کرتی ہے۔
import 'dart:io';
void main(List args) {
if (args.isEmpty) {
stderr.writeln('Error: no arguments provided');
exit(1);
}
stdout.writeln('Processing: ${args[0]}');
}
ان کو الگ رکھیں کیونکہ صارف فائل کو آلودہ کرنے والی غلطیوں کے بغیر stdout کو فائل میں بھیج سکتے ہیں۔
dart run bin/tool.dart > output.txt
# Errors still appear in the terminal
# Normal output goes cleanly to the file
اوزار جیسے git، flutterاور curl سب کچھ ٹھیک کرو۔ آپ کے CLI کے لیے بھی یہی ہے۔
stdin یہ تیسرا سلسلہ ہے۔ رن ٹائم پر انٹرایکٹو طور پر صارف کے ان پٹ کو پڑھتا ہے۔
import 'dart:io';
void main() {
stdout.write('Enter your name: ');
final name = stdin.readLineSync();
if (name == null || name.trim().isEmpty) {
stderr.writeln('Error: no name provided');
exit(1);
}
stdout.writeln('Hello, $name!');
}
stdout.write (بغیر ln) کرسر کو ایک ہی لائن پر رکھتا ہے، صارف کو فوری طور پر پرامپٹ کے بعد ٹائپ کرنے کی اجازت دیتا ہے۔ stdin.readLineSync() یہ اس وقت تک بلاک ہوجاتا ہے جب تک کہ صارف Enter کو دباتا ہے اور داخل کردہ اسٹرنگ کو واپس نہیں کرتا ہے۔ null جب کوئی سلسلہ غیر متوقع طور پر بند ہو جاتا ہے۔ ہمیشہ کالعدم کیسز کو ہینڈل کریں۔
باہر نکلنے کا کوڈ
تمام پروگرام مکمل ہونے پر ایگزٹ کوڈ واپس کرتے ہیں۔ اس طرح کوئی بھی اسکرپٹ یا سی آئی سسٹم جو شیلز اور ٹولز کو کال کرتا ہے جانتا ہے کہ آیا یہ کامیاب ہوا یا ناکام۔
import 'dart:io';
void main(List args) {
if (args.isEmpty) {
stderr.writeln('Error: please provide an argument');
exit(1); // failure
}
stdout.writeln('Done');
exit(0); // success — also the default if you don't call exit()
}
قواعد درج ذیل ہیں:
ایگزٹ کوڈ اہم ہوتا ہے جب CLI کو شیل اسکرپٹ یا GitHub ایکشن ورک فلو کے اندر سے بلایا جاتا ہے۔ ایک غیر صفر ایگزٹ کوڈ پائپ لائن کو فوری طور پر روک دیتا ہے۔ یہ بالکل وہی طرز عمل ہے جو آپ اپنے کوالٹی گیٹ یا تصدیقی مرحلے میں چاہتے ہیں۔
ماحولیاتی متغیرات
CLI صارف کے شیل میں سیٹ کردہ ماحولیاتی متغیرات کو پڑھ سکتا ہے۔
import 'dart:io';
void main() {
final token = Platform.environment['API_TOKEN'];
if (token == null) {
stderr.writeln('Error: API_TOKEN environment variable is not set');
exit(1);
}
stdout.writeln('Token found — proceeding...');
}
اسے اپنے ٹرمینل میں سیٹ کریں اور چلائیں:
export API_TOKEN=mytoken123
dart run bin/tool.dart
# Token found — proceeding...
یہ پیٹرن CLI ٹولز کے لیے ضروری ہے جو APIs، کلاؤڈ سروسز، یا CI ماحولیات کے ساتھ تعامل کرتے ہیں جہاں اسناد کو ہارڈ کوڈ نہیں کیا جانا چاہیے۔
فائل اور ڈائریکٹری آپریشنز
بہت سے CLI ٹولز فائل سسٹم سے پڑھتے یا لکھتے ہیں۔ ڈارٹ dart:io لائبریری آپ کو درکار ہر چیز کا احاطہ کرتی ہے۔
import 'dart:io';
void main(List args) {
if (args.isEmpty) {
stderr.writeln('Usage: tool ');
exit(2);
}
final file = File(args[0]);
if (!file.existsSync()) {
stderr.writeln('Error: "${args[0]}" not found');
exit(1);
}
final contents = file.readAsStringSync();
stdout.writeln(contents);
final output = File('output.txt');
output.writeAsStringSync('Processed:\n$contents');
stdout.writeln('Written to output.txt');
}
ڈائریکٹری آپریشنز:
import 'dart:io';
void main() {
// Where the command was run from
final cwd = Directory.current.path;
stdout.writeln('Working directory: $cwd');
// Create a directory relative to current location
final dir = Directory('$cwd/generated');
if (!dir.existsSync()) {
dir.createSync(recursive: true);
stdout.writeln('Created: ${dir.path}');
} else {
stdout.writeln('Already exists: ${dir.path}');
}
}
کہ recursive: true ایک جھنڈا لگائیں createSync اس کا مطلب ہے تمام انٹرمیڈیٹ ڈائریکٹریز بنانا۔ mkdir -p باش میں۔
بیرونی عمل کو انجام دیں۔
سب سے طاقتور چیزوں میں سے ایک جو CLI کر سکتا ہے دوسرے پروگراموں کو کال کرنا ہے۔ آپ ڈارٹ سی ایل آئی چلا سکتے ہیں۔ git، flutter، dartیا پروگرامی طور پر کوئی شیل کمانڈ:
import 'dart:io';
void main() async {
// Run a command and wait for it to finish
final result = await Process.run('dart', ['pub', 'get']);
stdout.write(result.stdout);
if (result.exitCode != 0) {
stderr.write(result.stderr);
exit(result.exitCode);
}
stdout.writeln('Dependencies installed successfully');
}
طویل عرصے سے چلنے والی کمانڈز کے لیے جہاں آپ حقیقی وقت میں آؤٹ پٹ کو اسٹریم کرنا چاہتے ہیں:
import 'dart:io';
void main() async {
final process = await Process.start('flutter', ['build', 'apk']);
// Pipe output directly to the terminal in real time
process.stdout.pipe(stdout);
process.stderr.pipe(stderr);
final exitCode = await process.exitCode;
exit(exitCode);
}
Process.run – تکمیل کا انتظار کریں اور ایک ساتھ تمام آؤٹ پٹ واپس کریں۔ مختصر احکامات کے لیے استعمال کریں۔
Process.start – آپ کے آؤٹ پٹ کو آتے ہی لائیو نشر کیا جائے گا۔ طویل عرصے سے چلنے والی کمانڈز کے لیے استعمال کریں جہاں صارف کو پیش رفت کی جانچ کرنے کی ضرورت ہے۔
پلیٹ فارم کا پتہ لگانا
CLI کو مختلف طریقے سے برتاؤ کرنے کی ضرورت ہو سکتی ہے اس پر منحصر ہے کہ وہ جس آپریٹنگ سسٹم پر چل رہا ہے۔
import 'dart:io';
void main() {
if (Platform.isWindows) {
stdout.writeln('Running on Windows');
} else if (Platform.isMacOS) {
stdout.writeln('Running on macOS');
} else if (Platform.isLinux) {
stdout.writeln('Running on Linux');
}
// Useful for path handling across operating systems
stdout.writeln(Platform.pathSeparator); // \ on Windows, / elsewhere
stdout.writeln(Platform.operatingSystem); // 'macos', 'linux', 'windows'
}
یہ اہم ہے جب CLI فائلیں بناتا ہے، راستے حل کرتا ہے، یا شیل کمانڈز کو کال کرتا ہے جو آپریٹنگ سسٹم سے آپریٹنگ سسٹم تک مختلف ہوتی ہیں۔
CLI میں غیر مطابقت پذیر
ڈارٹ سی ایل آئی سپورٹ async/await بنیادی طور پر۔ کوئی بھی main آپ فنکشنز کو غیر مطابقت پذیر بنا سکتے ہیں۔
import 'dart:io';
void main() async {
stdout.writeln('Starting...');
await Future.delayed(const Duration(seconds: 1)); // simulating async work
stdout.writeln('Done');
}
فائل I/O، HTTP درخواستیں، یا تخلیق کے عمل پر مشتمل تمام آپریشنز غیر مطابقت پذیر ہیں۔ غیر مطابقت پذیر سے واقف ہونا main ابتدائی خصوصیات—آپ ان کا استعمال جاری رکھیں گے۔
ڈارٹ سی ایل آئی پروجیکٹ سیٹ اپ
ایک نیا ڈارٹ کنسول پروجیکٹ بنائیں۔
dart create -t console my_cli_tool
cd my_cli_tool
یہ ایک صاف ڈھانچہ بناتا ہے۔
my_cli_tool/
bin/
my_cli_tool.dart ← entry point
lib/ ← shared library code
test/ ← tests
pubspec.yaml
README.md
کہ bin/ ایک ڈائرکٹری وہ ہے جہاں قابل عمل انٹری پوائنٹ واقع ہے۔ کہ lib/ ڈائریکٹری وہ جگہ ہے جہاں آپ سب کچھ ذخیرہ کرتے ہیں: کمانڈز، یوٹیلیٹیز، ماڈلز وغیرہ۔ bin/ ہم اسے درآمد کرتے ہیں اور استعمال کرتے ہیں۔
کھلا pubspec.yaml. آپ کو شامل کرنے کی ضرورت ہے: executables پوسٹ کرنے سے پہلے بلاک کریں۔
name: my_cli_tool
description: A sample CLI tool built with Dart
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
executables:
my_cli_tool: my_cli_tool # executable name: bin file name
dependencies:
args: ^2.4.2
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
کہ executables بلاکس بنائے جاتے ہیں dart pub global activate my_cli_tool کام یہ ڈارٹ کو بتاتا ہے کہ کون سی اسکرپٹ شامل ہیں۔ bin/ تنصیب کے بعد، یہ ایک قابل عمل کمانڈ کے طور پر سامنے آتا ہے۔
CLI 1 - ہیلو CLI: بنیادی باتیں
یہ پہلا CLI بغیر کسی پیکج کے خالص ڈارٹ استعمال کرتا ہے۔ مقصد یہ ہے کہ بیرونی انحصار کو متعارف کرانے سے پہلے دلائل، ذیلی کمانڈ، ان پٹ کی توثیق، اور ایگزٹ کوڈز سے واقف ہو جائیں۔
درج ذیل کو تبدیل کریں: bin/my_cli_tool.dart:
import 'dart:io';
void main(List args) {
if (args.isEmpty) {
printHelp();
exit(0);
}
final command = args[0];
switch (command) {
case 'greet':
handleGreet(args.sublist(1));
case 'time':
handleTime();
case 'echo':
handleEcho(args.sublist(1));
case 'help':
printHelp();
default:
stderr.writeln('Unknown command: "$command"');
stderr.writeln('Run "mytool help" to see available commands.');
exit(1);
}
}
void handleGreet(List args) {
if (args.isEmpty) {
stderr.writeln('Usage: mytool greet ');
exit(2);
}
final name = args[0];
stdout.writeln('Hello, $name! Welcome to your first Dart CLI.');
}
void handleTime() {
final now = DateTime.now();
stdout.writeln(
'Current time: ${now.hour.toString().padLeft(2, '0')}:'
'${now.minute.toString().padLeft(2, '0')}:'
'${now.second.toString().padLeft(2, '0')}',
);
}
void handleEcho(List args) {
if (args.isEmpty) {
stderr.writeln('Usage: mytool echo ');
exit(2);
}
stdout.writeln(args.join(' '));
}
void printHelp() {
stdout.writeln('''
mytool — a simple Dart CLI
Usage:
mytool [arguments]
Commands:
greet Greet someone by name
time Show the current time
echo Echo a message back to the terminal
help Show this help message
Examples:
mytool greet Seyi
mytool echo "Hello from the terminal"
mytool time
''');
}
چلائیں:
dart run bin/my_cli_tool.dart help
dart run bin/my_cli_tool.dart greet Seyi
# Hello, Seyi! Welcome to your first Dart CLI.
dart run bin/my_cli_tool.dart time
# Current time: 14:32:10
dart run bin/my_cli_tool.dart echo "Dart CLIs are powerful"
# Dart CLIs are powerful
dart run bin/my_cli_tool.dart unknown
# Unknown command: "unknown"
# Run "mytool help" to see available commands.
یہ CLI ظاہر کرتا ہے کہ تین چیزیں ہیں جو اندرونی بنانے کے قابل ہیں۔
-
ایک ذیلی کمانڈ آسانی سے ایک سوئچ آن کر دیتی ہے۔
args[0]. پیٹرن سادہ اور قابل توسیع ہے۔ ایک نیا پیٹرن شامل کریں۔caseایک نیا کمانڈ شامل کرنے کے لیے -
args.sublist(1)بقیہ دلائل ہینڈلر کو دیں۔ جبgreetاستقبالیہ['greet', 'Seyi']یہ کال کرتا ہےhandleGreet(['Seyi'])- صاف اور الگ تھلگ۔ -
ہر ایرر پاتھ میں ایک پیغام اور غیر صفر ایگزٹ کوڈ ہوتا ہے۔ صارفین ہمیشہ جانتے ہیں کہ کیا غلط ہوا اور آگے کیا کرنا ہے۔
CLI 2 — ڈارٹ_ٹوڈو: ٹرمینل ٹاسک مینیجر
یہ CLI ہے۔ args پیکیجز، JSON فائل استقامت، اور ساختی ٹرمینل آؤٹ پٹ۔ یہ CLI 1 سے کہیں زیادہ پیچیدہ ہے اور حقیقی دنیا کے نمونوں کی عکاسی کرتا ہے جسے آپ پروڈکشن ٹولز میں استعمال کریں گے۔
آرگس پیکج کا تعارف
دستی طور پر تجزیہ کریں۔ List یہ سادہ معاملات میں کام کرتا ہے، لیکن جب آپ اس طرح کے جھنڈے شامل کرتے ہیں تو تیزی سے ٹوٹ جاتا ہے۔ --priority=highبولین اختیارات جیسے --doneیا ایک سے زیادہ اختیاری دلائل کے ساتھ ایک کمانڈ۔
کہ args پیکیج ان سب کو صاف ستھرا ہینڈل کرتا ہے۔
آپ کا pubspec.yaml:
dependencies:
args: ^2.4.2
چلائیں:
dart pub get
کا بنیادی تصور args چاندی ArgParser. وضاحت کریں کہ CLI کیا اجازت دیتا ہے اور args خودکار طور پر تجزیہ، توثیق، اور ٹیکسٹ جنریشن میں مدد کرتا ہے۔
import 'package:args/args.dart';
void main(List arguments) {
final parser = ArgParser()
..addCommand('add')
..addCommand('list')
..addFlag('help', abbr: 'h', negatable: false);
final results = parser.parse(arguments);
if (results['help'] as bool) {
print(parser.usage);
return;
}
}
ذیلی کمانڈ کے ساتھ زیادہ پیچیدہ CLI کے لیے ہر ایک اپنے اپنے جھنڈوں کے ساتھ، استعمال کریں: ArgParser فی حکم:
final parser = ArgParser();
final addCommand = ArgParser()
..addOption('priority', abbr: 'p', defaultsTo: 'normal');
parser.addCommand('add', addCommand);
ڈارٹ_ٹوڈو بلڈ
ایک نیا پروجیکٹ بنائیں:
dart create -t console dart_todo
cd dart_todo
اپ ڈیٹ pubspec.yaml:
name: dart_todo
description: A terminal task manager built with Dart
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
executables:
dart_todo: dart_todo
dependencies:
args: ^2.4.2
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
چلائیں dart pub get.
فولڈر کا ڈھانچہ بنائیں۔
dart_todo/
bin/
dart_todo.dart
lib/
models/
task.dart
storage/
task_storage.dart
commands/
add_command.dart
list_command.dart
complete_command.dart
delete_command.dart
clear_command.dart
pubspec.yaml
مرحلہ 1 - ورکنگ ماڈل (lib/models/task.dart)
class Task {
final int id;
final String title;
final String priority;
final bool isComplete;
final DateTime createdAt;
Task({
required this.id,
required this.title,
required this.priority,
this.isComplete = false,
required this.createdAt,
});
Task copyWith({bool? isComplete}) {
return Task(
id: id,
title: title,
priority: priority,
isComplete: isComplete ?? this.isComplete,
createdAt: createdAt,
);
}
Map toJson() => {
'id': id,
'title': title,
'priority': priority,
'isComplete': isComplete,
'createdAt': createdAt.toIso8601String(),
};
factory Task.fromJson(Map json) => Task(
id: json['id'] as int,
title: json['title'] as String,
priority: json['priority'] as String,
isComplete: json['isComplete'] as bool,
createdAt: DateTime.parse(json['createdAt'] as String),
);
}
مرحلہ 2 - محفوظ کریں (lib/storage/task_storage.dart)
یہ کلاس مقامی JSON فائلوں کو پڑھنے اور لکھنے کی کارروائیوں کو ہینڈل کرتی ہے، لہذا یہ CLI عملدرآمد کے درمیان برقرار رہتی ہے۔
import 'dart:convert';
import 'dart:io';
import '../models/task.dart';
class TaskStorage {
static final _file = File(
'${Platform.environment['HOME'] ?? Directory.current.path}/.dart_todo.json',
);
static List loadAll() {
if (!_file.existsSync()) return [];
try {
final content = _file.readAsStringSync();
final List json = jsonDecode(content) as List;
return json
.map((e) => Task.fromJson(e as Map))
.toList();
} catch (_) {
return [];
}
}
static void saveAll(List tasks) {
final json = jsonEncode(tasks.map(
_file.writeAsStringSync(json);
}
}
کاموں کو صارف کی ہوم ڈائرکٹری میں چھپی ہوئی JSON فائل میں محفوظ کیا جاتا ہے۔ یہ CLI ٹولز کے لیے ایک عام نمونہ ہے جس کے لیے ہلکے وزن کی مقامی استقامت کی ضرورت ہوتی ہے۔
مرحلہ 3 - کمانڈز
lib/commands/add_command.dart:
import 'dart:io';
import '../models/task.dart';
import '../storage/task_storage.dart';
void runAdd(List args, String priority) {
if (args.isEmpty) {
stderr.writeln('Usage: dart_todo add [--priority=high|normal|low]');
exit(2);
}
final title = args.join(' ');
final tasks = TaskStorage.loadAll();
final newTask = Task(
id: tasks.isEmpty ? 1 : tasks.last.id + 1,
title: title,
priority: priority,
createdAt: DateTime.now(),
);
tasks.add(newTask);
TaskStorage.saveAll(tasks);
stdout.writeln('Added task #\({newTask.id}: "\)title" [$priority]');
}
lib/commands/list_command.dart:
import 'dart:io';
import '../storage/task_storage.dart';
void runList() {
final tasks = TaskStorage.loadAll();
if (tasks.isEmpty) {
stdout.writeln('No tasks yet. Add one with: dart_todo add ');
return;
}
stdout.writeln('');
stdout.writeln(' ID Status Priority Title');
stdout.writeln(' ─── ────────── ───────── ────────────────────────');
for (final task in tasks) {
final status = task.isComplete ? 'done ' : 'pending';
final id = task.id.toString().padRight(4);
final priority = task.priority.padRight(9);
stdout.writeln(' \(id \)status \(priority \){task.title}');
}
stdout.writeln('');
}
lib/commands/complete_command.dart:
import 'dart:io';
import '../storage/task_storage.dart';
void runComplete(List args) {
if (args.isEmpty) {
stderr.writeln('Usage: dart_todo complete ');
exit(2);
}
final id = int.tryParse(args[0]);
if (id == null) {
stderr.writeln('Error: "${args[0]}" is not a valid task ID');
exit(1);
}
final tasks = TaskStorage.loadAll();
final index = tasks.indexWhere(
if (index == -1) {
stderr.writeln('Error: No task found with ID $id');
exit(1);
}
if (tasks[index].isComplete) {
stdout.writeln('Task #$id is already complete.');
return;
}
tasks[index] = tasks[index].copyWith(isComplete: true);
TaskStorage.saveAll(tasks);
stdout.writeln('Task #\(id marked as complete: "\){tasks[index].title}"');
}
lib/commands/delete_command.dart:
import 'dart:io';
import '../storage/task_storage.dart';
void runDelete(List args) {
if (args.isEmpty) {
stderr.writeln('Usage: dart_todo delete ');
exit(2);
}
final id = int.tryParse(args[0]);
if (id == null) {
stderr.writeln('Error: "${args[0]}" is not a valid task ID');
exit(1);
}
final tasks = TaskStorage.loadAll();
final index = tasks.indexWhere(
if (index == -1) {
stderr.writeln('Error: No task found with ID $id');
exit(1);
}
final title = tasks[index].title;
tasks.removeAt(index);
TaskStorage.saveAll(tasks);
stdout.writeln('Deleted task #\(id: "\)title"');
}
lib/commands/clear_command.dart:
import 'dart:io';
import '../storage/task_storage.dart';
void runClear() {
stdout.write('Are you sure you want to delete all tasks? (y/N): ');
final input = stdin.readLineSync()?.trim().toLowerCase();
if (input != 'y') {
stdout.writeln('Cancelled.');
return;
}
TaskStorage.saveAll([]);
stdout.writeln('All tasks cleared.');
}
مرحلہ 4 - انٹری پوائنٹ (bin/dart_todo.dart)
import 'dart:io';
import 'package:args/args.dart';
import '../lib/commands/add_command.dart';
import '../lib/commands/clear_command.dart';
import '../lib/commands/complete_command.dart';
import '../lib/commands/delete_command.dart';
import '../lib/commands/list_command.dart';
void main(List arguments) {
final parser = ArgParser();
// Add subcommand parsers
final addParser = ArgParser()
..addOption(
'priority',
abbr: 'p',
defaultsTo: 'normal',
allowed: ['high', 'normal', 'low'],
help: 'Task priority level',
);
parser
..addCommand('add', addParser)
..addCommand('list')
..addCommand('complete')
..addCommand('delete')
..addCommand('clear')
..addFlag('help', abbr: 'h', negatable: false, help: 'Show help');
ArgResults results;
try {
results = parser.parse(arguments);
} catch (e) {
stderr.writeln('Error: $e');
stderr.writeln(parser.usage);
exit(2);
}
if (results['help'] as bool || results.command == null) {
printHelp(parser);
exit(0);
}
final command = results.command!;
switch (command.name) {
case 'add':
runAdd(command.rest, command['priority'] as String);
case 'list':
runList();
case 'complete':
runComplete(command.rest);
case 'delete':
runDelete(command.rest);
case 'clear':
runClear();
default:
stderr.writeln('Unknown command: "${command.name}"');
exit(1);
}
}
void printHelp(ArgParser parser) {
stdout.writeln('''
dart_todo — a terminal task manager
Usage:
dart_todo [arguments]
Commands:
add Add a new task
-p, --priority Priority: high, normal, low (default: normal)
list List all tasks
complete Mark a task as complete
delete Delete a task
clear Delete all tasks
Examples:
dart_todo add "Write the CLI article" --priority=high
dart_todo list
dart_todo complete 1
dart_todo delete 2
dart_todo clear
''');
}
چلائیں:
dart run bin/dart_todo.dart add "Write the CLI article" --priority=high
# Added task #1: "Write the CLI article" [high]
dart run bin/dart_todo.dart add "Review PR comments"
# Added task #2: "Review PR comments" [normal]
dart run bin/dart_todo.dart list
# ID Status Priority Title
# ─── ────────── ───────── ────────────────────────
# 1 ⬜ pending high Write the CLI article
# 2 ⬜ pending normal Review PR comments
dart run bin/dart_todo.dart complete 1
# Task #1 marked as complete: "Write the CLI article"
dart run bin/dart_todo.dart delete 2
# Deleted task #2: "Review PR comments"
dart_todo یہ ان نمونوں کو ظاہر کرتا ہے جو تقریباً تمام عملی CLI ٹولز کی ریڑھ کی ہڈی کی تشکیل کرتے ہیں۔ argsJSON استقامت، انٹرایکٹو پرامپٹس، سٹرکچرڈ آؤٹ پٹ، اور تمام کمانڈز کے لیے واضح ایرر ہینڈلنگ۔
CLI 3 - ڈارٹ_http: ہلکا پھلکا API درخواست ایگزیکیوٹر
یہ اس مضمون میں سب سے پیچیدہ CLI ہے اور فوری طور پر مفید ہے۔ dart_http ڈیولپرز خوبصورت پرنٹ شدہ JSON جوابات، رسپانس میٹا ڈیٹا، ہیڈر سپورٹ، اور فائلوں کے جوابات کو محفوظ کرنے کی صلاحیت کے ساتھ براہ راست ٹرمینل سے HTTP درخواستیں کر سکتے ہیں۔
dart_http get https://jsonplaceholder.typicode.com/users/1
dart_http post https://jsonplaceholder.typicode.com/posts --body='{"title":"Hello"}'
dart_http get https://jsonplaceholder.typicode.com/users --save=users.json
dart_http get https://api.example.com/me --header="Authorization: Bearer mytoken"
ڈارٹس بنانا_http
ایک پروجیکٹ بنائیں:
dart create -t console dart_http
cd dart_http
اپ ڈیٹ pubspec.yaml:
name: dart_http
description: A lightweight API request runner for the terminal
version: 1.0.0
environment:
sdk: '>=3.0.0 <4.0.0'
executables:
dart_http: dart_http
dependencies:
args: ^2.4.2
http: ^1.2.1
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
چلائیں dart pub get.
پروجیکٹ کی ساخت:
dart_http/
bin/
dart_http.dart
lib/
runner/
request_runner.dart
printer/
response_printer.dart
utils/
headers_parser.dart
pubspec.yaml
Map parseHeaders(List rawHeaders) {
final headers = {};
for (final header in rawHeaders) {
final index = header.indexOf(':');
if (index == -1) continue;
final key = header.substring(0, index).trim();
final value = header.substring(index + 1).trim();
headers[key] = value;
}
return headers;
}
مرحلہ 2 - رسپانس پرنٹر (lib/printer/response_printer.dart)
import 'dart:convert';
import 'dart:io';
void printResponse({
required int statusCode,
required String body,
required int durationMs,
required int bodyBytes,
}) {
final statusLabel = _statusLabel(statusCode);
final size = _formatSize(bodyBytes);
stdout.writeln('');
stdout.writeln('\(statusLabel | \){durationMs}ms | $size');
stdout.writeln('─' * 50);
try {
final decoded = jsonDecode(body);
const encoder = JsonEncoder.withIndent(' ');
stdout.writeln(encoder.convert(decoded));
} catch (_) {
// Not JSON — print as plain text
stdout.writeln(body);
}
stdout.writeln('');
}
String _statusLabel(int code) {
if (code >= 200 && code < 300) return '✅ $code';
if (code >= 300 && code < 400) return '↪ $code';
if (code >= 400 && code < 500) return '❌ $code';
return '$code';
}
String _formatSize(int bytes) {
if (bytes < 1024) return '${bytes}b';
if (bytes < 1024 * 1024) return '${(bytes / 1024).toStringAsFixed(1)}kb';
return '${(bytes / (1024 * 1024)).toStringAsFixed(1)}mb';
}
مرحلہ 3 - درخواست کرنے والےlib/runner/request_runner.dart)
import 'dart:io';
import 'package:http/http.dart' as http;
import '../printer/response_printer.dart';
Future runRequest({
required String method,
required String url,
required Map headers,
String? body,
String? saveToFile,
}) async {
final uri = Uri.tryParse(url);
if (uri == null) {
stderr.writeln('Error: "$url" is not a valid URL');
exit(1);
}
stdout.writeln('→ \({method.toUpperCase()} \)url');
http.Response response;
final stopwatch = Stopwatch()..start();
try {
switch (method.toLowerCase()) {
case 'get':
response = await http.get(uri, headers: headers);
case 'post':
response = await http.post(uri, headers: headers, body: body);
case 'put':
response = await http.put(uri, headers: headers, body: body);
case 'patch':
response = await http.patch(uri, headers: headers, body: body);
case 'delete':
response = await http.delete(uri, headers: headers);
default:
stderr.writeln('Error: unsupported method "$method"');
exit(2);
}
} catch (e) {
stderr.writeln('Error: request failed — $e');
exit(1);
}
stopwatch.stop();
printResponse(
statusCode: response.statusCode,
body: response.body,
durationMs: stopwatch.elapsedMilliseconds,
bodyBytes: response.bodyBytes.length,
);
if (saveToFile != null) {
final file = File(saveToFile);
file.writeAsStringSync(response.body);
stdout.writeln('Response saved to $saveToFile');
}
}
مرحلہ 4 - انٹری پوائنٹ (bin/dart_http.dart)
import 'dart:io';
import 'package:args/args.dart';
import '../lib/runner/request_runner.dart';
import '../lib/utils/headers_parser.dart';
void main(List arguments) async {
final parser = ArgParser();
for (final method in ['get', 'post', 'put', 'patch', 'delete']) {
final commandParser = ArgParser()
..addMultiOption('header', abbr: 'H', help: 'Request header (repeatable)')
..addOption('body', abbr: 'b', help: 'Request body (for POST/PUT/PATCH)')
..addOption('save', abbr: 's', help: 'Save response body to a file');
parser.addCommand(method, commandParser);
}
parser.addFlag('help', abbr: 'h', negatable: false, help: 'Show help');
ArgResults results;
try {
results = parser.parse(arguments);
} catch (e) {
stderr.writeln('Error: $e');
printHelp();
exit(2);
}
if (results['help'] as bool || results.command == null) {
printHelp();
exit(0);
}
final command = results.command!;
final method = command.name!;
final rest = command.rest;
if (rest.isEmpty) {
stderr.writeln('Error: please provide a URL');
stderr.writeln('Usage: dart_http $method ');
exit(2);
}
final url = rest[0];
final rawHeaders = command['header'] as List;
final body = command['body'] as String?;
final saveToFile = command['save'] as String?;
final headers = parseHeaders(rawHeaders);
// Default Content-Type for requests with a body
if (body != null && !headers.containsKey('Content-Type')) {
headers['Content-Type'] = 'application/json';
}
await runRequest(
method: method,
url: url,
headers: headers,
body: body,
saveToFile: saveToFile,
);
}
void printHelp() {
stdout.writeln('''
dart_http — a lightweight API request runner
Usage:
dart_http [options]
Methods:
get Send a GET request
post Send a POST request
put Send a PUT request
patch Send a PATCH request
delete Send a DELETE request
Options:
-H, --header Add a request header (repeatable)
-b, --body Request body (JSON string)
-s, --save Save response body to a file
-h, --help Show this help message
Examples:
dart_http get https://jsonplaceholder.typicode.com/users
dart_http get https://api.example.com/me --header="Authorization: Bearer token"
dart_http post https://api.example.com/posts --body=\'{"title":"Hello"}\'
dart_http get https://api.example.com/users --save=users.json
''');
}
چلائیں:
dart run bin/dart_http.dart get https://jsonplaceholder.typicode.com/users/1
# → GET https://jsonplaceholder.typicode.com/users/1
# 200 | 87ms | 510b
# ──────────────────────────────────────────────────
# {
# "id": 1,
# "name": "Leanne Graham",
# "username": "Bret",
# "email": "Sincere@april.biz"
# }
dart run bin/dart_http.dart get https://jsonplaceholder.typicode.com/users --save=users.json
# → GET https://jsonplaceholder.typicode.com/users
# 200 | 143ms | 5.3kb
# ──────────────────────────────────────────────────
# [ ... ]
# Response saved to users.json
dart run bin/dart_http.dart post https://jsonplaceholder.typicode.com/posts \
--body='{"title":"Hello from dart_http","userId":1}'
# → POST https://jsonplaceholder.typicode.com/posts
# 201 | 312ms | 72b
CLI میں رنگ اور چمک شامل کریں۔
مندرجہ بالا CLI فعال ہے، لیکن رنگوں کا استعمال ٹرمینل آؤٹ پٹ کو زیادہ پڑھنے کے قابل بنا سکتا ہے۔ کہ ansi_styles پیکیج ٹرمینلز میں متن کو رنگنے کے لیے ANSI فرار کوڈ سپورٹ فراہم کرتا ہے۔
اسے اگلی بار شامل کریں۔ pubspec.yaml:
dependencies:
ansi_styles: ^0.3.0
اس کا استعمال:
import 'package:ansi_styles/ansi_styles.dart';
stdout.writeln(AnsiStyles.green('✅ Success'));
stdout.writeln(AnsiStyles.red('❌ Error: something went wrong'));
stdout.writeln(AnsiStyles.yellow('⚠ Warning: check your config'));
stdout.writeln(AnsiStyles.bold('dart_http — API request runner'));
stdout.writeln(AnsiStyles.cyan('→ GET https://api.example.com/users'));
جان بوجھ کر اور مستقل طور پر رنگ لگائیں۔
-
سبز - کامیابی کی حیثیت، کام مکمل
-
سرخ - غلطیاں اور ناکامیاں
-
پیلا - انتباہ اور غیر مسدود مسائل
-
فیروزی - معلومات کی پیداوار، URL، راستہ
-
بہادر - ہیڈر، ٹول کا نام، اہم اقدار
ہر چیز کو رنگ نہ دیں۔ رنگ جب ہر جگہ ہوتے ہیں تو اپنا معنی کھو دیتے ہیں۔ آپ اسے صارفین کی توجہ اس طرف مبذول کرنے کے لیے استعمال کر سکتے ہیں کہ اصل میں کیا اہم ہے۔
CLI ٹولز قابل آزمائش ہیں اور ان کی جانچ ہونی چاہیے۔ سب سے قابل اعتماد نقطہ نظر ٹرمینل آؤٹ پٹ فارمیٹ کے بجائے براہ راست طرز عمل کی جانچ کرنا ہے۔
شامل کریں test اگر آپ کے پاس پہلے سے ڈویلپر انحصار نہیں ہے:
dev_dependencies:
test: ^1.24.0
ٹیسٹ کمانڈ منطق:
import 'package:test/test.dart';
import '../lib/models/task.dart';
void main() {
group('Task model', () {
test('copyWith updates isComplete correctly', () {
final task = Task(
id: 1,
title: 'Write tests',
priority: 'high',
createdAt: DateTime.now(),
);
final completed = task.copyWith(isComplete: true);
expect(completed.isComplete, isTrue);
expect(completed.title, equals('Write tests'));
expect(completed.id, equals(1));
});
test('toJson and fromJson round-trips correctly', () {
final task = Task(
id: 2,
title: 'Ship the tool',
priority: 'normal',
createdAt: DateTime.parse('2025-01-01T00:00:00.000'),
);
final json = task.toJson();
final restored = Task.fromJson(json);
expect(restored.id, equals(task.id));
expect(restored.title, equals(task.title));
expect(restored.priority, equals(task.priority));
});
});
}
ہیڈر پارسر ٹیسٹ:
import 'package:test/test.dart';
import '../lib/utils/headers_parser.dart';
void main() {
group('parseHeaders', () {
test('parses a single header correctly', () {
final result = parseHeaders(['Authorization: Bearer mytoken']);
expect(result['Authorization'], equals('Bearer mytoken'));
});
test('parses multiple headers', () {
final result = parseHeaders([
'Authorization: Bearer token',
'Accept: application/json',
]);
expect(result.length, equals(2));
expect(result['Accept'], equals('application/json'));
});
test('ignores malformed headers without a colon', () {
final result = parseHeaders(['malformed-header']);
expect(result.isEmpty, isTrue);
});
});
}
ٹیسٹ چلائیں۔
dart test
CLI تعیناتی اور تعیناتی۔
CLI ٹول بنانا آدھا کام ہے۔ اسے ڈویلپرز کے ہاتھوں میں ڈالنا دوسرا نصف ہے۔ تعیناتی کے پانچ راستے دستیاب ہیں، ہر ایک مختلف استعمال کے معاملے کے لیے موزوں ہے۔
موڈ 1: pub.dev — عوامی پیکیج کی تقسیم
pub.dev پر شائع کر کے، Dart اور Flutter کمیونٹی میں کوئی بھی شخص آپ کے ٹولز کو ایک کمانڈ سے انسٹال کر سکتا ہے۔
اپنا پیکج تیار کریں:
آپ کا pubspec.yaml آپ کو مکمل کرنا ہوگا:
name: dart_http
description: A lightweight API request runner for Dart developers.
version: 1.0.0
homepage: https://github.com/yourname/dart_http
environment:
sdk: '>=3.0.0 <4.0.0'
executables:
dart_http: dart_http
کہ executables بلاکس اہم ہیں۔ یہ آپ کو بتاتا ہے کہ pub.dev میں کون سی اسکرپٹ ہیں۔ bin/ یہ ایک قابل عمل کمانڈ کے طور پر سامنے آیا ہے۔
آپ کو بھی ضرورت ہو گی:
-
README.md- ٹول کیا کرتا ہے، اسے کیسے انسٹال کیا جائے، استعمال کی مثالیں۔ -
CHANGELOG.md- ورژن کی تاریخ -
LICENSE- اوپن سورس لائسنس (MIT معیاری ہے)
پوسٹ کرنے سے پہلے چیک کریں۔
dart pub publish --dry-run
اصل میں شائع کیے بغیر تمام توثیق چلاتا ہے۔ براہ کرم جاری رکھنے سے پہلے وارننگ کو درست کریں۔
میں پوسٹ کیا گیا:
dart pub publish
آپ کو اپنے pub.dev اکاؤنٹ سے تصدیق کرنے کے لیے کہا جائے گا۔ ایک بار شائع ہونے کے بعد، ٹول عالمی سطح پر دستیاب ہوگا۔
dart pub global activate dart_http
dart_http get https://api.example.com/users
موڈ 2: لوکل پاتھ کو فعال کریں۔
ٹیم کے اندرونی ٹولز کے لیے جنہیں آپ عوامی طور پر شائع نہیں کرنا چاہتے، انہیں براہ راست مقامی یا کلون شدہ ریپوزٹری پر فعال کریں۔
dart pub global activate --source path /path/to/dart_http
ٹیم کا ہر ڈویلپر ریپوزٹری کو کلون کرتا ہے اور اس کمانڈ کو ایک بار چلاتا ہے۔ اس کے بعد یہ ٹول آپ کے ٹرمینل میں pub.dev کی اشاعت کی ضرورت کے بغیر عالمی سطح پر دستیاب ہوگا۔
یہ اس کے لیے موزوں تعیناتی موڈ ہے:
موڈ 3: GitHub ریلیز کے ذریعے مرتب کردہ بائنریز
ڈارٹ کو خود ساختہ مقامی ایگزیکیوٹیبل میں مرتب کیا جاسکتا ہے۔ ٹارگٹ سسٹم پر Dart SDK کی ضرورت نہیں ہے۔ یہ ٹولز کو ڈارٹ ماحولیاتی نظام سے باہر کے ڈویلپرز کے لیے قابل رسائی بناتا ہے۔
plait:
# macOS
dart compile exe bin/dart_http.dart -o dist/dart_http-macos
# Linux
dart compile exe bin/dart_http.dart -o dist/dart_http-linux
# Windows
dart compile exe bin/dart_http.dart -o dist/dart_http-windows.exe
مرتب شدہ بائنریز مکمل طور پر خود ساختہ ہیں۔ اسے کسی بھی کمپیوٹر پر کاپی کر کے چلائیں۔ آپ کو ڈارٹ انسٹال کرنے کی ضرورت نہیں ہے۔
GitHub ایکشن کے ساتھ خودکار:
بنانا .github/workflows/release.yml:
name: Release
on:
push:
tags:
- 'v*'
jobs:
build:
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- uses: dart-lang/setup-dart@v1
with:
sdk: stable
- name: Install dependencies
run: dart pub get
- name: Compile binary
run: |
mkdir -p dist
dart compile exe bin/dart_http.dart -o dist/dart_http-${{ runner.os }}
- name: Upload binary to release
uses: softprops/action-gh-release@v1
with:
files: dist/dart_http-${{ runner.os }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ورژن ٹیگ (v1.0.0)، GitHub ایکشن تینوں پلیٹ فارمز کے لیے بائنریز کو مرتب کرتا ہے اور خود بخود انہیں GitHub ریلیز سے جوڑ دیتا ہے۔
انسٹالیشن اسکرپٹ لکھیں:
#!/usr/bin/env bash
set -euo pipefail
VERSION="1.0.0"
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
BINARY="dart_http-$OS"
INSTALL_DIR="/usr/local/bin"
curl -L "https://github.com/yourname/dart_http/releases/download/v\(VERSION/\)BINARY" \
-o "$INSTALL_DIR/dart_http"
chmod +x "$INSTALL_DIR/dart_http"
echo "dart_http installed successfully"
ڈویلپرز استعمال کرتے ہوئے انسٹال کرتے ہیں:
curl -fsSL https://raw.githubusercontent.com/yourname/dart_http/main/install.sh | bash
موڈ 4: ہومبریو ٹیب
ہومبریو میک او ایس پر معیاری پیکیج مینیجر ہے اور لینکس پر وسیع پیمانے پر استعمال ہوتا ہے۔ ہومبریو ٹیب آپ کو ٹولز انسٹال کرنے کی اجازت دیتا ہے۔ brew install - یہ میکوس ڈویلپرز کے لیے سب سے زیادہ مانوس انسٹالیشن پیٹرن ہے۔
ایک ٹیب اسٹور بنائیں۔
نام کا ایک نیا GitHub ذخیرہ بنائیں: homebrew-tools (وہ homebrew- ہومبریو کے نام سازی کنونشن کے ذریعہ سابقہ کی ضرورت ہے)۔
فارمولا لکھیں:
بنانا Formula/dart_http.rb اس ذخیرہ سے:
class DartHttp < Formula
desc "A lightweight API request runner for the terminal"
homepage "https://github.com/yourname/dart_http"
version "1.0.0"
on_macos do
url "https://github.com/yourname/dart_http/releases/download/v1.0.0/dart_http-macOS"
sha256 "YOUR_SHA256_HASH_HERE"
end
on_linux do
url "https://github.com/yourname/dart_http/releases/download/v1.0.0/dart_http-Linux"
sha256 "YOUR_SHA256_HASH_HERE"
end
def install
bin.install "dart_http-#{OS.mac? ? 'macOS' : 'Linux'}" => "dart_http"
end
test do
system "#{bin}/dart_http", "--help"
end
end
ہر بائنری کے لیے SHA256 ہیش بنائیں۔
shasum -a 256 dist/dart_http-macOS
ٹیب سے انسٹال کریں:
brew tap yourname/tools
brew install dart_http
نیا ورژن جاری ہونے پر براہ کرم اپ ڈیٹ کریں۔ url اور sha256 فارمولے کی قدریں درج کریں اور اپنی تبدیلیوں کو آگے بڑھائیں۔ صارف کے ذریعہ چلایا جاتا ہے۔ brew upgrade dart_http اپ ڈیٹ کریں۔
موڈ 5: ڈوکر
ڈوکر کی تعیناتیاں CI ماحولیات، کنٹینرز کو معیاری بنانے والی ٹیموں، یا پیچیدہ انحصار والے ٹولز کے لیے بہترین ہیں۔
ایک ڈاکر فائل لکھیں۔
FROM dart:stable AS build
WORKDIR /app
COPY pubspec.* ./
RUN dart pub get
COPY . .
RUN dart compile exe bin/dart_http.dart -o /app/dart_http
FROM debian:stable-slim
COPY --from=build /app/dart_http /usr/local/bin/dart_http
ENTRYPOINT ["dart_http"]
یہ ایک کثیر مرحلے کی تعمیر کا استعمال کرتا ہے. پہلا مرحلہ ڈارٹ SDK امیج کا استعمال کرتے ہوئے بائنریز کو مرتب کرتا ہے، اور دوسرا مرحلہ صرف بائنریز کو کم سے کم ڈیبین امیج پر کاپی کرتا ہے۔ حتمی تصویر میں Dart SDK نہیں ہے، صرف مرتب شدہ بائنری ہے۔
بنائیں اور چلائیں:
docker build -t dart_http .
docker run dart_http get https://jsonplaceholder.typicode.com/users/1
Docker Hub پر شائع کریں:
docker tag dart_http yourname/dart_http:1.0.0
docker push yourname/dart_http:1.0.0
اس کے بعد صارف مقامی طور پر کچھ بھی انسٹال کیے بغیر اس ٹول کو چلا سکتے ہیں۔
docker run yourname/dart_http get https://api.example.com/users
صحیح تعیناتی موڈ کا انتخاب کریں۔
| طریقہ | کے لیے بہترین موزوں ہے۔ | Dart SDK کی ضرورت ہے۔ |
|---|---|---|
| pub.dev | پبلک ڈارٹ/فلٹر ڈویلپر ٹولز | ہاں |
| مقامی راستے کو فعال کریں۔ | اندرونی ٹیم ٹولز، پری ریلیز کی تعمیر | ہاں |
| مرتب شدہ بائنری | زبان-ایگنوسٹک ٹولز، وسیع پیمانے پر اپنانے | نہیں |
| ہومبریو ٹیب | macOS/Linux ڈویلپر ٹولز | نہیں |
| ڈاکر | CI ماحول، پیچیدہ انحصار | نہیں |
زیادہ تر ٹولز کے لیے میری اصل سفارشات یہ ہیں:
-
سے شروع کریں۔ pub.dev اگر آپ کے سامعین ڈارٹ ڈویلپر ہیں۔
-
شامل کریں مرتب شدہ بائنریز + GitHub ریلیز اگر آپ وسیع تر اپنانا چاہتے ہیں۔
-
اضافہ ہومبریو ٹیب جب macOS ڈویلپرز مطالبہ کرنا شروع کرتے ہیں۔
-
استعمال کریں ڈاکر صرف اس صورت میں جب یہ پہلے سے ہی آپ کی ٹیم کے ورک فلو کا حصہ ہو۔
نتیجہ
ہم یہ سمجھنے سے آگے نکل گئے کہ CLI کیا ہے تین بتدریج پیچیدہ ٹولز بنانا اور انہیں پانچ مختلف چینلز پر تعینات کرنا۔
بنیادی مہارتیں - args، stdin، stdout، stderrایگزٹ کوڈ، فائل I/O، اور پروسیس تخلیق وہی اجزاء ہیں جیسے ٹولز: flutter، gitاور dart اپنے طور پر بنایا گیا ہے۔ باقی سب کچھ کنفیگریشن ہے۔
تین CLIs جو ہم نے بنائے ہیں (ہیلو CLI، dart_todoاور dart_http) ہر ایک ایک نئی پرت متعارف کراتا ہے: خام ڈارٹ کی بنیادی باتیں۔ args JSON استقامت اور حقیقی HTTP تعامل کے ساتھ ایک پیکیج۔ تعیناتی سیکشن آپ کو ایک واضح راستہ فراہم کرتا ہے کہ آپ اسے ڈویلپرز کے سامنے آشکار کریں جو آپ جو بھی تعمیر کریں گے اسے استعمال کریں گے۔
ڈارٹ CLI کی ترقی کے لیے ایک طاقتور زبان ہے۔ مضبوط ٹائپنگ، غیر مطابقت پذیر سپورٹ، مقامی تالیف، اور pub.dev ماحولیاتی نظام اسے موبائل ایپس کے ساتھ ساتھ ڈویلپر ٹولز بنانے کے لیے بہترین انتخاب بناتا ہے۔
اگلا مرحلہ کچھ ایسا بنانا ہے جو آپ یا آپ کی ٹیم کے لیے ایک حقیقی مسئلہ حل کرے اور اسے جاری کرے۔
کوڈنگ کا مزہ لیں !!