2020import shlex
2121import subprocess
2222from os .path import expanduser ,expandvars
23+ from pathlib import Path
2324from typing import List ,Optional ,Union
2425
25- from gitlab .const import USER_AGENT
26+ from gitlab .const import DEFAULT_URL , USER_AGENT
2627
27-
28- def _env_config ()-> List [str ]:
29- if "PYTHON_GITLAB_CFG" in os .environ :
30- return [os .environ ["PYTHON_GITLAB_CFG" ]]
31- return []
32-
33-
34- _DEFAULT_FILES :List [str ]= _env_config ()+ [
28+ _DEFAULT_FILES :List [str ]= [
3529"/etc/python-gitlab.cfg" ,
36- os . path . expanduser ( "~/ .python-gitlab.cfg" ),
30+ str ( Path . home () / " .python-gitlab.cfg" ),
3731]
3832
3933HELPER_PREFIX = "helper:"
4034
4135HELPER_ATTRIBUTES = ["job_token" ,"http_password" ,"private_token" ,"oauth_token" ]
4236
4337
38+ def _resolve_file (filepath :Union [Path ,str ])-> str :
39+ resolved = Path (filepath ).resolve (strict = True )
40+ return str (resolved )
41+
42+
43+ def _get_config_files (
44+ config_files :Optional [List [str ]]= None ,
45+ )-> Union [str ,List [str ]]:
46+ """
47+ Return resolved path(s) to config files if they exist, with precedence:
48+ 1. Files passed in config_files
49+ 2. File defined in PYTHON_GITLAB_CFG
50+ 3. User- and system-wide config files
51+ """
52+ resolved_files = []
53+
54+ if config_files :
55+ for config_file in config_files :
56+ try :
57+ resolved = _resolve_file (config_file )
58+ except OSError as e :
59+ raise GitlabConfigMissingError (f"Cannot read config from file:{ e } " )
60+ resolved_files .append (resolved )
61+
62+ return resolved_files
63+
64+ try :
65+ env_config = os .environ ["PYTHON_GITLAB_CFG" ]
66+ return _resolve_file (env_config )
67+ except KeyError :
68+ pass
69+ except OSError as e :
70+ raise GitlabConfigMissingError (
71+ f"Cannot read config from PYTHON_GITLAB_CFG:{ e } "
72+ )
73+
74+ for config_file in _DEFAULT_FILES :
75+ try :
76+ resolved = _resolve_file (config_file )
77+ except OSError :
78+ continue
79+ resolved_files .append (resolved )
80+
81+ return resolved_files
82+
83+
4484class ConfigError (Exception ):
4585pass
4686
@@ -66,155 +106,149 @@ def __init__(
66106self ,gitlab_id :Optional [str ]= None ,config_files :Optional [List [str ]]= None
67107 )-> None :
68108self .gitlab_id = gitlab_id
69- _files = config_files or _DEFAULT_FILES
70- file_exist = False
71- for file in _files :
72- if os .path .exists (file ):
73- file_exist = True
74- if not file_exist :
75- raise GitlabConfigMissingError (
76- "Config file not found.\n Please create one in "
77- "one of the following locations: {}\n or "
78- "specify a config file using the '-c' parameter." .format (
79- ", " .join (_DEFAULT_FILES )
80- )
81- )
109+ self .http_username :Optional [str ]= None
110+ self .http_password :Optional [str ]= None
111+ self .job_token :Optional [str ]= None
112+ self .oauth_token :Optional [str ]= None
113+ self .private_token :Optional [str ]= None
114+
115+ self .api_version :str = "4"
116+ self .order_by :Optional [str ]= None
117+ self .pagination :Optional [str ]= None
118+ self .per_page :Optional [int ]= None
119+ self .retry_transient_errors :bool = False
120+ self .ssl_verify :Union [bool ,str ]= True
121+ self .timeout :int = 60
122+ self .url :str = DEFAULT_URL
123+ self .user_agent :str = USER_AGENT
82124
83- self ._config = configparser .ConfigParser ()
84- self ._config .read (_files )
125+ self ._files = _get_config_files (config_files )
126+ if self ._files :
127+ self ._parse_config ()
128+
129+ def _parse_config (self )-> None :
130+ _config = configparser .ConfigParser ()
131+ _config .read (self ._files )
85132
86133if self .gitlab_id is None :
87134try :
88- self .gitlab_id = self . _config .get ("global" ,"default" )
135+ self .gitlab_id = _config .get ("global" ,"default" )
89136except Exception as e :
90137raise GitlabIDError (
91138"Impossible to get the gitlab id (not specified in config file)"
92139 )from e
93140
94141try :
95- self .url = self . _config .get (self .gitlab_id ,"url" )
142+ self .url = _config .get (self .gitlab_id ,"url" )
96143except Exception as e :
97144raise GitlabDataError (
98145"Impossible to get gitlab details from "
99146f"configuration ({ self .gitlab_id } )"
100147 )from e
101148
102- self .ssl_verify :Union [bool ,str ]= True
103149try :
104- self .ssl_verify = self . _config .getboolean ("global" ,"ssl_verify" )
150+ self .ssl_verify = _config .getboolean ("global" ,"ssl_verify" )
105151except ValueError :
106152# Value Error means the option exists but isn't a boolean.
107153# Get as a string instead as it should then be a local path to a
108154# CA bundle.
109155try :
110- self .ssl_verify = self . _config .get ("global" ,"ssl_verify" )
156+ self .ssl_verify = _config .get ("global" ,"ssl_verify" )
111157except Exception :
112158pass
113159except Exception :
114160pass
115161try :
116- self .ssl_verify = self . _config .getboolean (self .gitlab_id ,"ssl_verify" )
162+ self .ssl_verify = _config .getboolean (self .gitlab_id ,"ssl_verify" )
117163except ValueError :
118164# Value Error means the option exists but isn't a boolean.
119165# Get as a string instead as it should then be a local path to a
120166# CA bundle.
121167try :
122- self .ssl_verify = self . _config .get (self .gitlab_id ,"ssl_verify" )
168+ self .ssl_verify = _config .get (self .gitlab_id ,"ssl_verify" )
123169except Exception :
124170pass
125171except Exception :
126172pass
127173
128- self .timeout = 60
129174try :
130- self .timeout = self . _config .getint ("global" ,"timeout" )
175+ self .timeout = _config .getint ("global" ,"timeout" )
131176except Exception :
132177pass
133178try :
134- self .timeout = self . _config .getint (self .gitlab_id ,"timeout" )
179+ self .timeout = _config .getint (self .gitlab_id ,"timeout" )
135180except Exception :
136181pass
137182
138- self .private_token = None
139183try :
140- self .private_token = self . _config .get (self .gitlab_id ,"private_token" )
184+ self .private_token = _config .get (self .gitlab_id ,"private_token" )
141185except Exception :
142186pass
143187
144- self .oauth_token = None
145188try :
146- self .oauth_token = self . _config .get (self .gitlab_id ,"oauth_token" )
189+ self .oauth_token = _config .get (self .gitlab_id ,"oauth_token" )
147190except Exception :
148191pass
149192
150- self .job_token = None
151193try :
152- self .job_token = self . _config .get (self .gitlab_id ,"job_token" )
194+ self .job_token = _config .get (self .gitlab_id ,"job_token" )
153195except Exception :
154196pass
155197
156- self .http_username = None
157- self .http_password = None
158198try :
159- self .http_username = self . _config .get (self .gitlab_id ,"http_username" )
160- self .http_password = self . _config .get (self .gitlab_id ,"http_password" )
199+ self .http_username = _config .get (self .gitlab_id ,"http_username" )
200+ self .http_password = _config .get (self .gitlab_id ,"http_password" )
161201except Exception :
162202pass
163203
164204self ._get_values_from_helper ()
165205
166- self .api_version = "4"
167206try :
168- self .api_version = self . _config .get ("global" ,"api_version" )
207+ self .api_version = _config .get ("global" ,"api_version" )
169208except Exception :
170209pass
171210try :
172- self .api_version = self . _config .get (self .gitlab_id ,"api_version" )
211+ self .api_version = _config .get (self .gitlab_id ,"api_version" )
173212except Exception :
174213pass
175214if self .api_version not in ("4" ,):
176215raise GitlabDataError (f"Unsupported API version:{ self .api_version } " )
177216
178- self .per_page = None
179217for section in ["global" ,self .gitlab_id ]:
180218try :
181- self .per_page = self . _config .getint (section ,"per_page" )
219+ self .per_page = _config .getint (section ,"per_page" )
182220except Exception :
183221pass
184222if self .per_page is not None and not 0 <= self .per_page <= 100 :
185223raise GitlabDataError (f"Unsupported per_page number:{ self .per_page } " )
186224
187- self .pagination = None
188225try :
189- self .pagination = self . _config .get (self .gitlab_id ,"pagination" )
226+ self .pagination = _config .get (self .gitlab_id ,"pagination" )
190227except Exception :
191228pass
192229
193- self .order_by = None
194230try :
195- self .order_by = self . _config .get (self .gitlab_id ,"order_by" )
231+ self .order_by = _config .get (self .gitlab_id ,"order_by" )
196232except Exception :
197233pass
198234
199- self .user_agent = USER_AGENT
200235try :
201- self .user_agent = self . _config .get ("global" ,"user_agent" )
236+ self .user_agent = _config .get ("global" ,"user_agent" )
202237except Exception :
203238pass
204239try :
205- self .user_agent = self . _config .get (self .gitlab_id ,"user_agent" )
240+ self .user_agent = _config .get (self .gitlab_id ,"user_agent" )
206241except Exception :
207242pass
208243
209- self .retry_transient_errors = False
210244try :
211- self .retry_transient_errors = self . _config .getboolean (
245+ self .retry_transient_errors = _config .getboolean (
212246"global" ,"retry_transient_errors"
213247 )
214248except Exception :
215249pass
216250try :
217- self .retry_transient_errors = self . _config .getboolean (
251+ self .retry_transient_errors = _config .getboolean (
218252self .gitlab_id ,"retry_transient_errors"
219253 )
220254except Exception :