Skip to content

Commit 7e8208e

Browse files
authored
Merge pull request #2937 from spacedriveapp/cursor/search-ui-integration-ephemeral-1978
feat: Integrate search UI with ephemeral and persistent indexes
2 parents b608822 + 2b6f2a1 commit 7e8208e

39 files changed

Lines changed: 5299 additions & 576 deletions

.github/workflows/release.yml

Lines changed: 91 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -18,89 +18,89 @@ env:
1818

1919
jobs:
2020
# CLI builds for v2
21-
cli-build:
22-
strategy:
23-
matrix:
24-
include:
25-
# macOS builds
26-
- host: self-hosted
27-
target: aarch64-apple-darwin
28-
platform: macos-aarch64
29-
- host: macos-15-intel
30-
target: x86_64-apple-darwin
31-
platform: macos-x86_64
32-
# Linux builds
33-
- host: ubuntu-22.04
34-
target: x86_64-unknown-linux-gnu
35-
platform: linux-x86_64
36-
# Windows builds
37-
- host: windows-latest
38-
target: x86_64-pc-windows-msvc
39-
platform: windows-x86_64
40-
name: CLI - ${{ matrix.platform }}
41-
runs-on: ${{ matrix.host }}
42-
steps:
43-
- name: Checkout repository
44-
uses: actions/checkout@v4
45-
46-
- name: Setup Rust
47-
uses: dtolnay/rust-toolchain@stable
48-
with:
49-
targets: ${{ matrix.target }}
50-
51-
- name: Setup System and Rust
52-
uses: ./.github/actions/setup-system
53-
with:
54-
token: ${{ secrets.GITHUB_TOKEN }}
55-
target: ${{ matrix.target }}
56-
57-
- name: Install cross-compilation tools (Linux ARM)
58-
if: matrix.target == 'aarch64-unknown-linux-gnu'
59-
run: |
60-
sudo apt-get update
61-
sudo apt-get install -y gcc-aarch64-linux-gnu
62-
63-
- name: Setup native dependencies
64-
run: cargo run -p xtask -- setup
65-
66-
- name: Build CLI binaries
67-
run: |
68-
cargo build --release --bin sd-cli --bin sd-daemon --features heif,ffmpeg --target ${{ matrix.target }}
69-
env:
70-
# Set linker for cross-compilation
71-
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
72-
73-
- name: Prepare binaries (Unix)
74-
if: runner.os != 'Windows'
75-
run: |
76-
mkdir -p dist
77-
cp target/${{ matrix.target }}/release/sd-cli dist/sd-${{ matrix.platform }}
78-
cp target/${{ matrix.target }}/release/sd-daemon dist/sd-daemon-${{ matrix.platform }}
79-
chmod +x dist/*
80-
81-
- name: Prepare binaries (Windows)
82-
if: runner.os == 'Windows'
83-
shell: pwsh
84-
run: |
85-
New-Item -ItemType Directory -Force -Path dist
86-
Copy-Item target/${{ matrix.target }}/release/sd-cli.exe dist/sd-${{ matrix.platform }}.exe
87-
Copy-Item target/${{ matrix.target }}/release/sd-daemon.exe dist/sd-daemon-${{ matrix.platform }}.exe
88-
89-
- name: Generate checksums
90-
shell: bash
91-
run: |
92-
cd dist
93-
if [ "$RUNNER_OS" == "Windows" ]; then
94-
sha256sum *.exe > checksums-${{ matrix.platform }}.txt
95-
else
96-
sha256sum * > checksums-${{ matrix.platform }}.txt
97-
fi
98-
99-
- name: Upload artifacts
100-
uses: actions/upload-artifact@v4
101-
with:
102-
name: cli-${{ matrix.platform }}
103-
path: dist/*
21+
# cli-build:
22+
# strategy:
23+
# matrix:
24+
# include:
25+
# # macOS builds
26+
# - host: self-hosted
27+
# target: aarch64-apple-darwin
28+
# platform: macos-aarch64
29+
# - host: macos-15-intel
30+
# target: x86_64-apple-darwin
31+
# platform: macos-x86_64
32+
# # Linux builds
33+
# - host: ubuntu-22.04
34+
# target: x86_64-unknown-linux-gnu
35+
# platform: linux-x86_64
36+
# # Windows builds
37+
# - host: windows-latest
38+
# target: x86_64-pc-windows-msvc
39+
# platform: windows-x86_64
40+
# name: CLI - ${{ matrix.platform }}
41+
# runs-on: ${{ matrix.host }}
42+
# steps:
43+
# - name: Checkout repository
44+
# uses: actions/checkout@v4
45+
46+
# - name: Setup Rust
47+
# uses: dtolnay/rust-toolchain@stable
48+
# with:
49+
# targets: ${{ matrix.target }}
50+
51+
# - name: Setup System and Rust
52+
# uses: ./.github/actions/setup-system
53+
# with:
54+
# token: ${{ secrets.GITHUB_TOKEN }}
55+
# target: ${{ matrix.target }}
56+
57+
# - name: Install cross-compilation tools (Linux ARM)
58+
# if: matrix.target == 'aarch64-unknown-linux-gnu'
59+
# run: |
60+
# sudo apt-get update
61+
# sudo apt-get install -y gcc-aarch64-linux-gnu
62+
63+
# - name: Setup native dependencies
64+
# run: cargo run -p xtask -- setup
65+
66+
# - name: Build CLI binaries
67+
# run: |
68+
# cargo build --release --bin sd-cli --bin sd-daemon --features heif,ffmpeg --target ${{ matrix.target }}
69+
# env:
70+
# # Set linker for cross-compilation
71+
# CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
72+
73+
# - name: Prepare binaries (Unix)
74+
# if: runner.os != 'Windows'
75+
# run: |
76+
# mkdir -p dist
77+
# cp target/${{ matrix.target }}/release/sd-cli dist/sd-${{ matrix.platform }}
78+
# cp target/${{ matrix.target }}/release/sd-daemon dist/sd-daemon-${{ matrix.platform }}
79+
# chmod +x dist/*
80+
81+
# - name: Prepare binaries (Windows)
82+
# if: runner.os == 'Windows'
83+
# shell: pwsh
84+
# run: |
85+
# New-Item -ItemType Directory -Force -Path dist
86+
# Copy-Item target/${{ matrix.target }}/release/sd-cli.exe dist/sd-${{ matrix.platform }}.exe
87+
# Copy-Item target/${{ matrix.target }}/release/sd-daemon.exe dist/sd-daemon-${{ matrix.platform }}.exe
88+
89+
# - name: Generate checksums
90+
# shell: bash
91+
# run: |
92+
# cd dist
93+
# if [ "$RUNNER_OS" == "Windows" ]; then
94+
# sha256sum *.exe > checksums-${{ matrix.platform }}.txt
95+
# else
96+
# sha256sum * > checksums-${{ matrix.platform }}.txt
97+
# fi
98+
99+
# - name: Upload artifacts
100+
# uses: actions/upload-artifact@v4
101+
# with:
102+
# name: cli-${{ matrix.platform }}
103+
# path: dist/*
104104

105105
# V2 Desktop builds
106106
desktop-main:
@@ -234,7 +234,7 @@ jobs:
234234
if: startsWith(github.ref, 'refs/tags/')
235235
runs-on: self-hosted
236236
name: Create Release
237-
needs: [cli-build, desktop-main]
237+
needs: [desktop-main]
238238
permissions:
239239
contents: write
240240
steps:
@@ -245,4 +245,10 @@ jobs:
245245
uses: softprops/action-gh-release@v2
246246
with:
247247
draft: true
248-
files: "*/**"
248+
files: |
249+
cli-*/*
250+
*/*.dmg
251+
*/*.msi
252+
*/*.deb
253+
*/*.tar.xz
254+
*/*.sig

