Skip to content

Commit c1efe89

Browse files
authored
Merge pull request darklang#5545 from StachuDotNet/scm
refactors: package manager, sync, and dev UX across CLI + VS Code
2 parents e2b9aeb + 2a0fbce commit c1efe89

File tree

190 files changed

+13136
-6635
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

190 files changed

+13136
-6635
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ ENV NUGET_SCRATCH=/tmp/NuGetScratch
320320
# TODO Occasionally, check https://ziglang.org/download to see if we're using the latest version
321321
ENV ZIG_VERSION=0.11.0
322322
ENV ZIG_ARM64_MINISIG="RUSGOq2NVecA2XPwbgbN5SvU46UcCmhhfcfrjVC+YvcwUcjAYfIXQmqE//df1Mes7iyGZvGoy2+PSJ8pog7QGLE+3nvP8gtlSAs="
323-
ENV ZIG=AMD64_MINISIG="RUSGOq2NVecA2X2did6P61CXthPLZEUwi07GDWQ2MWU58W+asm3v85+PRVHN5SljhdsKoAMmbg4fdyseAcbVZayGaV1Iv6chcgE="
323+
ENV ZIG_AMD64_MINISIG="RUSGOq2NVecA2X2did6P61CXthPLZEUwi07GDWQ2MWU58W+asm3v85+PRVHN5SljhdsKoAMmbg4fdyseAcbVZayGaV1Iv6chcgE="
324324
#############
325325
RUN set -e; \
326326
case ${TARGETARCH} in \
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
-- Rewrites package storage for branch support and sync tracking
2+
-- Old: 3 tables (package_types_v0, package_values_v0, package_fns_v0)
3+
-- combining id, name/location, PT and RT
4+
-- New: Separate content storage from naming:
5+
-- - Content tables: package_types/values/functions (content-addressed)
6+
-- - Naming table: locations (maps owner.modules.name to item_id)
7+
-- - Branches: track work-in-progress
8+
-- - Package ops: source of truth for all changes
9+
10+
-- Drop old package tables
11+
DROP TABLE IF EXISTS package_types_v0;
12+
DROP TABLE IF EXISTS package_values_v0;
13+
DROP TABLE IF EXISTS package_functions_v0;
14+
15+
16+
-- Content tables store definitions (content-addressed, no naming)
17+
CREATE TABLE IF NOT EXISTS package_types (
18+
id TEXT PRIMARY KEY,
19+
pt_def BLOB NOT NULL,
20+
rt_def BLOB NOT NULL,
21+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
22+
);
23+
24+
CREATE TABLE IF NOT EXISTS package_values (
25+
id TEXT PRIMARY KEY,
26+
pt_def BLOB NOT NULL,
27+
rt_dval BLOB NOT NULL,
28+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
29+
);
30+
31+
CREATE TABLE IF NOT EXISTS package_functions (
32+
id TEXT PRIMARY KEY,
33+
pt_def BLOB NOT NULL,
34+
rt_instrs BLOB NOT NULL,
35+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
36+
);
37+
38+
-- Locations table: name resolution
39+
-- Maps (owner, modules, name, branch_id) -> item_id
40+
-- Supports branch-specific overrides and deprecation
41+
CREATE TABLE IF NOT EXISTS locations (
42+
location_id TEXT PRIMARY KEY,
43+
item_id TEXT NOT NULL, -- refs package_types/values/functions
44+
branch_id TEXT NULL, -- NULL = main, non-null = branch override
45+
owner TEXT NOT NULL, -- e.g., "Darklang"
46+
modules TEXT NOT NULL, -- e.g., "Stdlib.List"
47+
name TEXT NOT NULL, -- e.g., "map"
48+
item_type TEXT NOT NULL, -- 'fn', 'type', or 'value'
49+
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now')),
50+
deprecated_at TIMESTAMP NULL -- NULL = active
51+
-- No unique constraint: branches can have conflicting names
52+
);
53+
54+
-- Indexes for name lookups, module searches, and branch queries
55+
CREATE INDEX IF NOT EXISTS idx_locations_lookup
56+
ON locations(owner, modules, name, branch_id) WHERE deprecated_at IS NULL;
57+
CREATE INDEX IF NOT EXISTS idx_locations_module
58+
ON locations(owner, modules) WHERE deprecated_at IS NULL;
59+
CREATE INDEX IF NOT EXISTS idx_locations_conflicts
60+
ON locations(owner, modules, name, branch_id)
61+
WHERE deprecated_at IS NULL AND branch_id IS NOT NULL;
62+
CREATE INDEX IF NOT EXISTS idx_locations_shadowing
63+
ON locations(owner, modules, name, item_type, branch_id, deprecated_at);
64+
CREATE INDEX IF NOT EXISTS idx_locations_branch
65+
ON locations(branch_id) WHERE branch_id IS NOT NULL;
66+
67+
68+
CREATE TABLE IF NOT EXISTS branches (
69+
id TEXT PRIMARY KEY,
70+
name TEXT NOT NULL,
71+
created_at TIMESTAMP NOT NULL,
72+
--CLEANUP consider an `updated_at` col
73+
merged_at TIMESTAMP NULL
74+
);
75+
76+
CREATE INDEX IF NOT EXISTS idx_branches_name ON branches(name);
77+
78+
-- Package ops: the source of truth for all package changes
79+
-- Other tables (types/values/functions/locations) are projections
80+
CREATE TABLE IF NOT EXISTS package_ops (
81+
id TEXT PRIMARY KEY,
82+
branch_id TEXT NULL, -- NULL = merged to main
83+
op_blob BLOB NOT NULL, -- Serialized PackageOp
84+
applied BOOLEAN NOT NULL DEFAULT FALSE, -- Track whether op has been processed
85+
created_at TIMESTAMP NOT NULL DEFAULT (datetime('now'))
86+
);
87+
88+
CREATE INDEX IF NOT EXISTS idx_package_ops_branch ON package_ops(branch_id);
89+
CREATE INDEX IF NOT EXISTS idx_package_ops_created ON package_ops(created_at);
90+
CREATE INDEX IF NOT EXISTS idx_package_ops_applied ON package_ops(applied) WHERE applied = FALSE;
91+
92+
-- Instances table tracks remote Darklang instances for syncing
93+
CREATE TABLE IF NOT EXISTS instances (
94+
id TEXT PRIMARY KEY,
95+
name TEXT NOT NULL UNIQUE,
96+
url TEXT NOT NULL
97+
);
98+
99+
CREATE INDEX IF NOT EXISTS idx_instances_name ON instances(name);
100+
101+
-- Syncs table tracks synchronization history with remote instances
102+
CREATE TABLE IF NOT EXISTS syncs (
103+
id TEXT PRIMARY KEY, -- UUID
104+
instance_id TEXT NOT NULL, -- UUID reference to instances table
105+
synced_at TIMESTAMP NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
106+
ops_pushed INTEGER NOT NULL DEFAULT 0, -- Count of ops sent to remote instance
107+
ops_fetched INTEGER NOT NULL DEFAULT 0, -- Count of ops received from remote instance
108+
FOREIGN KEY (instance_id) REFERENCES instances(id) ON DELETE CASCADE
109+
);
110+
111+
CREATE INDEX IF NOT EXISTS idx_syncs_instance ON syncs(instance_id, synced_at DESC);
112+
CREATE INDEX IF NOT EXISTS idx_syncs_recent ON syncs(synced_at DESC);
113+
114+
-- Index for package tree queries (speeds up owner.modules LIKE queries)
115+
CREATE INDEX IF NOT EXISTS idx_locations_owner_modules ON locations(owner, modules);

