From 45a297a8e526094e8fce6e2c5c0fd89b381d1765 Mon Sep 17 00:00:00 2001 From: ewy Date: Tue, 14 Apr 2026 16:37:17 +0200 Subject: i have to commit at some point! --- runner/python/filetarget.go | 51 +++++++++++++++++++++++++++ runner/python/indexer.go | 44 +++++++++++++++++++++++ runner/python/projtarget.go | 50 ++++++++++++++++++++++++++ runner/python/runner.go | 86 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 runner/python/filetarget.go create mode 100644 runner/python/indexer.go create mode 100644 runner/python/projtarget.go create mode 100644 runner/python/runner.go (limited to 'runner/python') diff --git a/runner/python/filetarget.go b/runner/python/filetarget.go new file mode 100644 index 0000000..6793f4b --- /dev/null +++ b/runner/python/filetarget.go @@ -0,0 +1,51 @@ +package python + +import ( + "os/exec" + "path/filepath" + "pik/model" + "pik/runner" +) + +type FileTarget struct { + runner.BaseTarget + File string +} + +type HydratedFileTarget struct { + runner.BaseHydration[*FileTarget] +} + +func (h *HydratedFileTarget) Icon() string { + return "\uE606" +} + +func (p *FileTarget) Create(s *model.Source) *exec.Cmd { + var cmd []string + if Python.Uv != "" { + cmd = []string{Python.Uv, "run", "--", p.File} + } else if venv := Python.VenvFor(s); venv != "" { + cmd = []string{filepath.Join(s.Path, venv, "bin", "python3"), p.File} + } else { + sysPath, err := exec.LookPath("python3") + if err != nil { + return nil + } + cmd = []string{sysPath, p.File} + } + return exec.Command(cmd[0], cmd[1:]...) +} + +func (p *FileTarget) Sub() []string { + return nil +} + +func (p *FileTarget) Label() string { + return p.Full +} + +func (p *FileTarget) Hydrate(src *model.Source) (model.HydratedTarget, error) { + return &HydratedFileTarget{ + BaseHydration: runner.Hydrated(p), + }, nil +} diff --git a/runner/python/indexer.go b/runner/python/indexer.go new file mode 100644 index 0000000..d0dd4e3 --- /dev/null +++ b/runner/python/indexer.go @@ -0,0 +1,44 @@ +package python + +import ( + "github.com/pelletier/go-toml/v2" + "io/fs" + "os" + "path/filepath" + "pik/model" +) + +type Pyproj struct { + Project struct { + Scripts map[string]string + } +} + +func (p python) Index(path string, f fs.FS, runners []model.Runner) ([]model.Target, error) { + for _, pt := range VenvPaths { + if stat, err := fs.Stat(f, filepath.Join(pt)); err == nil { + if stat.IsDir() { + p.Venvs[path] = filepath.Join(path, pt) + } + } + } + content, err := fs.ReadFile(f, "pyproject.toml") + if os.IsNotExist(err) { + return nil, nil + } else if err != nil { + return nil, err + } + + pp := &Pyproj{} + + err = toml.Unmarshal(content, pp) + if err != nil { + return nil, err + } + + var targets = make([]model.Target, 0, len(pp.Project.Scripts)) + for n, s := range pp.Project.Scripts { + targets = append(targets, Python.CreateProjTarget(n, s)) + } + return targets, nil +} diff --git a/runner/python/projtarget.go b/runner/python/projtarget.go new file mode 100644 index 0000000..1604948 --- /dev/null +++ b/runner/python/projtarget.go @@ -0,0 +1,50 @@ +package python + +import ( + "os/exec" + "path/filepath" + "pik/model" + "pik/runner" +) + +type ProjTarget struct { + runner.BaseTarget + Cmd string +} + +type HydratedProjTarget struct { + runner.BaseHydration[*ProjTarget] +} + +func (h *HydratedProjTarget) Icon() string { + return "\uE606" +} + +func (h *HydratedProjTarget) Description() string { + //TODO implement me + return "//TODO" +} + +func (p *ProjTarget) Create(s *model.Source) *exec.Cmd { + var cmd []string + if Python.Uv != "" { + cmd = []string{Python.Uv, "run", "--", p.Cmd} + } else if venv := Python.VenvFor(s); venv != "" { + cmd = []string{filepath.Join(s.Path, venv, "bin", "python"), p.Cmd} + } + return exec.Command(cmd[0], cmd[1:]...) +} + +func (p *ProjTarget) Sub() []string { + return nil +} + +func (p *ProjTarget) Label() string { + return p.Cmd +} + +func (p *ProjTarget) Hydrate(src *model.Source) (model.HydratedTarget, error) { + return &HydratedProjTarget{ + BaseHydration: runner.Hydrated(p), + }, nil +} diff --git a/runner/python/runner.go b/runner/python/runner.go new file mode 100644 index 0000000..b06d8ab --- /dev/null +++ b/runner/python/runner.go @@ -0,0 +1,86 @@ +package python + +import ( + "errors" + "io/fs" + "os/exec" + "path/filepath" + "pik/identity" + "pik/model" + "pik/runner" +) + +type python struct { + Venvs map[string]string + Uv string + System string +} + +func (p python) Init() error { + uv, err := exec.LookPath("uv") + if err != nil && !errors.Is(err, exec.ErrNotFound) { + return err + } + p.Uv = uv + sys, err := exec.LookPath("python3") + if err == nil { + p.System = sys + } + return err +} + +func (p python) Hydrate(target model.Target) (model.HydratedTarget, error) { + //TODO implement me + panic("implement me") +} + +func (p python) Wants(fs fs.FS, file string, entry fs.DirEntry) (bool, error) { + return !entry.IsDir() && filepath.Ext(entry.Name()) == ".py", nil +} + +func (p python) VenvFor(src *model.Source) string { + venvPath := p.Venvs[src.Path] + if venvPath != "" { + return venvPath + } + return "" +} + +func (p python) PyFor(src *model.Source) []string { + if p.Uv != "" { + return []string{p.Uv, "run", "--"} + } + if venv := p.VenvFor(src); venv != "" { + return []string{filepath.Join(src.Path, venv, "bin", "python")} + } + return nil +} + +func (p python) CreateProjTarget(name string, cmd string) model.Target { + return &ProjTarget{ + BaseTarget: runner.BaseTarget{ + Identity: identity.New(name), + }, + Cmd: cmd, + } +} + +func (p python) CreateTarget(fs fs.FS, source string, file string, entry fs.DirEntry) (model.Target, error) { + _, filename := filepath.Split(file) + return &FileTarget{ + BaseTarget: runner.BaseTarget{ + Identity: identity.New(filename), + MyTags: model.TagsFromFilename(filename), + }, + File: file, + }, nil +} + +var VenvPaths = []string{ + ".venv", + "venv", +} + +var Python = &python{ + Venvs: map[string]string{}, +} -- cgit v1.3