Merge pull request #105 from jumanjiman/python3

prepare for python3 compatibility
This commit is contained in:
Devan Goodwin 2014-03-03 08:30:53 -04:00
commit eeef2ae6e9
29 changed files with 492 additions and 205 deletions

23
.editorconfig Normal file
View file

@ -0,0 +1,23 @@
; Unify the coding style for different editors and IDEs.
; Plugins are available for emacs, vim, gedit, textmate, and more
; at http://editorconfig.org/#download
;
; See http://editorconfig.org or https://github.com/editorconfig/
;
; If you change a setting in this file,
; you should also change .gitattributes
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.py]
indent_size = 4
[*.yml]
indent_size = 2

14
.gitattributes vendored Normal file
View file

@ -0,0 +1,14 @@
######################################################################
# gitattributes(5) describes the format and usage of this file.
#
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html
# http://git-scm.com/book/ch7-2.html
# http://urbanautomaton.com/blog/2011/07/28/git-grep-and-language-specific-diffs/
# https://help.github.com/articles/dealing-with-line-endings
######################################################################
#
# If you change a setting here,
# you should also change .editorconfig
#
*.py diff=python text eol=lf whitespace="trailing-space,space-before-tab,tab-in-indent,blank-at-eof,tabwidth=4"
*.yml text eol=lf whitespace="trailing-space,space-before-tab,tab-in-indent,blank-at-eof,tabwidth=2"

8
.travis-install-kludge.sh Executable file
View file

@ -0,0 +1,8 @@
#!/bin/bash
# GitPython does not currently support python3 and
# may be replaced by pygit2.
# https://fedoraproject.org/wiki/User:Churchyard/python3
if [[ $(python --version 2>&1) =~ ^2 ]]; then
pip install 'GitPython >= 0.2.0' --use-mirrors --pre
fi

View file

@ -1,8 +1,12 @@
# http://docs.travis-ci.com/user/languages/python/
language: python
python:
- "2.5"
- "2.6"
- "2.7"
- "3.3"
install:
- ./.travis-install-kludge.sh
- pip install 'pep8' --use-mirrors
install: pip install 'GitPython >= 0.2.0' --use-mirrors
script: nosetests test/unit

61
HACKING
View file

