Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sdk tweaks #2791

Merged
merged 3 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions core/startos/src/s9pk/v2/pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,9 @@ pub enum ImageSource {
Packed,
#[serde(rename_all = "camelCase")]
DockerBuild {
#[ts(optional)]
workdir: Option<PathBuf>,
#[ts(optional)]
dockerfile: Option<PathBuf>,
#[serde(skip_serializing_if = "Option::is_none")]
#[ts(optional)]
Expand All @@ -366,8 +368,15 @@ impl ImageSource {
pub fn ingredients(&self) -> Vec<PathBuf> {
match self {
Self::Packed => Vec::new(),
Self::DockerBuild { dockerfile, .. } => {
vec![dockerfile.clone().unwrap_or_else(|| "Dockerfile".into())]
Self::DockerBuild {
dockerfile,
workdir,
..
} => {
vec![workdir
.as_deref()
.unwrap_or(Path::new("."))
.join(dockerfile.as_deref().unwrap_or(Path::new("Dockerfile")))]
}
Self::DockerTag(_) => Vec::new(),
}
Expand Down
10 changes: 6 additions & 4 deletions core/startos/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ impl<'a> std::ops::DerefMut for ExtendedCommand<'a> {
}

impl<'a> Invoke<'a> for tokio::process::Command {
type Extended<'ext> = ExtendedCommand<'ext>
type Extended<'ext>
= ExtendedCommand<'ext>
where
Self: 'ext,
'ext: 'a;
Expand Down Expand Up @@ -162,7 +163,8 @@ impl<'a> Invoke<'a> for tokio::process::Command {
}

impl<'a> Invoke<'a> for ExtendedCommand<'a> {
type Extended<'ext> = &'ext mut ExtendedCommand<'ext>
type Extended<'ext>
= &'ext mut ExtendedCommand<'ext>
where
Self: 'ext,
'ext: 'a;
Expand Down Expand Up @@ -663,8 +665,8 @@ impl FromStr for PathOrUrl {
type Err = <PathBuf as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(url) = s.parse::<Url>() {
if url.scheme() == "file" {
Ok(Self::Path(url.path().parse()?))
if let Some(path) = s.strip_prefix("file://") {
Ok(Self::Path(path.parse()?))
} else {
Ok(Self::Url(url))
}
Expand Down
9 changes: 5 additions & 4 deletions sdk/base/lib/actions/input/builder/inputSpec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ValueSpec } from "../inputSpecTypes"
import { PartialValue, Value } from "./value"
import { Value } from "./value"
import { _ } from "../../../util"
import { Effects } from "../../../Effects"
import { Parser, object } from "ts-matches"
import { DeepPartial } from "../../../types"

export type LazyBuildOptions<Store> = {
effects: Effects
Expand All @@ -22,8 +23,8 @@ export type ExtractPartialInputSpecType<
| InputSpec<Record<string, any>, any>
| InputSpec<Record<string, any>, never>,
> = A extends InputSpec<infer B, any> | InputSpec<infer B, never>
? PartialValue<B>
: PartialValue<A>
? DeepPartial<B>
: DeepPartial<A>

export type InputSpecOf<A extends Record<string, any>, Store = never> = {
[K in keyof A]: Value<A[K], Store>
Expand Down Expand Up @@ -94,7 +95,7 @@ export class InputSpec<Type extends Record<string, any>, Store = never> {
public validator: Parser<unknown, Type>,
) {}
_TYPE: Type = null as any as Type
_PARTIAL: PartialValue<Type> = null as any as PartialValue<Type>
_PARTIAL: DeepPartial<Type> = null as any as DeepPartial<Type>
async build(options: LazyBuildOptions<Store>) {
const answer = {} as {
[K in keyof Type]: ValueSpec
Expand Down
45 changes: 20 additions & 25 deletions sdk/base/lib/actions/input/builder/value.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { InputSpec, LazyBuild } from "./inputSpec"
import { List } from "./list"
import { PartialUnionRes, UnionRes, Variants } from "./variants"
import { Variants } from "./variants"
import {
FilePath,
Pattern,
Expand Down Expand Up @@ -30,29 +30,20 @@ import { DeepPartial } from "../../../types"

type AsRequired<T, Required extends boolean> = Required extends true
? T
: T | null | undefined
: T | null

const testForAsRequiredParser = once(
() => object({ required: literal(true) }).test,
)
function asRequiredParser<
Type,
Input,
Return extends
| Parser<unknown, Type>
| Parser<unknown, Type | null | undefined>,
Return extends Parser<unknown, Type> | Parser<unknown, Type | null>,
>(parser: Parser<unknown, Type>, input: Input): Return {
if (testForAsRequiredParser()(input)) return parser as any
return parser.optional() as any
return parser.nullable() as any
}

export type PartialValue<T> =
T extends UnionRes<infer A, infer B>
? PartialUnionRes<A, B>
: T extends {}
? { [P in keyof T]?: PartialValue<T[P]> }
: T

export class Value<Type, Store> {
protected constructor(
public build: LazyBuild<Store, ValueSpec>,
Expand Down Expand Up @@ -196,7 +187,7 @@ export class Value<Type, Store> {
}
>,
) {
return new Value<string | null | undefined, Store>(async (options) => {
return new Value<string | null, Store>(async (options) => {
const a = await getA(options)
return {
type: "text" as const,
Expand All @@ -213,7 +204,7 @@ export class Value<Type, Store> {
generate: a.generate ?? null,
...a,
}
}, string.optional())
}, string.nullable())
}
static textarea<Required extends boolean>(a: {
name: string
Expand Down Expand Up @@ -265,7 +256,7 @@ export class Value<Type, Store> {
}
>,
) {
return new Value<string | null | undefined, Store>(async (options) => {
return new Value<string | null, Store>(async (options) => {
const a = await getA(options)
return {
description: null,
Expand All @@ -278,7 +269,7 @@ export class Value<Type, Store> {
immutable: false,
...a,
}
}, string.optional())
}, string.nullable())
}
static number<Required extends boolean>(a: {
name: string
Expand Down Expand Up @@ -351,7 +342,7 @@ export class Value<Type, Store> {
}
>,
) {
return new Value<number | null | undefined, Store>(async (options) => {
return new Value<number | null, Store>(async (options) => {
const a = await getA(options)
return {
type: "number" as const,
Expand All @@ -366,7 +357,7 @@ export class Value<Type, Store> {
immutable: false,
...a,
}
}, number.optional())
}, number.nullable())
}
static color<Required extends boolean>(a: {
name: string
Expand Down Expand Up @@ -413,7 +404,7 @@ export class Value<Type, Store> {
}
>,
) {
return new Value<string | null | undefined, Store>(async (options) => {
return new Value<string | null, Store>(async (options) => {
const a = await getA(options)
return {
type: "color" as const,
Expand All @@ -423,7 +414,7 @@ export class Value<Type, Store> {
immutable: false,
...a,
}
}, string.optional())
}, string.nullable())
}
static datetime<Required extends boolean>(a: {
name: string
Expand Down Expand Up @@ -483,7 +474,7 @@ export class Value<Type, Store> {
}
>,
) {
return new Value<string | null | undefined, Store>(async (options) => {
return new Value<string | null, Store>(async (options) => {
const a = await getA(options)
return {
type: "datetime" as const,
Expand All @@ -496,7 +487,7 @@ export class Value<Type, Store> {
immutable: false,
...a,
}
}, string.optional())
}, string.nullable())
}
static select<Values extends Record<string, string>>(a: {
name: string
Expand Down Expand Up @@ -690,14 +681,14 @@ export class Value<Type, Store> {
// }
// >,
// ) {
// return new Value<FilePath | null | undefined, Store>(
// return new Value<FilePath | null, Store>(
// async (options) => ({
// type: "file" as const,
// description: null,
// warning: null,
// ...(await a(options)),
// }),
// object({ filePath: string }).optional(),
// object({ filePath: string }).nullable(),
// )
// }
static union<
Expand Down Expand Up @@ -822,6 +813,10 @@ export class Value<Type, Store> {
}, parser)
}

map<U>(fn: (value: Type) => U): Value<U, Store> {
return new Value(this.build, this.validator.map(fn))
}

/**
* Use this during the times that the input needs a more specific type.
* Used in types that the value/ variant/ list/ inputSpec is constructed somewhere else.
Expand Down
21 changes: 0 additions & 21 deletions sdk/base/lib/actions/input/builder/variants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,6 @@ export type UnionRes<
}
}[K]

export type PartialUnionRes<
Store,
VariantValues extends {
[K in string]: {
name: string
spec: InputSpec<any, Store> | InputSpec<any, never>
}
},
K extends keyof VariantValues & string = keyof VariantValues & string,
> = {
[key in keyof VariantValues]: {
selection?: key
value?: ExtractPartialInputSpecType<VariantValues[key]["spec"]>
other?: {
[key2 in Exclude<keyof VariantValues & string, key>]?: DeepPartial<
ExtractInputSpecType<VariantValues[key2]["spec"]>
>
}
}
}[K]

/**
* Used in the the Value.select { @link './value.ts' }
* to indicate the type of select variants that are available. The key for the record passed in will be the
Expand Down
40 changes: 35 additions & 5 deletions sdk/base/lib/dependencies/setupDependencies.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
import * as T from "../types"
import { once } from "../util"

type DependencyType<Manifest extends T.SDKManifest> = {
[K in keyof Manifest["dependencies"]]: Omit<T.DependencyRequirement, "id">
}
export type RequiredDependenciesOf<Manifest extends T.SDKManifest> = {
[K in keyof Manifest["dependencies"]]: Manifest["dependencies"][K]["optional"] extends false
? K
: never
}[keyof Manifest["dependencies"]]
export type OptionalDependenciesOf<Manifest extends T.SDKManifest> = Exclude<
keyof Manifest["dependencies"],
RequiredDependenciesOf<Manifest>
>

type DependencyRequirement =
| {
kind: "running"
healthChecks: Array<T.HealthCheckId>
versionRange: string
}
| {
kind: "exists"
versionRange: string
}
type Matches<T, U> = T extends U ? (U extends T ? null : never) : never
const _checkType: Matches<
DependencyRequirement & { id: T.PackageId },
T.DependencyRequirement
> = null

export type CurrentDependenciesResult<Manifest extends T.SDKManifest> = {
[K in RequiredDependenciesOf<Manifest>]: DependencyRequirement
} & {
[K in OptionalDependenciesOf<Manifest>]?: DependencyRequirement
} & Record<string, DependencyRequirement>

export function setupDependencies<Manifest extends T.SDKManifest>(
fn: (options: { effects: T.Effects }) => Promise<DependencyType<Manifest>>,
fn: (options: {
effects: T.Effects
}) => Promise<CurrentDependenciesResult<Manifest>>,
): (options: { effects: T.Effects }) => Promise<null> {
const cell = { updater: async (_: { effects: T.Effects }) => null }
cell.updater = async (options: { effects: T.Effects }) => {
Expand All @@ -21,7 +51,7 @@ export function setupDependencies<Manifest extends T.SDKManifest>(
dependencies: Object.entries(dependencyType).map(
([id, { versionRange, ...x }, ,]) =>
({
id,
// id,
...x,
versionRange: versionRange.toString(),
}) as T.DependencyRequirement,
Expand Down
4 changes: 2 additions & 2 deletions sdk/base/lib/osBindings/ImageSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export type ImageSource =
| "packed"
| {
dockerBuild: {
workdir: string | null
dockerfile: string | null
workdir?: string
dockerfile?: string
buildArgs?: { [key: string]: BuildArg }
}
}
Expand Down
13 changes: 10 additions & 3 deletions sdk/base/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ import { Effects } from "./Effects"
export { Effects }
export * from "./osBindings"
export { SDKManifest } from "./types/ManifestTypes"
export {
RequiredDependenciesOf as RequiredDependencies,
OptionalDependenciesOf as OptionalDependencies,
CurrentDependenciesResult,
} from "./dependencies/setupDependencies"

export type ExposedStorePaths = string[] & Affine<"ExposedStorePaths">
declare const HealthProof: unique symbol
Expand Down Expand Up @@ -224,6 +229,8 @@ export type KnownError =

export type Dependencies = Array<DependencyRequirement>

export type DeepPartial<T> = T extends {}
? { [P in keyof T]?: DeepPartial<T[P]> }
: T
export type DeepPartial<T> = T extends unknown[]
? T
: T extends {}
? { [P in keyof T]?: DeepPartial<T[P]> }
: T
17 changes: 13 additions & 4 deletions sdk/base/lib/types/ManifestTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,19 @@ export type SDKManifest = {
}
}

export type SDKImageInputSpec = {
source: Exclude<ImageSource, "packed">
arch?: string[]
emulateMissingAs?: string | null
// this is hacky but idk a more elegant way
type ArchOptions = {
0: ["x86_64", "aarch64"]
1: ["aarch64", "x86_64"]
2: ["x86_64"]
3: ["aarch64"]
}
export type SDKImageInputSpec = {
[A in keyof ArchOptions]: {
source: Exclude<ImageSource, "packed">
arch?: ArchOptions[A]
emulateMissingAs?: ArchOptions[A][number] | null
}
}[keyof ArchOptions]

export type ManifestDependency = T.Manifest["dependencies"][string]
Loading