core/src/infra/db/entities/entry.rs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct Model {
2727
pub permissions: Option<String>, // Unix permissions as string
2828
pub inode: Option<i64>, // Platform-specific file identifier for change detection
2929
pub parent_id: Option<i32>, // Reference to parent entry for hierarchical relationships
30+
pub device_id: Option<i32>, // Device that owns this entry (denormalized for efficient queries)
3031
}
3132

3233
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
@@ -45,6 +46,12 @@ pub enum Relation {
4546
ContentIdentity,
4647
#[sea_orm(belongs_to = "Entity", from = "Column::ParentId", to = "Column::Id")]
4748
Parent,
49+
#[sea_orm(
50+
belongs_to = "super::device::Entity",
51+
from = "Column::DeviceId",
52+
to = "super::device::Column::Id"
53+
)]
54+
Device,
4855
}
4956

5057
impl Related<super::user_metadata::Entity> for Entity {
@@ -59,6 +66,12 @@ impl Related<super::content_identity::Entity> for Entity {
5966
}
6067
}
6168

69+
impl Related<super::device::Entity> for Entity {
70+
fn to() -> RelationDef {
71+
Relation::Device.def()
72+
}
73+
}
74+
6275
impl ActiveModelBehavior for ActiveModel {}
6376

6477
// Syncable Implementation
@@ -79,16 +92,17 @@ impl crate::infra::sync::Syncable for Model {
7992
}
8093

8194
fn sync_depends_on() -> &'static [&'static str] {
82-
// Entries depend on content_identity and user_metadata to ensure FK references
95+
// Entries depend on device, content_identity, and user_metadata to ensure FK references
8396
// exist before entries arrive. parent_id is self-reference (handled via closure rebuild).
84-
// This prevents entries arriving with content_id references that don't exist yet.
85-
&["content_identity", "user_metadata"]
97+
// This prevents entries arriving with FK references that don't exist yet.
98+
&["device", "content_identity", "user_metadata"]
8699
}
87100

