Skip to content

Commit

Permalink
Merge pull request #72 from teaxyz/plus-pkg
Browse files Browse the repository at this point in the history
Plus pkg
  • Loading branch information
mxcl authored Oct 2, 2022
2 parents c2a3428 + 82179b7 commit 4c8228b
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 41 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Change how your team works.
 


# tea/cli 0.6.10
# tea/cli 0.7.0

tea is a universal virtual‑environment manager:

Expand Down Expand Up @@ -553,11 +553,7 @@ deno test \
## Typecheck
```sh
find \
scripts src/app.ts \
-name \*.ts \
-exec \
deno check --import-map="$SRCROOT"/import-map.json {} \;
deno check --import-map="$SRCROOT"/import-map.json src/*.ts scripts/*.ts
```
Expand Down
12 changes: 7 additions & 5 deletions src/app.dump.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { Installation, PackageRequirement } from "types"
import { Installation, PackageSpecification } from "types"
import { useShellEnv, usePantry, useCellar } from "hooks"
import { VirtualEnv } from "hooks/useVirtualEnv.ts"
import { str as pkgstr } from "utils/pkg.ts"
import { print, undent } from "utils"

interface Options {
env: VirtualEnv | undefined
pkgs: PackageSpecification[]
}

//TODO needs to take a argish parameter

