Skip to content
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
2 changes: 1 addition & 1 deletion .claude/skills/fix-issue/references/platform-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Pass `--platform linux`, which a Linux machine picks by default. Every step runs

| Step | When |
| --- | --- |
| `setup` | a new tree; `linux/meson.build`, `linux/meson_options.txt` or a file under `linux/data/` changed |
| `setup` | a new tree; `linux/meson.build`, `linux/meson.options` or a file under `linux/data/` changed |
| `build` | always |
| `test <package> [filter]` | always, for each crate you changed |
| `test` | before the pull request: every suite, as the CI fast job runs them |
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/fix-issue/references/verification-linux.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Cargo prints one "test result:" line per test binary and never adds them up, thr
- **The first build of a tree downloads every crate** into `linux/_build/cargo-home` and builds about 20 GB into `linux/_build/cargo-target`. No network means a failed build that is not the change; `--offline` sets `CARGO_NET_OFFLINE` once the tree has its crates.
- **`cargo` not on PATH** in a shell that never read the user's profile: the wrapper sources `~/.cargo/env`, which is where rustup puts it. Run by hand, `meson devenv cargo ...` fails with "Command not found: cargo".
- **A schema or desktop file edit needs `build`**, which recompiles the GSettings schema; a stale one aborts the app on its first settings read.
- **`setup` again after a merge** from the base, or after `linux/meson.build`, `linux/meson_options.txt` or a template under `linux/data/` changed. A new `.rs` file needs nothing: Cargo finds modules itself.
- **`setup` again after a merge** from the base, or after `linux/meson.build`, `linux/meson.options` or a template under `linux/data/` changed. A new `.rs` file needs nothing: Cargo finds modules itself.

