Skip to content

Commit cdc288f

Browse files
committed
feat: add upload command to instabug CLI
- Introduced a new command `upload-so-files` for uploading .so files with architecture and API key options. - Enhanced the main CLI to support command registration and help functionality. - Updated dependencies in `pubspec.yaml` for `args` and `http`.
1 parent 1efaecf commit cdc288f

File tree

4 files changed

+263
-50
lines changed

4 files changed

+263
-50
lines changed

bin/commands/upload_so_files.dart

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import 'dart:developer';
2+
import 'dart:io';
3+
import 'package:args/args.dart';
4+
import 'package:http/http.dart' as http;
5+
6+
/**
7+
* This script uploads .so files to the specified endpoint used in NDK crash reporting.
8+
* Usage: dart instabug.dart upload-so-files --arch <arch> --file <path> --api_key <key> --token <token> --name <name>
9+
*/
10+
11+
class UploadSoFilesOptions {
12+
final String arch;
13+
final String file;
14+
final String apiKey;
15+
final String token;
16+
final String name;
17+
18+
UploadSoFilesOptions({
19+
required this.arch,
20+
required this.file,
21+
required this.apiKey,
22+
required this.token,
23+
required this.name,
24+
});
25+
}
26+
27+
// ignore: avoid_classes_with_only_static_members
28+
class UploadSoFilesCommand {
29+
static const List<String> validArchs = [
30+
'x86',
31+
'x86_64',
32+
'arm64-v8a',
33+
'armeabi-v7a',
34+
];
35+
36+
static ArgParser createParser() {
37+
final parser = ArgParser()
38+
..addFlag('help', abbr: 'h', help: 'Show this help message')
39+
..addOption(
40+
'arch',
41+
abbr: 'a',
42+
help: 'Architecture',
43+
allowed: validArchs,
44+
mandatory: true,
45+
)
46+
..addOption(
47+
'file',
48+
abbr: 'f',
49+
help: 'The path of the symbol files in Zip format',
50+
mandatory: true,
51+
)
52+
..addOption(
53+
'api_key',
54+
help: 'Your App key',
55+
mandatory: true,
56+
)
57+
..addOption(
58+
'token',
59+
abbr: 't',
60+
help: 'Your App Token',
61+
mandatory: true,
62+
)
63+
..addOption(
64+
'name',
65+
abbr: 'n',
66+
help: 'The app version name',
67+
mandatory: true,
68+
);
69+
70+
return parser;
71+
}
72+
73+
static void execute(ArgResults results) {
74+
final options = UploadSoFilesOptions(
75+
arch: results['arch'] as String,
76+
file: results['file'] as String,
77+
apiKey: results['api_key'] as String,
78+
token: results['token'] as String,
79+
name: results['name'] as String,
80+
);
81+
82+
uploadSoFiles(options);
83+
}
84+
85+
static Future<void> uploadSoFiles(UploadSoFilesOptions options) async {
86+
try {
87+
// Validate file exists
88+
final file = File(options.file);
89+
if (!await file.exists()) {
90+
print('[Instabug-CLI] Error: File not found: ${options.file}');
91+
throw Exception('File not found: ${options.file}');
92+
}
93+
94+
// validate file is a zip file
95+
if (!file.path.endsWith('.zip')) {
96+
print('[Instabug-CLI] Error: File is not a zip file: ${options.file}');
97+
throw Exception('File is not a zip file: ${options.file}');
98+
}
99+
100+
// Validate architecture
101+
if (!validArchs.contains(options.arch)) {
102+
print('[Instabug-CLI] Error: Invalid architecture: ${options.arch}. Valid options: ${validArchs.join(', ')}');
103+
throw Exception(
104+
'Invalid architecture: ${options.arch}. Valid options: ${validArchs.join(', ')}');
105+
}
106+
107+
print('Uploading .so files...');
108+
print('Architecture: ${options.arch}');
109+
print('File: ${options.file}');
110+
print('App Version: ${options.name}');
111+
112+
// TODO: Implement the actual upload logic here
113+
// This would typically involve:
114+
// 1. Reading the zip file
115+
// 2. Making an HTTP request to the upload endpoint
116+
// 3. Handling the response
117+
118+
// Make an HTTP request to the upload endpoint
119+
final body = {
120+
'arch': options.arch,
121+
'api_key': options.apiKey,
122+
'application_token': options.token,
123+
'so_file': options.file,
124+
'app_version': options.name,
125+
};
126+
127+
const endPoint = 'https://api.instabug.com/api/web/public/so_files';
128+
129+
final response = await http.post(
130+
Uri.parse(endPoint),
131+
body: body,
132+
);
133+
134+
print('Successfully uploaded .so files for version: ${options.name} with arch ${options.arch}');
135+
} catch (e) {
136+
print('[Instabug-CLI] Error: Error uploading .so files: $e');
137+
exit(1);
138+
}
139+
}
140+
}

