Skip to content

Commit 7168376

Browse files
authored
feat(prepare): add a missing App_Resources/<Platform> from the default template (#6173)
ensureAppResourcesExist only fetched the default template's App_Resources when the whole folder was missing. An app created before Windows support has App_Resources/Android and iOS but no Windows folder, so `ns run windows` needed the folder copied by hand. Prepare now passes the platform's App_Resources folder name. When the app has App_Resources but no folder for that platform, the CLI copies it from the default template, or warns when the template has none.
1 parent 8e24d72 commit 7168376

4 files changed

Lines changed: 144 additions & 14 deletions

File tree

‎lib/controllers/prepare-controller.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,10 @@ export class PrepareController
143143
prepareData: IPrepareData,
144144
projectData: IProjectData,
145145
): Promise<IPrepareResultData> {
146-
await this.$projectService.ensureAppResourcesExist(projectData.projectDir);
146+
await this.$projectService.ensureAppResourcesExist(
147+
projectData.projectDir,
148+
this.$mobileHelper.normalizePlatformName(prepareData.platform),
149+
);
147150
await this.$platformController.addPlatformIfNeeded(
148151
prepareData,
149152
projectData,

‎lib/definitions/project.d.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,12 @@ interface IProjectService {
9595
* Checks if App_Resources exists, or pulls down a fresh set
9696
* from the default template otherwise.
9797
* @param {string} projectDir
98+
* @param {string} platformDirName When set, also adds App_Resources/<platformDirName> from the default template if it is missing.
9899
*/
99-
ensureAppResourcesExist(projectDir: string): Promise<void>;
100+
ensureAppResourcesExist(
101+
projectDir: string,
102+
platformDirName?: string,
103+
): Promise<void>;
100104
}
101105

102106
interface INsConfigPlaform {

‎lib/services/project-service.ts‎

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,10 @@ export class ProjectService implements IProjectService {
224224
}
225225

226226
@performanceLog()
227-
public async ensureAppResourcesExist(projectDir: string): Promise<void> {
227+
public async ensureAppResourcesExist(
228+
projectDir: string,
229+
platformDirName?: string
230+
): Promise<void> {
228231
const projectData = this.$projectDataService.getProjectData(projectDir);
229232
const appResourcesDestinationPath = projectData.getAppResourcesDirectoryPath(
230233
projectDir
@@ -235,23 +238,48 @@ export class ProjectService implements IProjectService {
235238
"Project does not have App_Resources - fetching from default template."
236239
);
237240
this.$fs.createDirectory(appResourcesDestinationPath);
238-
const tempDir = await this.$tempService.mkdirSync("ns-default-template");
239241
// the template installed doesn't have App_Resources -> get from a default template
240-
await this.$pacoteService.extractPackage(
241-
constants.RESERVED_TEMPLATE_NAMES["default"],
242-
tempDir
243-
);
244-
const templateProjectData = this.$projectDataService.getProjectData(
245-
tempDir
246-
);
247-
const templateAppResourcesDir = templateProjectData.getAppResourcesDirectoryPath(
248-
tempDir
249-
);
242+
const templateAppResourcesDir = await this.getDefaultTemplateAppResourcesDir();
250243
this.$fs.copyFile(
251244
path.join(templateAppResourcesDir, "*"),
252245
appResourcesDestinationPath
253246
);
247+
return;
254248
}
249+
250+
// An app created before a platform was supported (e.g. Windows) has no folder for it.
251+
if (
252+
platformDirName &&
253+
!this.$fs.exists(path.join(appResourcesDestinationPath, platformDirName))
254+
) {
255+
const templateAppResourcesDir = await this.getDefaultTemplateAppResourcesDir();
256+
const templatePlatformDir = path.join(
257+
templateAppResourcesDir,
258+
platformDirName
259+
);
260+
if (!this.$fs.exists(templatePlatformDir)) {
261+
this.$logger.warn(
262+
`App_Resources/${platformDirName} is missing and the default template does not provide one.`
263+
);
264+
return;
265+
}
266+
this.$logger.info(
267+
`Adding App_Resources/${platformDirName} from the default template.`
268+
);
269+
this.$fs.copyFile(templatePlatformDir, appResourcesDestinationPath);
270+
}
271+
}
272+
273+
private async getDefaultTemplateAppResourcesDir(): Promise<string> {
274+
const tempDir = await this.$tempService.mkdirSync("ns-default-template");
275+
await this.$pacoteService.extractPackage(
276+
constants.RESERVED_TEMPLATE_NAMES["default"],
277+
tempDir
278+
);
279+
const templateProjectData = this.$projectDataService.getProjectData(
280+
tempDir
281+
);
282+
return templateProjectData.getAppResourcesDirectoryPath(tempDir);
255283
}
256284

257285
@performanceLog()

‎test/project-service.ts‎

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,4 +342,99 @@ describe("projectService", () => {
342342
assert.isFalse(projectService.isValidNativeScriptProject("some-dir"));
343343
});
344344
});
345+
346+
describe("ensureAppResourcesExist", () => {
347+
const projectDir = path.resolve("app-resources-project");
348+
const appResources = path.join(projectDir, "App_Resources");
349+
const templateDir = path.resolve("default-template");
350+
const templateAppResources = path.join(templateDir, "App_Resources");
351+
352+
const setup = (existing: string[]) => {
353+
const exists = new Set(existing.map((p) => path.resolve(p)));
354+
const copies: { from: string; to: string }[] = [];
355+
let extracted = 0;
356+
const testInjector = new yok.Yok();
357+
testInjector.register("fs", {
358+
exists: (p: string) => exists.has(path.resolve(p)),
359+
createDirectory: (p: string) => exists.add(path.resolve(p)),
360+
copyFile: (from: string, to: string) => copies.push({ from, to }),
361+
});
362+
testInjector.register("logger", LoggerStub);
363+
testInjector.register("projectDataService", {
364+
getProjectData: (dir: string): IProjectData =>
365+
<any>{
366+
getAppResourcesDirectoryPath: (d: string) =>
367+
path.join(d === templateDir ? templateDir : dir, "App_Resources"),
368+
},
369+
});
370+
testInjector.register("pacoteService", {
371+
extractPackage: async () => {
372+
extracted++;
373+
},
374+
});
375+
testInjector.register("tempService", {
376+
mkdirSync: async () => templateDir,
377+
});
378+
for (const name of [
379+
"options",
380+
"hooksService",
381+
"packageManager",
382+
"errors",
383+
"projectConfigService",
384+
"projectHelper",
385+
"projectNameService",
386+
"projectTemplatesService",
387+
"staticConfig",
388+
"childProcess",
389+
]) {
390+
testInjector.register(name, {});
391+
}
392+
const projectService: IProjectService = testInjector.resolve(
393+
ProjectServiceLib.ProjectService
394+
);
395+
return { projectService, copies, extracted: () => extracted };
396+
};
397+
398+
it("copies the whole App_Resources when it is missing", async () => {
399+
const { projectService, copies } = setup([]);
400+
await projectService.ensureAppResourcesExist(projectDir, "Windows");
401+
assert.deepEqual(copies, [
402+
{ from: path.join(templateAppResources, "*"), to: appResources },
403+
]);
404+
});
405+
406+
it("adds a missing platform folder from the default template", async () => {
407+
const { projectService, copies } = setup([
408+
appResources,
409+
path.join(templateAppResources, "Windows"),
410+
]);
411+
await projectService.ensureAppResourcesExist(projectDir, "Windows");
412+
assert.deepEqual(copies, [
413+
{ from: path.join(templateAppResources, "Windows"), to: appResources },
414+
]);
415+
});
416+
417+
it("leaves an existing platform folder alone", async () => {
418+
const { projectService, copies, extracted } = setup([
419+
appResources,
420+
path.join(appResources, "Windows"),
421+
]);
422+
await projectService.ensureAppResourcesExist(projectDir, "Windows");
423+
assert.deepEqual(copies, []);
424+
assert.equal(extracted(), 0);
425+
});
426+
427+
it("copies nothing when the template has no folder for the platform", async () => {
428+
const { projectService, copies } = setup([appResources]);
429+
await projectService.ensureAppResourcesExist(projectDir, "Windows");
430+
assert.deepEqual(copies, []);
431+
});
432+
433+
it("does not look at platform folders without a platform", async () => {
434+
const { projectService, copies, extracted } = setup([appResources]);
435+
await projectService.ensureAppResourcesExist(projectDir);
436+
assert.deepEqual(copies, []);
437+
assert.equal(extracted(), 0);
438+
});
439+
});
345440
});

0 commit comments

Comments
 (0)