Skip to content

Commit

Permalink
Support oauth (and cache) files in $GCALCLI_CONFIG dir (#806)
Browse files Browse the repository at this point in the history
  • Loading branch information
dbarnett authored Oct 5, 2024
1 parent fd821e4 commit 521bf2a
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 32 deletions.
3 changes: 3 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
v4.5.2
* Support oauth (and cache) files in $GCALCLI_CONFIG dir

v4.5.1
* Fix gcalcli failing to run on python 3.10 if config file is present
* Fix `config edit` when missing config dir blowing up with FileNotFoundError
Expand Down
9 changes: 4 additions & 5 deletions gcalcli/argparsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,10 @@ class RawDescArgDefaultsHelpFormatter(
%(prog)s supports a few other configuration mechanisms in addition to
the command-line arguments listed below.
$GCALCLI_CONFIG={config_dir}
$GCALCLI_CONFIG={config_path}
Path to user config directory or file.
Note: this path is also used to determine fallback paths to check
for cache/oauth files to be migrated into their proper data dir
paths.
Note: you can place an 'oauth' file in this config directory to
support using different accounts per config.
{config_file}
A toml config file where some general-purpose settings can be
Expand Down Expand Up @@ -409,7 +408,7 @@ def get_argument_parser():

parser = argparse.ArgumentParser(
description=DESCRIPTION.format(
config_dir=config_path,
config_path=config_path,
config_file=utils.shorten_path(env.config_file()),
rc_paths=', '.join(str(p) for p in rc_paths),
),
Expand Down
4 changes: 3 additions & 1 deletion gcalcli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,9 @@ def main():
print(json.dumps(schema, indent=2))
elif parsed_args.subcommand == 'reset-cache':
deleted_something = False
for cache_filepath in env.data_file_paths('cache'):
for (cache_filepath, _) in env.data_file_paths(
'cache', parsed_args.config_folder
):
if cache_filepath.exists():
printer.msg(
f'Deleting cache file from {cache_filepath}...\n'
Expand Down
26 changes: 17 additions & 9 deletions gcalcli/env.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
import pathlib
from typing import Optional
from typing import Optional, Tuple

import platformdirs

Expand All @@ -14,18 +14,26 @@ def default_data_dir() -> pathlib.Path:
def data_file_paths(
name: str,
config_dir: Optional[pathlib.Path] = None,
) -> list[pathlib.Path]:
) -> list[Tuple[pathlib.Path, int]]:
"""Return all paths actively used for the given data file name.
The paths are returned with the preferred path first followed by any other
detected legacy paths in order of decreasing precedence.
The paths are returned as tuples in order of decreasing precedence like:
[(CONFIG/name, 1), (DATA_DIR/name, 0), (~/.gcalcli_{name}, -1)]
with the DATA_DIR path always present and others only present if the file
exists.
"""
paths = [default_data_dir().joinpath(name)]
legacy_path = (config_dir.joinpath(name)
if config_dir
else pathlib.Path(f'~/.gcalcli_{name}').expanduser())
paths = []
# Path in config dir takes precedence, if any.
if config_dir:
path_in_config = config_dir.joinpath(name)
if path_in_config.exists():
paths.append((path_in_config, 1))
# Standard data path comes next.
paths.append((default_data_dir().joinpath(name), 0))
# Lastly, fall back to legacy path if it exists and there's no config dir.
legacy_path = pathlib.Path(f'~/.gcalcli_{name}').expanduser()
if legacy_path.exists():
paths.append(legacy_path)
paths.append((legacy_path, -1))
return paths


Expand Down
35 changes: 22 additions & 13 deletions gcalcli/gcal.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,28 @@ def _retry_with_backoff(self, method: googleapiclient.http.HttpRequest):

@functools.cache
def data_file_path(self, name: str) -> pathlib.Path:
paths = env.data_file_paths(name)
primary_path = paths.pop(0)
if not primary_path.exists():
for alt_path in paths:
if not alt_path.exists():
continue
self.printer.msg(
f'Moving {name} file from legacy path {alt_path} to '
f'{primary_path}...\n'
)
primary_path.parent.mkdir(parents=True, exist_ok=True)
shutil.move(alt_path, primary_path)
break
paths = env.data_file_paths(name, self.options.get('config_folder'))
primary_path = None
legacy_path = None
for (path, category) in paths:
if path.exists():
if category >= 0:
return path
else:
legacy_path = path
elif category == 0:
primary_path = path
assert primary_path is not None

# No non-legacy config file found. Return primary_path, and move legacy
# file to that path if any.
if legacy_path:
self.printer.msg(
f'Moving {name} file from legacy path {legacy_path} to '
f'{primary_path}...\n'
)
primary_path.parent.mkdir(parents=True, exist_ok=True)
shutil.move(legacy_path, primary_path)

return primary_path

Expand Down
2 changes: 1 addition & 1 deletion gcalcli/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def shorten_path(path: pathlib.Path) -> pathlib.Path:
def inspect_auth() -> dict[str, Any]:
auth_data: dict[str, Any] = OrderedDict()
auth_path = None
for path in env.data_file_paths('oauth'):
for (path, _) in env.data_file_paths('oauth', env.config_dir()):
if path.exists():
auth_path = path
auth_data['path'] = shorten_path(path)
Expand Down
5 changes: 2 additions & 3 deletions tests/cli/__snapshot__/test-02-test_prints_correct_help.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ configuration:

$GCALCLI_CONFIG=/some/gcalcli/config
Path to user config directory or file.
Note: this path is also used to determine fallback paths to check
for cache/oauth files to be migrated into their proper data dir
paths.
Note: you can place an 'oauth' file in this config directory to
support using different accounts per config.

/some/gcalcli/config/config.toml
A toml config file where some general-purpose settings can be
Expand Down

0 comments on commit 521bf2a

Please sign in to comment.