backend/serialization/vanilla_LibExecution-ProgramTypes-PackageFn-PackageFn_function.json

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/serialization/vanilla_LibExecution-ProgramTypes-PackageType-PackageType_type.json

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/serialization/vanilla_LibExecution-ProgramTypes-PackageValue-PackageValue_value.json

Lines changed: 0 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/src/BuiltinCli/Builtin.fs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
module BuiltinCli.Builtin
22

3-
open Prelude
4-
open LibExecution.RuntimeTypes
5-
63
module Builtin = LibExecution.Builtin
74

8-
95
let fnRenames : Builtin.FnRenames =
106
// old names, new names
117
// eg: fn "Http" "respond" 0, fn "Http" "response" 0
@@ -19,5 +15,6 @@ let builtins =
1915
Libs.Execution.builtins
2016
Libs.Output.builtins
2117
Libs.Stdin.builtins
22-
Libs.Time.builtins ]
18+
Libs.Time.builtins
19+
Libs.Terminal.builtins ]
2320
fnRenames

backend/src/BuiltinCli/BuiltinCli.fsproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
<Compile Include="Libs/Execution.fs" />
1717
<Compile Include="Libs/Stdin.fs" />
1818
<Compile Include="Libs/Time.fs" />
19+
<Compile Include="Libs/Terminal.fs" />
1920
<Compile Include="Builtin.fs" />
2021
</ItemGroup>
2122
<ItemGroup>
2223
<ProjectReference Include="../Prelude/Prelude.fsproj" />
2324
<ProjectReference Include="../LibExecution/LibExecution.fsproj" />
25+
<ProjectReference Include="../LibConfig/LibConfig.fsproj" />
2426
</ItemGroup>
2527
<Import Project="..\..\.paket\Paket.Restore.targets" />
2628
</Project>

