Page MenuHomePhabricator

D9678.id27498.diff
No OneTemporary

D9678.id27498.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -150,6 +150,8 @@
'PhutilDocblockParserTestCase' => 'parser/__tests__/PhutilDocblockParserTestCase.php',
'PhutilEditDistanceMatrix' => 'utils/PhutilEditDistanceMatrix.php',
'PhutilEditDistanceMatrixTestCase' => 'utils/__tests__/PhutilEditDistanceMatrixTestCase.php',
+ 'PhutilEditorConfig' => 'parser/PhutilEditorConfig.php',
+ 'PhutilEditorConfigTestCase' => 'parser/__tests__/PhutilEditorConfigTestCase.php',
'PhutilEmailAddress' => 'parser/PhutilEmailAddress.php',
'PhutilEmailAddressTestCase' => 'parser/__tests__/PhutilEmailAddressTestCase.php',
'PhutilEmptyAuthAdapter' => 'auth/PhutilEmptyAuthAdapter.php',
@@ -587,6 +589,7 @@
'PhutilDisqusAuthAdapter' => 'PhutilOAuthAuthAdapter',
'PhutilDocblockParserTestCase' => 'PhutilTestCase',
'PhutilEditDistanceMatrixTestCase' => 'PhutilTestCase',
+ 'PhutilEditorConfigTestCase' => 'PhutilTestCase',
'PhutilEmailAddressTestCase' => 'PhutilTestCase',
'PhutilEmptyAuthAdapter' => 'PhutilAuthAdapter',
'PhutilErrorHandlerTestCase' => 'PhutilTestCase',
diff --git a/src/parser/PhutilEditorConfig.php b/src/parser/PhutilEditorConfig.php
new file mode 100644
--- /dev/null
+++ b/src/parser/PhutilEditorConfig.php
@@ -0,0 +1,97 @@
+<?php
+
+/**
+ * Utilities for parsing [[http://editorconfig.org/ | EditorConfig]] files.
+ */
+final class PhutilEditorConfig {
+
+ private $configs;
+ private $rootPath;
+
+ /**
+ * Constructor.
+ *
+ * @param string The root directory.
+ */
+ public function __construct($root) {
+ $this->rootPath = $root;
+
+ $paths = id(new FileFinder($root))
+ ->withType('f')
+ ->withName('.editorconfig')
+ ->find();
+
+ foreach ($paths as $path) {
+ $this->addEditorConfigFile(Filesystem::resolvePath($path, $root));
+ }
+ }
+
+ private function addEditorConfigFile($path) {
+ $file = Filesystem::readFile($path);
+ $config = phutil_ini_decode($file);
+
+ $path = dirname($path);
+ $this->configs[$path] = array();
+
+ foreach ($config as $key => $value) {
+ if (preg_match('@/@', $key)) {
+ $this->configs[$path][phutil_glob_to_regex('**/'.$key)] = $value;
+ } else if (preg_match('@^/@', $key)) {
+ $this->configs[$path][phutil_glob_to_regex(substr($key, 1))] = $value;
+ } else {
+ $this->configs[$path][phutil_glob_to_regex($key)] = $value;
+ }
+ }
+ }
+
+ public function getConfig($path, $key) {
+ $config = $this->config;
+ $parts = explode(DIRECTORY_SEPARATOR, $path);
+
+ foreach ($parts as $part) {
+ $config = idx($config, $part);
+ }
+ }
+
+ public function setConfig($path, $key, $value) {
+ foreach ($this->configs as $config_path => $config) {
+ if (Filesystem::isDescendant($path, $config_path)) {
+ foreach ($config as $config_key => $config_value) {
+
+ }
+ }
+ }
+ }
+
+ public function matches($path) {
+
+ }
+
+
+
+
+ /**
+ * Return the paths of all EditorConfig files that were found.
+ *
+ * @return list<string>
+ */
+ public function getPaths() {
+ $paths = array();
+
+ foreach (array_keys($this->configs) as $path) {
+ $paths[] = $path.'/.editorconfig';
+ }
+
+ return $paths;
+ }
+
+ /**
+ * Return the root path.
+ *
+ * @return string
+ */
+ public function getRootPath() {
+ return $this->rootPath;
+ }
+
+}
diff --git a/src/parser/__tests__/PhutilEditorConfigTestCase.php b/src/parser/__tests__/PhutilEditorConfigTestCase.php
new file mode 100644
--- /dev/null
+++ b/src/parser/__tests__/PhutilEditorConfigTestCase.php
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @group testcase
+ */
+final class PhutilEditorConfigTestCase extends PhutilTestCase {
+
+ public function testGetPaths() {
+ $tests = array(
+ dirname(__FILE__) => array(
+ dirname(__FILE__).'/editorconfig/.editorconfig',
+ dirname(__FILE__).'/editorconfig/subdir1/.editorconfig',
+ dirname(__FILE__).'/editorconfig/subdir2/.editorconfig',
+ ),
+ dirname(__FILE__).'/editorconfig/subdir1' => array(
+ dirname(__FILE__).'/editorconfig/subdir1/.editorconfig',
+ ),
+ dirname(__FILE__).'/editorconfig/subdir2' => array(
+ dirname(__FILE__).'/editorconfig/subdir2/.editorconfig',
+ ),
+ dirname(__FILE__).'/../../../' => array(
+ Filesystem::resolvePath('.editorconfig', dirname(__FILE__).'/../../..'),
+ dirname(__FILE__).'/editorconfig/.editorconfig',
+ dirname(__FILE__).'/editorconfig/subdir1/.editorconfig',
+ dirname(__FILE__).'/editorconfig/subdir2/.editorconfig',
+ ),
+ );
+
+ foreach ($tests as $input => $expect) {
+ $editorconfig = new PhutilEditorConfig($input);
+ $this->assertEqual($expect, $editorconfig->getPaths());
+ }
+ }
+
+ public function testGetRootPath() {
+ $tests = array(
+ dirname(__FILE__) => dirname(__FILE__),
+ dirname(__FILE__).'/editorconfig/subdir1'
+ => dirname(__FILE__).'/editorconfig/subdir1',
+ dirname(__FILE__).'/editorconfig/subdir2'
+ => dirname(__FILE__).'/editorconfig/subdir2',
+ );
+
+ foreach ($tests as $input => $expect) {
+ $editorconfig = new PhutilEditorConfig($input);
+ $this->assertEqual($expect, $editorconfig->getRootPath());
+ }
+ }
+
+}
diff --git a/src/parser/__tests__/editorconfig/.editorconfig b/src/parser/__tests__/editorconfig/.editorconfig
new file mode 100644
diff --git a/src/parser/__tests__/editorconfig/subdir1/.editorconfig b/src/parser/__tests__/editorconfig/subdir1/.editorconfig
new file mode 100644
diff --git a/src/parser/__tests__/editorconfig/subdir2/.editorconfig b/src/parser/__tests__/editorconfig/subdir2/.editorconfig
new file mode 100644
--- /dev/null
+++ b/src/parser/__tests__/editorconfig/subdir2/.editorconfig
@@ -0,0 +1 @@
+root = true

File Metadata

Mime Type
text/plain
Expires
Mon, May 13, 3:21 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6292168
Default Alt Text
D9678.id27498.diff (5 KB)

Event Timeline