For this moment only git is supported.
$ cugit check origin/master
This will check if local modifications will come when you merge origin/master in your local branch.
*.py[cod] | |
# C extensions | |
*.so | |
# Packages | |
*.egg | |
*.egg-info | |
dist | |
build | |
eggs | |
parts | |
bin | |
var | |
sdist | |
develop-eggs | |
.installed.cfg | |
lib | |
lib64 | |
# Installer logs | |
pip-log.txt | |
# Unit test / coverage reports | |
.coverage | |
.tox | |
nosetests.xml | |
#Translations | |
*.mo | |
#Mr Developer | |
.mr.developer.cfg | |
.project | |
.pydevproject |
try: | |
VERSION = __import__('pkg_resources').get_distribution('cutools').version | |
except Exception, e: | |
VERSION = 'unknown' |
from hashlib import md5 | |
from clint.textui import puts, colored | |
def clean_diff(diff): | |
"""Removes diff header from a diff. | |
""" | |
res = [] | |
skip = True | |
for line in diff.split('\n'): | |
if line.startswith('diff --git'): | |
skip = True | |
if line.startswith('@@ '): | |
skip = False | |
if not skip: | |
res.append(line) | |
return '\n'.join(res) | |
def print_diff(diff): | |
"""Prints colored diff. | |
""" | |
for line in diff.split('\n'): | |
line = unicode(line).encode('utf-8') | |
if line.startswith('+'): | |
puts(colored.green(line)) | |
elif line.startswith('-'): | |
puts(colored.red(line)) | |
else: | |
puts(line) | |
def get_chunks(diff): | |
"""Returns a list with all the chunks in this diff. | |
""" | |
diff = clean_diff(diff) | |
chunk = [] | |
chunks = [] | |
for line in diff.split('\n'): | |
if not line: | |
continue | |
if line.startswith('@@ '): | |
if chunk: | |
chunks.append('\n'.join(chunk)) | |
chunk = [line] | |
else: | |
chunk.append(line) | |
if chunk: | |
chunks.append('\n'.join(chunk)) | |
return chunks | |
def get_hashed_chunks(chunks): | |
chunks_dict = {} | |
for chunk in chunks: | |
chunks_dict[md5(unicode(chunk).encode('utf-8')).hexdigest()] = chunk | |
return chunks_dict | |
def clean_chunk(chunk): | |
"""Clean headers from chunk. | |
""" | |
return '\n'.join([x[1:] for x in chunk.split('\n') | |
if x and x[0] not in ('-', '@')]) | |
def chunk_in_text(chunk, text): | |
"""Checks if chunk is inside text. | |
""" | |
chunk = clean_chunk(chunk) | |
return text.find(chunk) >= 0 |
from collections import defaultdict | |
class VCSInterface(object): | |
"""Interface to create VCS objects to perform an upgrade check. | |
""" | |
def __init__(self, upstrem): | |
"""Sets the upstream to perform the upgrade check. | |
""" | |
raise NotImplementedError() | |
def get_md5_files(self): | |
"""Must return a list of list of tuples with (md5, filename) modified | |
in working directory. | |
[('43f6e228690472109d1c825bdcd1625b', 'README.rst), | |
('3af3d58716ec0776500dc970020a5100', 'src/foo.py)] | |
""" | |
raise NotImplementedError() | |
@property | |
def local_rev(self): | |
"""Returns local revision of HEAD. | |
""" | |
raise NotImplementedError() | |
@property | |
def remote_rev(self): | |
"""Returns remote revision of HEAD | |
""" | |
raise NotImplementedError() | |
def get_commits(self, check_file, rev_from, rev_to): | |
"""Returns a list of commits beetwen rev_from and rev_to for check_file | |
""" | |
raise NotImplementedError() | |
def get_chunks(self, commit, check_file): | |
"""Returns the chunks from a commit. | |
""" | |
raise NotImplementedError() | |
def get_remote_file(self, check_file): | |
"""Returns the content of the remote file | |
""" | |
raise NotImplementedError() |
from hashlib import md5 | |
from subcmd.app import App | |
from subcmd.decorators import arg | |
from cutools.vcs.git import Git | |
from cutools.diff import get_hashed_chunks, clean_chunk, print_diff | |
from cutools import VERSION | |
from clint.textui import puts, colored | |
class CuGitApp(App): | |
name = "cugit" | |
version = VERSION | |
@arg('upstream', help='Upstream branch') | |
def do_check(self, options): | |
"""Checks local modifcations if are in upstream. | |
""" | |
git = Git(options.upstream) | |
n_files = 0 | |
n_chunks = 0 | |
for pymd5, check_file in git.get_md5_files(): | |
if md5(open(check_file, 'r').read()).hexdigest() != pymd5: | |
local_chunks = get_hashed_chunks(git.get_chunks(check_file)) | |
rev_from = git.local_rev | |
rev_to = git.remote_rev | |
for commit in git.get_commits(check_file, rev_from, rev_to): | |
remote_chunks = [ | |
md5(unicode(x).encode('utf-8')).hexdigest() | |
for x in git.get_chunks(check_file, commit) | |
] | |
for lchunk in local_chunks.keys(): | |
if lchunk in remote_chunks: | |
del local_chunks[lchunk] | |
else: | |
rfile = git.get_remote_file(check_file) | |
chunk = clean_chunk(local_chunks[lchunk]) | |
if rfile.find(chunk) >= 0: | |
del local_chunks[lchunk] | |
if local_chunks: | |
n_files += 1 | |
for chunk in local_chunks.values(): | |
print_diff(chunk) | |
n_chunks += 1 | |
puts(colored.red("[x] %s %s" % (pymd5, check_file))) | |
else: | |
puts(colored.green("[o] %s %s" % (pymd5, check_file))) | |
app = CuGitApp() |
from hashlib import md5 | |
from cutools.vcs import VCSInterface | |
from cutools.diff import get_chunks | |
from plumbum.cmd import git | |
class Git(VCSInterface): | |
"""Git implementation for Check Upgrade Tools. | |
""" | |
def __init__(self, upstream): | |
self.upstream = upstream | |
def get_md5_files(self): | |
res = [] | |
files = ['%s' % x for x in git['ls-files', '-m']().split('\n') if x] | |
for fl in files: | |
cmd = git['show', '%s:%s' % (self.upstream, fl)] | |
pymd5 = md5(unicode(cmd()).encode('utf-8')).hexdigest() | |
res += [(pymd5, fl)] | |
return res | |
@property | |
def local_rev(self): | |
return git['rev-parse', 'HEAD']().strip() | |
@property | |
def remote_rev(self): | |
return git['rev-parse', self.upstream]().strip() | |
def get_commits(self, check_file, rev_from, rev_to): | |
hcommand = git['log', '--no-merges', '--pretty=oneline', | |
'%s..%s' % (rev_from, rev_to), | |
check_file] | |
return [x.split(' ')[0] for x in hcommand().split('\n') if x] | |
def get_chunks(self, check_file, commit=None): | |
if commit: | |
cmd = git['diff', '%s^1..%s'% (commit, commit), check_file] | |
else: | |
cmd = git['diff', check_file] | |
return get_chunks( | |
cmd() | |
) | |
def get_remote_file(self, check_file): | |
return git['show', '%s:%s' % (self.upstream, check_file)]() |
Copyright (c) 2012, Eduard Carreras <[email protected]> | |
Permission to use, copy, modify, and/or distribute this software for any | |
purpose with or without fee is hereby granted, provided that the above | |
copyright notice and this permission notice appear in all copies. | |
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
from setuptools import setup, find_packages | |
from cutools import VERSION | |
def readfile(rfile): | |
try: | |
with open(rfile, 'w') as f: | |
return f.read() | |
except: | |
return '' | |
setup( | |
name='cutools', | |
version='0.1.0', | |
description='Check local modifications in upstream branch', | |
long_description=readfile('README.rst'), | |
author='Eduard Carreras', | |
author_email='[email protected]', | |
url='https://github.com/ecarreras/cutools', | |
license=readfile('LICENSE'), | |
packages=find_packages(), | |
classifiers=[ | |
'Development Status :: 4 - Beta', | |
'Environment :: Console', | |
'Intended Audience :: Developers', | |
'Intended Audience :: System Administrators', | |
'Programming Language :: Python', | |
'Programming Language :: Python :: 2', | |
'Programming Language :: Python :: 2.7', | |
], | |
platforms=['Any'], | |
scripts=[], | |
entry_points={ | |
'console_scripts': [ | |
'cugit = cutools.cli.cugit:app.cmdline' | |
] | |
}, | |
provides=['cutools'], | |
install_requires=['clint', 'plumbum', 'subcmd'], | |
) |
Done! know if the md5 is different we search for chunks in remote repo
Use hashlib!
Poder acabar fent un:
gitcu check
: Et comprovi el que no tens en upstream i t'ho ensenyi
gitcu diff
: Et generi un diff en el format de git per després poder-lo aplicar.
It could be great, check only if local modifications are in remote modifications