@gengjiawen/os-init 1.7.0 → 1.7.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.7.1](https://github.com/gengjiawen/os-init/compare/v1.7.0...v1.7.1) (2025-11-09)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * android CI ([#12](https://github.com/gengjiawen/os-init/issues/12)) ([535b011](https://github.com/gengjiawen/os-init/commit/535b0115b513902ceb6fd9ef98bcb8338ac9972e))
9
+
3
10
  ## [1.7.0](https://github.com/gengjiawen/os-init/compare/v1.6.0...v1.7.0) (2025-11-09)
4
11
 
5
12
 
package/README.md CHANGED
@@ -57,7 +57,7 @@ pnpx @gengjiawen/os-init set-dev "ssh-rsa AAAAB3NzaC1yc2..."
57
57
  ### Setup Android Development Environment
58
58
 
59
59
  ```bash
60
- pnpx @gengjiawen/os-init set-android [options]
60
+ pnpx @gengjiawen/os-init set-android
61
61
  ```
62
62
 
63
63
  Sets up a complete Android development environment on macOS and Linux. This command will:
@@ -70,9 +70,6 @@ Sets up a complete Android development environment on macOS and Linux. This comm
70
70
 
71
71
  Example:
72
72
  ```bash
73
- # Basic installation
74
- pnpx @gengjiawen/os-init set-android
75
-
76
73
  # Custom installation path
77
74
  pnpx @gengjiawen/os-init set-android --android-home ~/my-android-sdk
78
75
 
@@ -5,7 +5,8 @@ const fs = require("fs");
5
5
  const path = require("path");
6
6
  const os = require("os");
7
7
  const execa_1 = require("execa");
8
- const unzip_url_1 = require("@compilets/unzip-url");
8
+ const unzip_url_1 = require("@gengjiawen/unzip-url");
9
+ const fish_shell_utils_1 = require("./fish-shell-utils");
9
10
  const ANDROID_CONFIG = {
10
11
  sdkVersion: '11076708',
11
12
  platformVersion: 'android-36',
@@ -30,11 +31,12 @@ function getSdkDownloadUrl(sdkVersion) {
30
31
  }
31
32
  function getAndroidEnvVars(androidHome, ndkVersion) {
32
33
  return `
33
- # Android development environment
34
+ # ===== Android development environment - START (2025-11-09) =====
34
35
  export ANDROID_HOME=${androidHome}
35
36
  export ANDROID_SDK_ROOT=\${ANDROID_HOME}
36
37
  export ANDROID_NDK_HOME=\${ANDROID_HOME}/ndk/${ndkVersion}
37
- export PATH=\${ANDROID_HOME}/cmdline-tools/latest/bin:\${ANDROID_HOME}/emulator:\${ANDROID_HOME}/platform-tools:\${ANDROID_HOME}/tools:\${ANDROID_HOME}/tools/bin:\${PATH}
38
+ export PATH=\${ANDROID_HOME}/cmdline-tools/bin:\${ANDROID_HOME}/cmdline-tools/latest/bin:\${ANDROID_HOME}/emulator:\${ANDROID_HOME}/platform-tools:\${ANDROID_HOME}/tools:\${ANDROID_HOME}/tools/bin:\${PATH}
39
+ # ===== Android development environment - END =====
38
40
  `;
39
41
  }
40
42
  function getShellRcFile() {
@@ -58,12 +60,20 @@ function hasAndroidEnvVars(rcFile) {
58
60
  return content.includes('ANDROID_HOME');
59
61
  }
60
62
  function appendEnvVarsToShellConfig(rcFile, envVars) {
61
- const dir = path.dirname(rcFile);
62
- if (!fs.existsSync(dir)) {
63
- fs.mkdirSync(dir, { recursive: true });
63
+ const shell = process.env.SHELL || '';
64
+ const homeDir = os.homedir();
65
+ const bashrcFile = path.join(homeDir, '.bashrc');
66
+ if (!fs.existsSync(bashrcFile) ||
67
+ !fs.readFileSync(bashrcFile, 'utf-8').includes('ANDROID_HOME')) {
68
+ fs.appendFileSync(bashrcFile, envVars);
69
+ console.log(`Environment variables added to: ${bashrcFile}`);
70
+ }
71
+ else {
72
+ console.log(`Environment variables already exist in: ${bashrcFile}`);
73
+ }
74
+ if (shell.includes('fish')) {
75
+ (0, fish_shell_utils_1.appendFishImportScript)(rcFile);
64
76
  }
65
- fs.appendFileSync(rcFile, envVars);
66
- console.log(`Environment variables added to: ${rcFile}`);
67
77
  }
68
78
  async function setupAndroidEnvironment(options) {
69
79
  const androidHome = options?.androidHome || getDefaultAndroidHome();
@@ -85,32 +95,34 @@ async function setupAndroidEnvironment(options) {
85
95
  }
86
96
  console.log('\nDownloading and setting up Android SDK...');
87
97
  const sdkUrl = getSdkDownloadUrl(sdkVersion);
98
+ const cmdlineToolsPath = path.join(androidHome, 'cmdline-tools');
99
+ const latestPath = path.join(cmdlineToolsPath, 'latest');
100
+ const latestBin = path.join(latestPath, 'bin');
88
101
  try {
89
- const cmdlineToolsPath = path.join(androidHome, 'cmdline-tools');
90
- if (!fs.existsSync(cmdlineToolsPath)) {
91
- fs.mkdirSync(cmdlineToolsPath, { recursive: true });
92
- }
93
- console.log(`Downloading and extracting from: ${sdkUrl}`);
94
- await (0, unzip_url_1.unzip)(sdkUrl, cmdlineToolsPath);
95
- const tempToolsPath = path.join(cmdlineToolsPath, 'cmdline-tools');
96
- const latestToolsPath = path.join(cmdlineToolsPath, 'latest');
97
- if (fs.existsSync(tempToolsPath)) {
98
- fs.renameSync(tempToolsPath, latestToolsPath);
102
+ if (!fs.existsSync(latestBin)) {
103
+ console.log(`Downloading and extracting from: ${sdkUrl} to ${androidHome}`);
104
+ await (0, unzip_url_1.unzip)(sdkUrl, cmdlineToolsPath);
105
+ const tmp_toolchain = path.join(cmdlineToolsPath, 'cmdline-tools');
106
+ fs.renameSync(tmp_toolchain, latestPath);
107
+ console.log('Android SDK extracted successfully');
99
108
  }
100
- console.log('Android SDK extracted successfully');
101
109
  }
102
110
  catch (error) {
103
111
  throw new Error(`Failed to download/extract Android SDK: ${error instanceof Error ? error.message : String(error)}`);
104
112
  }
113
+ const sdkmanagerBinary = path.join(latestBin, 'sdkmanager');
105
114
  const sdkmanagerEnv = {
106
115
  ...process.env,
107
116
  ANDROID_HOME: androidHome,
108
117
  ANDROID_SDK_ROOT: androidHome,
109
- PATH: `${androidHome}/cmdline-tools/latest/bin:${process.env.PATH}`,
118
+ PATH: `${latestBin}:${process.env.PATH}`,
110
119
  };
111
120
  console.log('\nAccepting Android SDK licenses...');
112
121
  try {
113
- await (0, execa_1.execa)('bash', ['-c', 'yes | sdkmanager --licenses'], {
122
+ await (0, execa_1.execa)('bash', [
123
+ '-c',
124
+ `yes | "${sdkmanagerBinary}" --sdk_root=${androidHome} --licenses`,
125
+ ], {
114
126
  env: sdkmanagerEnv,
115
127
  stdio: 'inherit',
116
128
  });
@@ -127,8 +139,7 @@ async function setupAndroidEnvironment(options) {
127
139
  `ndk;${ndkVersion}`,
128
140
  ];
129
141
  try {
130
- const componentsList = components.join(' ');
131
- await (0, execa_1.execa)('bash', ['-c', `yes | sdkmanager ${componentsList}`], {
142
+ await (0, execa_1.execa)(sdkmanagerBinary, [`--sdk_root=${androidHome}`, ...components], {
132
143
  env: sdkmanagerEnv,
133
144
  stdio: 'inherit',
134
145
  });
@@ -0,0 +1,2 @@
1
+ export declare function getFishImportBashExports(): string;
2
+ export declare function appendFishImportScript(fishConfigPath: string): void;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFishImportBashExports = getFishImportBashExports;
4
+ exports.appendFishImportScript = appendFishImportScript;
5
+ const fs = require("fs");
6
+ const path = require("path");
7
+ function getFishImportBashExports() {
8
+ return `
9
+ # ===== Import environment variables from .bashrc - START (2025-11-09) =====
10
+ egrep "^export " ~/.bashrc | while read e
11
+ set var (echo $e | sed -E "s/^export ([A-Za-z_0-9]+)=(.*)\\$/\\1/")
12
+ set value (echo $e | sed -E "s/^export ([A-Za-z_0-9]+)=(.*)\\$/\\2/")
13
+
14
+ # remove surrounding quotes if existing
15
+ set value (echo $value | sed -E "s/^\\"(.*)\\"\\$/\\1/")
16
+
17
+ # convert Bash \${VAR} to fish {\$VAR} before eval
18
+ set value (printf '%s' "$value" | sed -E 's/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/{$\\1}/g')
19
+
20
+ if test $var = "PATH"
21
+ # replace ":" by spaces. this is how PATH looks for Fish
22
+ set value (echo $value | sed -E "s/:/ /g")
23
+
24
+ # use eval because we need to expand the value
25
+ eval set -xg $var $value
26
+
27
+ continue
28
+ end
29
+
30
+ # evaluate variables. we can use eval because we most likely just used "$var"
31
+ set value (eval echo $value)
32
+
33
+ #echo "set -xg '$var' '$value' (via '$e')"
34
+ set -xg $var $value
35
+ end
36
+ # ===== Import environment variables from .bashrc - END =====
37
+ `;
38
+ }
39
+ function appendFishImportScript(fishConfigPath) {
40
+ const configDir = path.dirname(fishConfigPath);
41
+ if (!fs.existsSync(configDir)) {
42
+ fs.mkdirSync(configDir, { recursive: true });
43
+ }
44
+ const fishContent = fs.existsSync(fishConfigPath)
45
+ ? fs.readFileSync(fishConfigPath, 'utf-8')
46
+ : '';
47
+ if (!fishContent.includes('Import environment variables from .bashrc - START')) {
48
+ const fishScript = getFishImportBashExports();
49
+ fs.appendFileSync(fishConfigPath, fishScript);
50
+ console.log(`Fish import script added to: ${fishConfigPath}`);
51
+ }
52
+ else {
53
+ console.log(`Fish import script already exists in: ${fishConfigPath}`);
54
+ }
55
+ }
@@ -2,7 +2,8 @@ import * as fs from 'fs'
2
2
  import * as path from 'path'
3
3
  import * as os from 'os'
4
4
  import { execa } from 'execa'
5
- import { unzip } from '@compilets/unzip-url'
5
+ import { unzip } from '@gengjiawen/unzip-url'
6
+ import { appendFishImportScript } from './fish-shell-utils'
6
7
 
7
8
  /** Android SDK configuration */
8
9
  const ANDROID_CONFIG = {
@@ -35,11 +36,12 @@ function getSdkDownloadUrl(sdkVersion: string): string {
35
36
  /** Get Android environment variables */
36
37
  function getAndroidEnvVars(androidHome: string, ndkVersion: string): string {
37
38
  return `
38
- # Android development environment
39
+ # ===== Android development environment - START (2025-11-09) =====
39
40
  export ANDROID_HOME=${androidHome}
40
41
  export ANDROID_SDK_ROOT=\${ANDROID_HOME}
41
42
  export ANDROID_NDK_HOME=\${ANDROID_HOME}/ndk/${ndkVersion}
42
- export PATH=\${ANDROID_HOME}/cmdline-tools/latest/bin:\${ANDROID_HOME}/emulator:\${ANDROID_HOME}/platform-tools:\${ANDROID_HOME}/tools:\${ANDROID_HOME}/tools/bin:\${PATH}
43
+ export PATH=\${ANDROID_HOME}/cmdline-tools/bin:\${ANDROID_HOME}/cmdline-tools/latest/bin:\${ANDROID_HOME}/emulator:\${ANDROID_HOME}/platform-tools:\${ANDROID_HOME}/tools:\${ANDROID_HOME}/tools/bin:\${PATH}
44
+ # ===== Android development environment - END =====
43
45
  `
44
46
  }
45
47
 
@@ -68,13 +70,25 @@ function hasAndroidEnvVars(rcFile: string): boolean {
68
70
 
69
71
  /** Append Android environment variables to shell config */
70
72
  function appendEnvVarsToShellConfig(rcFile: string, envVars: string): void {
71
- const dir = path.dirname(rcFile)
72
- if (!fs.existsSync(dir)) {
73
- fs.mkdirSync(dir, { recursive: true })
73
+ const shell = process.env.SHELL || ''
74
+ const homeDir = os.homedir()
75
+ const bashrcFile = path.join(homeDir, '.bashrc')
76
+
77
+ // Write to bashrc
78
+ if (
79
+ !fs.existsSync(bashrcFile) ||
80
+ !fs.readFileSync(bashrcFile, 'utf-8').includes('ANDROID_HOME')
81
+ ) {
82
+ fs.appendFileSync(bashrcFile, envVars)
83
+ console.log(`Environment variables added to: ${bashrcFile}`)
84
+ } else {
85
+ console.log(`Environment variables already exist in: ${bashrcFile}`)
74
86
  }
75
87
 
76
- fs.appendFileSync(rcFile, envVars)
77
- console.log(`Environment variables added to: ${rcFile}`)
88
+ // For fish shell, always write to bashrc first, then add import script to fish config
89
+ if (shell.includes('fish')) {
90
+ appendFishImportScript(rcFile)
91
+ }
78
92
  }
79
93
 
80
94
  /** Setup Android development environment */
@@ -123,46 +137,49 @@ export async function setupAndroidEnvironment(options?: {
123
137
  console.log('\nDownloading and setting up Android SDK...')
124
138
  const sdkUrl = getSdkDownloadUrl(sdkVersion)
125
139
 
126
- try {
127
- // Create cmdline-tools directory
128
- const cmdlineToolsPath = path.join(androidHome, 'cmdline-tools')
129
- if (!fs.existsSync(cmdlineToolsPath)) {
130
- fs.mkdirSync(cmdlineToolsPath, { recursive: true })
131
- }
140
+ const cmdlineToolsPath = path.join(androidHome, 'cmdline-tools')
141
+ const latestPath = path.join(cmdlineToolsPath, 'latest')
142
+ const latestBin = path.join(latestPath, 'bin')
132
143
 
144
+ try {
133
145
  // Download and extract SDK using unzip-url
134
- console.log(`Downloading and extracting from: ${sdkUrl}`)
135
- await unzip(sdkUrl, cmdlineToolsPath)
136
-
137
- // Move cmdline-tools to latest
138
- const tempToolsPath = path.join(cmdlineToolsPath, 'cmdline-tools')
139
- const latestToolsPath = path.join(cmdlineToolsPath, 'latest')
140
- if (fs.existsSync(tempToolsPath)) {
141
- fs.renameSync(tempToolsPath, latestToolsPath)
146
+ if (!fs.existsSync(latestBin)) {
147
+ console.log(
148
+ `Downloading and extracting from: ${sdkUrl} to ${androidHome}`
149
+ )
150
+ await unzip(sdkUrl, cmdlineToolsPath)
151
+ const tmp_toolchain = path.join(cmdlineToolsPath, 'cmdline-tools')
152
+ fs.renameSync(tmp_toolchain, latestPath)
153
+ console.log('Android SDK extracted successfully')
142
154
  }
143
-
144
- console.log('Android SDK extracted successfully')
145
155
  } catch (error) {
146
156
  throw new Error(
147
157
  `Failed to download/extract Android SDK: ${error instanceof Error ? error.message : String(error)}`
148
158
  )
149
159
  }
160
+ const sdkmanagerBinary = path.join(latestBin, 'sdkmanager')
150
161
 
151
- // Set environment variables for sdkmanager
152
162
  const sdkmanagerEnv = {
153
163
  ...process.env,
154
164
  ANDROID_HOME: androidHome,
155
165
  ANDROID_SDK_ROOT: androidHome,
156
- PATH: `${androidHome}/cmdline-tools/latest/bin:${process.env.PATH}`,
166
+ PATH: `${latestBin}:${process.env.PATH}`,
157
167
  }
158
168
 
159
169
  // Accept licenses
160
170
  console.log('\nAccepting Android SDK licenses...')
161
171
  try {
162
- await execa('bash', ['-c', 'yes | sdkmanager --licenses'], {
163
- env: sdkmanagerEnv,
164
- stdio: 'inherit',
165
- })
172
+ await execa(
173
+ 'bash',
174
+ [
175
+ '-c',
176
+ `yes | "${sdkmanagerBinary}" --sdk_root=${androidHome} --licenses`,
177
+ ],
178
+ {
179
+ env: sdkmanagerEnv,
180
+ stdio: 'inherit',
181
+ }
182
+ )
166
183
  } catch (error) {
167
184
  console.warn(
168
185
  'Warning: License acceptance may have failed, but continuing...'
@@ -180,11 +197,14 @@ export async function setupAndroidEnvironment(options?: {
180
197
  ]
181
198
 
182
199
  try {
183
- const componentsList = components.join(' ')
184
- await execa('bash', ['-c', `yes | sdkmanager ${componentsList}`], {
185
- env: sdkmanagerEnv,
186
- stdio: 'inherit',
187
- })
200
+ await execa(
201
+ sdkmanagerBinary,
202
+ [`--sdk_root=${androidHome}`, ...components],
203
+ {
204
+ env: sdkmanagerEnv,
205
+ stdio: 'inherit',
206
+ }
207
+ )
188
208
  console.log('Android SDK components installed successfully')
189
209
  } catch (error) {
190
210
  throw new Error(
@@ -0,0 +1,64 @@
1
+ import * as fs from 'fs'
2
+ import * as path from 'path'
3
+
4
+ /** Get Fish shell script to import bash exports */
5
+ export function getFishImportBashExports(): string {
6
+ return `
7
+ # ===== Import environment variables from .bashrc - START (2025-11-09) =====
8
+ egrep "^export " ~/.bashrc | while read e
9
+ set var (echo $e | sed -E "s/^export ([A-Za-z_0-9]+)=(.*)\\$/\\1/")
10
+ set value (echo $e | sed -E "s/^export ([A-Za-z_0-9]+)=(.*)\\$/\\2/")
11
+
12
+ # remove surrounding quotes if existing
13
+ set value (echo $value | sed -E "s/^\\"(.*)\\"\\$/\\1/")
14
+
15
+ # convert Bash \${VAR} to fish {\$VAR} before eval
16
+ set value (printf '%s' "$value" | sed -E 's/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/{$\\1}/g')
17
+
18
+ if test $var = "PATH"
19
+ # replace ":" by spaces. this is how PATH looks for Fish
20
+ set value (echo $value | sed -E "s/:/ /g")
21
+
22
+ # use eval because we need to expand the value
23
+ eval set -xg $var $value
24
+
25
+ continue
26
+ end
27
+
28
+ # evaluate variables. we can use eval because we most likely just used "$var"
29
+ set value (eval echo $value)
30
+
31
+ #echo "set -xg '$var' '$value' (via '$e')"
32
+ set -xg $var $value
33
+ end
34
+ # ===== Import environment variables from .bashrc - END =====
35
+ `
36
+ }
37
+
38
+ /**
39
+ * Append bash import script to Fish shell config file
40
+ * This function adds the import script to fish config.fish to automatically
41
+ * source environment variables from .bashrc
42
+ */
43
+ export function appendFishImportScript(fishConfigPath: string): void {
44
+ // Ensure fish config directory exists
45
+ const configDir = path.dirname(fishConfigPath)
46
+ if (!fs.existsSync(configDir)) {
47
+ fs.mkdirSync(configDir, { recursive: true })
48
+ }
49
+
50
+ // Check if import script already exists
51
+ const fishContent = fs.existsSync(fishConfigPath)
52
+ ? fs.readFileSync(fishConfigPath, 'utf-8')
53
+ : ''
54
+
55
+ if (
56
+ !fishContent.includes('Import environment variables from .bashrc - START')
57
+ ) {
58
+ const fishScript = getFishImportBashExports()
59
+ fs.appendFileSync(fishConfigPath, fishScript)
60
+ console.log(`Fish import script added to: ${fishConfigPath}`)
61
+ } else {
62
+ console.log(`Fish import script already exists in: ${fishConfigPath}`)
63
+ }
64
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gengjiawen/os-init",
3
3
  "private": false,
4
- "version": "1.7.0",
4
+ "version": "1.7.1",
5
5
  "description": "",
6
6
  "main": "index.js",
7
7
  "bin": {
@@ -19,7 +19,7 @@
19
19
  "postbuild": "cpy '**/*' '!**/*.ts' ../build/ --cwd=libs --parents"
20
20
  },
21
21
  "dependencies": {
22
- "@compilets/unzip-url": "^1.0.0",
22
+ "@gengjiawen/unzip-url": "^1.0.0",
23
23
  "commander": "^12.1.0",
24
24
  "ip": "^2.0.1",
25
25
  "execa": "^8.0.1"