Commit 97345ebf authored by iannucci@chromium.org's avatar iannucci@chromium.org

Add git thaw/freeze to depot_tools.

R=agable@chromium.org, hinoka@chromium.org, stip@chromium.org, szager@chromium.org
BUG=261738

Review URL: https://codereview.chromium.org/181043018

git-svn-id: svn://svn.chromium.org/chrome/trunk/tools/depot_tools@256778 0039d316-1c4b-4281-b951-d872f2087c98
parent a112f03f
#!/bin/bash
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# git_freezer.py freeze -- a git-command to suspend all existing working
# directory modifications. This can be reversed with the 'git thaw' command.
SCRIPT=git_freezer.py
set -- freeze "$@"
. $(type -P python_git_runner.sh)
#!/bin/bash
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# git_freezer.py thaw -- a git-command to reverse the effect of the 'git freeze'
# command. Any changes suspended on this branch with the freeze command will be
# restored to the state they were in immediately prior to running the freeze
# command.
SCRIPT=git_freezer.py
set -- thaw "$@"
. $(type -P python_git_runner.sh)
......@@ -19,6 +19,7 @@ import binascii
import contextlib
import functools
import logging
import os
import signal
import sys
import tempfile
......@@ -139,7 +140,7 @@ def ScopedPool(*args, **kwargs):
class ProgressPrinter(object):
"""Threaded single-stat status message printer."""
def __init__(self, fmt, enabled=None, stream=sys.stderr, period=0.5):
def __init__(self, fmt, enabled=None, fout=sys.stderr, period=0.5):
"""Create a ProgressPrinter.
Use it as a context manager which produces a simple 'increment' method:
......@@ -155,7 +156,7 @@ class ProgressPrinter(object):
should go.
enabled (bool) - If this is None, will default to True if
logging.getLogger() is set to INFO or more verbose.
stream (file-like) - The stream to print status messages to.
fout (file-like) - The stream to print status messages to.
period (float) - The time in seconds for the printer thread to wait
between printing.
"""
......@@ -168,7 +169,7 @@ class ProgressPrinter(object):
self._count = 0
self._dead = False
self._dead_cond = threading.Condition()
self._stream = stream
self._stream = fout
self._thread = threading.Thread(target=self._run)
self._period = period
......@@ -239,17 +240,36 @@ def run(*cmd, **kwargs):
kwargs
autostrip (bool) - Strip the output. Defaults to True.
Output string is always strip()'d.
"""
autostrip = kwargs.pop('autostrip', True)
cmd = (GIT_EXE,) + cmd
logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd))
ret = subprocess2.check_output(cmd, stderr=subprocess2.PIPE, **kwargs)
retstream, proc = stream_proc(*cmd, **kwargs)
ret = retstream.read()
retcode = proc.wait()
if retcode != 0:
raise subprocess2.CalledProcessError(retcode, cmd, os.getcwd(), ret, None)
if autostrip:
ret = (ret or '').strip()
return ret
def stream_proc(*cmd, **kwargs):
"""Runs a git command. Returns stdout as a file.
If logging is DEBUG, we'll print the command before we run it.
"""
cmd = (GIT_EXE,) + cmd
logging.debug('Running %s', ' '.join(repr(tok) for tok in cmd))
proc = subprocess2.Popen(cmd, stderr=subprocess2.VOID,
stdout=subprocess2.PIPE, **kwargs)
return proc.stdout, proc
def stream(*cmd, **kwargs):
return stream_proc(*cmd, **kwargs)[0]
def hash_one(reflike):
return run('rev-parse', reflike)
......
#!/usr/local/bin/python
import sys
import re
import optparse
import subcommand
import subprocess2
from git_common import run, stream
FREEZE = 'FREEZE'
SECTIONS = {
'indexed': 'soft',
'unindexed': 'mixed'
}
MATCHER = re.compile(r'%s.(%s)' % (FREEZE, '|'.join(SECTIONS)))
def freeze():
took_action = False
try:
run('commit', '-m', FREEZE + '.indexed')
took_action = True
except subprocess2.CalledProcessError:
pass
try:
run('add', '-A')
run('commit', '-m', FREEZE + '.unindexed')
took_action = True
except subprocess2.CalledProcessError:
pass
if not took_action:
return 'Nothing to freeze.'
def thaw():
took_action = False
for sha in (s.strip() for s in stream('rev-list', 'HEAD').xreadlines()):
msg = run('show', '--format=%f%b', '-s', 'HEAD')
match = MATCHER.match(msg)
if not match:
if not took_action:
return 'Nothing to thaw.'
break
run('reset', '--' + SECTIONS[match.group(1)], sha)
took_action = True
def CMDfreeze(parser, args): # pragma: no cover
"""Freeze a branch's changes."""
parser.parse_args(args)
return freeze()
def CMDthaw(parser, args): # pragma: no cover
"""Returns a frozen branch to the state before it was frozen."""
parser.parse_args(args)
return thaw()
def main(): # pragma: no cover
dispatcher = subcommand.CommandDispatcher(__name__)
ret = dispatcher.execute(optparse.OptionParser(), sys.argv[1:])
if ret:
print ret
if __name__ == '__main__': # pragma: no cover
main()
\ No newline at end of file
......@@ -128,7 +128,7 @@ class ProgressPrinterTest(GitCommonTestBase):
fmt = '%(count)d/10'
stream = self.FakeStream()
pp = self.gc.ProgressPrinter(fmt, enabled=True, stream=stream, period=0.01)
pp = self.gc.ProgressPrinter(fmt, enabled=True, fout=stream, period=0.01)
with pp as inc:
for _ in xrange(10):
time.sleep(0.02)
......@@ -190,6 +190,17 @@ class GitReadOnlyFunctionsTest(git_test_utils.GitRepoReadOnlyTestBase,
self.repo['D']
)
def testStream(self):
items = set(self.repo.commit_map.itervalues())
def testfn():
for line in self.gc.stream('log', '--format=%H').xreadlines():
line = line.strip()
self.assertIn(line, items)
items.remove(line)
self.repo.run(testfn)
def testCurrentBranch(self):
self.repo.git('checkout', 'branch_D')
self.assertEqual(self.repo.run(self.gc.current_branch), 'branch_D')
......
#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Unit tests for git_freezer.py"""
import os
import sys
DEPOT_TOOLS_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, DEPOT_TOOLS_ROOT)
from testing_support import coverage_utils
from testing_support import git_test_utils
class GitFreezeThaw(git_test_utils.GitRepoReadWriteTestBase):
@classmethod
def setUpClass(cls):
super(GitFreezeThaw, cls).setUpClass()
import git_freezer
cls.gf = git_freezer
REPO = """
A B C D
B E D
"""
COMMIT_A = {
'some/files/file1': {'data': 'file1'},
'some/files/file2': {'data': 'file2'},
'some/files/file3': {'data': 'file3'},
'some/other/file': {'data': 'otherfile'},
}
COMMIT_C = {
'some/files/file2': {
'mode': 0755,
'data': 'file2 - vanilla'},
}
COMMIT_E = {
'some/files/file2': {'data': 'file2 - merged'},
}
COMMIT_D = {
'some/files/file2': {'data': 'file2 - vanilla\nfile2 - merged'},
}
def testNothing(self):
self.assertIsNotNone(self.repo.run(self.gf.thaw)) # 'Nothing to thaw'
self.assertIsNotNone(self.repo.run(self.gf.freeze)) # 'Nothing to freeze'
def testAll(self):
def inner():
with open('some/files/file2', 'a') as f2:
print >> f2, 'cool appended line'
os.mkdir('some/other_files')
with open('some/other_files/subdir_file', 'w') as f3:
print >> f3, 'new file!'
with open('some/files/file5', 'w') as f5:
print >> f5, 'New file!1!one!'
STATUS_1 = '\n'.join((
' M some/files/file2',
'A some/files/file5',
'?? some/other_files/'
)) + '\n'
self.repo.git('add', 'some/files/file5')
# Freeze group 1
self.assertEquals(self.repo.git('status', '--porcelain').stdout, STATUS_1)
self.assertIsNone(self.gf.freeze())
self.assertEquals(self.repo.git('status', '--porcelain').stdout, '')
# Freeze group 2
with open('some/files/file2', 'a') as f2:
print >> f2, 'new! appended line!'
self.assertEquals(self.repo.git('status', '--porcelain').stdout,
' M some/files/file2\n')
self.assertIsNone(self.gf.freeze())
self.assertEquals(self.repo.git('status', '--porcelain').stdout, '')
# Thaw it out!
self.assertIsNone(self.gf.thaw())
self.assertIsNotNone(self.gf.thaw()) # One thaw should thaw everything
self.assertEquals(self.repo.git('status', '--porcelain').stdout, STATUS_1)
self.repo.run(inner)
if __name__ == '__main__':
sys.exit(coverage_utils.covered_main(
os.path.join(DEPOT_TOOLS_ROOT, 'git_freezer.py')
))
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment