| 24 | const pubspecIsWorkspaceRootRegex = new RegExp("^workspace\\s*:", "im"); |
| 25 | |
| 26 | export function getPubWorkspaceStatus( |
| 27 | sdks: Sdks, |
| 28 | logger: Logger, |
| 29 | folderUris: Uri[], |
| 30 | includeDates = true, |
| 31 | existsSync: (itemPath: string) => boolean = fs.existsSync, |
| 32 | readFileSync: (itemPath: string) => string = (p) => fs.readFileSync(p, "utf8").toString(), |
| 33 | mtimeSync: (itemPath: string) => Date = (p) => fs.statSync(p).mtime, |
| 34 | ): PubPackageStatus[] { |
| 35 | // Compute the statuses for the requested packages. |
| 36 | const statuses = folderUris.map((folderUri) => getPubPackageStatus(sdks, logger, folderUri, includeDates, existsSync, readFileSync, mtimeSync)); |
| 37 | |
| 38 | // For any workspace projects, we need to also check their roots if they were not already in the initial set. |
| 39 | const workspaceProjects = statuses.filter((s) => s.workspace === "PROJECT"); |
| 40 | if (workspaceProjects.length) { |
| 41 | logger.info(`Found ${workspaceProjects.length} Pub workspace projects with roots that are not already in the set`); |
| 42 | const includedWorkspaceRootPaths = new Set<string>(); |
| 43 | statuses.filter((s) => s.workspace === "ROOT").forEach((p) => includedWorkspaceRootPaths.add(fsPath(p.folderUri))); |
| 44 | |
| 45 | projectLoop: |
| 46 | for (const project of workspaceProjects) { |
| 47 | const folderPath = fsPath(project.folderUri); |
| 48 | let currentFolder = path.dirname(folderPath); |
| 49 | while (true) { |
| 50 | // First check if the current folder is already a root we know about. |
| 51 | if (includedWorkspaceRootPaths.has(currentFolder)) { |
| 52 | continue projectLoop; |
| 53 | } |
| 54 | // Otherwise, see if it is actually the root. |
| 55 | let isRoot = false; |
| 56 | try { |
| 57 | isRoot = pubspecIsWorkspaceRootRegex.test(readFileSync(path.join(currentFolder, "pubspec.yaml"))); |
| 58 | } catch { |
| 59 | // File may not exist, but using exists first is a race, so just try to read and ignore failure. |
| 60 | } |
| 61 | |
| 62 | if (isRoot) { |
| 63 | logger.info(`Found new Pub workspace root at ${currentFolder}`); |
| 64 | // We found the root, add the result and to our set so we don't repeat this work. |
| 65 | statuses.push(getPubPackageStatus(sdks, logger, Uri.file(currentFolder), includeDates, existsSync, readFileSync, mtimeSync)); |
| 66 | includedWorkspaceRootPaths.add(currentFolder); |
| 67 | continue projectLoop; |
| 68 | } |
| 69 | |
| 70 | // Otherwise, try the next folder up. |
| 71 | const parent = path.dirname(currentFolder); |
| 72 | if (parent === currentFolder) { |
| 73 | logger.warn(`Failed to find a Pub workspace root for project at ${folderPath} before getting to root folder`); |
| 74 | continue projectLoop; |
| 75 | } |
| 76 | currentFolder = parent; |
| 77 | } |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | return statuses; |
| 82 | } |
| 83 | |