2008-10-21 14:00:00 +00:00
|
|
|
# Copyright (C) 2008 The Android Open Source Project
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
|
|
|
|
import pager
|
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
COLORS = {
|
|
|
|
None: -1,
|
|
|
|
"normal": -1,
|
|
|
|
"black": 0,
|
|
|
|
"red": 1,
|
|
|
|
"green": 2,
|
|
|
|
"yellow": 3,
|
|
|
|
"blue": 4,
|
|
|
|
"magenta": 5,
|
|
|
|
"cyan": 6,
|
|
|
|
"white": 7,
|
|
|
|
}
|
|
|
|
|
|
|
|
ATTRS = {None: -1, "bold": 1, "dim": 2, "ul": 4, "blink": 5, "reverse": 7}
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2015-03-28 21:10:17 +00:00
|
|
|
RESET = "\033[m"
|
|
|
|
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2012-09-24 03:15:13 +00:00
|
|
|
def is_color(s):
|
2023-03-11 06:46:20 +00:00
|
|
|
return s in COLORS
|
2012-09-24 03:15:13 +00:00
|
|
|
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2012-09-24 03:15:13 +00:00
|
|
|
def is_attr(s):
|
2023-03-11 06:46:20 +00:00
|
|
|
return s in ATTRS
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2015-03-28 21:10:17 +00:00
|
|
|
|
|
|
|
def _Color(fg=None, bg=None, attr=None):
|
2023-03-11 06:46:20 +00:00
|
|
|
fg = COLORS[fg]
|
|
|
|
bg = COLORS[bg]
|
|
|
|
attr = ATTRS[attr]
|
|
|
|
|
|
|
|
if attr >= 0 or fg >= 0 or bg >= 0:
|
|
|
|
need_sep = False
|
|
|
|
code = "\033["
|
|
|
|
|
|
|
|
if attr >= 0:
|
|
|
|
code += chr(ord("0") + attr)
|
|
|
|
need_sep = True
|
|
|
|
|
|
|
|
if fg >= 0:
|
|
|
|
if need_sep:
|
|
|
|
code += ";"
|
|
|
|
need_sep = True
|
|
|
|
|
|
|
|
if fg < 8:
|
|
|
|
code += "3%c" % (ord("0") + fg)
|
|
|
|
else:
|
|
|
|
code += "38;5;%d" % fg
|
|
|
|
|
|
|
|
if bg >= 0:
|
|
|
|
if need_sep:
|
|
|
|
code += ";"
|
|
|
|
|
|
|
|
if bg < 8:
|
|
|
|
code += "4%c" % (ord("0") + bg)
|
|
|
|
else:
|
|
|
|
code += "48;5;%d" % bg
|
|
|
|
code += "m"
|
|
|
|
else:
|
|
|
|
code = ""
|
|
|
|
return code
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2014-12-22 20:17:59 +00:00
|
|
|
DEFAULT = None
|
|
|
|
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2014-12-22 20:17:59 +00:00
|
|
|
def SetDefaultColoring(state):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Set coloring behavior to |state|.
|
2014-12-22 20:17:59 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
This is useful for overriding config options via the command line.
|
|
|
|
"""
|
|
|
|
if state is None:
|
|
|
|
# Leave it alone -- return quick!
|
|
|
|
return
|
2014-12-22 20:17:59 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
global DEFAULT
|
|
|
|
state = state.lower()
|
|
|
|
if state in ("auto",):
|
|
|
|
DEFAULT = state
|
|
|
|
elif state in ("always", "yes", "true", True):
|
|
|
|
DEFAULT = "always"
|
|
|
|
elif state in ("never", "no", "false", False):
|
|
|
|
DEFAULT = "never"
|
2014-12-22 20:17:59 +00:00
|
|
|
|
|
|
|
|
2008-10-21 14:00:00 +00:00
|
|
|
class Coloring(object):
|
2023-03-11 06:46:20 +00:00
|
|
|
def __init__(self, config, section_type):
|
|
|
|
self._section = "color.%s" % section_type
|
|
|
|
self._config = config
|
|
|
|
self._out = sys.stdout
|
|
|
|
|
|
|
|
on = DEFAULT
|
|
|
|
if on is None:
|
|
|
|
on = self._config.GetString(self._section)
|
|
|
|
if on is None:
|
|
|
|
on = self._config.GetString("color.ui")
|
|
|
|
|
|
|
|
if on == "auto":
|
|
|
|
if pager.active or os.isatty(1):
|
|
|
|
self._on = True
|
|
|
|
else:
|
|
|
|
self._on = False
|
|
|
|
elif on in ("true", "always"):
|
|
|
|
self._on = True
|
|
|
|
else:
|
|
|
|
self._on = False
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def redirect(self, out):
|
|
|
|
self._out = out
|
Change repo sync to be more friendly when updating the tree
We now try to sync all projects that can be done safely first, before
we start rebasing user commits over the upstream. This has the nice
effect of making the local tree as close to the upstream as possible
before the user has to start resolving merge conflicts, as that extra
information in other projects may aid in the conflict resolution.
Informational output is buffered and delayed until calculation for
all projects has been done, so that the user gets one concise list
of notice messages, rather than it interrupting the progress meter.
Fast-forward output is now prefixed with the project header, so the
user can see which project that update is taking place in, and make
some relation of the diffstat back to the project name.
Rebase output is now prefixed with the project header, so that if
the rebase fails, the user can see which project we were operating
on and can try to address the failure themselves.
Since rebase sits on a detached HEAD, we now look for an in-progress
rebase during sync, so we can alert the user that the given project
is in a state we cannot handle.
Signed-off-by: Shawn O. Pearce <sop@google.com>
2009-04-16 18:21:18 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
@property
|
|
|
|
def is_on(self):
|
|
|
|
return self._on
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def write(self, fmt, *args):
|
|
|
|
self._out.write(fmt % args)
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def flush(self):
|
|
|
|
self._out.flush()
|
2009-04-18 20:49:13 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def nl(self):
|
|
|
|
self._out.write("\n")
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def printer(self, opt=None, fg=None, bg=None, attr=None):
|
|
|
|
s = self
|
|
|
|
c = self.colorer(opt, fg, bg, attr)
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def f(fmt, *args):
|
|
|
|
s._out.write(c(fmt, *args))
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
return f
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def nofmt_printer(self, opt=None, fg=None, bg=None, attr=None):
|
|
|
|
s = self
|
|
|
|
c = self.nofmt_colorer(opt, fg, bg, attr)
|
2013-02-26 06:36:03 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def f(fmt):
|
|
|
|
s._out.write(c(fmt))
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
return f
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def colorer(self, opt=None, fg=None, bg=None, attr=None):
|
|
|
|
if self._on:
|
|
|
|
c = self._parse(opt, fg, bg, attr)
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def f(fmt, *args):
|
|
|
|
output = fmt % args
|
|
|
|
return "".join([c, output, RESET])
|
2015-03-28 21:10:17 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
return f
|
2012-09-24 03:15:13 +00:00
|
|
|
else:
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def f(fmt, *args):
|
|
|
|
return fmt % args
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
def nofmt_colorer(self, opt=None, fg=None, bg=None, attr=None):
|
|
|
|
if self._on:
|
|
|
|
c = self._parse(opt, fg, bg, attr)
|
|
|
|
|
|
|
|
def f(fmt):
|
|
|
|
return "".join([c, fmt, RESET])
|
|
|
|
|
|
|
|
return f
|
|
|
|
else:
|
|
|
|
|
|
|
|
def f(fmt):
|
|
|
|
return fmt
|
|
|
|
|
|
|
|
return f
|
|
|
|
|
|
|
|
def _parse(self, opt, fg, bg, attr):
|
|
|
|
if not opt:
|
|
|
|
return _Color(fg, bg, attr)
|
|
|
|
|
|
|
|
v = self._config.GetString("%s.%s" % (self._section, opt))
|
|
|
|
if v is None:
|
|
|
|
return _Color(fg, bg, attr)
|
|
|
|
|
|
|
|
v = v.strip().lower()
|
|
|
|
if v == "reset":
|
|
|
|
return RESET
|
|
|
|
elif v == "":
|
|
|
|
return _Color(fg, bg, attr)
|
|
|
|
|
|
|
|
have_fg = False
|
|
|
|
for a in v.split(" "):
|
|
|
|
if is_color(a):
|
|
|
|
if have_fg:
|
|
|
|
bg = a
|
|
|
|
else:
|
|
|
|
fg = a
|
|
|
|
elif is_attr(a):
|
|
|
|
attr = a
|
|
|
|
|
|
|
|
return _Color(fg, bg, attr)
|