Migrate run_lint_check_css to JS script
As part of the work to move more scripts to Node, not Python, over time,
picked this one as the starting point. I changed its API slightly to
allow more flags to be taken in, as we'll need that to do a stylelint
pass against TypeScript files, but I will do that in a subsequent CL.
I had to make quite a few changes to devtools_paths.js, but I think it's
now calculating paths correctly. It took a bit of messing to get the
equivalent of Python's path.abspath(__file__), as you'll see from the
large comment that tries to explain what's going on!
Bug: chromium:1166108, chromium:1166572
Change-Id: Ia0b19ff8956b2ede2447530be57876a88046887e
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2631113
Commit-Queue: Jack Franklin <[email protected]>
Reviewed-by: Tim van der Lippe <[email protected]>
diff --git a/scripts/devtools_paths.js b/scripts/devtools_paths.js
index 0f0b433..116b8b1 100644
--- a/scripts/devtools_paths.js
+++ b/scripts/devtools_paths.js
@@ -15,42 +15,114 @@
/**
* You would think we can use __filename here but we cannot because __filename
- * has any symlinks resolved. This means we can't use it to tell if the user
- * is using the external repo with a standalone build setup because the
- * symlink from chromium/src/third_party/devtools-frontend =>
- * devtools-frontend repo gets resolved by Node before it gives us __filename.
+ * has any symlinks resolved. This means we can't use it to tell if the user is
+ * using the external repo with a standalone build setup because the symlink
+ * from chromium/src/third_party/devtools-frontend => devtools-frontend repo
+ * gets resolved by Node before it gives us __filename.
*
- * Instead we can use process.argv, whose first two arguments are the path to
- * the Node binary, and then the path to the file being executed, but without
- * symlinks being resolved. So if this script gets run in the Chromium dir
- * through a symlink, the path will still contain
- * /path/to/chromium/src/third-party/devtools-frontend/scripts/... - this is
- * NOT the case if we were to use __filename.
+ * We can use process.argv[1], which is the path to the file currently being
+ * executed without any symlinks resolution. If we assume that file is always in
+ * the devtools-frontend repository/directory, we can use that file as the
+ * starting point for figuring out if we're in Chromium or not. until we find
+ * the scripts directory, at which point we've found this file and can use it
+ * for all subsequent logic.
+ *
+ * e.g. the user executes a script: scripts/test/run_lint_check_css.js
+ *
+ * process.argv[1] =
+ * /full/path/devtools-frontend/src/scripts/test/run_lint_check_css.js
*/
-const ABS_PATH_TO_CURRENT_FILE = process.argv[1];
+const PATH_TO_EXECUTED_FILE = process.argv[1];
-/** Find the root path of the checkout.
-* In the Chromium repository, this is the src/chromium directory.
-* In the external repository, standalone build, this is the devtools-frontend directory.
-* In the external repository, integrated build, this is the src/chromium directory.
-*/
-function rootPath() {
- const scriptsPath = path.dirname(ABS_PATH_TO_CURRENT_FILE);
- const devtoolsFrontendPath = path.dirname(scriptsPath);
- const devtoolsFrontendParentPath = path.dirname(devtoolsFrontendPath);
-
- if (path.basename(devtoolsFrontendParentPath) === 'devtools-frontend') {
- // External repository, integrated build
- // So go up two levels to the src/chromium directory
- return path.dirname(path.dirname(devtoolsFrontendParentPath));
- }
-
- // External repository, standalone build
- return devtoolsFrontendPath;
+function pathIsMostTopLevelPath(filePath) {
+ /**
+ * On Linux/Mac, if we do path.dirname(X) as many times as possible, it will
+ * eventually equal `/`. On Windows, it will end up equalling C:\, and
+ * path.dirname('C:\') === 'C:\', so we use that to figure out if we've made
+ * it as far up the tree as we can.
+ */
+ return filePath === path.sep || path.dirname(filePath) === filePath;
}
+
+const _lookUpCaches = new Map(
+ [['chromium', null]],
+);
+/**
+ * This function figures out if we're within a chromium directory, and therefore
+ * we are in the integrated workflow mode, rather than working in a standalone
+ * devtools-frontend repository.
+ */
+function isInChromiumDirectory() {
+ const cached = _lookUpCaches.get('chromium');
+ if (cached) {
+ return cached;
+ }
+
+ let potentialChromiumDir = PATH_TO_EXECUTED_FILE;
+ let isInChromium = false;
+ while (!pathIsMostTopLevelPath(potentialChromiumDir)) {
+ potentialChromiumDir = path.dirname(potentialChromiumDir);
+ if (path.basename(potentialChromiumDir) === 'chromium') {
+ isInChromium = true;
+ break;
+ }
+ }
+ const result = {isInChromium, chromiumDirectory: potentialChromiumDir};
+ _lookUpCaches.set('chromium', result);
+ return result;
+}
+/**
+ * Returns the path to the root of the devtools-frontend repository.
+ *
+ * If we're in Chromium, this will be /path/to/chromium/src/third_party/devtools-frontend/src
+ * If it's standalone, it will be /path/to/devtools-frontend
+ */
+function devtoolsRootPath() {
+ const nodeScriptFileThatIsBeingExecuted = PATH_TO_EXECUTED_FILE;
+ let devtoolsRootFolder = nodeScriptFileThatIsBeingExecuted;
+ while (path.basename(devtoolsRootFolder) !== 'devtools-frontend') {
+ devtoolsRootFolder = path.dirname(devtoolsRootFolder);
+ // We reached the end and can't find devtools-frontend.
+ if (pathIsMostTopLevelPath(devtoolsRootFolder)) {
+ throw new Error(
+ 'Could not find devtools-frontend in path. If you have cloned the repository to a different directory name, it will not work.');
+ }
+ }
+ // In Chromium the path to the source code for devtools-frontend is:
+ // third_party/devtools-frontend/src
+ const {isInChromium} = isInChromiumDirectory();
+ if (isInChromium) {
+ return path.join(devtoolsRootFolder, 'src');
+ }
+
+ // But if you're in a standalone repo it's just the devtools-frontend folder.
+ return devtoolsRootFolder;
+}
+
+/**
+ * Returns the path to the root of the main repository we're in.
+ * if we're in Chromium, this is /path/to/chromium/src
+ * if we're in standalone, this is /path/to/devtools-frontend
+ *
+ * Note this is different to devtoolsRootPath(), which always returns the path
+ * to the devtools-frontend source code.
+ */
+function rootPath() {
+ const {isInChromium, chromiumDirectory} = isInChromiumDirectory();
+ if (isInChromium) {
+ return path.join(chromiumDirectory, 'src');
+ }
+ return devtoolsRootPath();
+}
+
+/**
+ * Path to the third_party directory. Used because if we're running in Chromium
+ * land we need to use e.g. the Node executable from Chromium's third_party
+ * directory, not from the devtools-frontend third_party directory.
+ */
function thirdPartyPath() {
- path.join(rootPath(), 'third_party');
+ return path.join(rootPath(), 'third_party');
}
function nodePath() {
@@ -59,15 +131,24 @@
'linux': path.join('linux', 'node-linux-x64', 'bin', 'node'),
'win32': path.join('win', 'node.exe'),
};
- return path.join(thirdPartyPath(), 'node', paths[os.platform]);
+ return path.join(thirdPartyPath(), 'node', paths[os.platform()]);
}
-function devtoolsRootPath() {
- return path.dirname(path.dirname(ABS_PATH_TO_CURRENT_FILE));
-}
-
+/**
+ * The path to the devtools-frontend node_modules folder.
+ */
function nodeModulesPath() {
return path.join(devtoolsRootPath(), 'node_modules');
}
-export {thirdPartyPath, nodePath, devtoolsRootPath, nodeModulesPath};
+function stylelintExecutablePath() {
+ return path.join(nodeModulesPath(), 'stylelint', 'bin', 'stylelint.js');
+}
+
+module.exports = {
+ thirdPartyPath,
+ nodePath,
+ devtoolsRootPath,
+ nodeModulesPath,
+ stylelintExecutablePath
+};