Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix merge path handling #143

Merged
merged 4 commits into from
Jul 24, 2024
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
165 changes: 145 additions & 20 deletions specs/tools/tilesetProcessing/TilesetMergerSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,39 @@ import { TilesetOperations } from "../../../src/tools";
import { SpecHelpers } from "../../SpecHelpers";

const SPECS_DATA_BASE_DIRECTORY = SpecHelpers.getSpecsDataBaseDirectory();

const basicInputs = [
SPECS_DATA_BASE_DIRECTORY + "/mergeTilesets/basicMerge/TilesetA",
SPECS_DATA_BASE_DIRECTORY + "/mergeTilesets/basicMerge/sub/TilesetA",
];
const basicOutput =
SPECS_DATA_BASE_DIRECTORY + "/output/mergeTilesets/basicMerge";
const overwrite = true;

describe("TilesetMerger", function () {
afterEach(function () {
SpecHelpers.forceDeleteDirectory(
SPECS_DATA_BASE_DIRECTORY + "/output/mergeTilesets"
Paths.join(SPECS_DATA_BASE_DIRECTORY, "output/mergeTilesets")
);
});
it("merges tilesets from directories into a single tileset directory", async function () {
const inputDirectories = [
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/TilesetA"
),
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/sub/TilesetA"
),
];
const outputDirectory = Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"output/mergeTilesets/basicMerge"
);
const outputFile = Paths.join(outputDirectory, "tileset.json");

it("merges tilesets into a single tileset", async function () {
await TilesetOperations.merge(basicInputs, basicOutput, overwrite);
await TilesetOperations.merge(inputDirectories, outputDirectory, overwrite);

// Ensure that the output directory contains the expected files:
// All files of the input, disambiguated for the same base name
// (i.e. "TilesetA" and "TilesetA-0" - this is not specified,
// but has to be assumed here)
const actualRelativeFiles =
SpecHelpers.collectRelativeFileNames(basicOutput);
SpecHelpers.collectRelativeFileNames(outputDirectory);
actualRelativeFiles.sort();
const expectedRelativeFiles = [
"TilesetA-0/ll.b3dm",
Expand All @@ -52,9 +60,66 @@ describe("TilesetMerger", function () {

// Ensure that the single 'tileset.json' contains the
// proper content URIs for the external tilesets:
const tilesetJsonBuffer = fs.readFileSync(
Paths.join(basicOutput, "tileset.json")
const tilesetJsonBuffer = fs.readFileSync(outputFile);
const tileset = JSON.parse(tilesetJsonBuffer.toString());
const actualContentUris = await SpecHelpers.collectExplicitContentUris(
tileset.root
);
actualContentUris.sort();

const expectedContentUris = [
"TilesetA-0/tileset.json",
"TilesetA/tileset.json",
];
expect(actualContentUris).toEqual(expectedContentUris);
});

it("merges tilesets from files into a single tileset file", async function () {
const inputFiles = [
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/TilesetA/tileset.json"
),
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/sub/TilesetA/tileset.json"
),
];
const outputDirectory = Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"output/mergeTilesets/basicMerge"
);
const outputFile = Paths.join(outputDirectory, "tileset.json");

await TilesetOperations.merge(inputFiles, outputFile, overwrite);

// Ensure that the output directory contains the expected files:
// All files of the input, disambiguated for the same base name
// (i.e. "TilesetA" and "TilesetA-0" - this is not specified,
// but has to be assumed here)
const actualRelativeFiles =
SpecHelpers.collectRelativeFileNames(outputDirectory);
actualRelativeFiles.sort();
const expectedRelativeFiles = [
"TilesetA-0/ll.b3dm",
"TilesetA-0/lr.b3dm",
"TilesetA-0/parent.b3dm",
"TilesetA-0/tileset.json",
"TilesetA-0/ul.b3dm",
"TilesetA-0/ur.b3dm",
"TilesetA/ll.b3dm",
"TilesetA/lr.b3dm",
"TilesetA/parent.b3dm",
"TilesetA/tileset.json",
"TilesetA/ul.b3dm",
"TilesetA/ur.b3dm",
"tileset.json",
];
expect(actualRelativeFiles).toEqual(expectedRelativeFiles);

// Ensure that the single 'tileset.json' contains the
// proper content URIs for the external tilesets:
const tilesetJsonBuffer = fs.readFileSync(outputFile);
const tileset = JSON.parse(tilesetJsonBuffer.toString());
const actualContentUris = await SpecHelpers.collectExplicitContentUris(
tileset.root
Expand All @@ -68,30 +133,90 @@ describe("TilesetMerger", function () {
expect(actualContentUris).toEqual(expectedContentUris);
});

it("merges tilesets into a single tileset for mergeJson", async function () {
await TilesetOperations.mergeJson(basicInputs, basicOutput, overwrite);
it("merges tilesets from directories into a single tileset in a directory for mergeJson", async function () {
const inputDirectories = [
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/TilesetA"
),
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/sub/TilesetA"
),
];
const outputDirectory = Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"output/mergeTilesets/basicMerge"
);
const outputFile = Paths.join(outputDirectory, "tileset.json");

await TilesetOperations.mergeJson(
inputDirectories,
outputDirectory,
overwrite
);

// Ensure that the output directory contains the expected files:
const actualRelativeFiles =
SpecHelpers.collectRelativeFileNames(basicOutput);
SpecHelpers.collectRelativeFileNames(outputDirectory);
actualRelativeFiles.sort();
const expectedRelativeFiles = ["tileset.json"];
expect(actualRelativeFiles).toEqual(expectedRelativeFiles);

// Ensure that the single 'tileset.json' contains the
// proper content URIs for the external tilesets:
const tilesetJsonBuffer = fs.readFileSync(
Paths.join(basicOutput, "tileset.json")
const tilesetJsonBuffer = fs.readFileSync(outputFile);
const tileset = JSON.parse(tilesetJsonBuffer.toString());
const actualContentUris = await SpecHelpers.collectExplicitContentUris(
tileset.root
);
actualContentUris.sort();

const expectedContentUris = [
"../../../mergeTilesets/basicMerge/TilesetA/tileset.json",
"../../../mergeTilesets/basicMerge/sub/TilesetA/tileset.json",
];
expect(actualContentUris).toEqual(expectedContentUris);
});

it("merges tilesets from files into a single tileset file for mergeJson", async function () {
const inputFiles = [
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/TilesetA/tileset.json"
),
Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"mergeTilesets/basicMerge/sub/TilesetA/tileset.json"
),
];
const outputDirectory = Paths.join(
SPECS_DATA_BASE_DIRECTORY,
"output/mergeTilesets/basicMerge"
);
const outputFile = Paths.join(outputDirectory, "tileset.json");

await TilesetOperations.mergeJson(inputFiles, outputFile, overwrite);

// Ensure that the output directory contains the expected files:
const actualRelativeFiles =
SpecHelpers.collectRelativeFileNames(outputDirectory);
actualRelativeFiles.sort();
const expectedRelativeFiles = ["tileset.json"];
expect(actualRelativeFiles).toEqual(expectedRelativeFiles);

// Ensure that the single 'tileset.json' contains the
// proper content URIs for the external tilesets:
const tilesetJsonBuffer = fs.readFileSync(outputFile);
const tileset = JSON.parse(tilesetJsonBuffer.toString());
const actualContentUris = await SpecHelpers.collectExplicitContentUris(
tileset.root
);
actualContentUris.sort();

const expectedContentUris = [
"specs/data/mergeTilesets/basicMerge/TilesetA/tileset.json",
"specs/data/mergeTilesets/basicMerge/sub/TilesetA/tileset.json",
"../../../mergeTilesets/basicMerge/TilesetA/tileset.json",
"../../../mergeTilesets/basicMerge/sub/TilesetA/tileset.json",
];
expect(actualContentUris).toEqual(expectedContentUris);
});
Expand Down
11 changes: 11 additions & 0 deletions src/base/base/Paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ export class Paths {
* the result uses `/` forward slashes as the directory
* separator.
*
* Note:
* - The first argument is assumed to be a directory
* - The second argument is assumed to be a file name
* - The result is the relativized file name
*
* For example: In a call like
* `relativize("./example/directoryA", "./example/directoryB/file.txt")`
* the second argument has to be the file name, and the result
* will be "../directoryB/file.txt", which is the path of the
* file _relative to_ the directory that is given as the first argument.
*
* @param directory - The directory
* @param fileName - The file name
* @returns The resulting path
Expand Down
34 changes: 34 additions & 0 deletions src/tilesets/tilesets/Tilesets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,40 @@ export class Tilesets {
return "tileset.json";
}

/**
* Determine a directory name from the given tileset name.
*
* When the given name ends with `.json`, `.3tz`, or `.3dtiles`
* (case-insensitively), then the directory name of that file
* name is returned. Otherwise, the given name is assumed to
* be a directory name and returned directly.
*
* NOTE: This is working around the ambiguity that is related to
* https://github.com/CesiumGS/3d-tiles/issues/184 : When someone
* uses a path like "./data/target" as a target name, then it is
* not clear whether the result should be
*
* - a JSON file "./data/target" (without extension)
* - a file called "./data/target/tileset.json"
*
* The latter is the default assumption that is used for source
* data: When the source is a directory, then it assumes
* that there is a 'tileset.json' file in this directory.
*
* For the target, checking whether there is a file extension
* seems to be a reasonable workaround.
*
* @param tilesetName - The tileset name
* @returns The directory name
*/
static determineTilesetDirectoryName(tilesetName: string) {
const n = tilesetName.toLowerCase();
if (n.endsWith(".json") || n.endsWith(".3tz") || n.endsWith(".3dtiles")) {
return path.dirname(tilesetName);
}
return tilesetName;
}

/**
* Returns whether the given names likely refer to the same package.
*
Expand Down
Loading
Loading