backend/src/BuiltinCli/Libs/Environment.fs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,20 @@ let fns : List<BuiltInFn> =
5757
| _ -> incorrectArgs ())
5858
sqlSpec = NotQueryable
5959
previewable = Impure
60+
deprecated = NotDeprecated }
61+
62+
63+
{ name = fn "getBuildHash" 0
64+
typeParams = []
65+
parameters = [ Param.make "unit" TUnit "" ]
66+
returnType = TString
67+
description = "Returns the git hash of the current CLI build"
68+
fn =
69+
function
70+
| _, _, [], [ DUnit ] -> uply { return DString LibConfig.Config.buildHash }
71+
| _ -> incorrectArgs ()
72+
sqlSpec = NotQueryable
73+
previewable = Impure
6074
deprecated = NotDeprecated } ]
6175

6276

backend/src/BuiltinCli/Libs/Stdin.fs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,13 @@ let fns : List<BuiltInFn> =
196196
DEnum(typeName, typeName, [], keyCaseName, [])
197197

198198
// Get character representation based on keyboard layout
199-
let keyChar = readKey.KeyChar |> string |> DString
199+
// Only include keyChar for printable characters, not control characters
200+
let keyChar =
201+
let ch = readKey.KeyChar
202+
if System.Char.IsControl(ch) || ch = '\u0000' then
203+
DString "" // Empty string for control/special keys
204+
else
205+
ch |> string |> DString
200206