@ -1,8 +1,42 @@
To run all tests, install the python-nose package and from the root of the
project:
Hacking
=======
./runtests.py
Python versions
---------------
Tito supports Python versions 2.4 (RHEL 5) and up.
See http://docs.python.org/dev/howto/pyporting.html
and http://python3porting.com/differences.html
for tips on writing portable Python code.
In particular, you must capture exceptions in a way that's
compatible with both python 2.4 and 3.x. For example:
try:
raise Exception()
except Exception:
import sys
exc = sys.exc_info()[1]
# Current exception is 'exc'.
pass
Tests
-----
To run all tests, install these packages:
* python-nose and python3-nose
* python-pep8 and python3-pep8
* createrepo
Then from the root of the project:
python ./runtests.py -vv
python3 ./runtests.py -vv test/unit
(Run only the unit tests on python3 since GitPython does not
support python3 yet.)
When developing code for tito there are a couple ways you can test:
@ -10,7 +44,9 @@ When developing code for tito there are a couple ways you can test:
"bin/tito-dev" is a script that will run code from the local checkout
rather than what is installed on the system.
And of course, you can always use the installed tito to replace itself with a test build of the latest *committed* code in your git HEAD.
And of course, you can always use the installed tito to replace
itself with a test build of the latest *committed* code in your
git HEAD.
tito build --rpm --test -i
@ -19,3 +55,20 @@ If you screw anything up inside tito itself, you can just:
rpm -e tito
yum install tito
Code style
----------
Python3 does not allow mixing tabs and spaces for indentation.
http://docs.python.org/3.3/reference/lexical_analysis.html
You can force your editor to do the right thing by installing
a plugin for your editor from http://editorconfig.org/#download
For example, add the EditorConfig plugin for vim like this:
cd /tmp/
wget https://github.com/editorconfig/editorconfig-vim/archive/master.zip
unzip master.zip
mkdir ~/.vim
cp -r editorconfig-vim-master/* ~/.vim/

View file

@ -33,7 +33,10 @@ SRC_BIN_DIR = os.path.abspath(os.path.join(TEST_SCRIPT_DIR, "bin/"))
os.environ['TITO_SRC_BIN_DIR'] = SRC_BIN_DIR
if __name__ == '__main__':
import nose
print("Using Python %s" % sys.version[0:3])
print("Using nose %s" % nose.__version__[0:3])
print("Running tito tests against: %s" % SRC_DIR)
import nose
nose.main()

View file

@ -21,6 +21,7 @@ from tito.config_object import ConfigObject
from tito.common import error_out, debug, get_spec_version_and_release, \
get_class_by_name
class FetchBuilder(ConfigObject, BuilderBase):
"""
A separate Builder class for projects whose source is not in git. Source
@ -212,5 +213,3 @@ class ArgSourceStrategy(SourceStrategy):
in_f.close()
out_f.close()
shutil.move(self.spec_file + ".new", self.spec_file)

View file

@ -19,7 +19,6 @@ and rpms.
import os
import sys
import re
import commands
from pkg_resources import require
from distutils.version import LooseVersion as loose_version
from tempfile import mkdtemp
@ -27,6 +26,7 @@ from tempfile import mkdtemp
from tito.common import *
from tito.common import scl_to_rpm_option, get_latest_tagged_version, \
find_wrote_in_rpmbuild_output
from tito.compat import *
from tito.exception import RunCommandException
from tito.release import *
from tito.exception import TitoException
@ -224,15 +224,17 @@ class BuilderBase(object):
try:
output = run_command(cmd)
except (KeyboardInterrupt, SystemExit):
print ""
print("")
exit(1)
except RunCommandException, err:
except RunCommandException:
err = sys.exc_info()[1]
msg = str(err)
if (re.search('Failed build dependencies', err.output)):
msg = "Please run 'yum-builddep %s' as root." % \
find_spec_file(self.relative_project_dir)
error_out('%s' % msg)
except Exception, err:
except Exception:
err = sys.exc_info()[1]
error_out('%s' % str(err))
print(output)
files_written = find_wrote_in_rpmbuild_output(output)
@ -287,7 +289,6 @@ class BuilderBase(object):
pass
class Builder(ConfigObject, BuilderBase):
"""
Parent builder class.
@ -373,7 +374,6 @@ class Builder(ConfigObject, BuilderBase):
# Set to path to srpm once we build one.
self.srpm_location = None
def _get_build_version(self):
"""
Figure out the git tag and version-release we're building.
@ -384,7 +384,7 @@ class Builder(ConfigObject, BuilderBase):
build_version = self.build_tag[len(self.project_name + "-"):]
else:
build_version = get_latest_tagged_version(self.project_name)
if build_version == None:
if build_version is None:
error_out(["Unable to lookup latest package info.",
"Perhaps you need to tag first?"])
self.build_tag = "%s-%s" % (self.project_name, build_version)
@ -401,7 +401,7 @@ class Builder(ConfigObject, BuilderBase):
"""
self._setup_sources()
run_command("cp %s/%s %s/" % \
run_command("cp %s/%s %s/" %
(self.rpmbuild_sourcedir, self.tgz_filename,
self.rpmbuild_basedir))
@ -684,7 +684,7 @@ class CvsBuilder(NoTgzBuilder):
if not reuse_cvs_checkout:
self._verify_cvs_module_not_already_checked_out()
commands.getoutput("mkdir -p %s" % self.cvs_workdir)
getoutput("mkdir -p %s" % self.cvs_workdir)
cvs_releaser = CvsReleaser(self)
cvs_releaser.cvs_checkout_module()
cvs_releaser.cvs_verify_branches_exist()
@ -878,7 +878,7 @@ class UpstreamBuilder(NoTgzBuilder):
debug("Generating patch with: %s" % patch_command)
output = run_command(patch_command)
print(output)
(status, output) = commands.getstatusoutput(
(status, output) = getstatusoutput(
"grep 'Binary files .* differ' %s " % patch_file)
if status == 0 and output != "":
error_out("You are doomed. Diff contains binary files. You can not use this builder")
@ -914,7 +914,7 @@ class UpstreamBuilder(NoTgzBuilder):
with just the package release being incremented on rebuilds.
"""
# Use upstreamversion if defined in the spec file:
(status, output) = commands.getstatusoutput(
(status, output) = getstatusoutput(
"cat %s | grep 'define upstreamversion' | "
"awk '{ print $3 ; exit }'" % self.spec_file)
if status == 0 and output != "":
@ -1275,7 +1275,7 @@ class ExternalSourceBuilder(ConfigObject, BuilderBase):
build_version = self.build_tag[len(self.project_name + "-"):]
else:
build_version = get_latest_tagged_version(self.project_name)
if build_version == None:
if build_version is None:
pass
self.build_tag = "%s-%s" % (self.project_name, build_version)
@ -1295,7 +1295,3 @@ class ExternalSourceBuilder(ConfigObject, BuilderBase):
else:
version = self.build_version.split("-")[0]
return version

View file

@ -17,12 +17,11 @@ Tito's Command Line Interface
import sys
import os
import random
import commands
import ConfigParser
from optparse import OptionParser
from tito.common import *
from tito.compat import *
from tito.exception import *
# Hack for Python 2.4, seems to require we import these so they get compiled
@ -195,7 +194,7 @@ class BaseCliModule(object):
# Load the global config. Later, when we know what tag/package we're
# building, we may also load that and potentially override some global
# settings.
config = ConfigParser.ConfigParser()
config = ConfigParser()
config.read(filename)
# Verify the config contains what we need from it:
@ -262,13 +261,13 @@ class BaseCliModule(object):
cmd = "git show %s:%s%s" % (tag, relative_dir,
BUILD_PROPS_FILENAME)
debug(cmd)
(status, output) = commands.getstatusoutput(cmd)
(status, output) = getstatusoutput(cmd)
if status > 0:
# Give it another try looking for legacy props filename:
cmd = "git show %s:%s%s" % (tag, relative_dir,
"build.py.props")
debug(cmd)
(status, output) = commands.getstatusoutput(cmd)
(status, output) = getstatusoutput(cmd)
temp_filename = "%s-%s" % (random.randint(1, 10000),
BUILD_PROPS_FILENAME)
@ -287,7 +286,7 @@ class BaseCliModule(object):
cmd = "git show %s:%s%s | grep NO_TAR_GZ" % \
(tag, relative_dir, "Makefile")
debug(cmd)
(status, output) = commands.getstatusoutput(cmd)
(status, output) = getstatusoutput(cmd)
if status == 0 and output != "":
properties_file = temp_props_file
debug("Found Makefile with NO_TAR_GZ")
@ -297,7 +296,7 @@ class BaseCliModule(object):
wrote_temp_file = True
# TODO: can we parse config from a string and stop writing temp files?
if properties_file != None:
if properties_file is not None:
debug("Using package specific properties: %s" % properties_file)
self.config.read(properties_file)
else:
@ -308,7 +307,6 @@ class BaseCliModule(object):
# Delete the temp properties file we created.
run_command("rm %s" % properties_file)
def _validate_options(self):
"""
Subclasses can implement if they need to check for any
@ -330,7 +328,7 @@ class BuildModule(BaseCliModule):
help="Build rpm")
self.parser.add_option("-i", "--install", dest="auto_install",
action="store_true", default=False,
help="Install any binary rpms being built. (WARNING: " + \
help="Install any binary rpms being built. (WARNING: " +
"uses sudo rpm -Uvh --force)")
self.parser.add_option("--dist", dest="dist", metavar="DISTTAG",
help="Dist tag to apply to srpm and/or rpm. (i.e. .el5)")
@ -508,7 +506,7 @@ class ReleaseModule(BaseCliModule):
"""
rel_eng_dir = os.path.join(find_git_root(), "rel-eng")
filename = os.path.join(rel_eng_dir, RELEASERS_CONF_FILENAME)
config = ConfigParser.ConfigParser()
config = ConfigParser()
config.read(filename)
return config
@ -710,7 +708,8 @@ class TagModule(BaseCliModule):
try:
return tagger.run(self.options)
except TitoException, e:
except TitoException:
e = sys.exc_info()[1]
error_out(e.message)
def _validate_options(self):
@ -736,7 +735,7 @@ class InitModule(BaseCliModule):
propsfile = os.path.join(rel_eng_dir, GLOBAL_BUILD_PROPS_FILENAME)
if not os.path.exists(propsfile):
if not os.path.exists(rel_eng_dir):
commands.getoutput("mkdir -p %s" % rel_eng_dir)
getoutput("mkdir -p %s" % rel_eng_dir)
print(" - created %s" % rel_eng_dir)
# write out tito.props
@ -750,7 +749,7 @@ class InitModule(BaseCliModule):
out_f.close()
print(" - wrote %s" % GLOBAL_BUILD_PROPS_FILENAME)
commands.getoutput('git add %s' % propsfile)
getoutput('git add %s' % propsfile)
should_commit = True
# prep the packages metadata directory
@ -759,7 +758,7 @@ class InitModule(BaseCliModule):
if not os.path.exists(readme):
if not os.path.exists(pkg_dir):
commands.getoutput("mkdir -p %s" % pkg_dir)
getoutput("mkdir -p %s" % pkg_dir)
print(" - created %s" % pkg_dir)
# write out readme file explaining what pkg_dir is for
@ -771,11 +770,11 @@ class InitModule(BaseCliModule):
out_f.close()
print(" - wrote %s" % readme)
commands.getoutput('git add %s' % readme)
getoutput('git add %s' % readme)
should_commit = True
if should_commit:
commands.getoutput('git commit -m "Initialized to use tito. "')
getoutput('git commit -m "Initialized to use tito. "')
print(" - committed to git")
print("Done!")

View file

@ -17,9 +17,9 @@ Common operations.
import os
import re
import sys
import commands
import traceback
from tito.compat import *
from tito.exception import RunCommandException
DEFAULT_BUILD_DIR = "/tmp/tito"
@ -154,7 +154,7 @@ def create_builder(package_name, build_tag,
def find_file_with_extension(in_dir=None, suffix=None):
""" Find the file with given extension in the current directory. """
if in_dir == None:
if in_dir is None:
in_dir = os.getcwd()
file_name = None
debug("Looking for %s in %s" % (suffix, in_dir))
@ -169,6 +169,7 @@ def find_file_with_extension(in_dir=None, suffix=None):
else:
return file_name
def find_spec_file(in_dir=None):
"""
Find the first spec file in the current directory.
@ -193,9 +194,9 @@ def find_git_root():
Returned as a full path.
"""
(status, cdup) = commands.getstatusoutput("git rev-parse --show-cdup")
(status, cdup) = getstatusoutput("git rev-parse --show-cdup")
if status > 0:
error_out(["%s does not appear to be within a git checkout." % \
error_out(["%s does not appear to be within a git checkout." %
os.getcwd()])
if cdup.strip() == "":
@ -210,6 +211,7 @@ def extract_sha1(output):
else:
return ""
def run_command(command, print_on_success=False):
"""
Run command.
@ -217,12 +219,12 @@ def run_command(command, print_on_success=False):
If print_on_success is True, print status and output even
when command succeeds.
"""
(status, output) = commands.getstatusoutput(command)
(status, output) = getstatusoutput(command)
return output
def tag_exists_locally(tag):
(status, output) = commands.getstatusoutput("git tag | grep %s" % tag)
(status, output) = getstatusoutput("git tag | grep %s" % tag)
if status > 0:
return False
else:
@ -349,23 +351,24 @@ def scl_to_rpm_option(scl, silent=None):
output = run_command(cmd).rstrip()
if scl:
if (output != scl) and (output != "%scl") and not silent:
print "Warning: Meta package of software collection %s installed, but --scl defines %s" % (output, scl)
print " Redefining scl macro to %s for this package." % scl
print("Warning: Meta package of software collection %s installed, but --scl defines %s" % (output, scl))
print(" Redefining scl macro to %s for this package." % scl)
rpm_options += " --define 'scl %s'" % scl
else:
if (output != "%scl") and (not silent):
print "Warning: Meta package of software collection %s installed, but --scl is not present." % output
print " Undefining scl macro for this package."
print("Warning: Meta package of software collection %s installed, but --scl is not present." % output)
print(" Undefining scl macro for this package.")
# can be replaced by "--undefined scl" when el6 and fc17 is retired
rpm_options += " --eval '%undefine scl'"
return rpm_options
def get_project_name(tag=None, scl=None):
"""
Extract the project name from the specified tag or a spec file in the
current working directory. Error out if neither is present.
"""
if tag != None:
if tag is not None:
p = re.compile('(.*?)-(\d.*)')
m = p.match(tag)
if not m:
@ -540,7 +543,7 @@ def get_latest_tagged_version(package_name):
return None
output = run_command("awk '{ print $1 ; exit }' %s" % file_path)
if output == None or output.strip() == "":
if output is None or output.strip() == "":
error_out("Error looking up latest tagged version in: %s" % file_path)
return output
@ -632,4 +635,3 @@ def find_wrote_in_rpmbuild_output(output):
if not paths:
error_out("Unable to locate 'Wrote: ' lines in rpmbuild output")
return paths

49
src/tito/compat.py Normal file
View file

@ -0,0 +1,49 @@
# Copyright (c) 2008-2010 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
"""
Compatibility library for Python 2.4 up through Python 3.
"""
import sys
PY2 = sys.version_info[0] == 2
if PY2:
import commands
from ConfigParser import ConfigParser
from ConfigParser import NoOptionError
from ConfigParser import RawConfigParser
else:
import subprocess
from configparser import ConfigParser
from configparser import NoOptionError
from configparser import RawConfigParser
def getstatusoutput(cmd):
"""
Returns (status, output) of executing cmd in a shell.
Supports Python 2.4 and 3.x.
"""
if PY2:
return commands.getstatusoutput(cmd)
else:
return subprocess.getstatusoutput(cmd)
def getoutput(cmd):
"""
Returns output of executing cmd in a shell.
Supports Python 2.4 and 3.x.
"""
if PY2:
return commands.getoutput(cmd)
else:
return subprocess.getoutput(cmd)

View file

@ -17,6 +17,7 @@ Shared code for builder and tagger class
import os
from tito.common import find_git_root
class ConfigObject(object):
"""
Perent class for Builder and Tagger with shared code
@ -38,4 +39,3 @@ class ConfigObject(object):
self.git_root = find_git_root()
self.rel_eng_dir = os.path.join(self.git_root, "rel-eng")

View file

@ -66,8 +66,8 @@ class CoprReleaser(KojiReleaser):
self.print_dry_run_warning(cmd_submit)
return
if not self.srpm_submitted:
print "Uploading src.rpm."
print run_command(cmd_upload)
print("Uploading src.rpm.")
print(run_command(cmd_upload))
self.srpm_submitted = srpm_location
print "Submiting build into %s." % self.NAME
print run_command(cmd_submit)
print("Submiting build into %s." % self.NAME)
print(run_command(cmd_submit))

View file

@ -2,7 +2,8 @@ import os
from tito.builder import UpstreamBuilder
from tito.common import debug, run_command, error_out
import commands
from tito.compat import *
class DistributionBuilder(UpstreamBuilder):
""" This class is used for building packages for distributions.
@ -25,13 +26,13 @@ class DistributionBuilder(UpstreamBuilder):
ch_dir = os.path.join(self.git_root,
self.relative_project_dir)
os.chdir(ch_dir)
debug("Running /usr/bin/generate-patches.pl -d %s %s %s-1 %s %s" \
debug("Running /usr/bin/generate-patches.pl -d %s %s %s-1 %s %s"
% (self.rpmbuild_gitcopy, self.project_name, self.upstream_version, self.build_version, self.git_commit_id))
output = run_command("/usr/bin/generate-patches.pl -d %s %s %s-1 %s %s" \
output = run_command("/usr/bin/generate-patches.pl -d %s %s %s-1 %s %s"
% (self.rpmbuild_gitcopy, self.project_name, self.upstream_version, self.build_version, self.git_commit_id))
self.patch_files = output.split("\n")
for p_file in self.patch_files:
(status, output) = commands.getstatusoutput(
(status, output) = getstatusoutput(
"grep 'Binary files .* differ' %s/%s " % (self.rpmbuild_gitcopy, p_file))
if status == 0 and output != "":
error_out("You are doomed. Diff contains binary files. You can not use this builder")

View file

@ -29,6 +29,7 @@ class TitoException(Exception):
def __str__(self):
return "TitoException: %s" % self.message
class RunCommandException(Exception):
""" Raised by run_command() """
def __init__(self, msg, command, status, output):

View file

@ -12,12 +12,12 @@
# in this software or its documentation.
import os
import commands
import tempfile
import subprocess
import sys
from tito.common import run_command, debug, extract_bzs
from tito.compat import *
from tito.release import Releaser
@ -49,7 +49,7 @@ class ObsReleaser(Releaser):
self.dry_run = dry_run
self.no_build = no_build
commands.getoutput("mkdir -p %s" % self.working_dir)
getoutput("mkdir -p %s" % self.working_dir)
os.chdir(self.working_dir)
run_command("%s co %s %s" % (self.cli_tool, self.obs_project_name, self.obs_package_name))
@ -83,7 +83,7 @@ class ObsReleaser(Releaser):
os.lseek(fd, 0, 0)
commit_file = os.fdopen(fd)
for line in commit_file.readlines():
print line
print(line)
commit_file.close()
print("")
@ -109,7 +109,7 @@ class ObsReleaser(Releaser):
os.chdir(project_checkout)
(status, diff_output) = commands.getstatusoutput("%s diff" % self.cli_tool)
(status, diff_output) = getstatusoutput("%s diff" % self.cli_tool)
if diff_output.strip() == "":
print("No changes in main branch, skipping commit.")
@ -133,16 +133,15 @@ class ObsReleaser(Releaser):
else:
print("Proceeding with commit.")
os.chdir(self.package_workdir)
print run_command(cmd)
print(run_command(cmd))
os.unlink(commit_msg_file)
if self.no_build:
commands.getstatusoutput("%s abortbuild %s %s" % (
getstatusoutput("%s abortbuild %s %s" % (
self.cli_tool, self.obs_project_name, self.obs_package_name))
print("Aborting automatic rebuild because --no-build has been specified.")
def _obs_sync_files(self, project_checkout):
"""
Copy files from our obs checkout into each obs checkout and add them.
@ -164,4 +163,3 @@ class ObsReleaser(Releaser):
# Add/remove everything:
run_command("%s addremove" % (self.cli_tool))

View file

@ -16,7 +16,7 @@ Code for submitting builds for release.
import copy
import os
import commands
import sys
import tempfile
import subprocess
import rpm
@ -25,6 +25,7 @@ from tempfile import mkdtemp
import shutil
from tito.common import *
from tito.compat import *
from tito.buildparser import BuildTargetParser
from tito.exception import TitoException
from tito.config_object import ConfigObject
@ -454,7 +455,7 @@ class YumRepoReleaser(RsyncReleaser):
if artifact.endswith(".rpm") and not artifact.endswith(".src.rpm"):
try:
header = self._read_rpm_header(rpm_ts, artifact)
except rpm.error, e:
except rpm.error:
continue
self.new_rpm_dep_sets[header['name']] = header.dsOfHeader()
@ -467,8 +468,9 @@ class YumRepoReleaser(RsyncReleaser):
full_path = os.path.join(temp_dir, filename)
try:
hdr = self._read_rpm_header(rpm_ts, full_path)
except rpm.error, e:
print "error reading rpm header in '%s': %s" % (full_path, e)
except rpm.error:
e = sys.exc_info()[1]
print("error reading rpm header in '%s': %s" % (full_path, e))
continue
if hdr['name'] in self.new_rpm_dep_sets:
dep_set = hdr.dsOfHeader()
@ -520,7 +522,7 @@ class FedoraGitReleaser(Releaser):
def _git_release(self):
commands.getoutput("mkdir -p %s" % self.working_dir)
getoutput("mkdir -p %s" % self.working_dir)
os.chdir(self.working_dir)
run_command("%s clone %s" % (self.cli_tool, self.project_name))
@ -557,7 +559,7 @@ class FedoraGitReleaser(Releaser):
os.lseek(fd, 0, 0)
file = os.fdopen(fd)
for line in file.readlines():
print line
print(line)
file.close()
print("")
@ -586,10 +588,10 @@ class FedoraGitReleaser(Releaser):
os.chdir(project_checkout)
# Newer versions of git don't seem to want --cached here? Try both:
(status, diff_output) = commands.getstatusoutput("git diff --cached")
(status, diff_output) = getstatusoutput("git diff --cached")
if diff_output.strip() == "":
debug("git diff --cached returned nothing, falling back to git diff.")
(status, diff_output) = commands.getstatusoutput("git diff")
(status, diff_output) = getstatusoutput("git diff")
if diff_output.strip() == "":
print("No changes in main branch, skipping commit for: %s" % main_branch)
@ -678,7 +680,7 @@ class FedoraGitReleaser(Releaser):
return
print("Submitting build: %s" % build_cmd)
(status, output) = commands.getstatusoutput(build_cmd)
(status, output) = getstatusoutput(build_cmd)
if status > 0:
if "already been built" in output:
print("Build has been submitted previously, continuing...")
@ -690,7 +692,7 @@ class FedoraGitReleaser(Releaser):
# Print the task ID and URL:
for line in extract_task_info(output):
print line
print(line)
def _git_upload_sources(self, project_checkout):
"""
@ -795,7 +797,7 @@ class CvsReleaser(Releaser):
self._verify_cvs_module_not_already_checked_out()
print("Building release in CVS...")
commands.getoutput("mkdir -p %s" % self.working_dir)
getoutput("mkdir -p %s" % self.working_dir)
debug("cvs_branches = %s" % self.cvs_branches)
self.cvs_checkout_module()
@ -871,7 +873,7 @@ class CvsReleaser(Releaser):
# For entirely new files we need to cvs add:
for add_file in new:
commands.getstatusoutput("cvs add %s" % add_file)
getstatusoutput("cvs add %s" % add_file)
# Cleanup obsolete files:
for cleanup_file in old:
@ -911,7 +913,7 @@ class CvsReleaser(Releaser):
print("")
os.chdir(self.package_workdir)
(status, diff_output) = commands.getstatusoutput("cvs diff -u")
(status, diff_output) = getstatusoutput("cvs diff -u")
print(diff_output)
print("")
@ -940,7 +942,7 @@ class CvsReleaser(Releaser):
os.lseek(fd, 0, 0)
file = os.fdopen(fd)
for line in file.readlines():
print line
print(line)
file.close()
print("")
@ -976,7 +978,7 @@ class CvsReleaser(Releaser):
branch_dir = os.path.join(self.working_dir, self.project_name,
branch)
os.chdir(branch_dir)
(status, output) = commands.getstatusoutput(cmd)
(status, output) = getstatusoutput(cmd)
print(output)
if status > 1:
self.cleanup()

View file

@ -17,7 +17,6 @@ Code for tagging Spacewalk/Satellite packages.
import os
import re
import rpm
import commands
import StringIO
import shutil
import subprocess
@ -34,9 +33,11 @@ from tito.common import (debug, error_out, run_command,
get_script_path, get_spec_version_and_release, replace_version,
tag_exists_locally, tag_exists_remotely, head_points_to_tag, undo_tag,
increase_version, reset_release, increase_zstream)
from tito.compat import *
from tito.exception import TitoException
from tito.config_object import ConfigObject
class VersionTagger(ConfigObject):
"""
Standard Tagger class, used for tagging packages built from source in
@ -218,7 +219,7 @@ class VersionTagger(ConfigObject):
old_version = get_latest_tagged_version(self.project_name)
# don't die if this is a new package with no history
if old_version != None:
if old_version is not None:
last_tag = "%s-%s" % (self.project_name, old_version)
output = self._generate_default_changelog(last_tag)
else:
@ -226,7 +227,7 @@ class VersionTagger(ConfigObject):
fd, name = tempfile.mkstemp()
os.write(fd, "# Create your changelog entry below:\n")
if self.git_email is None or (('HIDE_EMAIL' in self.user_config) and \
if self.git_email is None or (('HIDE_EMAIL' in self.user_config) and
(self.user_config['HIDE_EMAIL'] not in ['0', ''])):
header = "* %s %s\n" % (self.today, self.git_user)
else:
@ -349,7 +350,7 @@ class VersionTagger(ConfigObject):
bump the version or release.
"""
old_version = get_latest_tagged_version(self.project_name)
if old_version == None:
if old_version is None:
old_version = "untagged"
if not self.keep_version:
version_regex = re.compile("^(version:\s*)(.+)$", re.IGNORECASE)
@ -469,7 +470,7 @@ class VersionTagger(ConfigObject):
print(" Push: git push && git push origin %s" % new_tag)
def _check_tag_does_not_exist(self, new_tag):
status, output = commands.getstatusoutput(
status, output = getstatusoutput(
'git tag -l %s|grep ""' % new_tag)
if status == 0:
raise Exception("Tag %s already exists!" % new_tag)
@ -555,7 +556,6 @@ class VersionTagger(ConfigObject):
run_command("git add %s" % version_file)
def _version_file_template(self):
"""
provide a configuration in tito.props to a file that is a
@ -575,7 +575,6 @@ class VersionTagger(ConfigObject):
return buf
return None
def _version_file_path(self):
"""
provide a version file to write in tito.props, like

View file

@ -15,7 +15,6 @@
Functional Tests for the FetchBuilder.
"""
import ConfigParser
import glob
import os
import shutil
@ -24,7 +23,8 @@ import tempfile
from os.path import join
from tito.common import run_command
from fixture import TitoGitTestFixture, tito
from tito.compat import *
from functional.fixture import TitoGitTestFixture, tito
EXT_SRC_PKG = "extsrc"
@ -35,6 +35,7 @@ builder = tito.builder.FetchBuilder
rsync = %s
"""
class FetchBuilderTests(TitoGitTestFixture):
def setUp(self):
@ -43,7 +44,7 @@ class FetchBuilderTests(TitoGitTestFixture):
spec = join(os.path.dirname(__file__), "specs/extsrc.spec")
# Setup test config:
self.config = ConfigParser.RawConfigParser()
self.config = RawConfigParser()
self.config.add_section("buildconfig")
self.config.set("buildconfig", "builder",
"tito.builder.FetchBuilder")
@ -74,9 +75,9 @@ class FetchBuilderTests(TitoGitTestFixture):
tito('build --rpm --output=%s --no-cleanup --debug --arg=source=%s ' %
(self.output_dir, self.source_filename))
self.assertEquals(1, len(glob.glob(join(self.output_dir,
"extsrc-0.0.2-1.*.src.rpm"))))
"extsrc-0.0.2-1.*src.rpm"))))
self.assertEquals(1, len(glob.glob(join(self.output_dir,
"noarch/extsrc-0.0.2-1.*.noarch.rpm"))))
"noarch/extsrc-0.0.2-1.*noarch.rpm"))))
def test_tag_rejected(self):
self.assertRaises(SystemExit, tito,
@ -94,7 +95,6 @@ class FetchBuilderTests(TitoGitTestFixture):
self.source_filename)
self.assertEquals(1, len(glob.glob(join(yum_repo_dir,
"extsrc-0.0.2-1.*.noarch.rpm"))))
"extsrc-0.0.2-1.*noarch.rpm"))))
self.assertEquals(1, len(glob.glob(join(yum_repo_dir,
"repodata/repomd.xml"))))

View file

@ -117,6 +117,13 @@ class TitoGitTestFixture(unittest.TestCase):
print("Testing in: %s" % self.repo_dir)
print
# GitPython calls os.login(), which throws OSError if there is no tty,
# but GitPython allows to avoid the call if env var USER exists.
try:
os.getlogin()
except OSError:
os.environ['USER'] = 'nobody'
# Initialize the repo:
self.repo = git.Repo.init(path=self.repo_dir, mkdir=True, bare=False)
@ -149,9 +156,9 @@ class TitoGitTestFixture(unittest.TestCase):
shutil.copyfile(spec, os.path.join(full_pkg_dir, os.path.basename(spec)))
# Write the config object we were given out to the project repo:
with open(os.path.join(full_pkg_dir, 'tito.props'), 'w') \
as configfile:
configfile = open(os.path.join(full_pkg_dir, 'tito.props'), 'w')
config.write(configfile)
configfile.close()
def create_project(self, pkg_name, pkg_dir=''):
"""

View file

@ -22,7 +22,7 @@ from os.path import join
from tito.common import run_command, \
get_latest_tagged_version, tag_exists_locally
from fixture import *
from functional.fixture import *
# A location where we can safely create a test git repository.
# WARNING: This location will be destroyed if present.

View file

@ -15,7 +15,6 @@
Functional Tests for the FetchBuilder.
"""
import ConfigParser
import glob
import os
import shutil
@ -23,7 +22,9 @@ import tempfile
from os.path import join
from fixture import TitoGitTestFixture, tito
from functional.fixture import TitoGitTestFixture, tito
from tito.compat import *
PKG_NAME = "releaseme"
@ -34,6 +35,7 @@ builder = tito.builder.Builder
rsync = %s
"""
class YumReleaserTests(TitoGitTestFixture):
def setUp(self):
@ -41,7 +43,7 @@ class YumReleaserTests(TitoGitTestFixture):
self.create_project(PKG_NAME)
# Setup test config:
self.config = ConfigParser.RawConfigParser()
self.config = RawConfigParser()
self.config.add_section("buildconfig")
self.config.set("buildconfig", "builder",
"tito.builder.Builder")
@ -65,8 +67,6 @@ class YumReleaserTests(TitoGitTestFixture):
tito('release --debug yum-test')
self.assertEquals(1, len(glob.glob(join(yum_repo_dir,
"releaseme-0.0.1-1.*.noarch.rpm"))))
"releaseme-0.0.1-1.*noarch.rpm"))))
self.assertEquals(1, len(glob.glob(join(yum_repo_dir,
"repodata/repomd.xml"))))

View file

@ -14,7 +14,7 @@
import os
from tito.common import *
from fixture import TitoGitTestFixture, tito
from functional.fixture import TitoGitTestFixture, tito
#TITO_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
PKG_NAME = "titotestpkg"
@ -79,4 +79,3 @@ class SingleProjectTests(TitoGitTestFixture):
def test_build_rpm_tag(self):
tito("build --rpm --tag=%s-0.0.1-1 -o %s" % (PKG_NAME,
self.repo_dir))

View file

@ -81,6 +81,7 @@ class CommonTests(unittest.TestCase):
self.assertEquals("fe87e2b75ed1850718d99c797cc171b88bfad5ca",
extract_sha1(ls_remote_output))
class VersionMathTest(unittest.TestCase):
def test_increase_version_minor(self):
line = "1.0.0"

33
test/unit/fixture.py Normal file
View file

@ -0,0 +1,33 @@
#
# Copyright (c) 2008-2014 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
import os
import unittest
from tito.compat import *
UNIT_DIR = os.path.abspath(os.path.dirname(__file__))
REPO_DIR = os.path.join(UNIT_DIR, '..', '..')
class TitoUnitTestFixture(unittest.TestCase):
"""
Fixture providing setup/teardown and utilities for unit tests.
"""
def setUp(self):
# GitPython calls os.login(), which throws OSError if there is no tty,
# but GitPython allows to avoid the call if env var USER exists.
try:
os.getlogin()
except OSError:
os.environ['USER'] = 'nobody'

96
test/unit/pep8-tests.py Normal file
View file

@ -0,0 +1,96 @@
#
# Copyright (c) 2008-2014 Red Hat, Inc.
#
# This software is licensed to you under the GNU General Public License,
# version 2 (GPLv2). There is NO WARRANTY for this software, express or
# implied, including the implied warranties of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
# along with this software; if not, see
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
#
# Red Hat trademarks are not licensed under GPLv2. No permission is
# granted to use or replicate Red Hat trademarks that are incorporated
# in this software or its documentation.
"""
Use pep8 to check for errors or deprecations that can cause Python 3 to fail.
source: https://github.com/jcrocholl/pep8
docs: http://pep8.readthedocs.org/en/latest/intro.html
Python 3 is picky about indentation:
http://docs.python.org/3.3/reference/lexical_analysis.html
"""
import pep8
from unit.fixture import *
class TestPep8(TitoUnitTestFixture):
def setUp(self):
TitoUnitTestFixture.setUp(self)
def test_conformance(self):
tests = [
# http://pep8.readthedocs.org/en/latest/intro.html#error-codes
'E101', # indentation contains mixed spaces and tabs
'E111', # indentation is not a multiple of four
'E112', # expected an indented block
'E113', # unexpected indentation
'E121', # continuation line indentation is not a multiple of four
'E122', # continuation line missing indentation or outdented
'E126', # continuation line over-indented for hanging indent
'E2', # whitespace errors
'E3', # blank line errors
'E4', # import errors
'E502', # the backslash is redundant between brackets
'E7', # statement errors
'E9', # runtime errors (SyntaxError, IndentationError, IOError)
'W1', # indentation warnings
'W2', # whitespace warnings
'W3', # blank line warnings
'W6', # deprecated features
]
try:
checker = pep8.StyleGuide(select=tests, paths=[REPO_DIR])
result = checker.check_files().total_errors
except AttributeError:
# We don't have pep8.StyleGuide, so we must be
# using pep8 older than git tag 1.1-72-gf20d656.
os.chdir(REPO_DIR)
checks = ','.join(tests)
cmd = "pep8 --select=%s %s | wc -l" % (checks, '.')
result = int(getoutput(cmd))
self.assertEqual(result, 0,
"Found PEP8 errors that may break your code in Python 3.")
class UglyHackishTest(TitoUnitTestFixture):
def setUp(self):
TitoUnitTestFixture.setUp(self)
os.chdir(REPO_DIR)
def test_exceptions_2_dot_4(self):
# detect 'except rpm.error as e:'
regex = "'^[[:space:]]*except .* as .*:'"
cmd = "find . -type f -regex '.*\.py$' -exec egrep %s {} + | wc -l" % regex
result = int(getoutput(cmd))
self.assertEqual(result, 0, "Found except clause not supported in Python 2.4")
def test_exceptions_3(self):
# detect 'except rpm.error, e:'
regex = "'^[[:space:]]*except [^,]+,[[:space:]]*[[:alpha:]]+:'"
cmd = "find . -type f -regex '.*\.py$' -exec egrep %s {} + | wc -l" % regex
result = int(getoutput(cmd))
self.assertEqual(result, 0, "Found except clause not supported in Python 3")
def test_import_commands(self):
cmd = "find . -type f -regex '.*\.py$' -exec egrep '^(import|from) commands\.' {} + | grep -v 'compat\.py' | wc -l"
result = int(getoutput(cmd))
self.assertEqual(result, 0, "Found commands module (not supported in Python 3)")
def test_print_function(self):
cmd = "find . -type f -regex '.*\.py$' -exec grep '^[[:space:]]*print .*' {} + | wc -l"
result = int(getoutput(cmd))
self.assertEqual(result, 0, "Found print statement (not supported in Python 3)")

View file

@ -1,7 +1,7 @@
import unittest
from tito.buildparser import BuildTargetParser
from ConfigParser import ConfigParser
from tito.compat import *
from tito.exception import TitoException