@mcesystems/adb-kit 1.0.32 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +191 -191
- package/dist/resources/bin/windows/AdbWinApi.dll +0 -0
- package/dist/resources/bin/windows/AdbWinUsbApi.dll +0 -0
- package/dist/resources/bin/windows/adb.exe +0 -0
- package/package.json +1 -1
- package/scripts/README.md +183 -183
- package/scripts/export-resources.ts +342 -342
- package/dist/resources/bin/darwin/adb +0 -0
|
@@ -1,342 +1,342 @@
|
|
|
1
|
-
#!/usr/bin/env tsx
|
|
2
|
-
/**
|
|
3
|
-
* Export ADB (Android Debug Bridge) resources to a specified path
|
|
4
|
-
*
|
|
5
|
-
* This script downloads ADB platform tools from Google and exports them
|
|
6
|
-
* to a target directory. The resources can then be used by applications
|
|
7
|
-
* that depend on adb-kit.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* npx tsx export-resources.ts <target-path>
|
|
11
|
-
*
|
|
12
|
-
* Example:
|
|
13
|
-
* npx tsx export-resources.ts /path/to/my-app/resources/adb-kit
|
|
14
|
-
*
|
|
15
|
-
* Platform support:
|
|
16
|
-
* - macOS: Downloads darwin platform-tools from Google
|
|
17
|
-
* - Windows: Downloads windows platform-tools from Google
|
|
18
|
-
* - Linux: Downloads linux platform-tools from Google
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { exec } from "node:child_process";
|
|
22
|
-
import {
|
|
23
|
-
chmodSync,
|
|
24
|
-
copyFileSync,
|
|
25
|
-
createWriteStream,
|
|
26
|
-
existsSync,
|
|
27
|
-
mkdirSync,
|
|
28
|
-
writeFileSync,
|
|
29
|
-
} from "node:fs";
|
|
30
|
-
import path from "node:path";
|
|
31
|
-
import { promisify } from "node:util";
|
|
32
|
-
|
|
33
|
-
const execAsync = promisify(exec);
|
|
34
|
-
|
|
35
|
-
// ============================================================================
|
|
36
|
-
// Configuration
|
|
37
|
-
// ============================================================================
|
|
38
|
-
|
|
39
|
-
// ADB download URLs from Google
|
|
40
|
-
const ADB_URLS: Record<string, string> = {
|
|
41
|
-
windows: "https://dl.google.com/android/repository/platform-tools-latest-windows.zip",
|
|
42
|
-
darwin: "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip",
|
|
43
|
-
linux: "https://dl.google.com/android/repository/platform-tools-latest-linux.zip",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
// Files to extract from platform-tools per platform
|
|
47
|
-
const PLATFORM_FILES: Record<string, string[]> = {
|
|
48
|
-
windows: ["adb.exe", "AdbWinApi.dll", "AdbWinUsbApi.dll"],
|
|
49
|
-
darwin: ["adb"],
|
|
50
|
-
linux: ["adb"],
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
// ============================================================================
|
|
54
|
-
// Utility Functions
|
|
55
|
-
// ============================================================================
|
|
56
|
-
|
|
57
|
-
function printUsage(): void {
|
|
58
|
-
console.log(`
|
|
59
|
-
Usage: npx tsx export-resources.ts <target-path>
|
|
60
|
-
|
|
61
|
-
Arguments:
|
|
62
|
-
target-path Directory where resources will be exported
|
|
63
|
-
|
|
64
|
-
Examples:
|
|
65
|
-
npx tsx export-resources.ts ./my-app/resources/adb-kit
|
|
66
|
-
npx tsx export-resources.ts /absolute/path/to/resources
|
|
67
|
-
|
|
68
|
-
The script will create the following structure:
|
|
69
|
-
<target-path>/
|
|
70
|
-
bin/
|
|
71
|
-
darwin/ (macOS ADB binary)
|
|
72
|
-
windows/ (Windows ADB binaries and DLLs)
|
|
73
|
-
linux/ (Linux ADB binary)
|
|
74
|
-
licenses/
|
|
75
|
-
APACHE-2.0.txt
|
|
76
|
-
`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function downloadFile(url: string, destPath: string): Promise<void> {
|
|
80
|
-
console.log(`Downloading ${url}...`);
|
|
81
|
-
|
|
82
|
-
let response: Response;
|
|
83
|
-
try {
|
|
84
|
-
response = await fetch(url);
|
|
85
|
-
} catch {
|
|
86
|
-
// Fallback to https module if fetch is not available
|
|
87
|
-
const https = await import("node:https");
|
|
88
|
-
const http = await import("node:http");
|
|
89
|
-
const urlObj = new URL(url);
|
|
90
|
-
const client = urlObj.protocol === "https:" ? https : http;
|
|
91
|
-
|
|
92
|
-
return new Promise((resolve, reject) => {
|
|
93
|
-
const fileStream = createWriteStream(destPath);
|
|
94
|
-
const request = client.get(url, (res) => {
|
|
95
|
-
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
96
|
-
// Handle redirect
|
|
97
|
-
fileStream.close();
|
|
98
|
-
return downloadFile(res.headers.location, destPath).then(resolve).catch(reject);
|
|
99
|
-
}
|
|
100
|
-
if (res.statusCode && res.statusCode !== 200) {
|
|
101
|
-
fileStream.close();
|
|
102
|
-
reject(new Error(`Failed to download ${url}: ${res.statusCode} ${res.statusMessage}`));
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
res.pipe(fileStream);
|
|
106
|
-
fileStream.on("finish", () => {
|
|
107
|
-
fileStream.close();
|
|
108
|
-
resolve();
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
request.on("error", (err) => {
|
|
112
|
-
fileStream.close();
|
|
113
|
-
reject(err);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!response.ok) {
|
|
119
|
-
throw new Error(`Failed to download ${url}: ${response.statusText}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const fileStream = createWriteStream(destPath);
|
|
123
|
-
const reader = response.body?.getReader();
|
|
124
|
-
if (!reader) {
|
|
125
|
-
throw new Error(`Failed to get response body for ${url}`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
try {
|
|
129
|
-
while (true) {
|
|
130
|
-
const { done, value } = await reader.read();
|
|
131
|
-
if (done) break;
|
|
132
|
-
fileStream.write(value);
|
|
133
|
-
}
|
|
134
|
-
fileStream.end();
|
|
135
|
-
await new Promise<void>((resolve, reject) => {
|
|
136
|
-
fileStream.on("finish", resolve);
|
|
137
|
-
fileStream.on("error", reject);
|
|
138
|
-
});
|
|
139
|
-
console.log(`✓ Downloaded to ${destPath}`);
|
|
140
|
-
} finally {
|
|
141
|
-
reader.releaseLock();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async function extractZip(zipPath: string, extractDir: string): Promise<void> {
|
|
146
|
-
console.log(`Extracting ${zipPath}...`);
|
|
147
|
-
|
|
148
|
-
if (process.platform === "win32") {
|
|
149
|
-
// On Windows, use PowerShell Expand-Archive
|
|
150
|
-
try {
|
|
151
|
-
const escapedZipPath = zipPath.replace(/'/g, "''");
|
|
152
|
-
const escapedExtractDir = extractDir.replace(/'/g, "''");
|
|
153
|
-
await execAsync(
|
|
154
|
-
`powershell -Command "Expand-Archive -Path '${escapedZipPath}' -DestinationPath '${escapedExtractDir}' -Force"`
|
|
155
|
-
);
|
|
156
|
-
} catch (error) {
|
|
157
|
-
const err = error as { message?: string };
|
|
158
|
-
throw new Error(
|
|
159
|
-
`Failed to extract zip file. Please ensure PowerShell is available. Error: ${err.message || error}`
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
} else {
|
|
163
|
-
// On Unix-like systems, use unzip command
|
|
164
|
-
try {
|
|
165
|
-
await execAsync(`unzip -o "${zipPath}" -d "${extractDir}"`);
|
|
166
|
-
} catch (error) {
|
|
167
|
-
const err = error as { message?: string };
|
|
168
|
-
throw new Error(
|
|
169
|
-
`Failed to extract zip file. Please ensure 'unzip' is installed. Error: ${err.message || error}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
console.log(`✓ Extracted to ${extractDir}`);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
async function copyFiles(sourceDir: string, targetDir: string, files: string[]): Promise<void> {
|
|
177
|
-
mkdirSync(targetDir, { recursive: true });
|
|
178
|
-
|
|
179
|
-
for (const file of files) {
|
|
180
|
-
const sourcePath = path.join(sourceDir, "platform-tools", file);
|
|
181
|
-
const targetPath = path.join(targetDir, file);
|
|
182
|
-
|
|
183
|
-
if (!existsSync(sourcePath)) {
|
|
184
|
-
console.warn(`Warning: ${file} not found in ${sourcePath}`);
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
copyFileSync(sourcePath, targetPath);
|
|
189
|
-
console.log(`✓ Copied ${file}`);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function makeExecutable(filePath: string): void {
|
|
194
|
-
if (process.platform !== "win32") {
|
|
195
|
-
chmodSync(filePath, 0o755);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
async function cleanupDir(dirPath: string): Promise<void> {
|
|
200
|
-
try {
|
|
201
|
-
const { rimraf } = await import("rimraf");
|
|
202
|
-
await rimraf(dirPath);
|
|
203
|
-
} catch {
|
|
204
|
-
// Ignore cleanup errors
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// ============================================================================
|
|
209
|
-
// Export Functions
|
|
210
|
-
// ============================================================================
|
|
211
|
-
|
|
212
|
-
type PlatformType = "windows" | "darwin" | "linux";
|
|
213
|
-
|
|
214
|
-
async function exportPlatformResources(platform: PlatformType, targetDir: string): Promise<void> {
|
|
215
|
-
console.log(`\n=== Exporting ${platform} Resources ===\n`);
|
|
216
|
-
|
|
217
|
-
const binDir = path.join(targetDir, "bin", platform);
|
|
218
|
-
const files = PLATFORM_FILES[platform];
|
|
219
|
-
const url = ADB_URLS[platform];
|
|
220
|
-
|
|
221
|
-
// Create temp directory for extraction
|
|
222
|
-
const tempDir = path.join(targetDir, ".temp", platform);
|
|
223
|
-
mkdirSync(tempDir, { recursive: true });
|
|
224
|
-
const zipPath = path.join(tempDir, `platform-tools-${platform}.zip`);
|
|
225
|
-
|
|
226
|
-
try {
|
|
227
|
-
// Download
|
|
228
|
-
await downloadFile(url, zipPath);
|
|
229
|
-
|
|
230
|
-
// Extract
|
|
231
|
-
await extractZip(zipPath, tempDir);
|
|
232
|
-
|
|
233
|
-
// Copy files to target
|
|
234
|
-
await copyFiles(tempDir, binDir, files);
|
|
235
|
-
|
|
236
|
-
// Make executable on Unix
|
|
237
|
-
if (platform !== "windows") {
|
|
238
|
-
for (const file of files) {
|
|
239
|
-
makeExecutable(path.join(binDir, file));
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
console.log(`\n✓ ${platform} resources exported to: ${binDir}`);
|
|
244
|
-
} finally {
|
|
245
|
-
// Clean up temp directory
|
|
246
|
-
await cleanupDir(tempDir);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// ============================================================================
|
|
251
|
-
// License
|
|
252
|
-
// ============================================================================
|
|
253
|
-
|
|
254
|
-
function createLicenseFile(targetDir: string): void {
|
|
255
|
-
const licensesDir = path.join(targetDir, "licenses");
|
|
256
|
-
mkdirSync(licensesDir, { recursive: true });
|
|
257
|
-
|
|
258
|
-
const apacheLicense = `Apache License
|
|
259
|
-
Version 2.0, January 2004
|
|
260
|
-
http://www.apache.org/licenses/
|
|
261
|
-
|
|
262
|
-
Android Debug Bridge (ADB) is licensed under the Apache License 2.0.
|
|
263
|
-
|
|
264
|
-
For full license text, see:
|
|
265
|
-
https://www.apache.org/licenses/LICENSE-2.0
|
|
266
|
-
|
|
267
|
-
These binaries are downloaded from Google's official Android SDK repository:
|
|
268
|
-
https://developer.android.com/studio/releases/platform-tools
|
|
269
|
-
|
|
270
|
-
Source code is available at:
|
|
271
|
-
https://android.googlesource.com/platform/packages/modules/adb/
|
|
272
|
-
`;
|
|
273
|
-
|
|
274
|
-
const licensePath = path.join(licensesDir, "APACHE-2.0.txt");
|
|
275
|
-
writeFileSync(licensePath, apacheLicense);
|
|
276
|
-
console.log(`✓ Created license file: ${licensePath}`);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// ============================================================================
|
|
280
|
-
// Main
|
|
281
|
-
// ============================================================================
|
|
282
|
-
|
|
283
|
-
async function main(): Promise<void> {
|
|
284
|
-
const args = process.argv.slice(2);
|
|
285
|
-
|
|
286
|
-
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
287
|
-
printUsage();
|
|
288
|
-
process.exit(args.length === 0 ? 1 : 0);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
const targetPath = path.resolve(args[0]);
|
|
292
|
-
|
|
293
|
-
// Check for optional platform argument
|
|
294
|
-
let platforms: PlatformType[];
|
|
295
|
-
if (args.includes("--all")) {
|
|
296
|
-
platforms = ["windows", "darwin", "linux"];
|
|
297
|
-
} else if (args.includes("--platform")) {
|
|
298
|
-
const platformIdx = args.indexOf("--platform");
|
|
299
|
-
const platformArg = args[platformIdx + 1] as PlatformType;
|
|
300
|
-
if (!["windows", "darwin", "linux"].includes(platformArg)) {
|
|
301
|
-
console.error(`Invalid platform: ${platformArg}`);
|
|
302
|
-
console.error("Valid platforms: windows, darwin, linux");
|
|
303
|
-
process.exit(1);
|
|
304
|
-
}
|
|
305
|
-
platforms = [platformArg];
|
|
306
|
-
} else {
|
|
307
|
-
// Default to current platform
|
|
308
|
-
const currentPlatform = process.platform === "win32" ? "windows" : process.platform;
|
|
309
|
-
if (!["windows", "darwin", "linux"].includes(currentPlatform)) {
|
|
310
|
-
console.error(`Unsupported platform: ${currentPlatform}`);
|
|
311
|
-
process.exit(1);
|
|
312
|
-
}
|
|
313
|
-
platforms = [currentPlatform as PlatformType];
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
console.log("=== ADB Resources Export ===");
|
|
317
|
-
console.log(`Target: ${targetPath}`);
|
|
318
|
-
console.log(`Platforms: ${platforms.join(", ")}`);
|
|
319
|
-
|
|
320
|
-
// Create target directory
|
|
321
|
-
mkdirSync(targetPath, { recursive: true });
|
|
322
|
-
|
|
323
|
-
// Export resources for each platform
|
|
324
|
-
for (const platform of platforms) {
|
|
325
|
-
await exportPlatformResources(platform, targetPath);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
// Create license file
|
|
329
|
-
console.log("");
|
|
330
|
-
createLicenseFile(targetPath);
|
|
331
|
-
|
|
332
|
-
// Clean up temp directory
|
|
333
|
-
await cleanupDir(path.join(targetPath, ".temp"));
|
|
334
|
-
|
|
335
|
-
console.log("\n=== Export Complete ===");
|
|
336
|
-
console.log(`Resources exported to: ${targetPath}`);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
main().catch((error) => {
|
|
340
|
-
console.error("Export failed:", error);
|
|
341
|
-
process.exit(1);
|
|
342
|
-
});
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Export ADB (Android Debug Bridge) resources to a specified path
|
|
4
|
+
*
|
|
5
|
+
* This script downloads ADB platform tools from Google and exports them
|
|
6
|
+
* to a target directory. The resources can then be used by applications
|
|
7
|
+
* that depend on adb-kit.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx tsx export-resources.ts <target-path>
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* npx tsx export-resources.ts /path/to/my-app/resources/adb-kit
|
|
14
|
+
*
|
|
15
|
+
* Platform support:
|
|
16
|
+
* - macOS: Downloads darwin platform-tools from Google
|
|
17
|
+
* - Windows: Downloads windows platform-tools from Google
|
|
18
|
+
* - Linux: Downloads linux platform-tools from Google
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { exec } from "node:child_process";
|
|
22
|
+
import {
|
|
23
|
+
chmodSync,
|
|
24
|
+
copyFileSync,
|
|
25
|
+
createWriteStream,
|
|
26
|
+
existsSync,
|
|
27
|
+
mkdirSync,
|
|
28
|
+
writeFileSync,
|
|
29
|
+
} from "node:fs";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { promisify } from "node:util";
|
|
32
|
+
|
|
33
|
+
const execAsync = promisify(exec);
|
|
34
|
+
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Configuration
|
|
37
|
+
// ============================================================================
|
|
38
|
+
|
|
39
|
+
// ADB download URLs from Google
|
|
40
|
+
const ADB_URLS: Record<string, string> = {
|
|
41
|
+
windows: "https://dl.google.com/android/repository/platform-tools-latest-windows.zip",
|
|
42
|
+
darwin: "https://dl.google.com/android/repository/platform-tools-latest-darwin.zip",
|
|
43
|
+
linux: "https://dl.google.com/android/repository/platform-tools-latest-linux.zip",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Files to extract from platform-tools per platform
|
|
47
|
+
const PLATFORM_FILES: Record<string, string[]> = {
|
|
48
|
+
windows: ["adb.exe", "AdbWinApi.dll", "AdbWinUsbApi.dll"],
|
|
49
|
+
darwin: ["adb"],
|
|
50
|
+
linux: ["adb"],
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Utility Functions
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
function printUsage(): void {
|
|
58
|
+
console.log(`
|
|
59
|
+
Usage: npx tsx export-resources.ts <target-path>
|
|
60
|
+
|
|
61
|
+
Arguments:
|
|
62
|
+
target-path Directory where resources will be exported
|
|
63
|
+
|
|
64
|
+
Examples:
|
|
65
|
+
npx tsx export-resources.ts ./my-app/resources/adb-kit
|
|
66
|
+
npx tsx export-resources.ts /absolute/path/to/resources
|
|
67
|
+
|
|
68
|
+
The script will create the following structure:
|
|
69
|
+
<target-path>/
|
|
70
|
+
bin/
|
|
71
|
+
darwin/ (macOS ADB binary)
|
|
72
|
+
windows/ (Windows ADB binaries and DLLs)
|
|
73
|
+
linux/ (Linux ADB binary)
|
|
74
|
+
licenses/
|
|
75
|
+
APACHE-2.0.txt
|
|
76
|
+
`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function downloadFile(url: string, destPath: string): Promise<void> {
|
|
80
|
+
console.log(`Downloading ${url}...`);
|
|
81
|
+
|
|
82
|
+
let response: Response;
|
|
83
|
+
try {
|
|
84
|
+
response = await fetch(url);
|
|
85
|
+
} catch {
|
|
86
|
+
// Fallback to https module if fetch is not available
|
|
87
|
+
const https = await import("node:https");
|
|
88
|
+
const http = await import("node:http");
|
|
89
|
+
const urlObj = new URL(url);
|
|
90
|
+
const client = urlObj.protocol === "https:" ? https : http;
|
|
91
|
+
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
const fileStream = createWriteStream(destPath);
|
|
94
|
+
const request = client.get(url, (res) => {
|
|
95
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
96
|
+
// Handle redirect
|
|
97
|
+
fileStream.close();
|
|
98
|
+
return downloadFile(res.headers.location, destPath).then(resolve).catch(reject);
|
|
99
|
+
}
|
|
100
|
+
if (res.statusCode && res.statusCode !== 200) {
|
|
101
|
+
fileStream.close();
|
|
102
|
+
reject(new Error(`Failed to download ${url}: ${res.statusCode} ${res.statusMessage}`));
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
res.pipe(fileStream);
|
|
106
|
+
fileStream.on("finish", () => {
|
|
107
|
+
fileStream.close();
|
|
108
|
+
resolve();
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
request.on("error", (err) => {
|
|
112
|
+
fileStream.close();
|
|
113
|
+
reject(err);
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
throw new Error(`Failed to download ${url}: ${response.statusText}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const fileStream = createWriteStream(destPath);
|
|
123
|
+
const reader = response.body?.getReader();
|
|
124
|
+
if (!reader) {
|
|
125
|
+
throw new Error(`Failed to get response body for ${url}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
while (true) {
|
|
130
|
+
const { done, value } = await reader.read();
|
|
131
|
+
if (done) break;
|
|
132
|
+
fileStream.write(value);
|
|
133
|
+
}
|
|
134
|
+
fileStream.end();
|
|
135
|
+
await new Promise<void>((resolve, reject) => {
|
|
136
|
+
fileStream.on("finish", resolve);
|
|
137
|
+
fileStream.on("error", reject);
|
|
138
|
+
});
|
|
139
|
+
console.log(`✓ Downloaded to ${destPath}`);
|
|
140
|
+
} finally {
|
|
141
|
+
reader.releaseLock();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function extractZip(zipPath: string, extractDir: string): Promise<void> {
|
|
146
|
+
console.log(`Extracting ${zipPath}...`);
|
|
147
|
+
|
|
148
|
+
if (process.platform === "win32") {
|
|
149
|
+
// On Windows, use PowerShell Expand-Archive
|
|
150
|
+
try {
|
|
151
|
+
const escapedZipPath = zipPath.replace(/'/g, "''");
|
|
152
|
+
const escapedExtractDir = extractDir.replace(/'/g, "''");
|
|
153
|
+
await execAsync(
|
|
154
|
+
`powershell -Command "Expand-Archive -Path '${escapedZipPath}' -DestinationPath '${escapedExtractDir}' -Force"`
|
|
155
|
+
);
|
|
156
|
+
} catch (error) {
|
|
157
|
+
const err = error as { message?: string };
|
|
158
|
+
throw new Error(
|
|
159
|
+
`Failed to extract zip file. Please ensure PowerShell is available. Error: ${err.message || error}`
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
} else {
|
|
163
|
+
// On Unix-like systems, use unzip command
|
|
164
|
+
try {
|
|
165
|
+
await execAsync(`unzip -o "${zipPath}" -d "${extractDir}"`);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const err = error as { message?: string };
|
|
168
|
+
throw new Error(
|
|
169
|
+
`Failed to extract zip file. Please ensure 'unzip' is installed. Error: ${err.message || error}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
console.log(`✓ Extracted to ${extractDir}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function copyFiles(sourceDir: string, targetDir: string, files: string[]): Promise<void> {
|
|
177
|
+
mkdirSync(targetDir, { recursive: true });
|
|
178
|
+
|
|
179
|
+
for (const file of files) {
|
|
180
|
+
const sourcePath = path.join(sourceDir, "platform-tools", file);
|
|
181
|
+
const targetPath = path.join(targetDir, file);
|
|
182
|
+
|
|
183
|
+
if (!existsSync(sourcePath)) {
|
|
184
|
+
console.warn(`Warning: ${file} not found in ${sourcePath}`);
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
copyFileSync(sourcePath, targetPath);
|
|
189
|
+
console.log(`✓ Copied ${file}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function makeExecutable(filePath: string): void {
|
|
194
|
+
if (process.platform !== "win32") {
|
|
195
|
+
chmodSync(filePath, 0o755);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function cleanupDir(dirPath: string): Promise<void> {
|
|
200
|
+
try {
|
|
201
|
+
const { rimraf } = await import("rimraf");
|
|
202
|
+
await rimraf(dirPath);
|
|
203
|
+
} catch {
|
|
204
|
+
// Ignore cleanup errors
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ============================================================================
|
|
209
|
+
// Export Functions
|
|
210
|
+
// ============================================================================
|
|
211
|
+
|
|
212
|
+
type PlatformType = "windows" | "darwin" | "linux";
|
|
213
|
+
|
|
214
|
+
async function exportPlatformResources(platform: PlatformType, targetDir: string): Promise<void> {
|
|
215
|
+
console.log(`\n=== Exporting ${platform} Resources ===\n`);
|
|
216
|
+
|
|
217
|
+
const binDir = path.join(targetDir, "bin", platform);
|
|
218
|
+
const files = PLATFORM_FILES[platform];
|
|
219
|
+
const url = ADB_URLS[platform];
|
|
220
|
+
|
|
221
|
+
// Create temp directory for extraction
|
|
222
|
+
const tempDir = path.join(targetDir, ".temp", platform);
|
|
223
|
+
mkdirSync(tempDir, { recursive: true });
|
|
224
|
+
const zipPath = path.join(tempDir, `platform-tools-${platform}.zip`);
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
// Download
|
|
228
|
+
await downloadFile(url, zipPath);
|
|
229
|
+
|
|
230
|
+
// Extract
|
|
231
|
+
await extractZip(zipPath, tempDir);
|
|
232
|
+
|
|
233
|
+
// Copy files to target
|
|
234
|
+
await copyFiles(tempDir, binDir, files);
|
|
235
|
+
|
|
236
|
+
// Make executable on Unix
|
|
237
|
+
if (platform !== "windows") {
|
|
238
|
+
for (const file of files) {
|
|
239
|
+
makeExecutable(path.join(binDir, file));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
console.log(`\n✓ ${platform} resources exported to: ${binDir}`);
|
|
244
|
+
} finally {
|
|
245
|
+
// Clean up temp directory
|
|
246
|
+
await cleanupDir(tempDir);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// License
|
|
252
|
+
// ============================================================================
|
|
253
|
+
|
|
254
|
+
function createLicenseFile(targetDir: string): void {
|
|
255
|
+
const licensesDir = path.join(targetDir, "licenses");
|
|
256
|
+
mkdirSync(licensesDir, { recursive: true });
|
|
257
|
+
|
|
258
|
+
const apacheLicense = `Apache License
|
|
259
|
+
Version 2.0, January 2004
|
|
260
|
+
http://www.apache.org/licenses/
|
|
261
|
+
|
|
262
|
+
Android Debug Bridge (ADB) is licensed under the Apache License 2.0.
|
|
263
|
+
|
|
264
|
+
For full license text, see:
|
|
265
|
+
https://www.apache.org/licenses/LICENSE-2.0
|
|
266
|
+
|
|
267
|
+
These binaries are downloaded from Google's official Android SDK repository:
|
|
268
|
+
https://developer.android.com/studio/releases/platform-tools
|
|
269
|
+
|
|
270
|
+
Source code is available at:
|
|
271
|
+
https://android.googlesource.com/platform/packages/modules/adb/
|
|
272
|
+
`;
|
|
273
|
+
|
|
274
|
+
const licensePath = path.join(licensesDir, "APACHE-2.0.txt");
|
|
275
|
+
writeFileSync(licensePath, apacheLicense);
|
|
276
|
+
console.log(`✓ Created license file: ${licensePath}`);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ============================================================================
|
|
280
|
+
// Main
|
|
281
|
+
// ============================================================================
|
|
282
|
+
|
|
283
|
+
async function main(): Promise<void> {
|
|
284
|
+
const args = process.argv.slice(2);
|
|
285
|
+
|
|
286
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
287
|
+
printUsage();
|
|
288
|
+
process.exit(args.length === 0 ? 1 : 0);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const targetPath = path.resolve(args[0]);
|
|
292
|
+
|
|
293
|
+
// Check for optional platform argument
|
|
294
|
+
let platforms: PlatformType[];
|
|
295
|
+
if (args.includes("--all")) {
|
|
296
|
+
platforms = ["windows", "darwin", "linux"];
|
|
297
|
+
} else if (args.includes("--platform")) {
|
|
298
|
+
const platformIdx = args.indexOf("--platform");
|
|
299
|
+
const platformArg = args[platformIdx + 1] as PlatformType;
|
|
300
|
+
if (!["windows", "darwin", "linux"].includes(platformArg)) {
|
|
301
|
+
console.error(`Invalid platform: ${platformArg}`);
|
|
302
|
+
console.error("Valid platforms: windows, darwin, linux");
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
platforms = [platformArg];
|
|
306
|
+
} else {
|
|
307
|
+
// Default to current platform
|
|
308
|
+
const currentPlatform = process.platform === "win32" ? "windows" : process.platform;
|
|
309
|
+
if (!["windows", "darwin", "linux"].includes(currentPlatform)) {
|
|
310
|
+
console.error(`Unsupported platform: ${currentPlatform}`);
|
|
311
|
+
process.exit(1);
|
|
312
|
+
}
|
|
313
|
+
platforms = [currentPlatform as PlatformType];
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
console.log("=== ADB Resources Export ===");
|
|
317
|
+
console.log(`Target: ${targetPath}`);
|
|
318
|
+
console.log(`Platforms: ${platforms.join(", ")}`);
|
|
319
|
+
|
|
320
|
+
// Create target directory
|
|
321
|
+
mkdirSync(targetPath, { recursive: true });
|
|
322
|
+
|
|
323
|
+
// Export resources for each platform
|
|
324
|
+
for (const platform of platforms) {
|
|
325
|
+
await exportPlatformResources(platform, targetPath);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Create license file
|
|
329
|
+
console.log("");
|
|
330
|
+
createLicenseFile(targetPath);
|
|
331
|
+
|
|
332
|
+
// Clean up temp directory
|
|
333
|
+
await cleanupDir(path.join(targetPath, ".temp"));
|
|
334
|
+
|
|
335
|
+
console.log("\n=== Export Complete ===");
|
|
336
|
+
console.log(`Resources exported to: ${targetPath}`);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
main().catch((error) => {
|
|
340
|
+
console.error("Export failed:", error);
|
|
341
|
+
process.exit(1);
|
|
342
|
+
});
|