201207
let keyRead =
202208
let typeName =
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
module BuiltinCli.Libs.Terminal
2+
3+
open System.Threading.Tasks
4+
open FSharp.Control.Tasks
5+
6+
open Prelude
7+
open LibExecution.RuntimeTypes
8+
open LibExecution.Builtin.Shortcuts
9+
10+
11+
let fns : List<BuiltInFn> =
12+
[ { name = fn "cliGetTerminalHeight" 0
13+
typeParams = []
14+
parameters = [ Param.make "unit" TUnit "" ]
15+
returnType = TInt64
16+
description = "Get the current terminal viewport height in number of lines"
17+
fn =
18+
(function
19+
| _, _, [], [ DUnit ] ->
20+
uply {
21+
try
22+
// First try environment variable (most reliable across different terminals)
23+
match System.Environment.GetEnvironmentVariable("LINES") with
24+
| null ->
25+
// Try Console.WindowHeight
26+
let height = System.Console.WindowHeight
27+
28+
// If we get exactly 24, it might be a default value
29+
// Let's try alternative methods
30+
if height = 24 then
31+
// On Unix systems, try tput command
32+
if
33+
System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
34+
System.Runtime.InteropServices.OSPlatform.Linux
35+
)
36+
|| System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
37+
System.Runtime.InteropServices.OSPlatform.OSX
38+
)
39+
then
40+
try
41+
let p = new System.Diagnostics.Process()
42+
p.StartInfo.FileName <- "/bin/sh"
43+
p.StartInfo.Arguments <-
44+
"-c \"tput lines 2>/dev/null || echo 24\""
45+
p.StartInfo.UseShellExecute <- false
46+
p.StartInfo.RedirectStandardOutput <- true
47+
p.StartInfo.CreateNoWindow <- true
48+
if p.Start() then
49+
let output = p.StandardOutput.ReadToEnd().Trim()
50+
p.WaitForExit()
51+
match System.Int32.TryParse(output) with
52+
| true, h when h > 0 -> return DInt64(int64 h)
53+
| _ -> return DInt64(int64 height)
54+
else
55+
return DInt64(int64 height)
56+
with _ ->
57+
return DInt64(int64 height)
58+
else
59+
return DInt64(int64 height)
60+
else
61+
return DInt64(int64 height)
62+
| lines ->
63+
match System.Int32.TryParse(lines) with
64+
| true, h when h > 0 -> return DInt64(int64 h)
65+
| _ -> return DInt64 24L
66+
with _ ->
67+
// Fallback if unable to detect terminal size
68+
return DInt64 24L
69+
}
70+
| _ -> incorrectArgs ())
71+
sqlSpec = NotQueryable
72+
previewable = Impure
73+
deprecated = NotDeprecated }
74+
75+
76+
{ name = fn "cliGetTerminalWidth" 0
77+
typeParams = []
78+
parameters = [ Param.make "unit" TUnit "" ]
79+
returnType = TInt64
80+
description = "Get the current terminal viewport width in number of columns"
81+
fn =
82+
(function
83+
| _, _, [], [ DUnit ] ->
84+
uply {
85+
try
86+
// First try environment variable (most reliable across different terminals)
87+
match System.Environment.GetEnvironmentVariable("COLUMNS") with
88+
| null ->
89+
// Try Console.WindowWidth
90+
let width = System.Console.WindowWidth
91+
92+
// If we get exactly 80, it might be a default value
93+
// Let's try alternative methods
94+
if width = 80 then
95+
// On Unix systems, try tput command
96+
if
97+
System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
98+
System.Runtime.InteropServices.OSPlatform.Linux
99+
)
100+
|| System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(
101+
System.Runtime.InteropServices.OSPlatform.OSX
102+
)
103+
then
104+
try
105+
let p = new System.Diagnostics.Process()
106+
p.StartInfo.FileName <- "/bin/sh"
107+
p.StartInfo.Arguments <-
108+
"-c \"tput cols 2>/dev/null || echo 80\""
109+
p.StartInfo.UseShellExecute <- false
110+
p.StartInfo.RedirectStandardOutput <- true
111+
p.StartInfo.CreateNoWindow <- true
112+
if p.Start() then
113+
let output = p.StandardOutput.ReadToEnd().Trim()
114+
p.WaitForExit()
115+
match System.Int32.TryParse(output) with
116+
| true, w when w > 0 -> return DInt64(int64 w)
117+
| _ -> return DInt64(int64 width)
118+
else
119+
return DInt64(int64 width)
120+
with _ ->
121+
return DInt64(int64 width)
122+
else
123+
return DInt64(int64 width)
124+
else
125+
return DInt64(int64 width)
126+
| columns ->
127+
match System.Int32.TryParse(columns) with
128+
| true, w when w > 0 -> return DInt64(int64 w)
129+
| _ -> return DInt64 80L
130+
with _ ->
131+
// Fallback if unable to detect terminal size
132+
return DInt64 80L
133+
}
134+
| _ -> incorrectArgs ())
135+
sqlSpec = NotQueryable
136+
previewable = Impure
137+
deprecated = NotDeprecated } ]
138+
139+
let builtins = LibExecution.Builtin.make [] fns

0 commit comments

Comments
 (0)