| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- # Copyright 2022-present, the HuggingFace Inc. team.
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- """Contains utilities to manage Git credentials."""
- import re
- import subprocess
- from ..constants import ENDPOINT
- from ._subprocess import run_interactive_subprocess, run_subprocess
- GIT_CREDENTIAL_REGEX = re.compile(
- r"""
- ^\s* # start of line
- credential\.helper # credential.helper value
- \s*=\s* # separator
- ([\w\-\/]+) # the helper name or absolute path (group 1)
- (\s|$) # whitespace or end of line
- """,
- flags=re.MULTILINE | re.IGNORECASE | re.VERBOSE,
- )
- def list_credential_helpers(folder: str | None = None) -> list[str]:
- """Return the list of git credential helpers configured.
- See https://git-scm.com/docs/gitcredentials.
- Credentials are saved in all configured helpers (store, cache, macOS keychain,...).
- Calls "`git credential approve`" internally. See https://git-scm.com/docs/git-credential.
- Args:
- folder (`str`, *optional*):
- The folder in which to check the configured helpers.
- """
- try:
- output = run_subprocess("git config --list", folder=folder).stdout
- parsed = _parse_credential_output(output)
- return parsed
- except subprocess.CalledProcessError as exc:
- raise OSError(exc.stderr)
- def set_git_credential(token: str, username: str = "hf_user", folder: str | None = None) -> None:
- """Save a username/token pair in git credential for HF Hub registry.
- Credentials are saved in all configured helpers (store, cache, macOS keychain,...).
- Calls "`git credential approve`" internally. See https://git-scm.com/docs/git-credential.
- Args:
- username (`str`, defaults to `"hf_user"`):
- A git username. Defaults to `"hf_user"`, the default user used in the Hub.
- token (`str`, defaults to `"hf_user"`):
- A git password. In practice, the User Access Token for the Hub.
- See https://huggingface.co/settings/tokens.
- folder (`str`, *optional*):
- The folder in which to check the configured helpers.
- """
- with run_interactive_subprocess("git credential approve", folder=folder) as (
- stdin,
- _,
- ):
- stdin.write(f"url={ENDPOINT}\nusername={username.lower()}\npassword={token}\n\n")
- stdin.flush()
- def unset_git_credential(username: str = "hf_user", folder: str | None = None) -> None:
- """Erase credentials from git credential for HF Hub registry.
- Credentials are erased from the configured helpers (store, cache, macOS
- keychain,...), if any. If `username` is not provided, any credential configured for
- HF Hub endpoint is erased.
- Calls "`git credential erase`" internally. See https://git-scm.com/docs/git-credential.
- Args:
- username (`str`, defaults to `"hf_user"`):
- A git username. Defaults to `"hf_user"`, the default user used in the Hub.
- folder (`str`, *optional*):
- The folder in which to check the configured helpers.
- """
- with run_interactive_subprocess("git credential reject", folder=folder) as (
- stdin,
- _,
- ):
- standard_input = f"url={ENDPOINT}\n"
- if username is not None:
- standard_input += f"username={username.lower()}\n"
- standard_input += "\n"
- stdin.write(standard_input)
- stdin.flush()
- def _parse_credential_output(output: str) -> list[str]:
- """Parse the output of `git credential fill` to extract the password.
- Args:
- output (`str`):
- The output of `git credential fill`.
- """
- # NOTE: If user has set a helper for a custom URL, it will not be caught here.
- # Example: `credential.https://huggingface.co.helper=store`
- # See: https://github.com/huggingface/huggingface_hub/pull/1138#discussion_r1013324508
- return sorted( # Sort for nice printing
- { # Might have some duplicates
- match[0] for match in GIT_CREDENTIAL_REGEX.findall(output)
- }
- )
|