bin/instabug.dart

Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,77 @@
11
#!/usr/bin/env dart
22

3+
import 'dart:developer';
4+
import 'dart:io';
5+
36
import 'package:args/args.dart';
47

5-
void main(List<String> args) {
8+
import 'commands/upload_so_files.dart';
9+
10+
// Command registry for easy management
11+
class CommandRegistry {
12+
static final Map<String, CommandHandler> _commands = {
13+
'upload-so-files': CommandHandler(
14+
parser: UploadSoFilesCommand.createParser(),
15+
execute: UploadSoFilesCommand.execute,
16+
),
17+
};
18+
19+
static Map<String, CommandHandler> get commands => _commands;
20+
static List<String> get commandNames => _commands.keys.toList();
21+
}
22+
23+
class CommandHandler {
24+
final ArgParser parser;
25+
final Function(ArgResults) execute;
26+
27+
CommandHandler({required this.parser, required this.execute});
28+
}
29+
30+
void main(List<String> args) async {
631
final parser = ArgParser()..addFlag('help', abbr: 'h');
7-
final result = parser.parse(args);
8-
if (result['help'] as bool) {
9-
print('Usage: instabug [options]');
32+
33+
// Add all commands to the parser
34+
for (final entry in CommandRegistry.commands.entries) {
35+
parser.addCommand(entry.key, entry.value.parser);
36+
}
37+
38+
print('--------------------------------');
39+
40+
try {
41+
final result = parser.parse(args);
42+
43+
final command = result.command;
44+
if (command != null) {
45+
// Check if help is requested for the subcommand (before mandatory validation)
46+
if (command['help'] == true) {
47+
final commandHandler = CommandRegistry.commands[command.name];
48+
if (commandHandler != null) {
49+
print('Usage: instabug ${command.name} [options]');
50+
print(commandHandler.parser.usage);
51+
}
52+
return;
53+
}
54+
55+
final commandHandler = CommandRegistry.commands[command.name];
56+
// Extra safety check just in case
57+
if (commandHandler != null) {
58+
commandHandler.execute(command);
59+
} else {
60+
print('Unknown command: ${command.name}');
61+
print('Available commands: ${CommandRegistry.commandNames.join(', ')}');
62+
exit(1);
63+
}
64+
} else {
65+
print('No applicable command found');
66+
print('Usage: instabug [options] <command>');
67+
print('Available commands: ${CommandRegistry.commandNames.join(', ')}');
68+
print('\nFor help on a specific command:');
69+
print(' instabug <command> --help\n');
70+
print(parser.usage);
71+
}
72+
} catch (e) {
73+
print('[Instabug-CLI] Error: $e');
1074
print(parser.usage);
11-
return;
75+
exit(1);
1276
}
13-
// …call into your SDK’s API…
14-
}
77+
}

0 commit comments

Comments
 (0)