diff options
author | Gavin Mak <gavinmak@google.com> | 2023-07-22 02:56:44 +0000 |
---|---|---|
committer | LUCI <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2023-07-28 18:55:04 +0000 |
commit | 1d2e99d0289a36e8c2a53ff3bf5690f0f780ba63 (patch) | |
tree | 2df20c20871fa0dceb8d545e76b75ff76b9e755d /subcmds/sync.py | |
parent | c657844efe40b97700c3654989bdbe3a33e409d7 (diff) | |
download | git-repo-1d2e99d0289a36e8c2a53ff3bf5690f0f780ba63.tar.gz |
sync: Track last completed fetch/checkout
Save the latest time any project is fetched and checked out. This will
be used to detect partial checkouts.
Bug: b/286126621
Change-Id: I53b264dc70ba168d506076dbd693ef79a696b61d
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/380514
Commit-Queue: Gavin Mak <gavinmak@google.com>
Reviewed-by: Joanna Wang <jojwang@google.com>
Tested-by: Gavin Mak <gavinmak@google.com>
Diffstat (limited to 'subcmds/sync.py')
-rw-r--r-- | subcmds/sync.py | 87 |
1 files changed, 71 insertions, 16 deletions
diff --git a/subcmds/sync.py b/subcmds/sync.py index a2cc1f89..5f8bc2f0 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
@@ -737,6 +737,7 @@ later is required to fix a server side protocol bug. | |||
737 | start = result.start | 737 | start = result.start |
738 | finish = result.finish | 738 | finish = result.finish |
739 | self._fetch_times.Set(project, finish - start) | 739 | self._fetch_times.Set(project, finish - start) |
740 | self._local_sync_state.SetFetchTime(project) | ||
740 | self.event_log.AddSync( | 741 | self.event_log.AddSync( |
741 | project, | 742 | project, |
742 | event_log.TASK_SYNC_NETWORK, | 743 | event_log.TASK_SYNC_NETWORK, |
@@ -807,6 +808,7 @@ later is required to fix a server side protocol bug. | |||
807 | sync_event.set() | 808 | sync_event.set() |
808 | pm.end() | 809 | pm.end() |
809 | self._fetch_times.Save() | 810 | self._fetch_times.Save() |
811 | self._local_sync_state.Save() | ||
810 | 812 | ||
811 | if not self.outer_client.manifest.IsArchive: | 813 | if not self.outer_client.manifest.IsArchive: |
812 | self._GCProjects(projects, opt, err_event) | 814 | self._GCProjects(projects, opt, err_event) |
@@ -949,7 +951,9 @@ later is required to fix a server side protocol bug. | |||
949 | ) | 951 | ) |
950 | # Check for any errors before running any more tasks. | 952 | # Check for any errors before running any more tasks. |
951 | # ...we'll let existing jobs finish, though. | 953 | # ...we'll let existing jobs finish, though. |
952 | if not success: | 954 | if success: |
955 | self._local_sync_state.SetCheckoutTime(project) | ||
956 | else: | ||
953 | ret = False | 957 | ret = False |
954 | err_results.append( | 958 | err_results.append( |
955 | project.RelPath(local=opt.this_manifest_only) | 959 | project.RelPath(local=opt.this_manifest_only) |
@@ -961,21 +965,19 @@ later is required to fix a server side protocol bug. | |||
961 | pm.update(msg=project.name) | 965 | pm.update(msg=project.name) |
962 | return ret | 966 | return ret |
963 | 967 | ||
964 | return ( | 968 | proc_res = self.ExecuteInParallel( |
965 | self.ExecuteInParallel( | 969 | opt.jobs_checkout, |
966 | opt.jobs_checkout, | 970 | functools.partial( |
967 | functools.partial( | 971 | self._CheckoutOne, opt.detach_head, opt.force_sync |
968 | self._CheckoutOne, opt.detach_head, opt.force_sync | 972 | ), |
969 | ), | 973 | all_projects, |
970 | all_projects, | 974 | callback=_ProcessResults, |
971 | callback=_ProcessResults, | 975 | output=Progress("Checking out", len(all_projects), quiet=opt.quiet), |
972 | output=Progress( | ||
973 | "Checking out", len(all_projects), quiet=opt.quiet | ||
974 | ), | ||
975 | ) | ||
976 | and not err_results | ||
977 | ) | 976 | ) |
978 | 977 | ||
978 | self._local_sync_state.Save() | ||
979 | return proc_res and not err_results | ||
980 | |||
979 | @staticmethod | 981 | @staticmethod |
980 | def _GetPreciousObjectsState(project: Project, opt): | 982 | def _GetPreciousObjectsState(project: Project, opt): |
981 | """Get the preciousObjects state for the project. | 983 | """Get the preciousObjects state for the project. |
@@ -1684,6 +1686,7 @@ later is required to fix a server side protocol bug. | |||
1684 | ) | 1686 | ) |
1685 | 1687 | ||
1686 | self._fetch_times = _FetchTimes(manifest) | 1688 | self._fetch_times = _FetchTimes(manifest) |
1689 | self._local_sync_state = _LocalSyncState(manifest) | ||
1687 | if not opt.local_only: | 1690 | if not opt.local_only: |
1688 | with multiprocessing.Manager() as manager: | 1691 | with multiprocessing.Manager() as manager: |
1689 | with ssh.ProxyManager(manager) as ssh_proxy: | 1692 | with ssh.ProxyManager(manager) as ssh_proxy: |
@@ -1898,12 +1901,64 @@ class _FetchTimes(object): | |||
1898 | platform_utils.remove(self._path, missing_ok=True) | 1901 | platform_utils.remove(self._path, missing_ok=True) |
1899 | 1902 | ||
1900 | 1903 | ||
1904 | class _LocalSyncState(object): | ||
1905 | _LAST_FETCH = "last_fetch" | ||
1906 | _LAST_CHECKOUT = "last_checkout" | ||
1907 | |||
1908 | def __init__(self, manifest): | ||
1909 | self._path = os.path.join(manifest.repodir, ".repo_localsyncstate.json") | ||
1910 | self._time = time.time() | ||
1911 | self._state = None | ||
1912 | self._Load() | ||
1913 | |||
1914 | def SetFetchTime(self, project): | ||
1915 | self._Set(project, self._LAST_FETCH) | ||
1916 | |||
1917 | def SetCheckoutTime(self, project): | ||
1918 | self._Set(project, self._LAST_CHECKOUT) | ||
1919 | |||
1920 | def GetFetchTime(self, project): | ||
1921 | return self._Get(project, self._LAST_FETCH) | ||
1922 | |||
1923 | def GetCheckoutTime(self, project): | ||
1924 | return self._Get(project, self._LAST_CHECKOUT) | ||
1925 | |||
1926 | def _Get(self, project, key): | ||
1927 | self._Load() | ||
1928 | p = project.relpath | ||
1929 | if p not in self._state: | ||
1930 | return | ||
1931 | return self._state[p].get(key) | ||
1932 | |||
1933 | def _Set(self, project, key): | ||
1934 | p = project.relpath | ||
1935 | if p not in self._state: | ||
1936 | self._state[p] = {} | ||
1937 | self._state[p][key] = self._time | ||
1938 | |||
1939 | def _Load(self): | ||
1940 | if self._state is None: | ||
1941 | try: | ||
1942 | with open(self._path) as f: | ||
1943 | self._state = json.load(f) | ||
1944 | except (IOError, ValueError): | ||
1945 | platform_utils.remove(self._path, missing_ok=True) | ||
1946 | self._state = {} | ||
1947 | |||
1948 | def Save(self): | ||
1949 | if not self._state: | ||
1950 | return | ||
1951 | try: | ||
1952 | with open(self._path, "w") as f: | ||
1953 | json.dump(self._state, f, indent=2) | ||
1954 | except (IOError, TypeError): | ||
1955 | platform_utils.remove(self._path, missing_ok=True) | ||
1956 | |||
1957 | |||
1901 | # This is a replacement for xmlrpc.client.Transport using urllib2 | 1958 | # This is a replacement for xmlrpc.client.Transport using urllib2 |
1902 | # and supporting persistent-http[s]. It cannot change hosts from | 1959 | # and supporting persistent-http[s]. It cannot change hosts from |
1903 | # request to request like the normal transport, the real url | 1960 | # request to request like the normal transport, the real url |
1904 | # is passed during initialization. | 1961 | # is passed during initialization. |
1905 | |||
1906 | |||
1907 | class PersistentTransport(xmlrpc.client.Transport): | 1962 | class PersistentTransport(xmlrpc.client.Transport): |
1908 | def __init__(self, orig_host): | 1963 | def __init__(self, orig_host): |
1909 | self.orig_host = orig_host | 1964 | self.orig_host = orig_host |