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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,13 @@ apps, which nobody could connect there. An app's own page, reached from an older
available yet and that an administrator has to finish setting it up, instead of naming the setting.
The administrator's page for the app still names `COMPOSIO_API_KEY`.

### A new desktop install of v0.2.0 gets past Install again

A desktop app built from `main` stopped every new install at "Installing OpenBot" with
`shared/package.json: No such file or directory`. It had started reading `shared`, `toolkit` and
`extension` as packages, which v0.2.0 does not have: there `shared` is plain source and there is no
`toolkit` or `extension`. It now reads them only when the release includes them.

### A built-in Bot behind an OpenAI proxy answers again

A built-in Bot behind a gateway or proxy in front of OpenAI (an `OPENAI_BASE_URL` that is not OpenAI or
Expand Down
43 changes: 41 additions & 2 deletions desktop/src-tauri/src/preparation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ const PACKAGES: [&str; 7] = [
"toolkit",
"extension",
];
/// Packages a release has only since #784 (`shared` as a package, `toolkit`) and #858 (`extension`).
/// v0.2.0, still the latest release when this desktop was built, has `shared` as plain source and no
/// `toolkit` or `extension`; requiring their manifests failed every new install with
/// "shared/package.json: No such file or directory".
const LATER_PACKAGES: [&str; 3] = ["shared", "toolkit", "extension"];

/// The packages this release actually has: every one in `PACKAGES`, less a later one it predates.
fn packages(root: &Path) -> impl Iterator<Item = &'static str> + '_ {
PACKAGES.into_iter().filter(move |package| {
!LATER_PACKAGES.contains(package) || root.join(package).join("package.json").is_file()
})
}

#[derive(Serialize, Deserialize)]
struct Dependencies {
Expand Down Expand Up @@ -142,7 +154,7 @@ fn dependency_fingerprint(root: &Path) -> Result<String, Problem> {
hash_files(
root,
std::iter::once(PathBuf::from("bun.lock"))
.chain(PACKAGES.map(|path| Path::new(path).join("package.json")))
.chain(packages(root).map(|path| Path::new(path).join("package.json")))
.chain(separate_packages(root).into_iter().flat_map(|package| {
[
Path::new(package).join("bun.lock"),
Expand Down Expand Up @@ -198,7 +210,7 @@ pub fn invalidate(root: &Path) -> Result<(), Problem> {
/// Record resolved package manifests, not just the existence of a partial node_modules directory.
fn package_files(root: &Path) -> Result<Vec<PathBuf>, Problem> {
let mut files = BTreeSet::new();
for package in PACKAGES.into_iter().chain(separate_packages(root)) {
for package in packages(root).chain(separate_packages(root)) {
let directory = root.join(package);
let manifest: serde_json::Value = serde_json::from_slice(
&std::fs::read(directory.join("package.json")).map_err(|e| required(e.to_string()))?,
Expand Down Expand Up @@ -482,6 +494,33 @@ pub fn image_settings(
mod tests {
use super::*;

#[test]
fn a_release_from_before_the_toolkit_needs_no_shared_or_toolkit_manifest() {
let root = crate::test_support::temp_root("preparation-v020-layout");
for package in ["", "server", "app", "worker"] {
std::fs::create_dir_all(root.join(package)).unwrap();
std::fs::write(root.join(package).join("package.json"), "{}").unwrap();
}
// v0.2.0: `shared` is source with no manifest, and there is no `toolkit` or `extension`.
std::fs::create_dir_all(root.join("shared")).unwrap();
assert_eq!(
packages(&root).collect::<Vec<_>>(),
["", "server", "app", "worker"]
);
std::fs::write(root.join("bun.lock"), "lock").unwrap();
assert!(dependency_fingerprint(&root).is_ok());
assert!(package_files(&root).is_ok());
// A release that has them is held to them.
for package in LATER_PACKAGES {
std::fs::create_dir_all(root.join(package)).unwrap();
std::fs::write(root.join(package).join("package.json"), "{}").unwrap();
}
assert_eq!(packages(&root).count(), PACKAGES.len());
// The packages every release has stay required.
std::fs::remove_file(root.join("server").join("package.json")).unwrap();
assert!(dependency_fingerprint(&root).is_err());
}

struct Fixture {
root: PathBuf,
bun: PathBuf,
Expand Down
Loading