## Tests

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/linux-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ on:
- "linux/Cargo.toml"
- "linux/Cargo.lock"
- "linux/meson.build"
- "linux/meson_options.txt"
- "linux/meson.options"
- "linux/crates/**/meson.build"
- "linux/data/**/meson.build"
- "linux/po/meson.build"
Expand Down
10 changes: 5 additions & 5 deletions linux/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ The driver registry is built once, by `build_registry` in `crates/app/src/lib.rs
```rust
fn build_registry() -> DriverRegistry {
let mut r = DriverRegistry::new();
r.register(Arc::new(drivers_clickhouse::ClickhouseDriver));
r.register(Arc::new(drivers_mssql::MssqlDriver));
r.register(Arc::new(drivers_mysql::MysqlDriver));
r.register(Arc::new(drivers_postgres::PgDriver));
r.register(Arc::new(drivers_sqlite::SqliteDriver));
r.register(Arc::new(tablepro_driver_clickhouse::ClickhouseDriver));
r.register(Arc::new(tablepro_driver_mssql::MssqlDriver));
r.register(Arc::new(tablepro_driver_mysql::MysqlDriver));
r.register(Arc::new(tablepro_driver_postgres::PgDriver));
r.register(Arc::new(tablepro_driver_sqlite::SqliteDriver));
r
}
```
Expand Down
16 changes: 15 additions & 1 deletion linux/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
resolver = "2"
resolver = "3"
members = [
"crates/app",
"crates/core",
Expand All @@ -23,6 +23,18 @@ license = "AGPL-3.0-or-later"
publish = false

[workspace.dependencies]
tablepro-core = { path = "crates/core" }
tablepro-driver-clickhouse = { path = "crates/drivers/clickhouse" }
tablepro-driver-mssql = { path = "crates/drivers/mssql" }
tablepro-driver-mysql = { path = "crates/drivers/mysql" }
tablepro-driver-postgres = { path = "crates/drivers/postgres" }
tablepro-driver-sqlite = { path = "crates/drivers/sqlite" }
tablepro-net = { path = "crates/net" }
tablepro-session = { path = "crates/session" }
tablepro-ssh = { path = "crates/ssh" }
tablepro-storage = { path = "crates/storage" }
tablepro-test-fixtures = { path = "crates/test-fixtures" }
tablepro-test-support = { path = "crates/test-support" }
async-trait = "0.1"
thiserror = "2"
serde = { version = "1", features = ["derive"] }
Expand Down Expand Up @@ -67,6 +79,7 @@ rustls-native-certs = "0.8"
rustls-platform-verifier = "0.7"
pem-rfc7468 = { version = "1", features = ["alloc"] }
socket2 = { version = "0.6", features = ["all"] }
rustix = { version = "1.1", default-features = false, features = ["std"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["aws_lc_rs", "logging", "tls12"] }
hyper-util = { version = "0.1", features = ["client-legacy", "http1", "tokio"] }
hyper-rustls = { version = "0.27", default-features = false, features = ["aws-lc-rs", "http1", "tls12"] }
Expand Down Expand Up @@ -105,6 +118,7 @@ allow_attributes = "deny"
allow_attributes_without_reason = "deny"
ignore_without_reason = "deny"
too_many_lines = "deny"
self_named_module_files = "deny"

[profile.release]
lto = "fat"
Expand Down
44 changes: 15 additions & 29 deletions linux/crates/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,87 +3,73 @@ name = "tablepro"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
publish = false
publish.workspace = true

[lib]
name = "tablepro_app"
path = "src/lib.rs"

[[bin]]
name = "tablepro"
path = "src/main.rs"

[[test]]
name = "startup"
path = "tests/startup.rs"
harness = false

[[test]]
name = "i18n_catalog"
path = "tests/i18n_catalog.rs"
harness = false

[[test]]
name = "logging"
path = "tests/logging.rs"
harness = false

# A panic hook is process-wide and the crash ends the process, so each
# case runs in a child of the binary.
[[test]]
name = "crash_report"
path = "tests/crash_report.rs"
harness = false

# These start the application, which GTK allows only on the process's
# main thread, so they run without the test harness.
[[test]]
name = "application_uniqueness"
path = "tests/application_uniqueness.rs"
harness = false

[[test]]
name = "application_lifecycle"
path = "tests/application_lifecycle.rs"
harness = false

# D-Bus starts the binary, which opens its windows on GTK's main thread.
[[test]]
name = "open_files"
path = "tests/open_files.rs"
harness = false

[[test]]
name = "application_session_restore"
path = "tests/application_session_restore.rs"
harness = false

[[test]]
name = "accessibility"
path = "tests/accessibility/main.rs"
harness = false

[features]
default = ["kerberos"]
kerberos = ["tablepro-driver-mssql/kerberos"]

[dependencies]
tablepro-core = { path = "../core" }
tablepro-driver-clickhouse = { path = "../drivers/clickhouse" }
tablepro-driver-mssql = { path = "../drivers/mssql" }
tablepro-driver-mysql = { path = "../drivers/mysql" }
tablepro-driver-postgres = { path = "../drivers/postgres" }
tablepro-driver-sqlite = { path = "../drivers/sqlite" }
tablepro-core.workspace = true
tablepro-driver-clickhouse.workspace = true
tablepro-driver-mssql.workspace = true
tablepro-driver-mysql.workspace = true
tablepro-driver-postgres.workspace = true
tablepro-driver-sqlite.workspace = true
tablepro-net.workspace = true
tablepro-session.workspace = true
tablepro-ssh.workspace = true
tablepro-storage.workspace = true
async-trait.workspace = true
chrono.workspace = true
futures.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
tablepro-net = { path = "../net" }
tablepro-ssh = { path = "../ssh" }
tablepro-session = { path = "../session" }
tablepro-storage = { path = "../storage" }
gio.workspace = true
gio-unix.workspace = true
gtk4.workspace = true
Expand All @@ -92,7 +78,7 @@ sourceview5.workspace = true
glib.workspace = true
relm4.workspace = true
# CLOCK_BOOTTIME, which std does not expose, tells a suspend apart.
rustix = { version = "1.1", default-features = false, features = ["std", "time"] }
rustix = { workspace = true, features = ["time"] }
secrecy.workspace = true
tokio.workspace = true
tokio-util = { workspace = true, features = ["rt"] }
Expand All @@ -107,9 +93,9 @@ sqlformat = "0.5"

[dev-dependencies]
proptest.workspace = true
tablepro-session = { path = "../session", features = ["fakes"] }
tablepro-test-fixtures = { path = "../test-fixtures" }
tablepro-test-support = { path = "../test-support" }
tablepro-session = { workspace = true, features = ["fakes"] }
tablepro-test-fixtures.workspace = true
tablepro-test-support.workspace = true
tempfile.workspace = true
tokio = { workspace = true, features = ["macros", "rt", "test-util"] }
# tokio-postgres logs through `log`, so the logging tests drive that
Expand Down
4 changes: 2 additions & 2 deletions linux/crates/app/src/application/debug_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ mod tests {
flatpak: true,
};
let mut drivers = DriverRegistry::new();
drivers.register(Arc::new(drivers_sqlite::SqliteDriver));
drivers.register(Arc::new(drivers_postgres::PgDriver));
drivers.register(Arc::new(tablepro_driver_sqlite::SqliteDriver));
drivers.register(Arc::new(tablepro_driver_postgres::PgDriver));

let expected = format!(
"TablePro {version}\n\
Expand Down
10 changes: 5 additions & 5 deletions linux/crates/app/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,11 @@ pub fn run() -> Result<glib::ExitCode, StartupError> {

fn build_registry() -> DriverRegistry {
let mut r = DriverRegistry::new();
r.register(Arc::new(drivers_clickhouse::ClickhouseDriver));
r.register(Arc::new(drivers_mssql::MssqlDriver));
r.register(Arc::new(drivers_mysql::MysqlDriver));
r.register(Arc::new(drivers_postgres::PgDriver));
r.register(Arc::new(drivers_sqlite::SqliteDriver));
r.register(Arc::new(tablepro_driver_clickhouse::ClickhouseDriver));
r.register(Arc::new(tablepro_driver_mssql::MssqlDriver));
r.register(Arc::new(tablepro_driver_mysql::MysqlDriver));
r.register(Arc::new(tablepro_driver_postgres::PgDriver));
r.register(Arc::new(tablepro_driver_sqlite::SqliteDriver));
r
}

Expand Down
2 changes: 1 addition & 1 deletion linux/crates/app/src/logging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ mod tests {
log::info!(target: "tokio_postgres::connection", "NOTICE: {SECRET}");
log::debug!(target: "sqlparser::parser", "Parsing sql '{SECRET}'...");
log::debug!(target: "sqlparser::dialect", "get_next_precedence_full() {SECRET}");
log::debug!(target: "drivers_postgres::pool", "a pooled connection ended");
log::debug!(target: "tablepro_driver_postgres::pool", "a pooled connection ended");
});

assert!(!text.contains("hunter2"), "{text}");
Expand Down
4 changes: 2 additions & 2 deletions linux/crates/app/src/services/change_tracker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,8 +1226,8 @@ mod tests {
assert!(!t.can_undo());
}

fn postgres() -> drivers_postgres::PgDialect {
drivers_postgres::PgDialect::new(&tablepro_core::ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0))
fn postgres() -> tablepro_driver_postgres::PgDialect {
tablepro_driver_postgres::PgDialect::new(&tablepro_core::ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0))
}

fn plan(tracker: &TabChangeTracker, columns: &[ColumnInfo]) -> (TrackedChanges, tablepro_core::save::SavePlan) {
Expand Down
33 changes: 18 additions & 15 deletions linux/crates/app/src/services/pending_structure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ mod tests {
#[test]
fn pending_structure_plans_with_supplied_dialect() {
let pending = created();
let postgres = drivers_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let mysql = drivers_mysql::MySqlDialect::new(
drivers_mysql::MySqlFlavour::MySql,
let postgres = tablepro_driver_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let mysql = tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MySql,
&ServerInfo::new("MySQL", "8.4.3", 8, 4, 3),
);

Expand All @@ -160,7 +160,7 @@ mod tests {
}

fn orders() -> TableDefinition {
let dialect = drivers_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let dialect = tablepro_driver_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let column = |name: &str, primary_key: bool| {
ColumnDefinition::new(
ColumnInfo {
Expand Down Expand Up @@ -201,7 +201,7 @@ mod tests {

#[test]
fn a_save_waits_for_a_valid_draft_and_every_typed_default() {
let postgres = drivers_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let postgres = tablepro_driver_postgres::PgDialect::new(&ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0));
let mut typed_default = edited(|draft| draft.columns[1].nullable = false);
typed_default.unparsed_defaults = vec!["total".to_owned()];
let unnamed = edited(|draft| draft.columns[1].name = String::new());
Expand Down Expand Up @@ -292,15 +292,15 @@ mod tests {
vec![
engine(
"PostgreSQL",
Box::new(drivers_postgres::PgDialect::new(&server("PostgreSQL", 18))),
Box::new(tablepro_driver_postgres::PgDialect::new(&server("PostgreSQL", 18))),
"integer",
"text",
Some("t_pkey"),
),
engine(
"MySQL",
Box::new(drivers_mysql::MySqlDialect::new(
drivers_mysql::MySqlFlavour::MySql,
Box::new(tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MySql,
&ServerInfo::new("MySQL", "8.4.3", 8, 4, 3),
)),
"int",
Expand All @@ -309,8 +309,8 @@ mod tests {
),
engine(
"MariaDB",
Box::new(drivers_mysql::MySqlDialect::new(
drivers_mysql::MySqlFlavour::MariaDb,
Box::new(tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MariaDb,
&ServerInfo::new("MariaDB", "11.4.5", 11, 4, 5),
)),
"int",
Expand All @@ -319,23 +319,26 @@ mod tests {
),
engine(
"SQL Server",
Box::new(drivers_mssql::MssqlDialect::new(16)),
Box::new(tablepro_driver_mssql::MssqlDialect::new(16)),
"int",
"nvarchar(40)",
Some("PK_t"),
),
engine(
"SQLite",
Box::new(drivers_sqlite::SqliteDialect::new(drivers_sqlite::SqliteVersion::new(
3, 46, 0,
))),
Box::new(tablepro_driver_sqlite::SqliteDialect::new(
tablepro_driver_sqlite::SqliteVersion::new(3, 46, 0),
)),
"INTEGER",
"TEXT",
None,
),
engine(
"ClickHouse",
Box::new(drivers_clickhouse::ClickHouseDialect::new(&server("ClickHouse", 25))),
Box::new(tablepro_driver_clickhouse::ClickHouseDialect::new(&server(
"ClickHouse",
25,
))),
"Int32",
"String",
None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ mod key_injector;
mod main_loop;
mod memory_settings;
mod owned_window;
#[path = "../tests/support/settings_schema.rs"]
#[path = "../../tests/support/settings_schema.rs"]
pub(crate) mod settings_schema;
pub(crate) mod shortcut_keys;
mod signal_log;
Expand Down
4 changes: 2 additions & 2 deletions linux/crates/app/src/ui/browse_tab/clipboard_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ impl BrowseModel {

/// The table a browse tab's rows came from, so an export can
/// write them back as `INSERT` statements.
fn sql_target(&self) -> crate::ui::export_dialog::SqlTarget {
crate::ui::export_dialog::SqlTarget {
fn sql_target(&self) -> crate::ui::export::dialog::SqlTarget {
crate::ui::export::dialog::SqlTarget {
table: self.table_ref(),
generated: self
.current_columns
Expand Down
6 changes: 3 additions & 3 deletions linux/crates/app/src/ui/browse_tab/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -952,8 +952,8 @@ fn f004_copy_row_as_insert_uses_row_below_draft() {
#[gtk4::test]
fn copy_as_in_clause_writes_the_servers_literals() {
let mut script = serving_table();
script.dialect = Arc::new(drivers_mysql::MySqlDialect::new(
drivers_mysql::MySqlFlavour::MySql,
script.dialect = Arc::new(tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MySql,
&tablepro_core::ServerInfo::new("MySQL", "8.4.3", 8, 4, 3),
));
let injected = "\\') OR 1=1 -- ";
Expand Down Expand Up @@ -1015,7 +1015,7 @@ pub(super) fn rows_from(first: i64, names: &[&str]) -> QueryResult {
fn partitioned_table() -> ConnectionScript {
let server = tablepro_core::ServerInfo::new("PostgreSQL", "18.0", 18, 0, 0);
let mut script = ConnectionScript {
dialect: Arc::new(drivers_postgres::PgDialect::new(&server)),
dialect: Arc::new(tablepro_driver_postgres::PgDialect::new(&server)),
..ConnectionScript::default()
};
script
Expand Down
4 changes: 2 additions & 2 deletions linux/crates/app/src/ui/clipboard/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ fn copy_insert_uses_visible_columns_only() {
/// in one would close the string and run the rest as SQL.
#[test]
fn an_in_clause_copy_is_written_in_the_engines_literals() {
let dialect = Arc::new(drivers_mysql::MySqlDialect::new(
drivers_mysql::MySqlFlavour::MySql,
let dialect = Arc::new(tablepro_driver_mysql::MySqlDialect::new(
tablepro_driver_mysql::MySqlFlavour::MySql,
&tablepro_core::ServerInfo::new("MySQL", "8.4.3", 8, 4, 3),
));
let injected = "\\') OR 1=1 -- ";
Expand Down
Loading
Loading