121 lines
4.5 KiB
Python
121 lines
4.5 KiB
Python
# coding=utf-8
|
|
# 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 typing import List, Optional
|
|
|
|
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 (group 1)
|
|
(\s|$) # whitespace or end of line
|
|
""",
|
|
flags=re.MULTILINE | re.IGNORECASE | re.VERBOSE,
|
|
)
|
|
|
|
|
|
def list_credential_helpers(folder: Optional[str] = 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 EnvironmentError(exc.stderr)
|
|
|
|
|
|
def set_git_credential(token: str, username: str = "hf_user", folder: Optional[str] = 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: Optional[str] = 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 an helper for a custom URL, it will not we 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
|
|
set( # Might have some duplicates
|
|
match[0] for match in GIT_CREDENTIAL_REGEX.findall(output)
|
|
)
|
|
)
|