@@ -26,6 +26,15 @@ class GitRevision:
26
26
file : str
27
27
28
28
29
+ class UbuntuGitServer503Error (Exception ):
30
+ """Exception raised when the ubuntu git server returns a 503"""
31
+
32
+ def __init__ (self ):
33
+ super ().__init__ (
34
+ "The ubuntu git server is unavailable, try again later or switch to the git protocol endpoint git://git.launchpad.net/ubuntu-cve-tracker"
35
+ )
36
+
37
+
29
38
class GitWrapper :
30
39
__active_retired_filename_regex__ = re .compile (r"(active|retired)/CVE-\S+" )
31
40
__cve_id_regex__ = re .compile (r"CVE-\S+" )
@@ -36,12 +45,14 @@ class GitWrapper:
36
45
_check_out_cmd_ = "git checkout {branch}"
37
46
_pull_cmd_ = "git pull -f"
38
47
_fetch_cmd_ = "git fetch --all"
48
+ _clean_cmd_ = "git clean --force -d"
39
49
_reset_cmd_ = "git reset --hard HEAD"
40
50
_pull_ff_only_cmd_ = "git pull --ff-only"
41
51
_write_graph_ = "git commit-graph write --reachable --changed-paths"
42
52
_change_set_cmd_ = "git log --no-renames --no-merges --name-status --format=oneline {from_rev}..{to_rev}"
43
53
_get_rev_content_cmd_ = "git show {sha}:{file}"
44
54
_head_rev_cmd_ = "git rev-parse HEAD"
55
+ _ubuntu_server_503_message = "error: RPC failed; HTTP 503 curl 22 The requested URL returned error: 503"
45
56
46
57
def __init__ (
47
58
self , source : str , branch : str , checkout_dest : str , workspace : str | None = None , logger : logging .Logger | None = None
@@ -78,30 +89,34 @@ def _check(self, destination):
78
89
79
90
return True
80
91
81
- @utils .retry_with_backoff ()
82
- def init_repo (self , force = False ):
83
- if force :
84
- if os .path .exists (self .dest ):
85
- self .logger .debug ("deleting existing repository" )
86
- shutil .rmtree (self .dest , ignore_errors = True )
87
-
88
- if self ._check (self .dest ):
89
- self .logger .debug ("found git repository at {}" .format (self .dest ))
90
- self .sync_with_upstream ()
91
- return
92
+ def _delete_repo (self ):
93
+ if os .path .exists (self .dest ):
94
+ self .logger .debug ("deleting existing repository" )
95
+ shutil .rmtree (self .dest , ignore_errors = True )
92
96
97
+ def _clone_repo (self ):
93
98
try :
94
99
self .logger .info (f"cloning git repository { self .src } branch { self .branch } to { self .dest } " )
95
-
96
100
cmd = self ._clone_cmd_ .format (src = self .src , dest = self .dest , branch = self .branch )
97
101
out = self ._exec_cmd (cmd )
98
-
99
102
self .logger .debug ("initialized git repo, cmd: {}, output: {}" .format (cmd , out .decode ()))
100
103
self ._write_graph ()
101
104
except :
102
105
self .logger .exception (f"failed to clone git repository { self .src } branch { self .branch } to { self .dest } " )
103
106
raise
104
107
108
+ @utils .retry_with_backoff ()
109
+ def init_repo (self , force = False ):
110
+ if force :
111
+ self ._delete_repo ()
112
+
113
+ if self ._check (self .dest ):
114
+ self .logger .debug ("found git repository at {}" .format (self .dest ))
115
+ self .sync_with_upstream ()
116
+ return
117
+
118
+ self ._clone_repo ()
119
+
105
120
def parse_full_cve_revision_history (self , git_log_output : str ) -> dict [str , list [GitRevision ]]:
106
121
hist = {}
107
122
entries = self ._parse_log (git_log_output )
@@ -126,13 +141,29 @@ def sync_with_upstream(self):
126
141
try :
127
142
try :
128
143
self ._exec_cmd (self ._set_remote_cmd_ .format (src = self .src ), cwd = self .dest )
144
+
145
+ # Cleanup any untracked files which might be present and reset any changes on the current branch
146
+ try :
147
+ self ._exec_cmd (self ._clean_cmd_ , cwd = self .dest )
148
+ self ._exec_cmd (self ._reset_cmd_ , cwd = self .dest )
149
+ except :
150
+ pass
151
+
129
152
self ._exec_cmd (self ._check_out_cmd_ .format (branch = self .branch ), cwd = self .dest )
130
- self ._exec_cmd (self ._reset_cmd_ , cwd = self .dest )
131
153
except : # nosec
132
154
pass
133
- out = self ._exec_cmd (self ._pull_ff_only_cmd_ , cwd = self .dest )
134
- self .logger .debug ("synced with upstream git repo, output: {}" .format (out .decode ()))
135
- self ._write_graph ()
155
+
156
+ try :
157
+ out = self ._exec_cmd (self ._pull_ff_only_cmd_ , cwd = self .dest )
158
+ self .logger .debug ("synced with upstream git repo, output: {}" .format (out .decode ()))
159
+ self ._write_graph ()
160
+ except UbuntuGitServer503Error :
161
+ raise
162
+ except : # nosec
163
+ # if something other than 503 occurred at this point just remove the repo and re-clone
164
+ self ._delete_repo ()
165
+ self ._clone_repo ()
166
+
136
167
except :
137
168
self .logger .exception ("failed to git pull" )
138
169
raise
@@ -358,7 +389,12 @@ def _exec_cmd(self, cmd, *args, **kwargs) -> bytes:
358
389
try :
359
390
self .logger .trace ("running: {}" .format (cmd ))
360
391
cmd_list = shlex .split (cmd )
361
- return subprocess .check_output (cmd_list , * args , ** kwargs ) # nosec
392
+ return subprocess .check_output (cmd_list , * args , ** kwargs , stderr = subprocess . PIPE ) # nosec
362
393
except Exception as e :
363
394
self .logger .exception ("error executing command: {}" .format (cmd ))
395
+
396
+ if isinstance (e , subprocess .CalledProcessError ):
397
+ if e .stderr and self ._ubuntu_server_503_message in e .stderr .decode ():
398
+ raise UbuntuGitServer503Error ()
399
+
364
400
raise e
0 commit comments