plash-cli 0.0.2__tar.gz → 0.0.4__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: CLI for the Plash hosting service
5
5
  Home-page: https://github.com/AnswerDotAI/plash_cli
6
6
  Author: Jeremy Howard
@@ -23,6 +23,19 @@ License-File: LICENSE
23
23
  Requires-Dist: fastcore
24
24
  Requires-Dist: httpx
25
25
  Provides-Extra: dev
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: license-file
35
+ Dynamic: provides-extra
36
+ Dynamic: requires-dist
37
+ Dynamic: requires-python
38
+ Dynamic: summary
26
39
 
27
40
  # plash-cli
28
41
 
@@ -47,20 +60,20 @@ $ pip install git+https://github.com/AnswerDotAI/plash-cli.git
47
60
  or from [pypi](https://pypi.org/project/plash-cli/)
48
61
 
49
62
  ``` sh
50
- $ pip install plash_cli
63
+ $ pip install plash-cli
51
64
  ```
52
65
 
53
66
  ## Deploy Your First FastHTML App
54
67
 
55
- ### Set Up Your Plash Token
68
+ ### Authentication
56
69
 
57
- You’ll need to set a PLASH_TOKEN and PLASH_EMAIL environment variables
58
- to use Plash. To obtain these, do the following:
70
+ To use Plash, you’ll need to authenticate:
59
71
 
60
72
  1. Signup for an account at https://pla.sh/
61
73
  2. Activate your Plash subscription
62
- 3. Follow instructions in your Plash dashboard to save credentials
63
- locally
74
+ 3. Run `plash_login` in your terminal
75
+ 4. A browser window will open for authentication
76
+ 5. Once authenticated, your credentials will be saved locally
64
77
 
65
78
  ### Create a FastHTML App
66
79
 
@@ -95,6 +108,19 @@ Run `plash_deploy`. Your app will be live at
95
108
  `https://<app-name>.pla.sh`. The URL will be shown in the deployment
96
109
  output.
97
110
 
111
+ ### Managing Your App
112
+
113
+ Plash CLI provides several commands to manage your apps:
114
+
115
+ - `plash_login` - Login to Plash
116
+ - `plash_deploy` - Deploy your app
117
+ - `plash_view` - Open your deployed app in a browser
118
+ - `plash_start` - Start your app if it’s stopped
119
+ - `plash_stop` - Stop your running app
120
+ - `plash_logs` - View your app’s logs
121
+ - `plash_download` - Download your deployed app files
122
+ - `plash_delete` - Delete your deployed app
123
+
98
124
  ### App Dependencies
99
125
 
100
126
  If your app needs additional dependencies to run, we offer a number of
@@ -147,3 +173,48 @@ in your Plash container, to modify your apps behavior for local and
147
173
  production development. You can download any deployed database names by
148
174
  clicking the Download App button to get a compressed file of all files
149
175
  in your /app folder in your deployed app.
176
+
177
+ ## Deploy to Pla.sh via GitHub Actions
178
+
179
+ If you’d like to deploy your plash app every time you commit changes to
180
+ your GitHub repo, you can use the following workflow to your
181
+ `.github/workflows/` folder in the root of your repo:
182
+
183
+ ``` yaml
184
+ name: Deploy to Plash
185
+
186
+ on:
187
+ push:
188
+ branches:
189
+ - main
190
+ workflow_dispatch:
191
+
192
+ jobs:
193
+ deploy:
194
+ runs-on: ubuntu-latest
195
+ steps:
196
+ - name: Checkout repository
197
+ uses: actions/checkout@v3
198
+
199
+ - name: Set up Python
200
+ uses: actions/setup-python@v4
201
+ with:
202
+ python-version: '3.x'
203
+
204
+ - name: Create Plash config
205
+ run: |
206
+ mkdir -p ~/.config
207
+ echo '${{ secrets.PLASH_CONFIG }}' > ~/.config/plash_config.json
208
+
209
+ - name: Install plash-cli with pip
210
+ run: pip install plash-cli
211
+
212
+ - name: Deploy to Plash
213
+ run: plash_deploy
214
+ ```
215
+
216
+ It relies on storing your plash config as a secret named `PLASH_CONFIG`
217
+ in your GitHub repo. After running `plash_login`, you can find these in
218
+ `~/.config/plash_config.json` (unless you haved changed the
219
+ XDG_CONFIG_HOME environment variable). Learn more about GitHub secrets
220
+ [here](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions).
@@ -21,20 +21,20 @@ $ pip install git+https://github.com/AnswerDotAI/plash-cli.git
21
21
  or from [pypi](https://pypi.org/project/plash-cli/)
22
22
 
23
23
  ``` sh
24
- $ pip install plash_cli
24
+ $ pip install plash-cli
25
25
  ```
26
26
 
27
27
  ## Deploy Your First FastHTML App
28
28
 
29
- ### Set Up Your Plash Token
29
+ ### Authentication
30
30
 
31
- You’ll need to set a PLASH_TOKEN and PLASH_EMAIL environment variables
32
- to use Plash. To obtain these, do the following:
31
+ To use Plash, you’ll need to authenticate:
33
32
 
34
33
  1. Signup for an account at https://pla.sh/
35
34
  2. Activate your Plash subscription
36
- 3. Follow instructions in your Plash dashboard to save credentials
37
- locally
35
+ 3. Run `plash_login` in your terminal
36
+ 4. A browser window will open for authentication
37
+ 5. Once authenticated, your credentials will be saved locally
38
38
 
39
39
  ### Create a FastHTML App
40
40
 
@@ -69,6 +69,19 @@ Run `plash_deploy`. Your app will be live at
69
69
  `https://<app-name>.pla.sh`. The URL will be shown in the deployment
70
70
  output.
71
71
 
72
+ ### Managing Your App
73
+
74
+ Plash CLI provides several commands to manage your apps:
75
+
76
+ - `plash_login` - Login to Plash
77
+ - `plash_deploy` - Deploy your app
78
+ - `plash_view` - Open your deployed app in a browser
79
+ - `plash_start` - Start your app if it’s stopped
80
+ - `plash_stop` - Stop your running app
81
+ - `plash_logs` - View your app’s logs
82
+ - `plash_download` - Download your deployed app files
83
+ - `plash_delete` - Delete your deployed app
84
+
72
85
  ### App Dependencies
73
86
 
74
87
  If your app needs additional dependencies to run, we offer a number of
@@ -121,3 +134,48 @@ in your Plash container, to modify your apps behavior for local and
121
134
  production development. You can download any deployed database names by
122
135
  clicking the Download App button to get a compressed file of all files
123
136
  in your /app folder in your deployed app.
137
+
138
+ ## Deploy to Pla.sh via GitHub Actions
139
+
140
+ If you’d like to deploy your plash app every time you commit changes to
141
+ your GitHub repo, you can use the following workflow to your
142
+ `.github/workflows/` folder in the root of your repo:
143
+
144
+ ``` yaml
145
+ name: Deploy to Plash
146
+
147
+ on:
148
+ push:
149
+ branches:
150
+ - main
151
+ workflow_dispatch:
152
+
153
+ jobs:
154
+ deploy:
155
+ runs-on: ubuntu-latest
156
+ steps:
157
+ - name: Checkout repository
158
+ uses: actions/checkout@v3
159
+
160
+ - name: Set up Python
161
+ uses: actions/setup-python@v4
162
+ with:
163
+ python-version: '3.x'
164
+
165
+ - name: Create Plash config
166
+ run: |
167
+ mkdir -p ~/.config
168
+ echo '${{ secrets.PLASH_CONFIG }}' > ~/.config/plash_config.json
169
+
170
+ - name: Install plash-cli with pip
171
+ run: pip install plash-cli
172
+
173
+ - name: Deploy to Plash
174
+ run: plash_deploy
175
+ ```
176
+
177
+ It relies on storing your plash config as a secret named `PLASH_CONFIG`
178
+ in your GitHub repo. After running `plash_login`, you can find these in
179
+ `~/.config/plash_config.json` (unless you haved changed the
180
+ XDG_CONFIG_HOME environment variable). Learn more about GitHub secrets
181
+ [here](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions).
@@ -0,0 +1 @@
1
+ __version__ = "0.0.4"
@@ -0,0 +1,21 @@
1
+ # Autogenerated by nbdev
2
+
3
+ d = { 'settings': { 'branch': 'main',
4
+ 'doc_baseurl': '/plash_cli',
5
+ 'doc_host': 'https://AnswerDotAI.github.io',
6
+ 'git_url': 'https://github.com/AnswerDotAI/plash_cli',
7
+ 'lib_path': 'plash_cli'},
8
+ 'syms': { 'plash_cli.core': { 'plash_cli.core.create_tar_archive': ('core.html#create_tar_archive', 'plash_cli/core.py'),
9
+ 'plash_cli.core.delete': ('core.html#delete', 'plash_cli/core.py'),
10
+ 'plash_cli.core.deploy': ('core.html#deploy', 'plash_cli/core.py'),
11
+ 'plash_cli.core.download': ('core.html#download', 'plash_cli/core.py'),
12
+ 'plash_cli.core.endpoint': ('core.html#endpoint', 'plash_cli/core.py'),
13
+ 'plash_cli.core.endpoint_func': ('core.html#endpoint_func', 'plash_cli/core.py'),
14
+ 'plash_cli.core.get_app_id': ('core.html#get_app_id', 'plash_cli/core.py'),
15
+ 'plash_cli.core.get_client': ('core.html#get_client', 'plash_cli/core.py'),
16
+ 'plash_cli.core.is_included': ('core.html#is_included', 'plash_cli/core.py'),
17
+ 'plash_cli.core.login': ('core.html#login', 'plash_cli/core.py'),
18
+ 'plash_cli.core.mk_auth_req': ('core.html#mk_auth_req', 'plash_cli/core.py'),
19
+ 'plash_cli.core.poll_cookies': ('core.html#poll_cookies', 'plash_cli/core.py'),
20
+ 'plash_cli.core.validate_app': ('core.html#validate_app', 'plash_cli/core.py'),
21
+ 'plash_cli.core.view': ('core.html#view', 'plash_cli/core.py')}}}
@@ -0,0 +1,204 @@
1
+ """The Plash CLI tool"""
2
+
3
+ # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.
4
+
5
+ # %% auto 0
6
+ __all__ = ['PLASH_CONFIG_HOME', 'stop', 'start', 'logs', 'get_client', 'mk_auth_req', 'get_app_id', 'endpoint', 'is_included',
7
+ 'create_tar_archive', 'validate_app', 'poll_cookies', 'login', 'deploy', 'view', 'delete', 'endpoint_func',
8
+ 'download']
9
+
10
+ # %% ../nbs/00_core.ipynb 2
11
+ from fastcore.all import *
12
+ from fastcore.xdg import *
13
+ import secrets, webbrowser, json, httpx, io, tarfile
14
+ from pathlib import Path
15
+ from uuid import uuid4
16
+ from time import time, sleep
17
+
18
+ import io, sys, tarfile
19
+
20
+ # %% ../nbs/00_core.ipynb 4
21
+ PLASH_CONFIG_HOME = xdg_config_home() / 'plash_config.json'
22
+
23
+ # %% ../nbs/00_core.ipynb 5
24
+ def get_client(cookie_file):
25
+ client = httpx.Client()
26
+ if not cookie_file.exists():
27
+ raise FileNotFoundError("Plash config not found. Please run plash_login and try again.")
28
+ cookies = Path(cookie_file).read_json()
29
+ client.cookies.update(cookies)
30
+ return client
31
+
32
+ # %% ../nbs/00_core.ipynb 6
33
+ def mk_auth_req(url:str, method:str='get', **kwargs): return getattr(get_client(PLASH_CONFIG_HOME), method)(url, **kwargs)
34
+
35
+ # %% ../nbs/00_core.ipynb 7
36
+ def get_app_id(path:Path):
37
+ plash_app = Path(path) / '.plash'
38
+ if not plash_app.exists(): raise FileNotFoundError(f"File not found: {plash_app=}")
39
+ return parse_env(fn=plash_app)['PLASH_APP_ID']
40
+
41
+ # %% ../nbs/00_core.ipynb 8
42
+ def endpoint(path, local, port=None):
43
+ p = "http" if local else "https"
44
+ d = f"localhost:{port}" if local else "pla.sh"
45
+ return f"{p}://{d}{path}"
46
+
47
+ # %% ../nbs/00_core.ipynb 9
48
+ def is_included(path):
49
+ "Returns True if path should be included in deployment"
50
+ if path.name.startswith('.'): return False
51
+ if path.suffix == '.pyc': return False
52
+ excludes = {'.git', '__pycache__', '.gitignore', '.env',
53
+ '.pytest_cache', '.venv', 'venv', '.ipynb_checkpoints',
54
+ '.vscode', '.idea', '.sesskey'}
55
+ return not any(p in excludes for p in path.parts)
56
+
57
+ # %% ../nbs/00_core.ipynb 10
58
+ def create_tar_archive(path # Path to directory containing FastHTML app
59
+ )->io.BytesIO: # Buffer of tar directory
60
+ "Creates a tar archive of a directory, excluding files based on is_included"
61
+ buf = io.BytesIO()
62
+ files = L(Path(path).iterdir()).filter(is_included)
63
+
64
+ with tarfile.open(fileobj=buf, mode='w:gz') as tar:
65
+ for f in files: tar.add(f, arcname=f.name)
66
+ buf.seek(0)
67
+ return buf, len(files)
68
+
69
+ # %% ../nbs/00_core.ipynb 11
70
+ def validate_app(path):
71
+ "Validates that the app in the directory `path` is deployable as a FastHTML app"
72
+ print("Analyzing project structure...")
73
+
74
+ main_file = Path(path) / "main.py"
75
+ if not main_file.exists():
76
+ print('[red bold]ERROR: Your FastHTML app must have a main.py[/red bold]')
77
+ print(f'Your path is: [bold]{path}[/bold]')
78
+ sys.exit(1)
79
+
80
+ # %% ../nbs/00_core.ipynb 13
81
+ def poll_cookies(paircode, local, port=None, interval=1, timeout=180):
82
+ "Poll server for token until received or timeout"
83
+ start = time()
84
+ client = httpx.Client()
85
+ url = endpoint(f"/cli_token?paircode={paircode}",local,port)
86
+ while time()-start < timeout:
87
+ resp = client.get(url).raise_for_status()
88
+ if resp.text.strip(): return dict(client.cookies)
89
+ sleep(interval)
90
+
91
+ @call_parse
92
+ def login(
93
+ local:bool=False, # Local dev
94
+ port:int=5002 # Port for local dev
95
+ ):
96
+ "Authenticate CLI with server and save config"
97
+ paircode = secrets.token_urlsafe(16)
98
+ login_url = httpx.get(endpoint(f"/cli_login?paircode={paircode}",local,port)).text
99
+ print(f"Opening browser for authentication:\n{login_url}\n")
100
+ webbrowser.open(login_url)
101
+
102
+ cookies = poll_cookies(paircode, local, port)
103
+ if cookies:
104
+ Path(PLASH_CONFIG_HOME).write_text(json.dumps(cookies))
105
+ print(f"Authentication successful! Config saved to {PLASH_CONFIG_HOME}")
106
+ else: print("Authentication timed out.")
107
+
108
+ # %% ../nbs/00_core.ipynb 15
109
+ @call_parse
110
+ def deploy(
111
+ path:Path=Path('.'), # Path to project
112
+ local:bool=False, # Local dev
113
+ port:int=5002): # Port for local dev
114
+ """🚀 Ship your app to production"""
115
+ print('Initializing deployment...')
116
+ validate_app(path)
117
+ tarz, filecount = create_tar_archive(path)
118
+
119
+ plash_app = Path(path) / '.plash'
120
+ if not plash_app.exists():
121
+ # Create the .plash file and write the app name
122
+ plash_app.write_text(f'export PLASH_APP_ID=fasthtml-app-{str(uuid4())[:8]}')
123
+ aid = parse_env(fn=plash_app)['PLASH_APP_ID']
124
+
125
+ resp = mk_auth_req(endpoint("/upload",local,port), "post", files={'file': tarz}, timeout=300.0, data={'aid': aid})
126
+ if resp.status_code == 200:
127
+ print('✅ Upload complete! Your app is currently being built.')
128
+ if local: print(f'It will be live at http://{aid}.localhost')
129
+ else: print(f'It will be live at https://{aid}.pla.sh')
130
+ else:
131
+ print(f'Failure {resp.status_code}')
132
+ print(f'Failure {resp.text}')
133
+
134
+ # %% ../nbs/00_core.ipynb 17
135
+ @call_parse
136
+ def view(
137
+ path:Path=Path('.'), # Path to project
138
+ local:bool=False, # Local dev
139
+ ):
140
+ aid = get_app_id(path)
141
+ if local: url = f"http://{aid}.localhost"
142
+ else: url = f"https://{aid}.pla.sh"
143
+ print(f"Opening browser to view app :\n{url}\n")
144
+ webbrowser.open(url)
145
+
146
+ # %% ../nbs/00_core.ipynb 19
147
+ @call_parse
148
+ def delete(
149
+ path:Path=Path('.'), # Path to project
150
+ local:bool=False, # Local dev
151
+ port:int=5002, # Port for local dev
152
+ force:bool=False): # Skip confirmation prompt
153
+ 'Delete your deployed app'
154
+ aid = get_app_id(path)
155
+ if not force:
156
+ confirm = input(f"Are you sure you want to delete app '{aid}'? This action cannot be undone. [y/N]: ")
157
+ if confirm.lower() not in ['y', 'yes']:
158
+ print("Deletion cancelled.")
159
+ return
160
+
161
+ print(f"Deleting app '{aid}'...")
162
+ r = mk_auth_req(endpoint(f"/delete?aid={aid}",local,port), "delete")
163
+ return r.text
164
+
165
+ # %% ../nbs/00_core.ipynb 21
166
+ def endpoint_func(endpoint_name):
167
+ 'Creates a function for a specific API endpoint'
168
+ @call_parse
169
+ def func(
170
+ path:Path=Path('.'), # Path to project
171
+ local:bool=False, # Local dev
172
+ port:int=5002): # Port for local dev
173
+ aid = get_app_id(path)
174
+ r = mk_auth_req(endpoint(f"{endpoint_name}?aid={aid}", local, port))
175
+ return r.text
176
+
177
+ # Set the function name and docstring
178
+ func.__name__ = endpoint_name
179
+ func.__doc__ = f"Access the '{endpoint_name}' endpoint for your app"
180
+
181
+ return func
182
+
183
+ # Create endpoint-specific functions
184
+ stop = endpoint_func('/stop')
185
+ start = endpoint_func('/start')
186
+ logs = endpoint_func('/logs')
187
+
188
+ # %% ../nbs/00_core.ipynb 23
189
+ @call_parse
190
+ def download(
191
+ path:Path=Path('.'), # Path to project
192
+ save_path:Path=Path("./download/"), # Save path (optional)
193
+ local:bool=False, # Local dev
194
+ port:int=5002, # Port for local dev
195
+ ):
196
+ 'Download your deployed app.'
197
+ aid = get_app_id(path)
198
+ try: save_path.mkdir(exist_ok=False)
199
+ except: print(f"ERROR: Save path ({save_path}) already exists. Please rename or delete this folder to avoid accidental overwrites.")
200
+ else:
201
+ response = mk_auth_req(endpoint(f'/download?aid={aid}', local, port)).raise_for_status()
202
+ file_bytes = io.BytesIO(response.content)
203
+ with tarfile.open(fileobj=file_bytes, mode="r:gz") as tar: tar.extractall(path=save_path)
204
+ print(f"Downloaded your app to: {save_path}")
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: plash_cli
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: CLI for the Plash hosting service
5
5
  Home-page: https://github.com/AnswerDotAI/plash_cli
6
6
  Author: Jeremy Howard
@@ -23,6 +23,19 @@ License-File: LICENSE
23
23
  Requires-Dist: fastcore
24
24
  Requires-Dist: httpx
25
25
  Provides-Extra: dev
26
+ Dynamic: author
27
+ Dynamic: author-email
28
+ Dynamic: classifier
29
+ Dynamic: description
30
+ Dynamic: description-content-type
31
+ Dynamic: home-page
32
+ Dynamic: keywords
33
+ Dynamic: license
34
+ Dynamic: license-file
35
+ Dynamic: provides-extra
36
+ Dynamic: requires-dist
37
+ Dynamic: requires-python
38
+ Dynamic: summary
26
39
 
27
40
  # plash-cli
28
41
 
@@ -47,20 +60,20 @@ $ pip install git+https://github.com/AnswerDotAI/plash-cli.git
47
60
  or from [pypi](https://pypi.org/project/plash-cli/)
48
61
 
49
62
  ``` sh
50
- $ pip install plash_cli
63
+ $ pip install plash-cli
51
64
  ```
52
65
 
53
66
  ## Deploy Your First FastHTML App
54
67
 
55
- ### Set Up Your Plash Token
68
+ ### Authentication
56
69
 
57
- You’ll need to set a PLASH_TOKEN and PLASH_EMAIL environment variables
58
- to use Plash. To obtain these, do the following:
70
+ To use Plash, you’ll need to authenticate:
59
71
 
60
72
  1. Signup for an account at https://pla.sh/
61
73
  2. Activate your Plash subscription
62
- 3. Follow instructions in your Plash dashboard to save credentials
63
- locally
74
+ 3. Run `plash_login` in your terminal
75
+ 4. A browser window will open for authentication
76
+ 5. Once authenticated, your credentials will be saved locally
64
77
 
65
78
  ### Create a FastHTML App
66
79
 
@@ -95,6 +108,19 @@ Run `plash_deploy`. Your app will be live at
95
108
  `https://<app-name>.pla.sh`. The URL will be shown in the deployment
96
109
  output.
97
110
 
111
+ ### Managing Your App
112
+
113
+ Plash CLI provides several commands to manage your apps:
114
+
115
+ - `plash_login` - Login to Plash
116
+ - `plash_deploy` - Deploy your app
117
+ - `plash_view` - Open your deployed app in a browser
118
+ - `plash_start` - Start your app if it’s stopped
119
+ - `plash_stop` - Stop your running app
120
+ - `plash_logs` - View your app’s logs
121
+ - `plash_download` - Download your deployed app files
122
+ - `plash_delete` - Delete your deployed app
123
+
98
124
  ### App Dependencies
99
125
 
100
126
  If your app needs additional dependencies to run, we offer a number of
@@ -147,3 +173,48 @@ in your Plash container, to modify your apps behavior for local and
147
173
  production development. You can download any deployed database names by
148
174
  clicking the Download App button to get a compressed file of all files
149
175
  in your /app folder in your deployed app.
176
+
177
+ ## Deploy to Pla.sh via GitHub Actions
178
+
179
+ If you’d like to deploy your plash app every time you commit changes to
180
+ your GitHub repo, you can use the following workflow to your
181
+ `.github/workflows/` folder in the root of your repo:
182
+
183
+ ``` yaml
184
+ name: Deploy to Plash
185
+
186
+ on:
187
+ push:
188
+ branches:
189
+ - main
190
+ workflow_dispatch:
191
+
192
+ jobs:
193
+ deploy:
194
+ runs-on: ubuntu-latest
195
+ steps:
196
+ - name: Checkout repository
197
+ uses: actions/checkout@v3
198
+
199
+ - name: Set up Python
200
+ uses: actions/setup-python@v4
201
+ with:
202
+ python-version: '3.x'
203
+
204
+ - name: Create Plash config
205
+ run: |
206
+ mkdir -p ~/.config
207
+ echo '${{ secrets.PLASH_CONFIG }}' > ~/.config/plash_config.json
208
+
209
+ - name: Install plash-cli with pip
210
+ run: pip install plash-cli
211
+
212
+ - name: Deploy to Plash
213
+ run: plash_deploy
214
+ ```
215
+
216
+ It relies on storing your plash config as a secret named `PLASH_CONFIG`
217
+ in your GitHub repo. After running `plash_login`, you can find these in
218
+ `~/.config/plash_config.json` (unless you haved changed the
219
+ XDG_CONFIG_HOME environment variable). Learn more about GitHub secrets
220
+ [here](https://docs.github.com/en/actions/security-for-github-actions/security-guides/using-secrets-in-github-actions).
@@ -0,0 +1,12 @@
1
+ [console_scripts]
2
+ plash_delete = plash_cli.core:delete
3
+ plash_deploy = plash_cli.core:deploy
4
+ plash_download = plash_cli.core:download
5
+ plash_login = plash_cli.core:login
6
+ plash_logs = plash_cli.core:logs
7
+ plash_start = plash_cli.core:start
8
+ plash_stop = plash_cli.core:stop
9
+ plash_view = plash_cli.core:view
10
+
11
+ [nbdev]
12
+ plash_cli = plash_cli._modidx:d
@@ -0,0 +1,11 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name="plash_cli"
7
+ requires-python=">=3.7"
8
+ dynamic = [ "keywords", "description", "version", "dependencies", "optional-dependencies", "readme", "license", "authors", "classifiers", "entry-points", "scripts", "urls"]
9
+
10
+ [tool.uv]
11
+ cache-keys = [{ file = "pyproject.toml" }, { file = "settings.ini" }, { file = "setup.py" }]
@@ -1,7 +1,7 @@
1
1
  [DEFAULT]
2
2
  repo = plash_cli
3
3
  lib_name = plash_cli
4
- version = 0.0.2
4
+ version = 0.0.4
5
5
  min_python = 3.7
6
6
  license = apache2
7
7
  black_formatting = False
@@ -28,6 +28,13 @@ status = 3
28
28
  user = AnswerDotAI
29
29
  requirements = fastcore httpx
30
30
  console_scripts = plash_deploy=plash_cli.core:deploy
31
+ plash_login=plash_cli.core:login
32
+ plash_view=plash_cli.core:view
33
+ plash_logs=plash_cli.core:logs
34
+ plash_delete=plash_cli.core:delete
35
+ plash_stop=plash_cli.core:stop
36
+ plash_start=plash_cli.core:start
37
+ plash_download=plash_cli.core:download
31
38
  readme_nb = index.ipynb
32
39
  allowed_metadata_keys =
33
40
  allowed_cell_metadata_keys =
@@ -36,4 +43,5 @@ clean_ids = True
36
43
  clear_all = False
37
44
  cell_number = True
38
45
  skip_procs =
46
+ update_pyproject = True
39
47
 
@@ -1 +0,0 @@
1
- __version__ = "0.0.2"
@@ -1,12 +0,0 @@
1
- # Autogenerated by nbdev
2
-
3
- d = { 'settings': { 'branch': 'main',
4
- 'doc_baseurl': '/plash_cli',
5
- 'doc_host': 'https://AnswerDotAI.github.io',
6
- 'git_url': 'https://github.com/AnswerDotAI/plash_cli',
7
- 'lib_path': 'plash_cli'},
8
- 'syms': { 'plash_cli.core': { 'plash_cli.core.create_tar_archive': ('core.html#create_tar_archive', 'plash_cli/core.py'),
9
- 'plash_cli.core.deploy': ('core.html#deploy', 'plash_cli/core.py'),
10
- 'plash_cli.core.get_global_cfg': ('core.html#get_global_cfg', 'plash_cli/core.py'),
11
- 'plash_cli.core.is_included': ('core.html#is_included', 'plash_cli/core.py'),
12
- 'plash_cli.core.validate_app': ('core.html#validate_app', 'plash_cli/core.py')}}}
@@ -1,90 +0,0 @@
1
- """The Plash CLI tool"""
2
-
3
- # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.
4
-
5
- # %% auto 0
6
- __all__ = ['PLASH_CONFIG_HOME', 'get_global_cfg', 'is_included', 'create_tar_archive', 'validate_app', 'deploy']
7
-
8
- # %% ../nbs/00_core.ipynb 2
9
- from fastcore.all import *
10
- from fastcore.xdg import *
11
- from httpx import post as xpost
12
- from pathlib import Path
13
- from uuid import uuid4
14
-
15
- import io, sys, tarfile
16
-
17
- # %% ../nbs/00_core.ipynb 3
18
- PLASH_CONFIG_HOME = xdg_config_home() / 'plash.env'
19
-
20
- # %% ../nbs/00_core.ipynb 4
21
- def get_global_cfg():
22
- """Works for all operating systems."""
23
- try: return parse_env(fn=Path(PLASH_CONFIG_HOME))
24
- except FileNotFoundError:
25
- Path(PLASH_CONFIG_HOME).touch()
26
- return parse_env(fn=Path(PLASH_CONFIG_HOME))
27
-
28
- # %% ../nbs/00_core.ipynb 5
29
- def is_included(path):
30
- "Returns True if path should be included in deployment"
31
- if path.name.startswith('.'): return False
32
- if path.suffix == '.pyc': return False
33
- excludes = {'.git', '__pycache__', '.gitignore', '.env',
34
- '.pytest_cache', '.venv', 'venv', '.ipynb_checkpoints',
35
- '.vscode', '.idea', '.sesskey'}
36
- return not any(p in excludes for p in path.parts)
37
-
38
- # %% ../nbs/00_core.ipynb 6
39
- def create_tar_archive(path # Path to directory containing FastHTML app
40
- )->io.BytesIO: # Buffer of tar directory
41
- "Creates a tar archive of a directory, excluding files based on is_included"
42
- buf = io.BytesIO()
43
- files = L(Path(path).iterdir()).filter(is_included)
44
-
45
- with tarfile.open(fileobj=buf, mode='w:gz') as tar:
46
- for f in files: tar.add(f, arcname=f.name)
47
- buf.seek(0)
48
- return buf, len(files)
49
-
50
- # %% ../nbs/00_core.ipynb 7
51
- def validate_app(path):
52
- "Validates that the app in the directory `path` is deployable as a FastHTML app"
53
- print("Analyzing project structure...")
54
-
55
- main_file = Path(path) / "main.py"
56
- if not main_file.exists():
57
- print('[red bold]ERROR: Your FastHTML app must have a main.py[/red bold]')
58
- print(f'Your path is: [bold]{path}[/bold]')
59
- sys.exit(1)
60
-
61
- # %% ../nbs/00_core.ipynb 8
62
- @call_parse
63
- def deploy(
64
- path:Path=Path('.'), # Path to project
65
- local:bool=False, # local dev
66
- port:int=5002):
67
- """🚀 Ship your app to production"""
68
- print('Initializing deployment...')
69
- validate_app(path)
70
- tarz, filecount = create_tar_archive(path)
71
-
72
- plash_app = Path(path) / '.plash'
73
- if not plash_app.exists():
74
- # Create the .plash file and write the app name
75
- plash_app.write_text(f'export PLASH_APP_ID=fasthtml-app-{str(uuid4())[:8]}')
76
-
77
- aid = parse_env(fn=plash_app)['PLASH_APP_ID']
78
- cfg = get_global_cfg()
79
- url = 'https://pla.sh/upload'
80
- if local: url = f'http://localhost:{port}/upload'
81
- headers = {'Authorization': f'Bearer {cfg["PLASH_TOKEN"]}'}
82
- print(f'Uploading {filecount} files...')
83
- resp = xpost(url, headers=headers, files={'file': tarz}, timeout=300.0,
84
- data={'aid': aid, 'email': cfg['PLASH_EMAIL']})
85
- if resp.status_code == 200:
86
- print('✅ Upload complete! Your app is currently being built.')
87
- print(f'It will be live at https://{aid}.pla.sh')
88
- else:
89
- print(f'Failure {resp.status_code}')
90
- print(f'Failure {resp.text}')
@@ -1,5 +0,0 @@
1
- [console_scripts]
2
- plash_deploy = plash_cli.core:deploy
3
-
4
- [nbdev]
5
- plash_cli = plash_cli._modidx:d
@@ -1,3 +0,0 @@
1
- [build-system]
2
- requires = ["setuptools>=64.0"]
3
- build-backend = "setuptools.build_meta"
File without changes
File without changes
File without changes
File without changes