Skip to content

Commit

Permalink
[INTERNAL] Clone resource when reading from Memory
Browse files Browse the repository at this point in the history
  • Loading branch information
flovogt committed Dec 12, 2022
1 parent 366500c commit add6c92
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 31 deletions.
2 changes: 2 additions & 0 deletions lib/Resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,8 @@ class Resource {
options.createStream = this._createStream;
} else if (this._buffer) {
options.buffer = this._buffer;
} else if (this.__project) {
options.project = this.__project;
}

return options;
Expand Down
66 changes: 35 additions & 31 deletions lib/adapters/Memory.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ class Memory extends AbstractAdapter {
this._virDirs = Object.create(null); // map full of directories
}

/**
* Matches and returns resources from a given map (either _virFiles or _virDirs).
*
* @private
* @param {string[]} patterns
* @param {object} resourceMap
* @returns {Promise<module:@ui5/fs.Resource[]>}
*/
async _matchPatterns(patterns, resourceMap) {
const resourcePaths = Object.keys(resourceMap);
const matchedPaths = micromatch(resourcePaths, patterns, {
dot: true
});
return Promise.all(matchedPaths.map((virPath) => {
return resourceMap[virPath] && resourceMap[virPath].clone();
}));
}

/**
* Locate resources by glob.
*
Expand Down Expand Up @@ -55,22 +73,11 @@ class Memory extends AbstractAdapter {
];
}

const filePaths = Object.keys(this._virFiles);
const matchedFilePaths = micromatch(filePaths, patterns, {
dot: true
});
let matchedResources = matchedFilePaths.map((virPath) => {
return this._virFiles[virPath];
});
let matchedResources = await this._matchPatterns(patterns, this._virFiles);

if (!options.nodir) {
const dirPaths = Object.keys(this._virDirs);
const matchedDirs = micromatch(dirPaths, patterns, {
dot: true
});
matchedResources = matchedResources.concat(matchedDirs.map((virPath) => {
return this._virDirs[virPath];
}));
const matchedDirs = await this._matchPatterns(patterns, this._virDirs);
matchedResources = matchedResources.concat(matchedDirs);
}

return matchedResources;
Expand All @@ -85,28 +92,25 @@ class Memory extends AbstractAdapter {
* @param {@ui5/fs/tracing.Trace} trace Trace instance
* @returns {Promise<@ui5/fs/Resource>} Promise resolving to a single resource
*/
_byPath(virPath, options, trace) {
async _byPath(virPath, options, trace) {
if (this.isPathExcluded(virPath)) {
return Promise.resolve(null);
return null;
}
if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) {
// Neither starts with basePath, nor equals baseDirectory
return null;
}
return new Promise((resolve, reject) => {
if (!virPath.startsWith(this._virBasePath) && virPath !== this._virBaseDir) {
// Neither starts with basePath, nor equals baseDirectory
resolve(null);
return;
}

const relPath = virPath.substr(this._virBasePath.length);
trace.pathCall();
const relPath = virPath.substr(this._virBasePath.length);
trace.pathCall();

const resource = this._virFiles[relPath];
const resource = this._virFiles[relPath];

if (!resource || (options.nodir && resource.getStatInfo().isDirectory())) {
resolve(null);
} else {
resolve(resource);
}
});
if (!resource || (options.nodir && resource.getStatInfo().isDirectory())) {
return null;
} else {
return await resource.clone();
}
}

/**
Expand Down
24 changes: 24 additions & 0 deletions test/lib/Resource.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,30 @@ test("Resource: clone resource with stream", async (t) => {
t.is(clonedResourceContent, "Content", "Cloned resource has correct content string");
});

test("Resource: clone resource with project", async (t) => {
t.plan(2);

const myProject = {
name: "my project"
};
const resourceOptions = {
path: "my/path/to/resource",
project: myProject
};

const resource = new Resource({
path: "my/path/to/resource",
project: myProject
});

const clonedResource = await resource.clone();
t.pass("Resource cloned");

const clonedResourceProject = await clonedResource.getProject();
t.is(clonedResourceProject, resourceOptions.project, "Cloned resource should have same " +
"project reference as the original resource");
});

test("getStream with createStream callback content: Subsequent content requests should throw error due " +
"to drained content", async (t) => {
const resource = createBasicResource();
Expand Down
56 changes: 56 additions & 0 deletions test/lib/adapters/Memory_read.js
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,59 @@ test("static excludes: glob with negated directory exclude, not excluding resour

t.is(resources.length, 4, "Found two resources and two directories");
});

test("byPath returns new resource", async (t) => {
const originalResource = createResource({
path: "/app/index.html",
string: "test"
});

const memoryAdapter = createAdapter({virBasePath: "/"});

await memoryAdapter.write(originalResource);

const returnedResource = await memoryAdapter.byPath("/app/index.html");

t.deepEqual(returnedResource, originalResource,
"Returned resource should be deep equal to original resource");
t.not(returnedResource, originalResource,
"Returned resource should not have same reference as original resource");

const anotherReturnedResource = await memoryAdapter.byPath("/app/index.html");

t.deepEqual(anotherReturnedResource, originalResource,
"Returned resource should be deep equal to original resource");
t.not(anotherReturnedResource, originalResource,
"Returned resource should not have same reference as original resource");

t.not(returnedResource, anotherReturnedResource,
"Both returned resources should not have same reference");
});

test("byGlob returns new resources", async (t) => {
const originalResource = createResource({
path: "/app/index.html",
string: "test"
});

const memoryAdapter = createAdapter({virBasePath: "/"});

await memoryAdapter.write(originalResource);

const [returnedResource] = await memoryAdapter.byGlob("/**");

t.deepEqual(returnedResource, originalResource,
"Returned resource should be deep equal to the original resource");
t.not(returnedResource, originalResource,
"Returned resource should not have same reference as the original resource");

const [anotherReturnedResource] = await memoryAdapter.byGlob("/**");

t.deepEqual(anotherReturnedResource, originalResource,
"Another returned resource should be deep equal to the original resource");
t.not(anotherReturnedResource, originalResource,
"Another returned resource should not have same reference as the original resource");

t.not(returnedResource, anotherReturnedResource,
"Both returned resources should not have same reference");
});

0 comments on commit add6c92

Please sign in to comment.