88101
fn foreign_key_mappings() -> Vec<crate::infra::sync::FKMapping> {
89102
// All FKs use dependency tracking - NEVER set to NULL on missing reference
90103
// Source data with NULL values is handled correctly (null UUID → null FK)
91104
vec![
105+
crate::infra::sync::FKMapping::new("device_id", "devices"),
92106
crate::infra::sync::FKMapping::new("parent_id", "entries"),
93107
crate::infra::sync::FKMapping::new("metadata_id", "user_metadata"),
94108
crate::infra::sync::FKMapping::new("content_id", "content_identities"),
@@ -462,6 +476,7 @@ impl Model {
462476
serde_json::from_value(get_field("permissions")?).unwrap();
463477
let inode: Option<i64> = serde_json::from_value(get_field("inode")?).unwrap();
464478
let parent_id: Option<i32> = serde_json::from_value(get_field("parent_id")?).unwrap();
479+
let device_id: Option<i32> = serde_json::from_value(get_field("device_id")?).unwrap();
465480

466481
// Check if parent is tombstoned (prevents orphaned children)
467482
if let Some(parent) = parent_id {
@@ -503,6 +518,7 @@ impl Model {
503518
permissions: Set(permissions.clone()),
504519
inode: Set(inode),
505520
parent_id: Set(parent_id),
521+
device_id: Set(device_id),
506522
};
507523
active.update(db).await?;
508524
existing_entry.id
@@ -527,6 +543,7 @@ impl Model {
527543
permissions: Set(permissions.clone()),
528544
inode: Set(inode),
529545
parent_id: Set(parent_id),
546+
device_id: Set(device_id),
530547
};
531548
let inserted = active.insert(db).await?;
532549
inserted.id
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//! Migration to add device_id column to entries table
2+
//!
3+
//! This denormalizes the device relationship onto entries for efficient queries.
4+
//! Previously, determining which device an entry belonged to required traversing
5+
//! the parent chain to find the location root, then looking up the device.
6+
//! With device_id directly on entries, it's a simple join.
7+
8+
use sea_orm_migration::prelude::*;
9+
10+
#[derive(DeriveMigrationName)]
11+
pub struct Migration;
12+
13+
#[async_trait::async_trait]
14+
impl MigrationTrait for Migration {
15+
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
16+
// 1. Add the device_id column (nullable to support entries without device)
17+
manager
18+
.alter_table(
19+
Table::alter()
20+
.table(Entries::Table)
21+
.add_column(ColumnDef::new(Entries::DeviceId).integer())
22+
.to_owned(),
23+
)
24+
.await?;
25+
26+
// 2. Add index for efficient joins
27+
manager
28+
.create_index(
29+
Index::create()
30+
.name("idx_entries_device_id")
31+
.table(Entries::Table)
32+
.col(Entries::DeviceId)
33+
.to_owned(),
34+
)
35+
.await?;
36+
37+
// 3. Backfill existing entries by traversing to location roots
38+
// This finds the ancestor chain for each entry, identifies the root (parent_id IS NULL),
39+
// then looks up which location has that root as entry_id to get the device_id
40+
let db = manager.get_connection();
41+
db.execute_unprepared(
42+
r#"
43+
UPDATE entries SET device_id = (
44+
SELECT l.device_id
45+
FROM locations l
46+
WHERE l.entry_id IN (
47+
WITH RECURSIVE ancestors AS (
48+
SELECT id, parent_id FROM entries e2 WHERE e2.id = entries.id
49+
UNION ALL
50+
SELECT e.id, e.parent_id FROM entries e
51+
INNER JOIN ancestors a ON e.id = a.parent_id
52+
)
53+
SELECT id FROM ancestors WHERE parent_id IS NULL
54+
)
55+
LIMIT 1
56+
)
57+
WHERE device_id IS NULL
58+
"#,
59+
)
60+
.await?;
61+
62+
Ok(())
63+
}
64+
65+
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
66+
// Drop index first
67+
manager
68+
.drop_index(
69+
Index::drop()
70+
.name("idx_entries_device_id")
71+
.table(Entries::Table)
72+
.to_owned(),
73+
)
74+
.await?;
75+
76+
// Drop column
77+
manager
78+
.alter_table(
79+
Table::alter()
80+
.table(Entries::Table)
81+
.drop_column(Entries::DeviceId)
82+
.to_owned(),
83+
)
84+
.await?;
85+
86+
Ok(())
87+
}
88+
}
89+
90+
#[derive(DeriveIden)]
91+
enum Entries {
92+
Table,
93+
DeviceId,
94+
}

core/src/infra/db/migration/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ mod m20251204_000001_create_cloud_credentials_table;
3232
mod m20251209_000001_add_indexing_stats_to_volumes;
3333
mod m20251216_000001_add_device_hardware_specs;
3434
mod m20251220_000001_add_file_count_to_content_kinds;
35+
mod m20251226_000001_add_device_id_to_entries;
3536

3637
pub struct Migrator;
3738

@@ -69,6 +70,7 @@ impl MigratorTrait for Migrator {
6970
Box::new(m20251209_000001_add_indexing_stats_to_volumes::Migration),
7071
Box::new(m20251216_000001_add_device_hardware_specs::Migration),
7172
Box::new(m20251220_000001_add_file_count_to_content_kinds::Migration),
73+
Box::new(m20251226_000001_add_device_id_to_entries::Migration),
7274
]
7375
}
7476
}

0 commit comments

Comments
 (0)