export default async function dump({ env: blueprint }: Options) {
export default async function dump({ env: blueprint, pkgs }: Options) {
console.verbose({ blueprint })

const shell = Deno.env.get("SHELL")?.split('/').pop()
Expand All @@ -35,9 +37,9 @@ export default async function dump({ env: blueprint }: Options) {
const {installations, pending} = await (async () => {
const cellar = useCellar()
const installations: Installation[] = []
const pending: PackageRequirement[] = []
const pending: PackageSpecification[] = []

for (const rq of blueprint?.requirements ?? []) {
for (const rq of pkgs) {
const installation = await cellar.has(rq)
if (installation) {
installations.push(installation)
Expand Down Expand Up @@ -74,7 +76,7 @@ export default async function dump({ env: blueprint }: Options) {
`
for (const pkg of pending) {
const cmds = (await pantry.getProvides(pkg)).join("|")
rv += ` ${cmds}) tea -xmP ${pkg.project}@'${pkg.constraint}' -- "$@";;\n`
rv += ` ${cmds}) tea -xmP '${pkgstr(pkg)}' -- "$@";;\n`
}
rv += ` *)\n printf 'zsh: command not found: %s\\n' "$1";;\n esac\n}`

Expand Down
12 changes: 7 additions & 5 deletions src/app.exec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useFlags, useShellEnv, usePantry, useExecutableMarkdown } from "hooks"
import { hydrate, resolve, install as base_install, link } from "prefab"
import { VirtualEnv } from "hooks/useVirtualEnv.ts"
import { PackageRequirement } from "types"
import { PackageSpecification } from "types"
import { run, undent } from "utils"
import Path from "path"

type Options = {
args: string[]
env: VirtualEnv | undefined
pkgs: PackageRequirement[]
pkgs: PackageSpecification[]
}

export default async function exec({ args, ...opts }: Options) {
Expand All @@ -22,8 +22,10 @@ export default async function exec({ args, ...opts }: Options) {
if (filename?.extname() == '.md') {
const target = args[1]
const sh = await useExecutableMarkdown({ filename }).findScript(target)
//TODO get shell from YAML, assume bash if not specified because we want `set -e`
const path = Path.mktmp().join('script').write({ text: undent`
#!/bin/sh
#!/bin/bash
set -e
${sh}
` }).chmod(0o500).string
args = [path, ...args.slice(2)]
Expand All @@ -43,8 +45,8 @@ export default async function exec({ args, ...opts }: Options) {
}

/////////////////////////////////////////////////////////////
async function install(dry: PackageRequirement[]) {
const get = (x: PackageRequirement) => usePantry().getDeps(x).then(x => x.runtime)
async function install(dry: PackageSpecification[]) {
const get = (x: PackageSpecification) => usePantry().getDeps(x).then(x => x.runtime)
const wet = await hydrate(dry, get) ; console.debug({wet})
const gas = await resolve(wet.pkgs) ; console.debug({gas})

Expand Down
1 change: 1 addition & 0 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { print } from "utils"
const rawArgs = useArgs(Deno.args)
const { silent } = useFlags()
const version = `${(await useVirtualEnv({ cwd: new URL(import.meta.url).path().parent() })).version?.toString()}+dev`
// ^^ this is statically replaced at deployment

if (rawArgs.cd) {
const chdir = rawArgs.cd
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import useSourceUnarchiver from "./useSourceUnarchiver.ts"
import usePantry from "./usePantry.ts"
import useVirtualEnv from "./useVirtualEnv.ts"
import useMagic from "./useMagic.ts"
import usePackageYAML, { usePackageYAMLFrontMatter } from "./usePackageYAML.ts"

// but we can sort these alphabetically
export {
Expand All @@ -26,6 +27,8 @@ export {
useInventory,
useMagic,
useOffLicense,
usePackageYAML,
usePackageYAMLFrontMatter,
usePantry,
usePrefix,
useShellEnv,
Expand Down
14 changes: 9 additions & 5 deletions src/hooks/useFlags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { parseFlags } from "cliffy/flags/mod.ts"
import { flatmap, chuzzle } from "utils"
import { Verbosity, PackageRequirement } from "types"
import { flatmap, chuzzle, pkg, pivot } from "utils"
import { Verbosity, PackageSpecification } from "types"
import { isNumber } from "is_what"
import { set_tmp } from "path"
import { usePrefix } from "hooks"
Expand Down Expand Up @@ -57,7 +57,7 @@ interface Args {
std: string[]
fwd: string[]
env: boolean
pkgs: PackageRequirement[]
pkgs: PackageSpecification[]
}

//FIXME -v=99 parses and gives v == 1
Expand Down Expand Up @@ -147,14 +147,18 @@ export function useArgs(args: string[]): ReturnValue {
// TEA_DIR must be absolute for security reasons
const getcd = flatmap(cd, x => Path.cwd().join(x))

const [pkgs, std] = pivot<string, PackageSpecification, string>(unknown, arg =>
arg.startsWith('+') ? ['L', pkg.parse(arg.slice(1))] : ['R', arg]
)

return {
...getMode(),
cd: getcd,
args: {
env: env ?? false,
std: unknown,
std,
fwd: literal,
pkgs: [] //FIXME
pkgs
}
}

Expand Down
42 changes: 22 additions & 20 deletions src/hooks/useMagic.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { PackageRequirement } from "types"
import { flatmap } from "utils"
import { usePackageYAMLFrontMatter, useExecutableMarkdown, useCache } from "hooks"
import useFlags, { ReturnValue, Mode } from "hooks/useFlags.ts"
import useVirtualEnv, { VirtualEnv } from "hooks/useVirtualEnv.ts"
import { useExecutableMarkdown, useCache } from "hooks"
import { usePackageYAMLFrontMatter } from "hooks/usePackageYAML.ts"
import { PackageSpecification } from "types"
import { flatmap } from "utils"
import Path from "path"
import * as semver from "semver"

Expand All @@ -13,7 +12,7 @@ export type ProcessedArgs = {
mode: Mode
args: string[]
env: VirtualEnv | undefined
pkgs: PackageRequirement[] // env.pkgs + explicit on CLI + YAML front matter etc.
pkgs: PackageSpecification[] // env.pkgs + explicit on CLI + YAML front matter etc.
}

export default async function useMagic(input: Args): Promise<ProcessedArgs> {
Expand All @@ -38,15 +37,15 @@ async function muggle(input: Args): Promise<ProcessedArgs> {

const [args, pkgs] = await (async () => {
if (!script) return [
getArguments(input),
mkargs(input),
env?.requirements ?? []
]

const yaml = await usePackageYAMLFrontMatter(script, env?.srcroot).swallow("no-front-matter")

return [
[...yaml?.getArgs() ?? [], ...getArguments(input)],
[...yaml?.getDeps(false) ?? [], ...env?.requirements ?? [], ]
[...yaml?.getArgs() ?? [], ...mkargs(input)],
[...yaml?.getDeps(false) ?? [], ...env?.requirements ?? [], ...input.args.pkgs]
]
})()

Expand Down Expand Up @@ -77,18 +76,18 @@ async function magic(input: Args): Promise<ProcessedArgs> {
if (!env) throw "no env found"
}

const pkgs = [...env?.requirements ?? [], ...input.args.pkgs]

if (script) {
//NOTE if you specify a script it won’t add the env automatically—even if there’s one present

const yaml = await usePackageYAMLFrontMatter(script, env?.srcroot).swallow("no-front-matter")

if (yaml) {
const pkgs = [...yaml.getDeps(false), ...env?.requirements ?? []]
const args = [...yaml.getArgs(), ...getArguments(input)]
pkgs.push(...yaml.getDeps(false))
const args = [...yaml.getArgs(), ...mkargs(input)]
return { mode, args, pkgs, env }
} else {
const pkgs = env?.requirements ?? []

// pushing at front so later specification tromps it
const push = (project: string) => pkgs.unshift({ project, constraint: new semver.Range("*") })
const args: string[] = []
Expand All @@ -105,7 +104,7 @@ async function magic(input: Args): Promise<ProcessedArgs> {
break
}

args.push(...getArguments(input))
args.push(...mkargs(input))

return { mode, args, pkgs, env }
}
Expand All @@ -120,7 +119,7 @@ async function magic(input: Args): Promise<ProcessedArgs> {
// k, we’re inferring executable markdown
return {
mode,
pkgs: env?.requirements ?? [],
pkgs,
args: flatmap(env?.requirementsFile, x=>[x.string]) ?? [],
env
}
Expand All @@ -131,8 +130,8 @@ async function magic(input: Args): Promise<ProcessedArgs> {
if (await useExecutableMarkdown({ filename: env!.requirementsFile }).findScript(arg0)) {
return {
mode,
pkgs: env!.requirements,
args: [env!.requirementsFile.string, ...getArguments(input)],
pkgs,
args: [env!.requirementsFile.string, ...mkargs(input)],
env
}
}
Expand All @@ -148,17 +147,20 @@ async function magic(input: Args): Promise<ProcessedArgs> {

return {
mode,
pkgs: env?.requirements ?? [],
args: getArguments(input),
pkgs,
args: mkargs(input),
env
}

async function maybe_env() {
return env ?? (env = await useVirtualEnv().swallow(/not-found/))
if (env) return env
env = await useVirtualEnv().swallow(/not-found/)
pkgs.push(...env?.requirements ?? [])
return env
}
}

function getArguments(input: Args): string[] {
function mkargs(input: Args): string[] {
const args = input.args.std
if (input.args.fwd.length) args.push("--", ...input.args.fwd)
return args
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface PackageRequirement {
constraint: SemVerRange
}

export type PackageSpecification = Package | PackageRequirement

export interface Installation {
path: Path
pkg: Package
Expand Down
13 changes: 13 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ export function flatmap<S, T>(t: T | undefined | null, body: (t: T) => S | undef
}
}

export function pivot<E, L, R>(input: E[], body: (e: E) => ['L', L] | ['R', R]): [L[], R[]] {
const rv = {
'L': [] as L[],
'R': [] as R[]
}
for (const e of input) {
const [side, value] = body(e)
// deno-lint-ignore no-explicit-any
rv[side].push(value as any)
}
return [rv['L'], rv['R']]
}

declare global {
interface Promise<T> {
swallow(err: unknown): Promise<T | undefined>
Expand Down
2 changes: 2 additions & 0 deletions src/utils/pkg.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export function parse(input: string): PackageRequirement | Package {

const project = match[1]

console.debug({ input })

if (match[2].startsWith("@") || match[2].startsWith("=")) {
let version = semver.parse(match[2].slice(1))
if (!version) {
Expand Down

0 comments on commit 4c8228b

Please sign in to comment.