chipfoundry-cli 1.0.0__tar.gz → 1.0.2__tar.gz

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.
@@ -0,0 +1,307 @@
1
+ Metadata-Version: 2.1
2
+ Name: chipfoundry-cli
3
+ Version: 1.0.2
4
+ Summary: CLI tool to automate ChipFoundry project submission to SFTP server
5
+ Home-page: https://chipfoundry.io
6
+ License: Apache-2.0
7
+ Author: ChipFoundry
8
+ Author-email: marwan.abbas@chipfoundry.io
9
+ Requires-Python: >=3.8.0
10
+ Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.8
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Dist: click (>=8.0.0,<9)
19
+ Requires-Dist: paramiko (>=3.0.0,<4)
20
+ Requires-Dist: rich (>=13,<14)
21
+ Requires-Dist: toml (>=0.10,<1.0)
22
+ Project-URL: Repository, https://github.com/chipfoundry/cf-cli
23
+ Description-Content-Type: text/markdown
24
+
25
+ # ChipFoundry CLI (`cf-cli`)
26
+
27
+ [![PyPI version](https://img.shields.io/pypi/v/chipfoundry-cli?color=blue)](https://badge.fury.io/py/chipfoundry-cli)
28
+ [![PyPI downloads](https://img.shields.io/pypi/dm/chipfoundry-cli.svg)](https://pypi.org/project/chipfoundry-cli/)
29
+
30
+ A command-line tool to automate the submission of ChipFoundry projects to the SFTP server.
31
+
32
+ ---
33
+
34
+ ## Overview
35
+
36
+ `cf-cli` is a user-friendly command-line tool for securely submitting your ChipFoundry project files to the official SFTP server. It automatically collects the required files, generates or updates your project configuration, and uploads everything to the correct location on the server.
37
+
38
+ ---
39
+
40
+ ## Installation
41
+
42
+ Install from PyPI:
43
+
44
+ ```bash
45
+ pip install chipfoundry-cli
46
+ cf --help
47
+ ```
48
+
49
+ ---
50
+
51
+ ## Quick Start
52
+
53
+ 1. **Generate SSH Key** (if you don't have one):
54
+ ```bash
55
+ cf keygen
56
+ ```
57
+
58
+ 2. **Register your key** at [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
59
+
60
+ 3. **Configure your credentials**:
61
+ ```bash
62
+ cf config
63
+ ```
64
+
65
+ 4. **Initialize your project**:
66
+ ```bash
67
+ cf init
68
+ ```
69
+
70
+ 5. **Upload your project**:
71
+ ```bash
72
+ cf push
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Project Structure Requirements
78
+
79
+ Your project directory **must** contain:
80
+
81
+ - `gds/` directory with **one** of the following:
82
+ - `user_project_wrapper.gds` (for digital projects)
83
+ - `user_analog_project_wrapper.gds` (for analog projects)
84
+ - `openframe_project_wrapper.gds` (for openframe projects)
85
+ - `verilog/rtl/user_defines.v` (required for digital/analog)
86
+ - `.cf/project.json` (optional; will be created/updated automatically)
87
+
88
+ **Example:**
89
+ ```
90
+ my_project/
91
+ ├── gds/
92
+ │ └── user_project_wrapper.gds
93
+ ├── verilog/
94
+ │ └── rtl/
95
+ │ └── user_defines.v
96
+ └── .cf/
97
+ └── project.json
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Authentication
103
+
104
+ The CLI uses SSH key authentication for secure SFTP access:
105
+
106
+ - **Default key location**: `~/.ssh/chipfoundry-key` (generated by `cf keygen`)
107
+ - **Alternative key**: Specify with `--sftp-key` option
108
+ - **SFTP username**: Required and configured via `cf config`
109
+
110
+ ---
111
+
112
+ ## SFTP Server
113
+
114
+ - **Default server**: `sftp.chipfoundry.io`
115
+ - **Username format**: `firstname-lastname` (e.g., `john-doe`)
116
+
117
+ ---
118
+
119
+ ## Commands
120
+
121
+ ### Generate SSH Key
122
+
123
+ ```bash
124
+ cf keygen [--overwrite]
125
+ ```
126
+
127
+ - Generates a new RSA SSH key at `~/.ssh/chipfoundry-key`
128
+ - Displays the public key for registration
129
+ - Use `--overwrite` to regenerate an existing key
130
+ - **Next step**: Submit the public key to [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
131
+
132
+ ### View SSH Key
133
+
134
+ ```bash
135
+ cf keyview
136
+ ```
137
+
138
+ - Displays the current ChipFoundry SSH public key
139
+ - Useful for viewing your key without generating a new one
140
+ - Shows the same registration instructions as `cf keygen`
141
+
142
+ ### Configure User Credentials
143
+
144
+ ```bash
145
+ cf config
146
+ ```
147
+
148
+ - Prompts for your SFTP username and key path
149
+ - Defaults to `~/.ssh/chipfoundry-key`
150
+ - Only needs to be run once per user/machine
151
+
152
+ ### Initialize a New Project
153
+
154
+ ```bash
155
+ cf init [--project-root DIRECTORY]
156
+ ```
157
+
158
+ - **Smart defaults**: Auto-detects project name from directory and project type from GDS files
159
+ - **Interactive prompts**: Shows detected values in prompts for easy acceptance
160
+ - Creates `.cf/project.json` with project metadata
161
+ - **Note**: GDS hash is generated during `push`, not `init`
162
+
163
+ ### Push a Project (Upload)
164
+
165
+ ```bash
166
+ cf push [OPTIONS]
167
+ ```
168
+
169
+ **Options:**
170
+ - `--project-root`: Specify project directory
171
+ - `--force-overwrite`: Overwrite existing files on SFTP
172
+ - `--dry-run`: Preview what would be uploaded
173
+ - `--sftp-username`: Override configured username
174
+ - `--sftp-key`: Override configured key path
175
+
176
+ **What happens:**
177
+ 1. Collects required project files
178
+ 2. Auto-detects project type from GDS file
179
+ 3. Updates project configuration and GDS hash
180
+ 4. Uploads files to SFTP with progress bars
181
+ 5. Shows clean, informative output
182
+
183
+ ### Pull Results
184
+
185
+ ```bash
186
+ cf pull [--project-name NAME]
187
+ ```
188
+
189
+ - Downloads project results from SFTP
190
+ - Saves to `sftp-output/<project_name>/`
191
+ - Shows download progress for each file
192
+
193
+ ### Check Status
194
+
195
+ ```bash
196
+ cf status
197
+ ```
198
+
199
+ - Lists all your projects on the SFTP server
200
+ - Shows which projects have input files and/or results
201
+ - Displays project status in a clean table format
202
+
203
+ ---
204
+
205
+ ## How the GDS Hash Works
206
+
207
+ - The `user_project_wrapper_hash` in `.cf/project.json` is **automatically generated and updated during `push`**
208
+ - The hash is calculated from the actual GDS file being uploaded
209
+ - This ensures the hash always matches the file you are submitting
210
+ - **You do not need to manage or update the hash manually**
211
+ - The hash is NOT generated during `init` because the GDS file may not exist or may change before submission
212
+
213
+ ---
214
+
215
+ ## What Happens When You Run `cf push`?
216
+
217
+ 1. **File Collection:**
218
+ - Checks for required GDS and Verilog files
219
+ - Auto-detects project type (digital, analog, openframe) based on GDS file name
220
+
221
+ 2. **Configuration:**
222
+ - Creates or updates `.cf/project.json`
223
+ - Updates the GDS hash and any CLI-overridden fields
224
+
225
+ 3. **SFTP Upload:**
226
+ - Connects to the SFTP server securely
227
+ - Creates project directory structure
228
+ - Uploads files with progress indicators
229
+ - Shows clean, minimal output
230
+
231
+ 4. **Success:**
232
+ - Displays confirmation with project location
233
+
234
+ ---
235
+
236
+ ## Examples
237
+
238
+ ### Basic Workflow
239
+
240
+ ```bash
241
+ # Generate SSH key and register it
242
+ cf keygen
243
+ # Copy the displayed key to https://chipfoundry.io/sftp-registration
244
+
245
+ # Configure your account
246
+ cf config
247
+ # Enter: john-doe
248
+ # Enter: (press Enter for default key)
249
+
250
+ # Initialize project (in your project directory)
251
+ cf init
252
+ # Project name (detected: my_awesome_project):
253
+ # Project type (digital/analog/openframe) (detected: digital):
254
+
255
+ # Upload your project
256
+ cf push
257
+ # Connecting to sftp.chipfoundry.io...
258
+ # Uploading project.json ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
259
+ # Uploading user_project_wrapper.gds ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
260
+ # ✓ Uploaded to incoming/projects/my_awesome_project
261
+ ```
262
+
263
+ ### Advanced Usage
264
+
265
+ ```bash
266
+ # Preview what would be uploaded
267
+ cf push --dry-run
268
+
269
+ # Force overwrite existing files
270
+ cf push --force-overwrite
271
+
272
+ # Use different project root
273
+ cf push --project-root /path/to/project
274
+
275
+ # Check project status
276
+ cf status
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Troubleshooting
282
+
283
+ - **Missing files:**
284
+ - The tool will error out if required files are missing or if more than one GDS type is present
285
+
286
+ - **Authentication errors:**
287
+ - Run `cf keygen` to generate a new key
288
+ - Ensure your key is registered at [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
289
+ - Check your username with `cf config`
290
+
291
+ - **SFTP errors:**
292
+ - Check your network connection
293
+ - Verify your credentials with `cf config`
294
+
295
+ - **Project type detection:**
296
+ - Only one of the recognized GDS files should be present in your `gds/` directory
297
+
298
+ - **ModuleNotFoundError:**
299
+ - Upgrade the CLI: `pip install --upgrade chipfoundry-cli`
300
+
301
+ ---
302
+
303
+ ## Support
304
+
305
+ - For help, contact info@chipfoundry.io or visit [chipfoundry.io](https://chipfoundry.io)
306
+ - For bug reports or feature requests, open an issue on [GitHub](https://github.com/chipfoundry/cf-cli)
307
+
@@ -0,0 +1,282 @@
1
+ # ChipFoundry CLI (`cf-cli`)
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/chipfoundry-cli?color=blue)](https://badge.fury.io/py/chipfoundry-cli)
4
+ [![PyPI downloads](https://img.shields.io/pypi/dm/chipfoundry-cli.svg)](https://pypi.org/project/chipfoundry-cli/)
5
+
6
+ A command-line tool to automate the submission of ChipFoundry projects to the SFTP server.
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ `cf-cli` is a user-friendly command-line tool for securely submitting your ChipFoundry project files to the official SFTP server. It automatically collects the required files, generates or updates your project configuration, and uploads everything to the correct location on the server.
13
+
14
+ ---
15
+
16
+ ## Installation
17
+
18
+ Install from PyPI:
19
+
20
+ ```bash
21
+ pip install chipfoundry-cli
22
+ cf --help
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Quick Start
28
+
29
+ 1. **Generate SSH Key** (if you don't have one):
30
+ ```bash
31
+ cf keygen
32
+ ```
33
+
34
+ 2. **Register your key** at [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
35
+
36
+ 3. **Configure your credentials**:
37
+ ```bash
38
+ cf config
39
+ ```
40
+
41
+ 4. **Initialize your project**:
42
+ ```bash
43
+ cf init
44
+ ```
45
+
46
+ 5. **Upload your project**:
47
+ ```bash
48
+ cf push
49
+ ```
50
+
51
+ ---
52
+
53
+ ## Project Structure Requirements
54
+
55
+ Your project directory **must** contain:
56
+
57
+ - `gds/` directory with **one** of the following:
58
+ - `user_project_wrapper.gds` (for digital projects)
59
+ - `user_analog_project_wrapper.gds` (for analog projects)
60
+ - `openframe_project_wrapper.gds` (for openframe projects)
61
+ - `verilog/rtl/user_defines.v` (required for digital/analog)
62
+ - `.cf/project.json` (optional; will be created/updated automatically)
63
+
64
+ **Example:**
65
+ ```
66
+ my_project/
67
+ ├── gds/
68
+ │ └── user_project_wrapper.gds
69
+ ├── verilog/
70
+ │ └── rtl/
71
+ │ └── user_defines.v
72
+ └── .cf/
73
+ └── project.json
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Authentication
79
+
80
+ The CLI uses SSH key authentication for secure SFTP access:
81
+
82
+ - **Default key location**: `~/.ssh/chipfoundry-key` (generated by `cf keygen`)
83
+ - **Alternative key**: Specify with `--sftp-key` option
84
+ - **SFTP username**: Required and configured via `cf config`
85
+
86
+ ---
87
+
88
+ ## SFTP Server
89
+
90
+ - **Default server**: `sftp.chipfoundry.io`
91
+ - **Username format**: `firstname-lastname` (e.g., `john-doe`)
92
+
93
+ ---
94
+
95
+ ## Commands
96
+
97
+ ### Generate SSH Key
98
+
99
+ ```bash
100
+ cf keygen [--overwrite]
101
+ ```
102
+
103
+ - Generates a new RSA SSH key at `~/.ssh/chipfoundry-key`
104
+ - Displays the public key for registration
105
+ - Use `--overwrite` to regenerate an existing key
106
+ - **Next step**: Submit the public key to [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
107
+
108
+ ### View SSH Key
109
+
110
+ ```bash
111
+ cf keyview
112
+ ```
113
+
114
+ - Displays the current ChipFoundry SSH public key
115
+ - Useful for viewing your key without generating a new one
116
+ - Shows the same registration instructions as `cf keygen`
117
+
118
+ ### Configure User Credentials
119
+
120
+ ```bash
121
+ cf config
122
+ ```
123
+
124
+ - Prompts for your SFTP username and key path
125
+ - Defaults to `~/.ssh/chipfoundry-key`
126
+ - Only needs to be run once per user/machine
127
+
128
+ ### Initialize a New Project
129
+
130
+ ```bash
131
+ cf init [--project-root DIRECTORY]
132
+ ```
133
+
134
+ - **Smart defaults**: Auto-detects project name from directory and project type from GDS files
135
+ - **Interactive prompts**: Shows detected values in prompts for easy acceptance
136
+ - Creates `.cf/project.json` with project metadata
137
+ - **Note**: GDS hash is generated during `push`, not `init`
138
+
139
+ ### Push a Project (Upload)
140
+
141
+ ```bash
142
+ cf push [OPTIONS]
143
+ ```
144
+
145
+ **Options:**
146
+ - `--project-root`: Specify project directory
147
+ - `--force-overwrite`: Overwrite existing files on SFTP
148
+ - `--dry-run`: Preview what would be uploaded
149
+ - `--sftp-username`: Override configured username
150
+ - `--sftp-key`: Override configured key path
151
+
152
+ **What happens:**
153
+ 1. Collects required project files
154
+ 2. Auto-detects project type from GDS file
155
+ 3. Updates project configuration and GDS hash
156
+ 4. Uploads files to SFTP with progress bars
157
+ 5. Shows clean, informative output
158
+
159
+ ### Pull Results
160
+
161
+ ```bash
162
+ cf pull [--project-name NAME]
163
+ ```
164
+
165
+ - Downloads project results from SFTP
166
+ - Saves to `sftp-output/<project_name>/`
167
+ - Shows download progress for each file
168
+
169
+ ### Check Status
170
+
171
+ ```bash
172
+ cf status
173
+ ```
174
+
175
+ - Lists all your projects on the SFTP server
176
+ - Shows which projects have input files and/or results
177
+ - Displays project status in a clean table format
178
+
179
+ ---
180
+
181
+ ## How the GDS Hash Works
182
+
183
+ - The `user_project_wrapper_hash` in `.cf/project.json` is **automatically generated and updated during `push`**
184
+ - The hash is calculated from the actual GDS file being uploaded
185
+ - This ensures the hash always matches the file you are submitting
186
+ - **You do not need to manage or update the hash manually**
187
+ - The hash is NOT generated during `init` because the GDS file may not exist or may change before submission
188
+
189
+ ---
190
+
191
+ ## What Happens When You Run `cf push`?
192
+
193
+ 1. **File Collection:**
194
+ - Checks for required GDS and Verilog files
195
+ - Auto-detects project type (digital, analog, openframe) based on GDS file name
196
+
197
+ 2. **Configuration:**
198
+ - Creates or updates `.cf/project.json`
199
+ - Updates the GDS hash and any CLI-overridden fields
200
+
201
+ 3. **SFTP Upload:**
202
+ - Connects to the SFTP server securely
203
+ - Creates project directory structure
204
+ - Uploads files with progress indicators
205
+ - Shows clean, minimal output
206
+
207
+ 4. **Success:**
208
+ - Displays confirmation with project location
209
+
210
+ ---
211
+
212
+ ## Examples
213
+
214
+ ### Basic Workflow
215
+
216
+ ```bash
217
+ # Generate SSH key and register it
218
+ cf keygen
219
+ # Copy the displayed key to https://chipfoundry.io/sftp-registration
220
+
221
+ # Configure your account
222
+ cf config
223
+ # Enter: john-doe
224
+ # Enter: (press Enter for default key)
225
+
226
+ # Initialize project (in your project directory)
227
+ cf init
228
+ # Project name (detected: my_awesome_project):
229
+ # Project type (digital/analog/openframe) (detected: digital):
230
+
231
+ # Upload your project
232
+ cf push
233
+ # Connecting to sftp.chipfoundry.io...
234
+ # Uploading project.json ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
235
+ # Uploading user_project_wrapper.gds ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100%
236
+ # ✓ Uploaded to incoming/projects/my_awesome_project
237
+ ```
238
+
239
+ ### Advanced Usage
240
+
241
+ ```bash
242
+ # Preview what would be uploaded
243
+ cf push --dry-run
244
+
245
+ # Force overwrite existing files
246
+ cf push --force-overwrite
247
+
248
+ # Use different project root
249
+ cf push --project-root /path/to/project
250
+
251
+ # Check project status
252
+ cf status
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Troubleshooting
258
+
259
+ - **Missing files:**
260
+ - The tool will error out if required files are missing or if more than one GDS type is present
261
+
262
+ - **Authentication errors:**
263
+ - Run `cf keygen` to generate a new key
264
+ - Ensure your key is registered at [https://chipfoundry.io/sftp-registration](https://chipfoundry.io/sftp-registration)
265
+ - Check your username with `cf config`
266
+
267
+ - **SFTP errors:**
268
+ - Check your network connection
269
+ - Verify your credentials with `cf config`
270
+
271
+ - **Project type detection:**
272
+ - Only one of the recognized GDS files should be present in your `gds/` directory
273
+
274
+ - **ModuleNotFoundError:**
275
+ - Upgrade the CLI: `pip install --upgrade chipfoundry-cli`
276
+
277
+ ---
278
+
279
+ ## Support
280
+
281
+ - For help, contact info@chipfoundry.io or visit [chipfoundry.io](https://chipfoundry.io)
282
+ - For bug reports or feature requests, open an issue on [GitHub](https://github.com/chipfoundry/cf-cli)
@@ -140,6 +140,29 @@ def keygen(overwrite):
140
140
  console.print(f"[red]Unexpected error: {e}[/red]")
141
141
  raise click.Abort()
142
142
 
143
+ @main.command('keyview')
144
+ def keyview():
145
+ """Display the current ChipFoundry SSH key."""
146
+ ssh_dir = Path.home() / '.ssh'
147
+ private_key_path = ssh_dir / 'chipfoundry-key'
148
+ public_key_path = ssh_dir / 'chipfoundry-key.pub'
149
+
150
+ if not public_key_path.exists():
151
+ console.print("[red]No ChipFoundry SSH key found.[/red]")
152
+ console.print("[yellow]Run 'cf keygen' to generate a new key.[/yellow]")
153
+ raise click.Abort()
154
+
155
+ console.print("[cyan]Your ChipFoundry SSH public key:[/cyan]")
156
+ with open(public_key_path, 'r') as f:
157
+ public_key = f.read().strip()
158
+ print(f"{public_key}")
159
+ print("")
160
+ console.print("[bold cyan]Next steps:[/bold cyan]")
161
+ console.print("1. Copy the public key above")
162
+ console.print("2. Submit it to the registration form at: https://chipfoundry.io/sftp-registration")
163
+ console.print("3. Wait for account approval")
164
+ console.print("4. Use 'cf config' to configure your SFTP credentials")
165
+
143
166
  @main.command('init')
144
167
  @click.option('--project-root', required=False, type=click.Path(file_okay=False), help='Directory to create the project in (defaults to current directory).')
145
168
  def init(project_root):
@@ -203,13 +226,12 @@ def init(project_root):
203
226
  @click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
204
227
  @click.option('--sftp-username', required=False, help='SFTP username (defaults to config).')
205
228
  @click.option('--sftp-key', type=click.Path(exists=True, dir_okay=False), help='Path to SFTP private key file (defaults to config).', default=None, show_default=False)
206
- @click.option('--sftp-password', help='SFTP password. If not provided, will prompt securely.', default=None)
207
229
  @click.option('--project-id', help='Project ID (e.g., "user123_proj456"). Overrides project.json if exists.')
208
230
  @click.option('--project-name', help='Project name (e.g., "my_project"). Overrides project.json if exists.')
209
231
  @click.option('--project-type', help='Project type (auto-detected if not provided).', default=None)
210
232
  @click.option('--force-overwrite', is_flag=True, help='Overwrite existing files on SFTP without prompting.')
211
233
  @click.option('--dry-run', is_flag=True, help='Preview actions without uploading files.')
212
- def push(project_root, sftp_host, sftp_username, sftp_key, sftp_password, project_id, project_name, project_type, force_overwrite, dry_run):
234
+ def push(project_root, sftp_host, sftp_username, sftp_key, project_id, project_name, project_type, force_overwrite, dry_run):
213
235
  """Upload your project files to the ChipFoundry SFTP server."""
214
236
  # If .cf/project.json exists in cwd, use it as default project_root and project_name
215
237
  cwd_root, cwd_project_name = get_project_json_from_cwd()
@@ -229,25 +251,17 @@ def push(project_root, sftp_host, sftp_username, sftp_key, sftp_password, projec
229
251
  raise click.Abort()
230
252
  if not sftp_key:
231
253
  sftp_key = config.get("sftp_key")
232
- # Determine which authentication method to use
233
- key_path = sftp_key
234
- password = sftp_password
254
+
235
255
  # Always resolve key_path to absolute path if set
236
- if key_path:
237
- key_path = os.path.abspath(os.path.expanduser(key_path))
238
- if not key_path and not password:
239
- if os.path.exists(DEFAULT_SSH_KEY):
240
- key_path = DEFAULT_SSH_KEY
241
- else:
242
- console.print("[yellow]No SFTP credentials found. Please run 'cf config' first.[/yellow]")
243
- raise click.Abort()
244
- elif key_path and password:
245
- console.print("[red]Options --sftp-password and --sftp-key are mutually exclusive.[/red]")
246
- raise click.UsageError("Options --sftp-password and --sftp-key are mutually exclusive.")
247
- elif key_path and not password:
248
- if not os.path.exists(key_path):
249
- console.print(f"[red]SFTP key file not found: {key_path}[/red]")
250
- raise click.UsageError(f"SFTP key file not found: {key_path}")
256
+ if sftp_key:
257
+ key_path = os.path.abspath(os.path.expanduser(sftp_key))
258
+ else:
259
+ key_path = DEFAULT_SSH_KEY
260
+
261
+ if not os.path.exists(key_path):
262
+ console.print(f"[red]SFTP key file not found: {key_path}[/red]")
263
+ console.print("[yellow]Please run 'cf keygen' to generate a key or 'cf config' to set a custom key path.[/yellow]")
264
+ raise click.Abort()
251
265
 
252
266
  # Collect project files
253
267
  try:
@@ -321,7 +335,6 @@ def push(project_root, sftp_host, sftp_username, sftp_key, sftp_password, projec
321
335
  sftp, transport = sftp_connect(
322
336
  host=sftp_host,
323
337
  username=sftp_username,
324
- password=password,
325
338
  key_path=key_path
326
339
  )
327
340
  # Ensure the project directory exists before uploading
@@ -356,8 +369,7 @@ def push(project_root, sftp_host, sftp_username, sftp_key, sftp_password, projec
356
369
  @click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
357
370
  @click.option('--sftp-username', required=False, help='SFTP username (defaults to config).')
358
371
  @click.option('--sftp-key', type=click.Path(exists=True, dir_okay=False), help='Path to SFTP private key file (defaults to config).', default=None, show_default=False)
359
- @click.option('--sftp-password', help='SFTP password. If not provided, will prompt securely.', default=None)
360
- def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key, sftp_password):
372
+ def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key):
361
373
  """Download results/artifacts from SFTP output dir to local sftp-output/<project_name>."""
362
374
  # If .cf/project.json exists in cwd, use its project name as default
363
375
  _, cwd_project_name = get_project_json_from_cwd()
@@ -374,43 +386,28 @@ def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key, sftp_pass
374
386
  raise click.Abort()
375
387
  if not sftp_key:
376
388
  sftp_key = config.get("sftp_key")
377
- key_path = sftp_key
378
- password = sftp_password
389
+
379
390
  # Always resolve key_path to absolute path if set
380
- if key_path:
381
- key_path = os.path.abspath(os.path.expanduser(key_path))
382
- if not key_path and not password:
383
- if os.path.exists(DEFAULT_SSH_KEY):
384
- key_path = DEFAULT_SSH_KEY
385
- console.print(f"[INFO] Using default SSH key: {DEFAULT_SSH_KEY}", style="bold cyan")
386
- else:
387
- console.print("[WARN] No SFTP key or password provided, and no default key found at ~/.ssh/id_rsa.", style="bold yellow")
388
- auth_method = click.prompt("Choose authentication method (key/password)", type=click.Choice(['key', 'password']), show_choices=True)
389
- if auth_method == 'key':
390
- key_path = click.prompt("Enter path to SFTP private key", type=click.Path(exists=True, dir_okay=False))
391
- else:
392
- password = click.prompt("SFTP Password", hide_input=True)
393
- elif key_path and password:
394
- console.print("[ERROR] Options --sftp-password and --sftp-key are mutually exclusive.", style="bold red")
395
- raise click.UsageError("Options --sftp-password and --sftp-key are mutually exclusive.")
396
- elif not key_path and password:
397
- pass # password provided
398
- elif key_path and not password:
399
- if not os.path.exists(key_path):
400
- console.print(f"[ERROR] SFTP key file not found: {key_path}", style="bold red")
401
- raise click.UsageError(f"SFTP key file not found: {key_path}")
391
+ if sftp_key:
392
+ key_path = os.path.abspath(os.path.expanduser(sftp_key))
393
+ else:
394
+ key_path = DEFAULT_SSH_KEY
395
+
396
+ if not os.path.exists(key_path):
397
+ console.print(f"[red]SFTP key file not found: {key_path}[/red]")
398
+ console.print("[yellow]Please run 'cf keygen' to generate a key or 'cf config' to set a custom key path.[/yellow]")
399
+ raise click.Abort()
402
400
 
403
- console.print(f"[INFO] Connecting to SFTP: {sftp_host} as {sftp_username}", style="bold cyan")
401
+ console.print(f"Connecting to {sftp_host}...")
404
402
  transport = None
405
403
  try:
406
404
  sftp, transport = sftp_connect(
407
405
  host=sftp_host,
408
406
  username=sftp_username,
409
- password=password,
410
407
  key_path=key_path
411
408
  )
412
409
  except Exception as e:
413
- console.print(f"[ERROR] Failed to connect to SFTP: {e}", style="bold red")
410
+ console.print(f"[red]Failed to connect to SFTP: {e}[/red]")
414
411
  raise click.Abort()
415
412
  try:
416
413
  remote_dir = f"outgoing/results/{project_name}"
@@ -456,54 +453,38 @@ def pull(project_name, output_dir, sftp_host, sftp_username, sftp_key, sftp_pass
456
453
  @click.option('--sftp-host', default=DEFAULT_SFTP_HOST, show_default=True, help='SFTP server hostname.')
457
454
  @click.option('--sftp-username', required=False, help='SFTP username (defaults to config).')
458
455
  @click.option('--sftp-key', type=click.Path(exists=True, dir_okay=False), help='Path to SFTP private key file (defaults to config).', default=None, show_default=False)
459
- @click.option('--sftp-password', help='SFTP password. If not provided, will prompt securely.', default=None)
460
- def status(sftp_host, sftp_username, sftp_key, sftp_password):
456
+ def status(sftp_host, sftp_username, sftp_key):
461
457
  """Show all projects and outputs for the user on the SFTP server."""
462
458
  config = load_user_config()
463
459
  if not sftp_username:
464
460
  sftp_username = config.get("sftp_username")
465
461
  if not sftp_username:
466
- console.print("[bold red]No SFTP username provided and not found in config. Please run 'chipfoundry init' or provide --sftp-username.[/bold red]")
462
+ console.print("[red]No SFTP username provided and not found in config. Please run 'cf config' or provide --sftp-username.[/red]")
467
463
  raise click.Abort()
468
464
  if not sftp_key:
469
465
  sftp_key = config.get("sftp_key")
470
- key_path = sftp_key
471
- password = sftp_password
466
+
472
467
  # Always resolve key_path to absolute path if set
473
- if key_path:
474
- key_path = os.path.abspath(os.path.expanduser(key_path))
475
- if not key_path and not password:
476
- if os.path.exists(DEFAULT_SSH_KEY):
477
- key_path = DEFAULT_SSH_KEY
478
- console.print(f"[INFO] Using default SSH key: {DEFAULT_SSH_KEY}", style="bold cyan")
479
- else:
480
- console.print("[WARN] No SFTP key or password provided, and no default key found at ~/.ssh/id_rsa.", style="bold yellow")
481
- auth_method = click.prompt("Choose authentication method (key/password)", type=click.Choice(['key', 'password']), show_choices=True)
482
- if auth_method == 'key':
483
- key_path = click.prompt("Enter path to SFTP private key", type=click.Path(exists=True, dir_okay=False))
484
- else:
485
- password = click.prompt("SFTP Password", hide_input=True)
486
- elif key_path and password:
487
- console.print("[ERROR] Options --sftp-password and --sftp-key are mutually exclusive.", style="bold red")
488
- raise click.UsageError("Options --sftp-password and --sftp-key are mutually exclusive.")
489
- elif not key_path and password:
490
- pass # password provided
491
- elif key_path and not password:
492
- if not os.path.exists(key_path):
493
- console.print(f"[ERROR] SFTP key file not found: {key_path}", style="bold red")
494
- raise click.UsageError(f"SFTP key file not found: {key_path}")
468
+ if sftp_key:
469
+ key_path = os.path.abspath(os.path.expanduser(sftp_key))
470
+ else:
471
+ key_path = DEFAULT_SSH_KEY
472
+
473
+ if not os.path.exists(key_path):
474
+ console.print(f"[red]SFTP key file not found: {key_path}[/red]")
475
+ console.print("[yellow]Please run 'cf keygen' to generate a key or 'cf config' to set a custom key path.[/yellow]")
476
+ raise click.Abort()
495
477
 
496
- console.print(f"[INFO] Connecting to SFTP: {sftp_host} as {sftp_username}", style="bold cyan")
478
+ console.print(f"Connecting to {sftp_host}...")
497
479
  transport = None
498
480
  try:
499
481
  sftp, transport = sftp_connect(
500
482
  host=sftp_host,
501
483
  username=sftp_username,
502
- password=password,
503
484
  key_path=key_path
504
485
  )
505
486
  except Exception as e:
506
- console.print(f"[ERROR] Failed to connect to SFTP: {e}", style="bold red")
487
+ console.print(f"[red]Failed to connect to SFTP: {e}[/red]")
507
488
  raise click.Abort()
508
489
  try:
509
490
  # List projects in incoming/projects/ and outgoing/results/
@@ -121,16 +121,13 @@ def load_private_key(key_path, password=None):
121
121
  last_exception = e
122
122
  raise RuntimeError(f"Could not load private key: {last_exception}")
123
123
 
124
- def sftp_connect(host: str, username: str, password: str = None, key_path: str = None):
124
+ def sftp_connect(host: str, username: str, key_path: str):
125
125
  """
126
126
  Establish an SFTP connection using paramiko. Returns an SFTP client.
127
127
  """
128
128
  transport = paramiko.Transport((host, 22))
129
- if key_path:
130
- private_key = load_private_key(key_path)
131
- transport.connect(username=username, pkey=private_key)
132
- else:
133
- transport.connect(username=username, password=password)
129
+ private_key = load_private_key(key_path)
130
+ transport.connect(username=username, pkey=private_key)
134
131
  sftp = paramiko.SFTPClient.from_transport(transport)
135
132
  return sftp, transport
136
133
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "chipfoundry-cli"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  description = "CLI tool to automate ChipFoundry project submission to SFTP server"
5
5
  authors = ["ChipFoundry <marwan.abbas@chipfoundry.io>"]
6
6
  readme = "README.md"
@@ -1,177 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: chipfoundry-cli
3
- Version: 1.0.0
4
- Summary: CLI tool to automate ChipFoundry project submission to SFTP server
5
- Home-page: https://chipfoundry.io
6
- License: Apache-2.0
7
- Author: ChipFoundry
8
- Author-email: marwan.abbas@chipfoundry.io
9
- Requires-Python: >=3.8.0
10
- Classifier: License :: OSI Approved :: Apache Software License
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.8
13
- Classifier: Programming Language :: Python :: 3.9
14
- Classifier: Programming Language :: Python :: 3.10
15
- Classifier: Programming Language :: Python :: 3.11
16
- Classifier: Programming Language :: Python :: 3.12
17
- Classifier: Programming Language :: Python :: 3.13
18
- Requires-Dist: click (>=8.0.0,<9)
19
- Requires-Dist: paramiko (>=3.0.0,<4)
20
- Requires-Dist: rich (>=13,<14)
21
- Requires-Dist: toml (>=0.10,<1.0)
22
- Project-URL: Repository, https://github.com/chipfoundry/cf-cli
23
- Description-Content-Type: text/markdown
24
-
25
- # ChipFoundry CLI (`cf-cli`)
26
-
27
- A command-line tool to automate the submission of ChipFoundry projects to the SFTP server.
28
-
29
- ---
30
-
31
- ## Overview
32
-
33
- `cf-cli` is a user-friendly command-line tool for securely submitting your ChipFoundry project files to the official SFTP server. It automatically collects the required files, generates or updates your project configuration, and uploads everything to the correct location on the server.
34
-
35
- ---
36
-
37
- ## Installation
38
-
39
- Install from PyPI:
40
-
41
- ```bash
42
- pip install chipfoundry-cli
43
- chipfoundry --help
44
- ```
45
-
46
- ---
47
-
48
- ## Project Structure Requirements
49
-
50
- Your project directory **must** contain:
51
-
52
- - `gds/` directory with **one** of the following:
53
- - `user_project_wrapper.gds` (for digital projects)
54
- - `user_analog_project_wrapper.gds` (for analog projects)
55
- - `openframe_project_wrapper.gds` (for openframe projects)
56
- - `verilog/rtl/user_defines.v` (required for digital/analog)
57
- - `.cf/project.json` (optional; will be created/updated automatically)
58
-
59
- **Example:**
60
- ```
61
- my_project/
62
- ├── gds/
63
- │ └── user_project_wrapper.gds
64
- ├── verilog/
65
- │ └── rtl/
66
- │ └── user_defines.v
67
- └── .cf/
68
- └── project.json
69
- ```
70
-
71
- ---
72
-
73
- ## Authentication
74
-
75
- - By default, the tool will look for an SSH key at `~/.ssh/id_rsa`.
76
- - You can specify a different key with `--sftp-key`.
77
- - If no key is found, you will be prompted to enter a key path or your SFTP password.
78
- - Your SFTP username is required (provided by ChipFoundry).
79
-
80
- ---
81
-
82
- ## SFTP Server
83
-
84
- - The default SFTP server is `sftp.chipfoundry.io` (no need to specify unless you want to override).
85
-
86
- ---
87
-
88
- ## Usage
89
-
90
- ### Configure User Credentials
91
-
92
- ```bash
93
- chipfoundry config
94
- ```
95
- - Prompts for your SFTP username and key path. Only needs to be run once per user/machine.
96
-
97
- ### Initialize a New Project
98
-
99
- ```bash
100
- chipfoundry init
101
- ```
102
- - Prompts for project name, type (auto-detected from GDS file if present), and version.
103
- - Creates `.cf/project.json` in the current directory.
104
- - **Note:** The GDS hash is NOT generated at this step (see below).
105
-
106
- ### Push a Project (Upload)
107
-
108
- ```bash
109
- chipfoundry push
110
- ```
111
- - Run from your project directory (with `.cf/project.json`).
112
- - Collects files, updates the GDS hash, and uploads to SFTP.
113
-
114
- ### Pull Results
115
-
116
- ```bash
117
- chipfoundry pull
118
- ```
119
- - Downloads results for the current project to a local directory.
120
-
121
- ### Check Status
122
-
123
- ```bash
124
- chipfoundry status
125
- ```
126
- - Shows all your projects and their input/output status on the SFTP server.
127
-
128
- ---
129
-
130
- ## How the GDS Hash Works
131
-
132
- - The `user_project_wrapper_hash` in `.cf/project.json` is **automatically generated and updated during `push`**.
133
- - The hash is calculated from the actual GDS file being uploaded.
134
- - This ensures the hash always matches the file you are submitting.
135
- - **You do not need to manage or update the hash manually.**
136
- - The hash is NOT generated during `init` because the GDS file may not exist or may change before submission.
137
-
138
- ---
139
-
140
- ## What Happens When You Run `chipfoundry push`?
141
-
142
- 1. **File Collection:**
143
- - The tool checks for the required GDS and Verilog files.
144
- - It auto-detects your project type (digital, analog, openframe) based on the GDS file name.
145
- 2. **Configuration:**
146
- - If `.cf/project.json` does not exist, it is created.
147
- - The tool updates the GDS hash and any fields you override via CLI.
148
- 3. **SFTP Upload:**
149
- - Connects to the SFTP server as your user.
150
- - Ensures the directory `incoming/projects/<project_name>` exists.
151
- - Uploads `.cf/project.json`, the GDS file, and `verilog/rtl/user_defines.v` (if present).
152
- - Shows a progress bar for each file upload.
153
- 4. **Success:**
154
- - You’ll see a green success message when all files are uploaded.
155
-
156
- ---
157
-
158
- ## Troubleshooting
159
-
160
- - **Missing files:**
161
- - The tool will error out if required files are missing or if more than one GDS type is present.
162
- - **Authentication errors:**
163
- - Make sure your SSH key is valid and registered with ChipFoundry, or use your password.
164
- - **SFTP errors:**
165
- - Check your network connection and credentials.
166
- - **Project type detection:**
167
- - Only one of the recognized GDS files should be present in your `gds/` directory.
168
- - **ModuleNotFoundError: No module named 'toml':**
169
- - This means your environment is missing the `toml` dependency. Upgrade `chipfoundry-cli` with `pip install --upgrade chipfoundry-cli`, or install `toml` manually with `pip install 'toml>=0.10,<1.0'`.
170
-
171
- ---
172
-
173
- ## Support
174
-
175
- - For help, contact info@chipfoundry.io or visit [chipfoundry.io](https://chipfoundry.io)
176
- - For bug reports or feature requests, open an issue on [GitHub](https://github.com/chipfoundry/cf-cli)
177
-
@@ -1,152 +0,0 @@
1
- # ChipFoundry CLI (`cf-cli`)
2
-
3
- A command-line tool to automate the submission of ChipFoundry projects to the SFTP server.
4
-
5
- ---
6
-
7
- ## Overview
8
-
9
- `cf-cli` is a user-friendly command-line tool for securely submitting your ChipFoundry project files to the official SFTP server. It automatically collects the required files, generates or updates your project configuration, and uploads everything to the correct location on the server.
10
-
11
- ---
12
-
13
- ## Installation
14
-
15
- Install from PyPI:
16
-
17
- ```bash
18
- pip install chipfoundry-cli
19
- chipfoundry --help
20
- ```
21
-
22
- ---
23
-
24
- ## Project Structure Requirements
25
-
26
- Your project directory **must** contain:
27
-
28
- - `gds/` directory with **one** of the following:
29
- - `user_project_wrapper.gds` (for digital projects)
30
- - `user_analog_project_wrapper.gds` (for analog projects)
31
- - `openframe_project_wrapper.gds` (for openframe projects)
32
- - `verilog/rtl/user_defines.v` (required for digital/analog)
33
- - `.cf/project.json` (optional; will be created/updated automatically)
34
-
35
- **Example:**
36
- ```
37
- my_project/
38
- ├── gds/
39
- │ └── user_project_wrapper.gds
40
- ├── verilog/
41
- │ └── rtl/
42
- │ └── user_defines.v
43
- └── .cf/
44
- └── project.json
45
- ```
46
-
47
- ---
48
-
49
- ## Authentication
50
-
51
- - By default, the tool will look for an SSH key at `~/.ssh/id_rsa`.
52
- - You can specify a different key with `--sftp-key`.
53
- - If no key is found, you will be prompted to enter a key path or your SFTP password.
54
- - Your SFTP username is required (provided by ChipFoundry).
55
-
56
- ---
57
-
58
- ## SFTP Server
59
-
60
- - The default SFTP server is `sftp.chipfoundry.io` (no need to specify unless you want to override).
61
-
62
- ---
63
-
64
- ## Usage
65
-
66
- ### Configure User Credentials
67
-
68
- ```bash
69
- chipfoundry config
70
- ```
71
- - Prompts for your SFTP username and key path. Only needs to be run once per user/machine.
72
-
73
- ### Initialize a New Project
74
-
75
- ```bash
76
- chipfoundry init
77
- ```
78
- - Prompts for project name, type (auto-detected from GDS file if present), and version.
79
- - Creates `.cf/project.json` in the current directory.
80
- - **Note:** The GDS hash is NOT generated at this step (see below).
81
-
82
- ### Push a Project (Upload)
83
-
84
- ```bash
85
- chipfoundry push
86
- ```
87
- - Run from your project directory (with `.cf/project.json`).
88
- - Collects files, updates the GDS hash, and uploads to SFTP.
89
-
90
- ### Pull Results
91
-
92
- ```bash
93
- chipfoundry pull
94
- ```
95
- - Downloads results for the current project to a local directory.
96
-
97
- ### Check Status
98
-
99
- ```bash
100
- chipfoundry status
101
- ```
102
- - Shows all your projects and their input/output status on the SFTP server.
103
-
104
- ---
105
-
106
- ## How the GDS Hash Works
107
-
108
- - The `user_project_wrapper_hash` in `.cf/project.json` is **automatically generated and updated during `push`**.
109
- - The hash is calculated from the actual GDS file being uploaded.
110
- - This ensures the hash always matches the file you are submitting.
111
- - **You do not need to manage or update the hash manually.**
112
- - The hash is NOT generated during `init` because the GDS file may not exist or may change before submission.
113
-
114
- ---
115
-
116
- ## What Happens When You Run `chipfoundry push`?
117
-
118
- 1. **File Collection:**
119
- - The tool checks for the required GDS and Verilog files.
120
- - It auto-detects your project type (digital, analog, openframe) based on the GDS file name.
121
- 2. **Configuration:**
122
- - If `.cf/project.json` does not exist, it is created.
123
- - The tool updates the GDS hash and any fields you override via CLI.
124
- 3. **SFTP Upload:**
125
- - Connects to the SFTP server as your user.
126
- - Ensures the directory `incoming/projects/<project_name>` exists.
127
- - Uploads `.cf/project.json`, the GDS file, and `verilog/rtl/user_defines.v` (if present).
128
- - Shows a progress bar for each file upload.
129
- 4. **Success:**
130
- - You’ll see a green success message when all files are uploaded.
131
-
132
- ---
133
-
134
- ## Troubleshooting
135
-
136
- - **Missing files:**
137
- - The tool will error out if required files are missing or if more than one GDS type is present.
138
- - **Authentication errors:**
139
- - Make sure your SSH key is valid and registered with ChipFoundry, or use your password.
140
- - **SFTP errors:**
141
- - Check your network connection and credentials.
142
- - **Project type detection:**
143
- - Only one of the recognized GDS files should be present in your `gds/` directory.
144
- - **ModuleNotFoundError: No module named 'toml':**
145
- - This means your environment is missing the `toml` dependency. Upgrade `chipfoundry-cli` with `pip install --upgrade chipfoundry-cli`, or install `toml` manually with `pip install 'toml>=0.10,<1.0'`.
146
-
147
- ---
148
-
149
- ## Support
150
-
151
- - For help, contact info@chipfoundry.io or visit [chipfoundry.io](https://chipfoundry.io)
152
- - For bug reports or feature requests, open an issue on [GitHub](https://github.com/chipfoundry/cf-cli)
File without changes