Repository navigation
fix: support running from outside the project with --path #6182
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1532,7 +1532,11 @@ export class IOSProjectService | |
| projectData: IProjectData, | ||
| ): Promise<void> { | ||
| const project = this.createPbxProj(projectData); | ||
| const group = await this.getRootGroup(groupName, sourceFolderPath); | ||
| const group = await this.getRootGroup( | ||
| groupName, | ||
| sourceFolderPath, | ||
| projectData.projectDir, | ||
| ); | ||
| // pin the sources to the main app target: without an explicit target the | ||
| // underlying xcode lib picks whichever "Sources" build phase it finds | ||
| // first, which can be an extension target (e.g. a widget) once one | ||
|
|
@@ -1543,16 +1547,26 @@ export class IOSProjectService | |
| filesRelativeToProject: true, | ||
| target: project.getFirstTarget()?.uuid, | ||
| }); | ||
| project.addToHeaderSearchPaths(group.path); | ||
| const headerFiles = this.$fs.exists(sourceFolderPath) | ||
| // A glob is no use as a search path, the folders of its headers are. | ||
| const headerSearchPaths = fastGlob.isDynamicPattern(sourceFolderPath) | ||
| ? _.uniq( | ||
| group.files | ||
| .filter((file) => path.extname(file) === ".h") | ||
| .map((file) => path.dirname(file)), | ||
| ) | ||
| : [group.path]; | ||
| headerSearchPaths.forEach((searchPath) => | ||
| project.addToHeaderSearchPaths(searchPath), | ||
| ); | ||
| const headerFiles = this.$fs.exists(group.path) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check matched headers for glob inputs. For a glob,
|
||
| ? this.$fs.enumerateFilesInDirectorySync( | ||
| sourceFolderPath, | ||
| group.path, | ||
| (file, stat) => stat.isDirectory() || path.extname(file) === ".h", | ||
| ) | ||
| : []; | ||
| if ( | ||
| headerFiles.length > 0 && | ||
| !this.$fs.exists(path.join(sourceFolderPath, "module.modulemap")) | ||
| !this.$fs.exists(path.join(group.path, "module.modulemap")) | ||
| ) { | ||
| this.$logger.warn( | ||
| `warning: Directory ${sourceFolderPath} with native iOS source code doesn't contain a modulemap file. Metadata for it will not be generated and it will not be accessible from JavaScript. To learn more see https://docs.nativescript.org/guides/ios-source-code`, | ||
|
|
@@ -1597,7 +1611,11 @@ export class IOSProjectService | |
| } | ||
| } | ||
|
|
||
| private async getRootGroup(name: string, rootPath: string) { | ||
| private async getRootGroup( | ||
| name: string, | ||
| rootPath: string, | ||
| projectRoot: string, | ||
| ) { | ||
| const filePathsArr: string[] = []; | ||
| const rootGroup: INativeSourceCodeGroup = { | ||
| name: name, | ||
|
|
@@ -1606,17 +1624,19 @@ export class IOSProjectService | |
| }; | ||
|
|
||
| if (fastGlob.isDynamicPattern(rootPath)) { | ||
| const projectRoot = this.$projectDataService.getProjectData().projectDir; | ||
| const filePaths = await fastGlob(rootPath); | ||
| // Relative to the project: --path can run the CLI from anywhere. | ||
| const filePaths = await fastGlob(rootPath, { cwd: projectRoot }); | ||
|
rigor789 marked this conversation as resolved.
Resolved
|
||
| for (const filePath of filePaths) { | ||
| const sourceFilePath = path.normalize(path.join(projectRoot, filePath)); | ||
| filePathsArr.push(sourceFilePath); | ||
| } | ||
| } else { | ||
| if (this.$fs.exists(rootPath)) { | ||
| const stats = this.$fs.getFsStats(rootPath); | ||
| if (stats.isDirectory() && !this.$fs.isEmptyDir(rootPath)) { | ||
| this.$fs.readDirectory(rootPath).forEach((fileName) => { | ||
| const folderPath = path.resolve(projectRoot, rootPath); | ||
| rootGroup.path = folderPath; | ||
| if (this.$fs.exists(folderPath)) { | ||
| const stats = this.$fs.getFsStats(folderPath); | ||
| if (stats.isDirectory() && !this.$fs.isEmptyDir(folderPath)) { | ||
| this.$fs.readDirectory(folderPath).forEach((fileName) => { | ||
| const filePath = path.join(rootGroup.path, fileName); | ||
| filePathsArr.push(filePath); | ||
| }); | ||
|
|
@@ -1684,6 +1704,7 @@ export class IOSProjectService | |
| const group = await this.getRootGroup( | ||
| pluginData.name, | ||
| pluginPlatformsFolderPath, | ||
| projectData.projectDir, | ||
| ); | ||
| project.removePbxGroup(group.name, group.path); | ||
| project.removeFromHeaderSearchPaths(group.path); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| import { assert } from "chai"; | ||
| import { BasePackageManager } from "../lib/base-package-manager"; | ||
|
|
||
| class TestPackageManager extends (<any>BasePackageManager) { | ||
| constructor() { | ||
| super({}, {}, {}, {}, {}, "npm"); | ||
| } | ||
| } | ||
|
|
||
| describe("BasePackageManager", () => { | ||
| const flags = (config: object): string[] => | ||
| (<any>new TestPackageManager()).getFlagsString(config, true); | ||
|
|
||
| it("doesn't pass the CLI's own options to the package manager", () => { | ||
| assert.deepEqual( | ||
| flags({ | ||
| path: "apps/app", | ||
| frameworkPath: "runtime.tgz", | ||
| disableNpmInstall: true, | ||
| ignoreScripts: true, | ||
| }), | ||
| [], | ||
| ); | ||
| }); | ||
|
|
||
| it("passes the package manager's options on", () => { | ||
| assert.deepEqual(flags({ "ignore-scripts": true, "save-dev": true }), [ | ||
| "--ignore-scripts", | ||
| "--save-dev", | ||
| ]); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import { assert } from "chai"; | ||
| import * as fs from "fs"; | ||
| import * as os from "os"; | ||
| import * as path from "path"; | ||
| import { FileSystem } from "../lib/common/file-system"; | ||
| import { IOSProjectService } from "../lib/services/ios-project-service"; | ||
|
|
||
| describe("iOSProjectService getRootGroup", () => { | ||
| let projectDir: string; | ||
| let sourcesDir: string; | ||
| let cwd: string; | ||
|
|
||
| beforeEach(() => { | ||
| const root = fs.mkdtempSync(path.join(os.tmpdir(), "native-source-")); | ||
| projectDir = path.join(root, "apps", "app"); | ||
| sourcesDir = path.join(root, "libs", "native"); | ||
| fs.mkdirSync(projectDir, { recursive: true }); | ||
| fs.mkdirSync(sourcesDir, { recursive: true }); | ||
| fs.writeFileSync(path.join(sourcesDir, "Source.swift"), ""); | ||
| cwd = process.cwd(); | ||
| process.chdir(root); | ||
| }); | ||
|
|
||
| afterEach(() => { | ||
| process.chdir(cwd); | ||
| }); | ||
|
|
||
| const getFiles = async (rootPath: string): Promise<string[]> => { | ||
| const { files } = await (<any>IOSProjectService.prototype).getRootGroup.call( | ||
| { $fs: new FileSystem(<any>{}) }, | ||
| "Native", | ||
| rootPath, | ||
| projectDir, | ||
| ); | ||
| return files.map((file: string) => fs.realpathSync(file)); | ||
| }; | ||
|
|
||
| const expectedSource = () => | ||
| fs.realpathSync(path.join(sourcesDir, "Source.swift")); | ||
|
|
||
| it("resolves a glob against the project, not the working directory", async () => { | ||
| assert.deepEqual(await getFiles("../../libs/native/*.swift"), [ | ||
| expectedSource(), | ||
| ]); | ||
| }); | ||
|
|
||
| it("resolves a folder against the project, not the working directory", async () => { | ||
| assert.deepEqual(await getFiles("../../libs/native"), [expectedSource()]); | ||
| }); | ||
|
|
||
| describe("header search paths", () => { | ||
| const prepare = async (rootPath: string): Promise<string[]> => { | ||
| const searchPaths: string[] = []; | ||
| const proto = <any>IOSProjectService.prototype; | ||
| await proto.prepareNativeSourceCode.call( | ||
| { | ||
| $fs: new FileSystem(<any>{}), | ||
| $logger: { warn: () => {} }, | ||
| getRootGroup: proto.getRootGroup, | ||
| savePbxProj: () => {}, | ||
| createPbxProj: () => ({ | ||
| addPbxGroup: () => {}, | ||
| getFirstTarget: () => ({ uuid: "target" }), | ||
| addToHeaderSearchPaths: (searchPath: string) => | ||
| searchPaths.push(searchPath), | ||
| }), | ||
| }, | ||
| "Native", | ||
| rootPath, | ||
| { projectDir }, | ||
| ); | ||
| return searchPaths.map((searchPath) => fs.realpathSync(searchPath)); | ||
| }; | ||
|
|
||
| it("uses the folders of the headers a glob matches", async () => { | ||
| const nested = path.join(sourcesDir, "nested"); | ||
| fs.mkdirSync(nested); | ||
| fs.writeFileSync(path.join(nested, "One.h"), ""); | ||
| fs.writeFileSync(path.join(nested, "Two.h"), ""); | ||
|
|
||
| assert.deepEqual(await prepare("../../libs/native/**/*.{h,swift}"), [ | ||
| fs.realpathSync(nested), | ||
| ]); | ||
| }); | ||
|
|
||
| it("adds nothing for a glob without headers", async () => { | ||
| assert.deepEqual(await prepare("../../libs/native/*.swift"), []); | ||
| }); | ||
|
|
||
| it("uses the folder itself, against the project", async () => { | ||
| assert.deepEqual(await prepare("../../libs/native"), [ | ||
| fs.realpathSync(sourcesDir), | ||
| ]); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 4422
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 32178
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 31981
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 8510
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 12681
Web query:
nativescript-dev-xcode 0.8.2 pbxProject addToHeaderSearchPaths removeFromHeaderSearchPaths implementationResult:
Web query:
site:github.com/NativeScript/nativescript-dev-xcode "addToHeaderSearchPaths" "removeFromHeaderSearchPaths" pbxProject.jsResult:
Script executed:
Repository: NativeScript/nativescript-cli
Length of output: 3654
Reconcile glob-owned header search paths on each prepare.
addToHeaderSearchPathsappends a path when it is not already present. It does not replace existing paths. Because each prepare reloads and saves the existing project, directories from earlier glob matches remain when later matches change.removeNativeSourceCoderemoves only the glob path, not the matched header directories.Track the paths owned by this group and remove paths that are no longer matched before adding the current paths. Fixed non-glob sources already used one stable
group.pathbefore this change; the accumulation of changing matched-directory entries is introduced by the new glob handling.