summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn O. Pearce <sop@google.com>2008-11-03 10:32:09 -0800
committerShawn O. Pearce <sop@google.com>2008-11-03 11:00:44 -0800
commitc9ef744c7b5f6bcab446cf0a0bc9cc1b016dd5f8 (patch)
treeff1bd7309698ef0dd312daf205512b1fa96d3e8d
parent438ee1cad98ac32509718976e63c36a449bfb679 (diff)
downloadgit-repo-c9ef744c7b5f6bcab446cf0a0bc9cc1b016dd5f8.tar.gz
Install a default pre-auto-gc hook in all repositories
This hook is evaluated by `git gc --auto` to determine if it is a good idea to execute a GC at this time, or defer it to some later date. When working on a laptop its a good idea to avoid GC if you are on battery power as the extra CPU and disk IO would consume a decent amount of the charge. The hook is the standard sample hook from git.git contrib/hooks, last modified in git.git by 84ed4c5d117d72f02cc918e413b9861a9d2846d7. I added the GPLv2 header to the script to ensure the license notice is clear, as it does not match repo's own APLv2 license. We only update hooks during initial repository creation or on a repo sync. This way we don't incur huge overheads from the hook stat operations during "repo status" or even the normal "repo sync" cases. Signed-off-by: Shawn O. Pearce <sop@google.com>
-rw-r--r--error.py2
-rwxr-xr-xhooks/pre-auto-gc44
-rwxr-xr-xmain.py8
-rw-r--r--project.py68
-rw-r--r--subcmds/sync.py10
5 files changed, 110 insertions, 22 deletions
diff --git a/error.py b/error.py
index e3cf41c1..029e1227 100644
--- a/error.py
+++ b/error.py
@@ -64,3 +64,5 @@ class RepoChangedException(Exception):
64 repo or manifest repositories. In this special case we must 64 repo or manifest repositories. In this special case we must
65 use exec to re-execute repo with the new code and manifest. 65 use exec to re-execute repo with the new code and manifest.
66 """ 66 """
67 def __init__(self, extra_args=[]):
68 self.extra_args = extra_args
diff --git a/hooks/pre-auto-gc b/hooks/pre-auto-gc
new file mode 100755
index 00000000..110e3194
--- /dev/null
+++ b/hooks/pre-auto-gc
@@ -0,0 +1,44 @@
1#!/bin/sh
2#
3# An example hook script to verify if you are on battery, in case you
4# are running Linux or OS X. Called by git-gc --auto with no arguments.
5# The hook should exit with non-zero status after issuing an appropriate
6# message if it wants to stop the auto repacking.
7
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation; either version 2 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program; if not, write to the Free Software
20# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
22if test -x /sbin/on_ac_power && /sbin/on_ac_power
23then
24 exit 0
25elif test "$(cat /sys/class/power_supply/AC/online 2>/dev/null)" = 1
26then
27 exit 0
28elif grep -q 'on-line' /proc/acpi/ac_adapter/AC/state 2>/dev/null
29then
30 exit 0
31elif grep -q '0x01$' /proc/apm 2>/dev/null
32then
33 exit 0
34elif grep -q "AC Power \+: 1" /proc/pmu/info 2>/dev/null
35then
36 exit 0
37elif test -x /usr/bin/pmset && /usr/bin/pmset -g batt |
38 grep -q "Currently drawing from 'AC Power'"
39then
40 exit 0
41fi
42
43echo "Auto packing deferred; not on AC"
44exit 1
diff --git a/main.py b/main.py
index 0901c845..be8da017 100755
--- a/main.py
+++ b/main.py
@@ -186,11 +186,13 @@ def _Main(argv):
186 repo._Run(argv) 186 repo._Run(argv)
187 except KeyboardInterrupt: 187 except KeyboardInterrupt:
188 sys.exit(1) 188 sys.exit(1)
189 except RepoChangedException: 189 except RepoChangedException, rce:
190 # If the repo or manifest changed, re-exec ourselves. 190 # If repo changed, re-exec ourselves.
191 # 191 #
192 argv = list(sys.argv)
193 argv.extend(rce.extra_args)
192 try: 194 try:
193 os.execv(__file__, sys.argv) 195 os.execv(__file__, argv)
194 except OSError, e: 196 except OSError, e:
195 print >>sys.stderr, 'fatal: cannot restart repo after upgrade' 197 print >>sys.stderr, 'fatal: cannot restart repo after upgrade'
196 print >>sys.stderr, 'fatal: %s' % e 198 print >>sys.stderr, 'fatal: %s' % e
diff --git a/project.py b/project.py
index 874a40bd..f963576b 100644
--- a/project.py
+++ b/project.py
@@ -46,6 +46,32 @@ def _info(fmt, *args):
46def not_rev(r): 46def not_rev(r):
47 return '^' + r 47 return '^' + r
48 48
49
50hook_list = None
51def repo_hooks():
52 global hook_list
53 if hook_list is None:
54 d = os.path.abspath(os.path.dirname(__file__))
55 d = os.path.join(d , 'hooks')
56 hook_list = map(lambda x: os.path.join(d, x), os.listdir(d))
57 return hook_list
58
59def relpath(dst, src):
60 src = os.path.dirname(src)
61 top = os.path.commonprefix([dst, src])
62 if top.endswith('/'):
63 top = top[:-1]
64 else:
65 top = os.path.dirname(top)
66
67 tmp = src
68 rel = ''
69 while top != tmp:
70 rel += '../'
71 tmp = os.path.dirname(tmp)
72 return rel + dst[len(top) + 1:]
73
74
49class DownloadedChange(object): 75class DownloadedChange(object):
50 _commit_cache = None 76 _commit_cache = None
51 77
@@ -472,7 +498,10 @@ class Project(object):
472 self._RepairAndroidImportErrors() 498 self._RepairAndroidImportErrors()
473 self._InitMRef() 499 self._InitMRef()
474 return True 500 return True
475 501
502 def PostRepoUpgrade(self):
503 self._InitHooks()
504
476 def _CopyFiles(self): 505 def _CopyFiles(self):
477 for file in self.copyfiles: 506 for file in self.copyfiles:
478 file._Copy() 507 file._Copy()
@@ -795,14 +824,29 @@ class Project(object):
795 to_rm = [] 824 to_rm = []
796 for old_hook in to_rm: 825 for old_hook in to_rm:
797 os.remove(os.path.join(hooks, old_hook)) 826 os.remove(os.path.join(hooks, old_hook))
798 827 self._InitHooks()
799 # TODO(sop) install custom repo hooks
800 828
801 m = self.manifest.manifestProject.config 829 m = self.manifest.manifestProject.config
802 for key in ['user.name', 'user.email']: 830 for key in ['user.name', 'user.email']:
803 if m.Has(key, include_defaults = False): 831 if m.Has(key, include_defaults = False):
804 self.config.SetString(key, m.GetString(key)) 832 self.config.SetString(key, m.GetString(key))
805 833
834 def _InitHooks(self):
835 hooks = self._gitdir_path('hooks')
836 if not os.path.exists(hooks):
837 os.makedirs(hooks)
838 for stock_hook in repo_hooks():
839 dst = os.path.join(hooks, os.path.basename(stock_hook))
840 try:
841 os.symlink(relpath(stock_hook, dst), dst)
842 except OSError, e:
843 if e.errno == errno.EEXIST:
844 pass
845 elif e.errno == errno.EPERM:
846 raise GitError('filesystem must support symlinks')
847 else:
848 raise
849
806 def _InitRemote(self): 850 def _InitRemote(self):
807 if self.remote.fetchUrl: 851 if self.remote.fetchUrl:
808 remote = self.GetRemote(self.remote.name) 852 remote = self.GetRemote(self.remote.name)
@@ -842,19 +886,6 @@ class Project(object):
842 if not os.path.exists(dotgit): 886 if not os.path.exists(dotgit):
843 os.makedirs(dotgit) 887 os.makedirs(dotgit)
844 888
845 topdir = os.path.commonprefix([self.gitdir, dotgit])
846 if topdir.endswith('/'):
847 topdir = topdir[:-1]
848 else:
849 topdir = os.path.dirname(topdir)
850
851 tmpdir = dotgit
852 relgit = ''
853 while topdir != tmpdir:
854 relgit += '../'
855 tmpdir = os.path.dirname(tmpdir)
856 relgit += self.gitdir[len(topdir) + 1:]
857
858 for name in ['config', 889 for name in ['config',
859 'description', 890 'description',
860 'hooks', 891 'hooks',
@@ -866,8 +897,9 @@ class Project(object):
866 'rr-cache', 897 'rr-cache',
867 'svn']: 898 'svn']:
868 try: 899 try:
869 os.symlink(os.path.join(relgit, name), 900 src = os.path.join(self.gitdir, name)
870 os.path.join(dotgit, name)) 901 dst = os.path.join(dotgit, name)
902 os.symlink(relpath(src, dst), dst)
871 except OSError, e: 903 except OSError, e:
872 if e.errno == errno.EPERM: 904 if e.errno == errno.EPERM:
873 raise GitError('filesystem must support symlinks') 905 raise GitError('filesystem must support symlinks')
diff --git a/subcmds/sync.py b/subcmds/sync.py
index 3eb44edf..9af12322 100644
--- a/subcmds/sync.py
+++ b/subcmds/sync.py
@@ -49,6 +49,9 @@ the manifest.
49 p.add_option('--no-repo-verify', 49 p.add_option('--no-repo-verify',
50 dest='no_repo_verify', action='store_true', 50 dest='no_repo_verify', action='store_true',
51 help='do not verify repo source code') 51 help='do not verify repo source code')
52 p.add_option('--repo-upgraded',
53 dest='repo_upgraded', action='store_true',
54 help='perform additional actions after a repo upgrade')
52 55
53 def _Fetch(self, *projects): 56 def _Fetch(self, *projects):
54 fetched = set() 57 fetched = set()
@@ -67,6 +70,11 @@ the manifest.
67 mp = self.manifest.manifestProject 70 mp = self.manifest.manifestProject
68 mp.PreSync() 71 mp.PreSync()
69 72
73 if opt.repo_upgraded:
74 for project in self.manifest.projects.values():
75 if project.Exists:
76 project.PostRepoUpgrade()
77
70 all = self.GetProjects(args, missing_ok=True) 78 all = self.GetProjects(args, missing_ok=True)
71 fetched = self._Fetch(rp, mp, *all) 79 fetched = self._Fetch(rp, mp, *all)
72 80
@@ -77,7 +85,7 @@ the manifest.
77 if not rp.Sync_LocalHalf(): 85 if not rp.Sync_LocalHalf():
78 sys.exit(1) 86 sys.exit(1)
79 print >>sys.stderr, 'info: Restarting repo with latest version' 87 print >>sys.stderr, 'info: Restarting repo with latest version'
80 raise RepoChangedException() 88 raise RepoChangedException(['--repo-upgraded'])
81 else: 89 else:
82 print >>sys.stderr, 'warning: Skipped upgrade to unverified version' 90 print >>sys.stderr, 'warning: Skipped upgrade to unverified version'
83 91