Skip to content

Commit

Permalink
Add mbtiles diff command (#1068)
Browse files Browse the repository at this point in the history
Implement `mbtiles diff a.mbtiles b.mbtiles diff.mbtiles` command

This should behave exactly the same as `mbtiles copy a.mbtiles
--diff-with-file b.mbtiles diff.mbtiles`.

---------

Co-authored-by: Yuri Astrakhan <[email protected]>
  • Loading branch information
sharkAndshark and nyurik authored Feb 8, 2024
1 parent 0aa6bd7 commit 79a8912
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
26 changes: 26 additions & 0 deletions docs/src/mbtiles-diff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Diffing MBTiles

## `mbtiles diff`

Diff command compares two mbtiles files `A` and `B`, and generates a diff (delta) file.
If the diff file is [applied](mbtiles-copy.md#mbtiles-apply-patch) to `A`, it will produce `B`.
The diff file will contain all tiles that are different between the two files
(modifications, insertions, and deletions as `NULL` values), for both the tile and metadata tables.
The only exception is `agg_tiles_has` metadata value. It will be renamed to `agg_tiles_hash_in_diff` and a
new `agg_tiles_hash` will be generated for the diff file itself.

```shell
# This command will comapre `a.mbtiles` and `b.mbtiles`, and generate a new diff file `diff.mbtiles`.
mbtiles diff a.mbtiles b.mbtiles diff.mbtiles

# If diff.mbtiles is applied to a.mbtiles, it will produce b.mbtiles
mbtiles apply-diff a.mbtiles diff.mbtiles b2.mbtiles

# b.mbtiles and b2.mbtiles should now be the same
# Validate both files and see that their hash values are identical
mbtiles validate b.mbtiles
[INFO ] The agg_tiles_hashes=E95C1081447FB25674DCC1EB97F60C26 has been verified for b.mbtiles

mbtiles validate b2.mbtiles
[INFO ] The agg_tiles_hashes=E95C1081447FB25674DCC1EB97F60C26 has been verified for b2.mbtiles
```
52 changes: 51 additions & 1 deletion mbtiles/src/bin/mbtiles.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ enum Commands {
/// Value to set, or nothing if the key should be deleted.
value: Option<String>,
},
/// Compare two files A and B, and generate a new diff file. If the diff file is applied to A, it will produce B.
#[command(name = "diff")]
Diff {
file_a: PathBuf,
file_b: PathBuf,
diff: PathBuf,
},
/// Copy tiles from one mbtiles file to another.
#[command(name = "copy", alias = "cp")]
Copy(CopyArgs),
Expand Down Expand Up @@ -212,6 +219,28 @@ async fn main_int() -> anyhow::Result<()> {
println!("MBTiles file summary for {mbt}");
println!("{}", mbt.summary(&mut conn).await?);
}
Commands::Diff {
file_a,
file_b,
diff,
} => {
let opts = MbtilesCopier {
src_file: file_a,
diff_with_file: Some(file_b),
dst_file: diff,
copy: CopyType::All,
skip_agg_tiles_hash: false,
on_duplicate: Some(CopyDuplicateMode::Override),
dst_type_cli: None,
dst_type: None,
min_zoom: None,
max_zoom: None,
zoom_levels: vec![],
bbox: vec![],
apply_patch: None,
};
opts.run().await?;
}
}

Ok(())
Expand Down Expand Up @@ -253,7 +282,7 @@ mod tests {
use mbtiles::CopyDuplicateMode;

use super::*;
use crate::Commands::{ApplyPatch, Copy, MetaGetValue, MetaSetValue, Validate};
use crate::Commands::{ApplyPatch, Copy, Diff, MetaGetValue, MetaSetValue, Validate};
use crate::{Args, IntegrityCheckType};

#[test]
Expand Down Expand Up @@ -524,4 +553,25 @@ mod tests {
}
);
}

#[test]
fn test_diff() {
assert_eq!(
Args::parse_from([
"mbtiles",
"diff",
"file-a.mbtiles",
"file-b.mbtiles",
"../delta.mbtiles",
]),
Args {
verbose: false,
command: Diff {
file_a: PathBuf::from("file-a.mbtiles"),
file_b: PathBuf::from("file-b.mbtiles"),
diff: PathBuf::from("../delta.mbtiles"),
}
}
);
}
}
6 changes: 5 additions & 1 deletion tests/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,11 @@ if [[ "$MBTILES_BIN" != "-" ]]; then
"$TEST_TEMP_DIR/world_cities_diff.mbtiles" \
--diff-with-file ./tests/fixtures/mbtiles/world_cities_modified.mbtiles \
2>&1 | tee "$TEST_OUT_DIR/copy_diff.txt"

$MBTILES_BIN diff \
./tests/fixtures/mbtiles/world_cities.mbtiles \
./tests/fixtures/mbtiles/world_cities_modified.mbtiles \
"$TEST_TEMP_DIR/world_cities_diff2.mbtiles" \
2>&1 | tee "$TEST_OUT_DIR/copy_diff2.txt"
if command -v sqlite3 > /dev/null; then
# Apply this diff to the original version of the file
cp ./tests/fixtures/mbtiles/world_cities.mbtiles "$TEST_TEMP_DIR/world_cities_copy.mbtiles"
Expand Down

0 comments on commit 79a8912

Please sign in to comment.