-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Adds xdg_directories package to access Linux well known directories. #117
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
Changes from 3 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 |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| # Miscellaneous | ||
| *.class | ||
| *.log | ||
| *.pyc | ||
| *.swp | ||
| .DS_Store | ||
| .atom/ | ||
| .buildlog/ | ||
| .history | ||
| .svn/ | ||
|
|
||
| # IntelliJ related | ||
| *.iml | ||
| *.ipr | ||
| *.iws | ||
| .idea/ | ||
|
|
||
| # The .vscode folder contains launch configuration and tasks you configure in | ||
| # VS Code which you may wish to be included in version control, so this line | ||
| # is commented out by default. | ||
| #.vscode/ | ||
|
|
||
| # Flutter/Dart/Pub related | ||
| **/doc/api/ | ||
| .dart_tool/ | ||
| .flutter-plugins | ||
| .flutter-plugins-dependencies | ||
| .packages | ||
| .pub-cache/ | ||
| .pub/ | ||
| build/ | ||
|
|
||
| # Android related | ||
| **/android/**/gradle-wrapper.jar | ||
| **/android/.gradle | ||
| **/android/captures/ | ||
| **/android/gradlew | ||
| **/android/gradlew.bat | ||
| **/android/local.properties | ||
| **/android/**/GeneratedPluginRegistrant.java | ||
|
|
||
| # iOS/XCode related | ||
| **/ios/**/*.mode1v3 | ||
| **/ios/**/*.mode2v3 | ||
| **/ios/**/*.moved-aside | ||
| **/ios/**/*.pbxuser | ||
| **/ios/**/*.perspectivev3 | ||
| **/ios/**/*sync/ | ||
| **/ios/**/.sconsign.dblite | ||
| **/ios/**/.tags* | ||
| **/ios/**/.vagrant/ | ||
| **/ios/**/DerivedData/ | ||
| **/ios/**/Icon? | ||
| **/ios/**/Pods/ | ||
| **/ios/**/.symlinks/ | ||
| **/ios/**/profile | ||
| **/ios/**/xcuserdata | ||
| **/ios/.generated/ | ||
| **/ios/Flutter/App.framework | ||
| **/ios/Flutter/Flutter.framework | ||
| **/ios/Flutter/Flutter.podspec | ||
| **/ios/Flutter/Generated.xcconfig | ||
| **/ios/Flutter/app.flx | ||
| **/ios/Flutter/app.zip | ||
| **/ios/Flutter/flutter_assets/ | ||
| **/ios/Flutter/flutter_export_environment.sh | ||
| **/ios/ServiceDefinitions.json | ||
| **/ios/Runner/GeneratedPluginRegistrant.* | ||
|
|
||
| # Exceptions to above rules. | ||
| !**/ios/**/default.mode1v3 | ||
| !**/ios/**/default.mode2v3 | ||
| !**/ios/**/default.pbxuser | ||
| !**/ios/**/default.perspectivev3 | ||
| !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # This file tracks properties of this Flutter project. | ||
| # Used by Flutter tool to assess capabilities and perform upgrades etc. | ||
| # | ||
| # This file should be version controlled and should not be manually edited. | ||
|
|
||
| version: | ||
| revision: d8c0deb1b6c116be79ceeca005f893be34ab5df2 | ||
| channel: master | ||
|
|
||
| project_type: package |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| ## [0.1.0] - Initial Release | ||
|
|
||
| * Initial release includes all the features described in the README.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| Copyright 2020 The Flutter Authors. All rights reserved. | ||
|
|
||
| Redistribution and use in source and binary forms, with or without | ||
| modification, are permitted provided that the following conditions are | ||
| met: | ||
|
|
||
| * Redistributions of source code must retain the above copyright | ||
| notice, this list of conditions and the following disclaimer. | ||
| * Redistributions in binary form must reproduce the above | ||
| copyright notice, this list of conditions and the following | ||
| disclaimer in the documentation and/or other materials provided | ||
| with the distribution. | ||
| * Neither the name of Google Inc. nor the names of its | ||
| contributors may be used to endorse or promote products derived | ||
| from this software without specific prior written permission. | ||
|
|
||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| # `xdg_directories` | ||
|
|
||
| A Dart package for reading XDG directory configuration information on Linux. | ||
|
|
||
| ## Getting Started | ||
|
|
||
| On Linux, `xdg` is a system developed by [freedesktop.org](freedesktop.org), a | ||
| project to work on interoperability and shared base technology for free software | ||
| desktop environments for Linux. | ||
|
|
||
| This Dart package can be used to determine the directory configuration | ||
| information defined by `xdg`, such as where the Documents or Desktop directories | ||
| are. These are called "user directories" and are defined in configuration file | ||
| in the user's home directory. | ||
|
|
||
| See [this wiki](https://wiki.archlinux.org/index.php/XDG_Base_Directory) for | ||
| more details of the XDG Base Directory implementation. | ||
|
|
||
| To use this package, the basic XDG values for the following are available via a Dart API: | ||
|
|
||
| - `dataHome` - The single base directory relative to which user-specific data | ||
| files should be written. (Corresponds to `$XDG_DATA_HOME`). | ||
|
|
||
| - `configHome` - The a single base directory relative to which user-specific | ||
| configuration files should be written. (Corresponds to `$XDG_CONFIG_HOME`). | ||
|
|
||
| - `dataDirs` - The list of preference-ordered base directories relative to | ||
| which data files should be searched. (Corresponds to `$XDG_DATA_DIRS`). | ||
|
|
||
| - `configDirs` - The list of preference-ordered base directories relative to | ||
| which configuration files should be searched. (Corresponds to | ||
| `$XDG_CONFIG_DIRS`). | ||
|
|
||
| - `cacheHome` - The base directory relative to which user-specific | ||
| non-essential (cached) data should be written. (Corresponds to | ||
| `$XDG_CACHE_HOME`). | ||
|
|
||
| - `runtimeDir` - The base directory relative to which user-specific runtime | ||
| files and other file objects should be placed. (Corresponds to | ||
| `$XDG_RUNTIME_DIR`). | ||
|
|
||
| - `getUserDirectoryNames()` - Returns a set of the names of user directories | ||
| defined in the `xdg` configuration files. | ||
|
|
||
| - `getUserDirectory(String dirName)` - Gets the value of the user dir with the | ||
| given name. Requesting a user dir that doesn't exist returns `null`. The | ||
| `dirName` argument is case-insensitive. See [this | ||
| wiki](https://wiki.archlinux.org/index.php/XDG_user_directories) for more | ||
| details and what values of `dirName` might be available. | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,163 @@ | ||
| // Copyright 2020 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| library xdg_directories; | ||
|
|
||
| import 'dart:convert'; | ||
| import 'dart:io'; | ||
|
|
||
| import 'package:flutter/cupertino.dart'; | ||
| import 'package:path/path.dart' as path; | ||
| import 'package:process/process.dart'; | ||
|
|
||
| /// An override function used by the tests to override the environment variable | ||
| /// lookups using [xdgEnvironmentOverride]. | ||
| typedef EnvironmentOverride = String Function(String envVar); | ||
|
|
||
| /// A testing setter that replaces the real environment lookups with an override. | ||
| /// | ||
| /// Set to null to stop overriding. | ||
| /// | ||
| /// Only available to tests. | ||
| @visibleForTesting | ||
| set xdgEnvironmentOverride(EnvironmentOverride override) { | ||
| _xdgEnvironmentOverride = override; | ||
| _getenv = _xdgEnvironmentOverride ?? _productionGetEnv; | ||
| } | ||
|
|
||
| /// A testing getter that returns the current value of the override that | ||
| /// replaces the real environment lookups with an override. | ||
| /// | ||
| /// Only available to tests. | ||
| EnvironmentOverride get xdgEnvironmentOverride => _xdgEnvironmentOverride; | ||
| EnvironmentOverride _xdgEnvironmentOverride; | ||
| EnvironmentOverride _productionGetEnv = (String value) => Platform.environment[value]; | ||
| EnvironmentOverride _getenv = _productionGetEnv; | ||
|
|
||
| /// A testing function that replaces the process manager used to run xdg-user-path | ||
| /// with the one supplied. | ||
| /// | ||
| /// Only available to tests. | ||
| @visibleForTesting | ||
| set xdgProcessManager(ProcessManager processManager) { | ||
| _processManager = processManager; | ||
| } | ||
|
|
||
| ProcessManager _processManager = const LocalProcessManager(); | ||
|
|
||
| List<Directory> _directoryListFromEnvironment(String envVar, String fallback) { | ||
|
Collaborator
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. It seems like it would be clearer to make this Plus it would eliminate the confusion of this
Contributor
Author
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. OK, done. |
||
| assert(envVar != null); | ||
| assert(fallback != null); | ||
| String value = _getenv(envVar); | ||
| if (value == null || value.isEmpty) { | ||
| value = fallback; | ||
| } | ||
| return value.split(':').where((String value) { | ||
| return value.isNotEmpty; | ||
| }).map<Directory>((String entry) { | ||
| return Directory(entry); | ||
| }).toList(); | ||
| } | ||
|
|
||
| Directory _directoryFromEnvironment(String envVar, String fallback) { | ||
| assert(envVar != null); | ||
| final String value = _getenv(envVar); | ||
| if (value == null || value.isEmpty) { | ||
| if (fallback == null) { | ||
| return null; | ||
| } | ||
| return _getDefaultDir(fallback); | ||
| } | ||
| return Directory(value); | ||
| } | ||
|
|
||
| Directory _getDefaultDir(String suffix) { | ||
|
Collaborator
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. This could use a function comment; I had no idea what
Contributor
Author
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. Ok, added, and I changed the name suffix to subdir. |
||
| assert(suffix != null); | ||
| assert(suffix.isNotEmpty); | ||
| final String homeDir = _getenv('HOME'); | ||
| if (homeDir == null || homeDir.isEmpty) { | ||
| throw StateError('The "HOME" environment variable is not set. This package (and POSIX) ' | ||
| 'requires that HOME be set.'); | ||
| } | ||
| return Directory(path.joinAll(<String>[homeDir, suffix])); | ||
| } | ||
|
|
||
| /// The base directory relative to which user-specific | ||
| /// non-essential (cached) data should be written. (Corresponds to | ||
| /// `$XDG_CACHE_HOME`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| Directory get cacheHome => _directoryFromEnvironment('XDG_CACHE_HOME', '.cache'); | ||
|
|
||
| /// The list of preference-ordered base directories relative to | ||
| /// which configuration files should be searched. (Corresponds to | ||
| /// `$XDG_CONFIG_DIRS`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| List<Directory> get configDirs => _directoryListFromEnvironment('XDG_CONFIG_DIRS', '/etc/xdg'); | ||
|
|
||
| /// The a single base directory relative to which user-specific | ||
| /// configuration files should be written. (Corresponds to `$XDG_CONFIG_HOME`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| Directory get configHome => _directoryFromEnvironment('XDG_CONFIG_HOME', '.config'); | ||
|
|
||
| /// The list of preference-ordered base directories relative to | ||
| /// which data files should be searched. (Corresponds to `$XDG_DATA_DIRS`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| List<Directory> get dataDirs => _directoryListFromEnvironment('XDG_DATA_DIRS', '/usr/local/share:/usr/share'); | ||
|
|
||
| /// The base directory relative to which user-specific data files should be | ||
| /// written. (Corresponds to `$XDG_DATA_HOME`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| Directory get dataHome => _directoryFromEnvironment('XDG_DATA_HOME', '.local/share'); | ||
|
|
||
| /// The base directory relative to which user-specific runtime | ||
| /// files and other file objects should be placed. (Corresponds to | ||
| /// `$XDG_RUNTIME_DIR`). | ||
| /// | ||
| /// Throws [StateError] if the HOME environment variable is not set. | ||
| Directory get runtimeDir => _directoryFromEnvironment('XDG_RUNTIME_DIR', null); | ||
|
|
||
| /// Gets the xdg user directory named by `dirName`. | ||
| /// | ||
| /// Use [getUserDirectoryNames] to find out the list of available names. | ||
| Directory getUserDirectory(String dirName) { | ||
| final ProcessResult result = _processManager.runSync( | ||
| <String>['xdg-user-dir', dirName], | ||
| includeParentEnvironment: true, | ||
| stdoutEncoding: Encoding.getByName('utf8'), | ||
| ); | ||
| final String path = utf8.decode(result.stdout).split('\n')[0]; | ||
|
Collaborator
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.
Contributor
Author
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. I'm going to keep what I have: I don't want to remove any leading/trailing whitespace that might be part of the path, as unlikely as that is. |
||
| return Directory(path); | ||
| } | ||
|
|
||
| /// Gets the set of user directory names that xdg knows about. | ||
| /// | ||
| /// These are not paths, they are names of xdg values. Call [getUserDirectory] | ||
| /// to get the associated directory. | ||
| /// | ||
| /// These are the names of the variables in "[configHome]/user-dirs.dirs", with | ||
| /// the `XDG_` prefix removed and the `_DIR` suffix removed. | ||
| Set<String> getUserDirectoryNames() { | ||
| final File configFile = File(path.join(configHome.path, 'user-dirs.dirs')); | ||
| List<String> contents; | ||
| try { | ||
| contents = configFile.readAsLinesSync(); | ||
| } on FileSystemException catch (e) { | ||
| return const <String>{}; | ||
| } | ||
| final Set<String> result = <String>{}; | ||
| final RegExp dirRegExp = RegExp(r'^\s*XDG_(?<dirname>.*)_DIR\s*=\s*(?<dir>.*)\s*$'); | ||
|
Collaborator
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. s/
Contributor
Author
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. Good point, thanks. Added. |
||
| for (String line in contents) { | ||
| final RegExpMatch match = dirRegExp.firstMatch(line); | ||
| if (match == null) { | ||
| continue; | ||
| } | ||
| result.add(match.namedGroup('dirname')); | ||
| } | ||
| return result; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| name: xdg_directories | ||
| description: A Dart package for reading XDG directory configuration information on Linux. | ||
| version: 1.0.0 | ||
| homepage: https://github.com/flutter/packages/tree/master/packages/animations | ||
|
|
||
| environment: | ||
| sdk: ">=2.3.0 <3.0.0" | ||
|
|
||
| dependencies: | ||
| path: ">=1.6.4" | ||
| process: ">=3.0.12" | ||
| flutter: | ||
| sdk: flutter | ||
|
|
||
| dev_dependencies: | ||
| mockito: ">=4.1.1" | ||
| flutter_test: | ||
| sdk: flutter |
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.
It seems odd to call the type
Overridewhen it's used for the real implementation too.EnviromentGetter?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.
Yeah, good point. I went with
EnvironmentAccessor.