devlaunch 0.0.1__tar.gz → 0.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.
- {devlaunch-0.0.1 → devlaunch-0.0.2}/PKG-INFO +1 -1
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/completions/dl.bash +23 -15
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/dl.py +109 -113
- {devlaunch-0.0.1 → devlaunch-0.0.2}/pyproject.toml +2 -2
- {devlaunch-0.0.1 → devlaunch-0.0.2}/.gitignore +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/LICENSE +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/README.md +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/__init__.py +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/completion.py +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/completion_loader.py +0 -0
- {devlaunch-0.0.1 → devlaunch-0.0.2}/devlaunch/completions/__init__.py +0 -0
|
@@ -5,14 +5,11 @@ _dl_completion() {
|
|
|
5
5
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
6
6
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
|
|
8
|
+
# Global command options (only valid as first arg)
|
|
9
|
+
local global_opts="--ls --install --help -h --version"
|
|
10
10
|
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
|
14
|
-
return 0
|
|
15
|
-
fi
|
|
11
|
+
# Workspace subcommands
|
|
12
|
+
local ws_cmds="stop rm code restart recreate reset --"
|
|
16
13
|
|
|
17
14
|
# Cache file location (honors XDG_CACHE_HOME)
|
|
18
15
|
local cache_dir="${XDG_CACHE_HOME:-$HOME/.cache}/dl"
|
|
@@ -28,16 +25,14 @@ _dl_completion() {
|
|
|
28
25
|
source "$cache_file"
|
|
29
26
|
fi
|
|
30
27
|
|
|
31
|
-
#
|
|
32
|
-
if [[
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
# First argument: global flags, workspaces, repos, owners, or paths
|
|
29
|
+
if [[ ${COMP_CWORD} -eq 1 ]]; then
|
|
30
|
+
# Global flags
|
|
31
|
+
if [[ ${cur} == -* ]]; then
|
|
32
|
+
COMPREPLY=( $(compgen -W "${global_opts}" -- ${cur}) )
|
|
33
|
+
return 0
|
|
35
34
|
fi
|
|
36
|
-
return 0
|
|
37
|
-
fi
|
|
38
35
|
|
|
39
|
-
# First positional argument: workspace, owner/repo, or path
|
|
40
|
-
if [[ ${COMP_CWORD} -eq 1 ]]; then
|
|
41
36
|
# Don't add space after completion to allow @branch suffix
|
|
42
37
|
compopt -o nospace
|
|
43
38
|
|
|
@@ -71,6 +66,19 @@ _dl_completion() {
|
|
|
71
66
|
return 0
|
|
72
67
|
fi
|
|
73
68
|
|
|
69
|
+
# Second argument (after workspace): subcommands
|
|
70
|
+
if [[ ${COMP_CWORD} -eq 2 ]]; then
|
|
71
|
+
# Don't complete after global flags
|
|
72
|
+
local first="${COMP_WORDS[1]}"
|
|
73
|
+
if [[ "$first" == --* ]]; then
|
|
74
|
+
return 0
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
COMPREPLY=( $(compgen -W "${ws_cmds}" -- ${cur}) )
|
|
78
|
+
return 0
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# After "--": no completion (user types shell command)
|
|
74
82
|
return 0
|
|
75
83
|
}
|
|
76
84
|
|
|
@@ -25,11 +25,21 @@ import logging
|
|
|
25
25
|
import os
|
|
26
26
|
import pathlib
|
|
27
27
|
import re
|
|
28
|
+
from importlib.metadata import version as pkg_version, PackageNotFoundError
|
|
28
29
|
from typing import List, Optional, Dict, Any
|
|
29
30
|
from dataclasses import dataclass
|
|
30
31
|
|
|
31
32
|
from .completion import install_completions
|
|
32
33
|
|
|
34
|
+
|
|
35
|
+
def get_version() -> str:
|
|
36
|
+
"""Get the package version."""
|
|
37
|
+
try:
|
|
38
|
+
return pkg_version("devlaunch")
|
|
39
|
+
except PackageNotFoundError:
|
|
40
|
+
return "unknown"
|
|
41
|
+
|
|
42
|
+
|
|
33
43
|
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
|
34
44
|
|
|
35
45
|
|
|
@@ -485,32 +495,41 @@ def print_help():
|
|
|
485
495
|
help_text = """dl - DevLaunch CLI
|
|
486
496
|
|
|
487
497
|
Usage:
|
|
488
|
-
dl
|
|
489
|
-
dl <
|
|
490
|
-
dl <
|
|
491
|
-
dl
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
498
|
+
dl Interactive workspace selector (fzf)
|
|
499
|
+
dl <user/repo> Start workspace and attach shell
|
|
500
|
+
dl <user/repo> <cmd> Run workspace command (stop, code, etc.)
|
|
501
|
+
dl <user/repo> -- <shell> Run shell command in workspace
|
|
502
|
+
|
|
503
|
+
Workspace sources:
|
|
504
|
+
dl myproject Existing workspace by name
|
|
505
|
+
dl user/repo Create from GitHub repo
|
|
506
|
+
dl user/repo@branch Create from specific branch
|
|
507
|
+
dl ./path Create from local path
|
|
508
|
+
|
|
509
|
+
Workspace commands:
|
|
510
|
+
dl <user/repo> stop Stop the workspace
|
|
511
|
+
dl <user/repo> rm, prune Delete the workspace
|
|
512
|
+
dl <user/repo> code Open in VS Code
|
|
513
|
+
dl <user/repo> restart Stop and start (no rebuild)
|
|
514
|
+
dl <user/repo> recreate Recreate container
|
|
515
|
+
dl <user/repo> reset Clean slate (remove all, recreate)
|
|
516
|
+
dl <user/repo> -- <command> Run shell command in workspace
|
|
517
|
+
|
|
518
|
+
Global commands:
|
|
519
|
+
dl --ls List all workspaces
|
|
520
|
+
dl --install Install shell completions
|
|
521
|
+
dl --help, -h Show this help
|
|
522
|
+
dl --version Show version
|
|
505
523
|
|
|
506
524
|
Examples:
|
|
507
|
-
dl
|
|
508
|
-
dl
|
|
509
|
-
dl loft-sh/devpod
|
|
510
|
-
dl blooop/devlaunch@main
|
|
511
|
-
dl ./my-project
|
|
512
|
-
dl
|
|
513
|
-
dl
|
|
525
|
+
dl # Select workspace with fzf
|
|
526
|
+
dl devpod # Open existing workspace
|
|
527
|
+
dl loft-sh/devpod # Create from GitHub
|
|
528
|
+
dl blooop/devlaunch@main # Create from specific branch
|
|
529
|
+
dl ./my-project # Create from local folder
|
|
530
|
+
dl blooop/devlaunch code # Open in VS Code
|
|
531
|
+
dl blooop/devlaunch -- make test # Run command in workspace
|
|
532
|
+
dl blooop/devlaunch stop # Stop workspace
|
|
514
533
|
"""
|
|
515
534
|
print(help_text)
|
|
516
535
|
|
|
@@ -519,20 +538,24 @@ def main() -> int:
|
|
|
519
538
|
"""Main entry point for dl CLI."""
|
|
520
539
|
args = sys.argv[1:]
|
|
521
540
|
|
|
522
|
-
#
|
|
523
|
-
if not args
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
541
|
+
# No args - try fzf selection
|
|
542
|
+
if not args:
|
|
543
|
+
selected = fuzzy_select_workspace()
|
|
544
|
+
if not selected:
|
|
545
|
+
print_help()
|
|
546
|
+
return 1
|
|
547
|
+
workspace_up(selected)
|
|
548
|
+
return workspace_ssh(selected)
|
|
549
|
+
|
|
550
|
+
# Global commands (no workspace required)
|
|
551
|
+
if args[0] in ("--help", "-h"):
|
|
532
552
|
print_help()
|
|
533
553
|
return 0
|
|
534
554
|
|
|
535
|
-
|
|
555
|
+
if args[0] == "--version":
|
|
556
|
+
print(f"dl {get_version()}")
|
|
557
|
+
return 0
|
|
558
|
+
|
|
536
559
|
if args[0] == "--ls":
|
|
537
560
|
print_workspaces()
|
|
538
561
|
return 0
|
|
@@ -572,80 +595,9 @@ def main() -> int:
|
|
|
572
595
|
update_completion_cache()
|
|
573
596
|
return install_completions(rc_path)
|
|
574
597
|
|
|
575
|
-
|
|
576
|
-
if len(args) < 2:
|
|
577
|
-
workspace = fuzzy_select_workspace()
|
|
578
|
-
if not workspace:
|
|
579
|
-
logging.error("Usage: dl --stop <workspace>")
|
|
580
|
-
return 1
|
|
581
|
-
else:
|
|
582
|
-
workspace = args[1]
|
|
583
|
-
return workspace_stop(workspace)
|
|
584
|
-
|
|
585
|
-
if args[0] == "--rm":
|
|
586
|
-
if len(args) < 2:
|
|
587
|
-
workspace = fuzzy_select_workspace()
|
|
588
|
-
if not workspace:
|
|
589
|
-
logging.error("Usage: dl --rm <workspace>")
|
|
590
|
-
return 1
|
|
591
|
-
else:
|
|
592
|
-
workspace = args[1]
|
|
593
|
-
return workspace_delete(workspace)
|
|
594
|
-
|
|
595
|
-
if args[0] == "--status":
|
|
596
|
-
if len(args) < 2:
|
|
597
|
-
workspace = fuzzy_select_workspace()
|
|
598
|
-
if not workspace:
|
|
599
|
-
logging.error("Usage: dl --status <workspace>")
|
|
600
|
-
return 1
|
|
601
|
-
else:
|
|
602
|
-
workspace = args[1]
|
|
603
|
-
return workspace_status(workspace)
|
|
604
|
-
|
|
605
|
-
if args[0] == "--code":
|
|
606
|
-
if len(args) < 2:
|
|
607
|
-
workspace = fuzzy_select_workspace()
|
|
608
|
-
if not workspace:
|
|
609
|
-
logging.error("Usage: dl --code <workspace>")
|
|
610
|
-
return 1
|
|
611
|
-
else:
|
|
612
|
-
workspace = args[1]
|
|
613
|
-
result = workspace_up(workspace, ide="vscode")
|
|
614
|
-
return result.returncode
|
|
615
|
-
|
|
616
|
-
if args[0] == "--recreate":
|
|
617
|
-
if len(args) < 2:
|
|
618
|
-
workspace = fuzzy_select_workspace()
|
|
619
|
-
if not workspace:
|
|
620
|
-
logging.error("Usage: dl --recreate <workspace>")
|
|
621
|
-
return 1
|
|
622
|
-
else:
|
|
623
|
-
workspace = args[1]
|
|
624
|
-
workspace_spec = expand_workspace_spec(workspace)
|
|
625
|
-
workspace_id = spec_to_workspace_id(workspace)
|
|
626
|
-
result = workspace_up(workspace_spec, recreate=True)
|
|
627
|
-
if result.returncode != 0:
|
|
628
|
-
return result.returncode
|
|
629
|
-
return workspace_ssh(workspace_id)
|
|
630
|
-
|
|
631
|
-
if args[0] == "--reset":
|
|
632
|
-
if len(args) < 2:
|
|
633
|
-
workspace = fuzzy_select_workspace()
|
|
634
|
-
if not workspace:
|
|
635
|
-
logging.error("Usage: dl --reset <workspace>")
|
|
636
|
-
return 1
|
|
637
|
-
else:
|
|
638
|
-
workspace = args[1]
|
|
639
|
-
workspace_spec = expand_workspace_spec(workspace)
|
|
640
|
-
workspace_id = spec_to_workspace_id(workspace)
|
|
641
|
-
result = workspace_up(workspace_spec, reset=True)
|
|
642
|
-
if result.returncode != 0:
|
|
643
|
-
return result.returncode
|
|
644
|
-
return workspace_ssh(workspace_id)
|
|
645
|
-
|
|
646
|
-
# Default: workspace name and optional command
|
|
598
|
+
# Workspace commands: dl <workspace> [subcommand] [-- command]
|
|
647
599
|
raw_spec = args[0]
|
|
648
|
-
|
|
600
|
+
subcommand = args[1] if len(args) > 1 else None
|
|
649
601
|
|
|
650
602
|
# Validate the workspace spec
|
|
651
603
|
existing_ids = get_workspace_ids()
|
|
@@ -654,8 +606,7 @@ def main() -> int:
|
|
|
654
606
|
logging.error(error)
|
|
655
607
|
return 1
|
|
656
608
|
|
|
657
|
-
#
|
|
658
|
-
# This prevents owner/repo-style workspace IDs from being rewritten
|
|
609
|
+
# Resolve workspace spec and ID
|
|
659
610
|
if raw_spec in existing_ids:
|
|
660
611
|
workspace_spec = raw_spec
|
|
661
612
|
workspace_id = raw_spec
|
|
@@ -663,13 +614,58 @@ def main() -> int:
|
|
|
663
614
|
workspace_spec = expand_workspace_spec(raw_spec)
|
|
664
615
|
workspace_id = spec_to_workspace_id(raw_spec)
|
|
665
616
|
|
|
666
|
-
#
|
|
617
|
+
# Handle workspace subcommands
|
|
618
|
+
if subcommand == "stop":
|
|
619
|
+
return workspace_stop(workspace_id)
|
|
620
|
+
|
|
621
|
+
if subcommand in ("rm", "prune"):
|
|
622
|
+
return workspace_delete(workspace_id)
|
|
623
|
+
|
|
624
|
+
if subcommand == "code":
|
|
625
|
+
result = workspace_up(workspace_spec, ide="vscode")
|
|
626
|
+
return result.returncode
|
|
627
|
+
|
|
628
|
+
if subcommand == "recreate":
|
|
629
|
+
result = workspace_up(workspace_spec, recreate=True)
|
|
630
|
+
if result.returncode != 0:
|
|
631
|
+
return result.returncode
|
|
632
|
+
return workspace_ssh(workspace_id)
|
|
633
|
+
|
|
634
|
+
if subcommand == "restart":
|
|
635
|
+
# Stop and start without rebuilding
|
|
636
|
+
stop_ret = workspace_stop(workspace_id)
|
|
637
|
+
if stop_ret != 0:
|
|
638
|
+
return stop_ret
|
|
639
|
+
result = workspace_up(workspace_spec)
|
|
640
|
+
if result.returncode != 0:
|
|
641
|
+
return result.returncode
|
|
642
|
+
return workspace_ssh(workspace_id)
|
|
643
|
+
|
|
644
|
+
if subcommand == "reset":
|
|
645
|
+
# Clean slate - remove everything and recreate
|
|
646
|
+
result = workspace_up(workspace_spec, reset=True)
|
|
647
|
+
if result.returncode != 0:
|
|
648
|
+
return result.returncode
|
|
649
|
+
return workspace_ssh(workspace_id)
|
|
650
|
+
|
|
651
|
+
# Check for shell command (after --)
|
|
652
|
+
shell_command = None
|
|
653
|
+
if subcommand == "--" and len(args) > 2:
|
|
654
|
+
shell_command = " ".join(args[2:])
|
|
655
|
+
elif subcommand is not None and subcommand != "--":
|
|
656
|
+
# Unknown subcommand - treat as error
|
|
657
|
+
logging.error(
|
|
658
|
+
f"Unknown command '{subcommand}'. Use 'dl {raw_spec} -- {subcommand}' to run a shell command."
|
|
659
|
+
)
|
|
660
|
+
return 1
|
|
661
|
+
|
|
662
|
+
# Default: start workspace and attach shell
|
|
667
663
|
result = workspace_up(workspace_spec)
|
|
668
664
|
if result.returncode != 0:
|
|
669
665
|
return result.returncode
|
|
670
666
|
|
|
671
|
-
# Attach to workspace
|
|
672
|
-
ret = workspace_ssh(workspace_id,
|
|
667
|
+
# Attach to workspace
|
|
668
|
+
ret = workspace_ssh(workspace_id, shell_command)
|
|
673
669
|
|
|
674
670
|
# Update cache in background after workspace operations
|
|
675
671
|
update_cache_background()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "devlaunch"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.2"
|
|
4
4
|
authors = [{ name = "Austin Gregg-Smith", email = "blooop@gmail.com" }]
|
|
5
5
|
description = "DevLaunch - A streamlined CLI for devpod workspaces"
|
|
6
6
|
readme = "README.md"
|
|
@@ -109,7 +109,7 @@ extension-pkg-whitelist = ["numpy"]
|
|
|
109
109
|
jobs = 16 #detect number of cores
|
|
110
110
|
|
|
111
111
|
[tool.pylint.'MESSAGES CONTROL']
|
|
112
|
-
disable = "C,logging-fstring-interpolation,line-too-long,fixme,broad-exception-caught,missing-module-docstring,too-many-instance-attributes,too-few-public-methods,too-many-arguments,too-many-locals,too-many-branches,too-many-statements,too-many-return-statements,use-dict-literal,cyclic-import,duplicate-code,too-many-public-methods"
|
|
112
|
+
disable = "C,logging-fstring-interpolation,line-too-long,fixme,broad-exception-caught,missing-module-docstring,too-many-instance-attributes,too-few-public-methods,too-many-arguments,too-many-positional-arguments,too-many-locals,too-many-branches,too-many-statements,too-many-return-statements,use-dict-literal,cyclic-import,duplicate-code,too-many-public-methods"
|
|
113
113
|
enable = "no-else-return,consider-using-in"
|
|
114
114
|
|
|
115
115
|
[tool.coverage.run]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|