diff options
author | Diana Picus <diana.picus@linaro.org> | 2016-09-15 12:48:04 +0300 |
---|---|---|
committer | Diana Picus <diana.picus@linaro.org> | 2016-09-15 13:24:14 +0300 |
commit | 9b6ce2d1dbb05ed01db4d7f5d40586a560ae289f (patch) | |
tree | a93d4334eecaac986dd7b4d9ae2a5f62e90d72bd | |
parent | 3cde4a2e1e8e727e9af66fa0aedfe18129780bb6 (diff) |
Run autopep8 with default settings
-rw-r--r-- | linaropy/cd.py | 7 | ||||
-rw-r--r-- | linaropy/git/clone.py | 395 | ||||
-rw-r--r-- | linaropy/git/gitrepo.py | 237 | ||||
-rw-r--r-- | linaropy/git/workdir.py | 229 | ||||
-rw-r--r-- | linaropy/proj.py | 117 | ||||
-rw-r--r-- | linaropy/rn/custom_wordwrap.py | 12 | ||||
-rw-r--r-- | linaropy/rn/gccclone.py | 27 | ||||
-rw-r--r-- | linaropy/rn/linaroseries.py | 550 | ||||
-rw-r--r-- | linaropy/rn/rngen.py | 148 | ||||
-rw-r--r-- | linaropy/rn/rnseries.py | 194 | ||||
-rw-r--r-- | linaropy/rn/template.py | 106 | ||||
-rw-r--r-- | linaropy/rninput.py | 31 | ||||
-rw-r--r-- | linaropy/series.py | 1121 | ||||
-rw-r--r-- | linaropy/vers.py | 560 | ||||
-rw-r--r-- | rn.py | 106 | ||||
-rw-r--r-- | testrn.py | 20 |
16 files changed, 2057 insertions, 1803 deletions
diff --git a/linaropy/cd.py b/linaropy/cd.py index b245117..abdf821 100644 --- a/linaropy/cd.py +++ b/linaropy/cd.py @@ -3,16 +3,17 @@ import os # Use this to manage 'cd' context from contextlib import contextmanager + @contextmanager def cd(newdir): """ Return to prevdir when context is exited. Use in the following manner: - + with cd("foodir"): operation1_in_foodir operation2_in_foodir - + operation3_in_prevdir """ prevdir = os.getcwd() @@ -21,5 +22,3 @@ def cd(newdir): yield finally: os.chdir(prevdir) - - diff --git a/linaropy/git/clone.py b/linaropy/git/clone.py index fe936dc..5511f0e 100644 --- a/linaropy/git/clone.py +++ b/linaropy/git/clone.py @@ -17,104 +17,118 @@ from gitrepo import GitRepo import time + class Clone(GitRepo): - def __init__(self, proj, clonedir=None, remote=None ): - super(Clone,self).__init__(proj) + + def __init__(self, proj, clonedir=None, remote=None): + super(Clone, self).__init__(proj) # If the user passes a clonedir then they want to reuse an existing - # clone. This will often be the case with large repositories like - # gcc, which take 20 minutes to clone. + # clone. This will often be the case with large repositories like + # gcc, which take 20 minutes to clone. - # Clone a new repo from the remote - if clonedir is None or (isinstance(clonedir, basestring) and clonedir == ""): - if remote=="" or remote is None: - raise TypeError('Clone input parameter \'remote\' can not be empty') + # Clone a new repo from the remote + if clonedir is None or (isinstance(clonedir, basestring) and clonedir == ""): + if remote == "" or remote is None: + raise TypeError( + 'Clone input parameter \'remote\' can not be empty') # TODO test that remote is a well formed URL? - # TODO if there's a trailing / strip it. - self.remote=remote + # TODO if there's a trailing / strip it. + self.remote = remote - # Strip the end off the repo url to find the clonedir name. - clone_dirname=remote.rsplit('/', 1)[-1] + # Strip the end off the repo url to find the clonedir name. + clone_dirname = remote.rsplit('/', 1)[-1] - logging.info('Cloning %s repository into %s/%s' % (self.remote, self.proj.projdir, clone_dirname)) + logging.info('Cloning %s repository into %s/%s' % + (self.remote, self.proj.projdir, clone_dirname)) - self.repodir=self.proj.projdir + '/' + clone_dirname - try: - with cd(self.proj.projdir): - git("clone", self.remote, clone_dirname, _err_to_out=True, _out="/dev/null") + self.repodir = self.proj.projdir + '/' + clone_dirname + try: + with cd(self.proj.projdir): + git("clone", self.remote, clone_dirname, + _err_to_out=True, _out="/dev/null") except ErrorReturnCode: - raise EnvironmentError("Git unable to clone into " + self.repodir) - + raise EnvironmentError( + "Git unable to clone into " + self.repodir) # Reuse an existing git clone directory - else: - if not isinstance(clonedir, basestring): - raise TypeError('clonedir must be of type basestring') + else: + if not isinstance(clonedir, basestring): + raise TypeError('clonedir must be of type basestring') elif not os.path.isdir(clonedir): - raise EnvironmentError("Specified clonedir directory '%s' does not exist" % clonedir) - - # Check to see if clonedir is a git repository. - with cd(clonedir): - # There might be a file called .git - if not os.path.isdir(clonedir + '/.git'): - try: - git("rev-parse", _err_to_out=True, _out="/dev/null") - except ErrorReturnCode: - raise EnvironmentError('Specified clonedir is not a git repository.') - - # Strip off any trailing / - clonedir=clonedir.rstrip('/') - # We only want the final directory name, not the whole path. - clone_dirname=clonedir.rsplit('/', 1)[-1] - self.repodir=self.proj.projdir + '/' + clone_dirname + raise EnvironmentError( + "Specified clonedir directory '%s' does not exist" % clonedir) + + # Check to see if clonedir is a git repository. + with cd(clonedir): + # There might be a file called .git + if not os.path.isdir(clonedir + '/.git'): + try: + git("rev-parse", _err_to_out=True, _out="/dev/null") + except ErrorReturnCode: + raise EnvironmentError( + 'Specified clonedir is not a git repository.') + + # Strip off any trailing / + clonedir = clonedir.rstrip('/') + # We only want the final directory name, not the whole path. + clone_dirname = clonedir.rsplit('/', 1)[-1] + self.repodir = self.proj.projdir + '/' + clone_dirname # TODO: verify that we don't get another clone dir in the projdir. # It's possible the clonedir is already in the projdir. - if os.path.exists(self.repodir): - logging.info('The clonedir %s already exists in %s' % (clonedir, self.repodir)) - else: - logging.info('Reusing existing clonedir %s and symlinking as %s in %s' % (clonedir, self.repodir, self.proj.projdir)) - try: - ln("-s", clonedir, self.repodir) + if os.path.exists(self.repodir): + logging.info('The clonedir %s already exists in %s' % + (clonedir, self.repodir)) + else: + logging.info('Reusing existing clonedir %s and symlinking as %s in %s' % ( + clonedir, self.repodir, self.proj.projdir)) + try: + ln("-s", clonedir, self.repodir) except ErrorReturnCode: - raise EnvironmentError("Can't create symlink %s to %s." % (clonedir, self.repodir)) + raise EnvironmentError( + "Can't create symlink %s to %s." % (clonedir, self.repodir)) - logging.info('Clone directory set as %s' % (self.repodir)) - return + logging.info('Clone directory set as %s' % (self.repodir)) + return def clonedir(self): - return self.repodir + return self.repodir def __repr__(self): - return "<Clone Class: remote = " + self.remote + ", clonedir =" + self.repodir +">" + return "<Clone Class: remote = " + self.remote + ", clonedir =" + self.repodir + ">" + class TestClone(unittest.TestCase): - testdirprefix="CloneUT" + testdirprefix = "CloneUT" @classmethod def setUpClass(cls): - # We need a Proj dir to store the mother clone in. - cls.proj=Proj(prefix=TestClone.testdirprefix) + # We need a Proj dir to store the mother clone in. + cls.proj = Proj(prefix=TestClone.testdirprefix) - # Setup a single remote clone in a Proj directory and then all of the - # other tests in this module should clone from this resulting local - # clone as if it were a remote. This will reduce the network burden on - # the remote git server being tested. If this fails then the entire - # TestClone will be marked as not executed. + # Setup a single remote clone in a Proj directory and then all of the + # other tests in this module should clone from this resulting local + # clone as if it were a remote. This will reduce the network burden on + # the remote git server being tested. If this fails then the entire + # TestClone will be marked as not executed. - #TODO: Perform a connectivity test to determine online or offline - # testing mode. + # TODO: Perform a connectivity test to determine online or offline + # testing mode. - cls.rnclone=Clone(cls.proj,remote=u'http://git.linaro.org/toolchain/release-notes.git') - #OFFLINE: cls.rnclone=Clone(cls.proj,remote=u'/var/run/media/ryanarn/sidecar/reldir/release-notes') - cls.startbranch=cls.rnclone.getbranch() + cls.rnclone = Clone( + cls.proj, remote=u'http://git.linaro.org/toolchain/release-notes.git') + # OFFLINE: + # cls.rnclone=Clone(cls.proj,remote=u'/var/run/media/ryanarn/sidecar/reldir/release-notes') + cls.startbranch = cls.rnclone.getbranch() - cls.rtremote=u'http://git.linaro.org/toolchain/tcwg-release-tools.git' - #OFFLINE: cls.rtremote=u'/var/run/media/ryanarn/sidecar/releases/tcwg-release-tools' + cls.rtremote = u'http://git.linaro.org/toolchain/tcwg-release-tools.git' + # OFFLINE: + # cls.rtremote=u'/var/run/media/ryanarn/sidecar/releases/tcwg-release-tools' - # All further tests will use this as the remote. - cls.rnremote=cls.rnclone.repodir + # All further tests will use this as the remote. + cls.rnremote = cls.rnclone.repodir @classmethod def tearDownClass(cls): @@ -122,200 +136,207 @@ class TestClone(unittest.TestCase): # Every instance of TestClass requires its own proj directory. def setUp(self): - # TODO: Is this redundant with the setUpClass()? - self.proj=Proj(prefix=TestClone.testdirprefix) + # TODO: Is this redundant with the setUpClass()? + self.proj = Proj(prefix=TestClone.testdirprefix) def tearDown(self): - # TODO: Is this redundant with the tearDownClass()? - self.proj.cleanup() + # TODO: Is this redundant with the tearDownClass()? + self.proj.cleanup() # These immediate tests clone from a remote repository def test_clone(self): - self.clone=Clone(self.proj,remote=TestClone.rnremote) + self.clone = Clone(self.proj, remote=TestClone.rnremote) self.assertTrue(os.path.isdir(self.clone.clonedir())) def test_two_different_clones_in_one_projdir(self): - self.clonern=Clone(self.proj,remote=TestClone.rnremote) - self.clonert=Clone(self.proj,remote=TestClone.rtremote) - self.assertTrue(os.path.isdir(self.clonern.clonedir()) and os.path.isdir(self.clonert.clonedir())) + self.clonern = Clone(self.proj, remote=TestClone.rnremote) + self.clonert = Clone(self.proj, remote=TestClone.rtremote) + self.assertTrue(os.path.isdir(self.clonern.clonedir()) + and os.path.isdir(self.clonert.clonedir())) # All clones after this point should use TestClone.rnremote as the remote. def test_str_function(self): - self.clone=Clone(self.proj,remote=TestClone.rnremote) + self.clone = Clone(self.proj, remote=TestClone.rnremote) self.assertEqual(str(self.clone), self.clone.clonedir()) def test_empty_string_clonedir_with_remote(self): - # This will use the remote because clonedir is an empty string. - self.clone=Clone(self.proj,remote=TestClone.rnremote, clonedir="") - self.assertTrue(os.path.isdir(self.clone.clonedir())) + # This will use the remote because clonedir is an empty string. + self.clone = Clone(self.proj, remote=TestClone.rnremote, clonedir="") + self.assertTrue(os.path.isdir(self.clone.clonedir())) def test_none_clonedir_with_remote(self): - # This will use the remote because there is no clonedir - self.clone=Clone(self.proj,remote=TestClone.rnremote) - self.assertTrue(os.path.isdir(self.clone.clonedir())) + # This will use the remote because there is no clonedir + self.clone = Clone(self.proj, remote=TestClone.rnremote) + self.assertTrue(os.path.isdir(self.clone.clonedir())) def test_empty_remote_empty_clonedir(self): - # A bogus directory will fail. - with self.assertRaises(TypeError): - self.clone=Clone(self.proj,remote="", clonedir="") + # A bogus directory will fail. + with self.assertRaises(TypeError): + self.clone = Clone(self.proj, remote="", clonedir="") def test_non_string_clonedir(self): - self.foo=Clone(self.proj,remote=TestClone.rnremote, clonedir="") - with self.assertRaises(TypeError): - self.clone=Clone(self.proj, clonedir=self.foo) + self.foo = Clone(self.proj, remote=TestClone.rnremote, clonedir="") + with self.assertRaises(TypeError): + self.clone = Clone(self.proj, clonedir=self.foo) def test_no_string_clonedir_empty_remote(self): - # remote can't be be empty if clonedir is not set. - with self.assertRaises(TypeError): - self.clone=Clone(self.proj,remote="") + # remote can't be be empty if clonedir is not set. + with self.assertRaises(TypeError): + self.clone = Clone(self.proj, remote="") def test_existing_clonedir(self): - # Clone's clonedir parameter allows a user to specify an existing - # directory use for the clone. It will setup a symlink in the proj - # directory pointing to the tree. This is a useful feature for - # very large repositories. + # Clone's clonedir parameter allows a user to specify an existing + # directory use for the clone. It will setup a symlink in the proj + # directory pointing to the tree. This is a useful feature for + # very large repositories. - # Use the clonedir from TestClone.rnclone - self.clone=Clone(self.proj,clonedir=TestClone.rnclone.clonedir()) + # Use the clonedir from TestClone.rnclone + self.clone = Clone(self.proj, clonedir=TestClone.rnclone.clonedir()) - # Verify that a symlink is used for the clone. + # Verify that a symlink is used for the clone. self.assertTrue(os.path.islink(self.clone.clonedir())) # This was a bug at some point, as it would strip off the repository name. def test_existing_clonedir_with_trailing_slash(self): - self.clone=Clone(self.proj,clonedir=TestClone.rnclone.clonedir() + "/") + self.clone = Clone( + self.proj, clonedir=TestClone.rnclone.clonedir() + "/") - # Verify that a symlink is used for the clone. + # Verify that a symlink is used for the clone. self.assertTrue(os.path.islink(self.clone.clonedir())) def test_failed_symlink(self): - # We'll make the projdir read-only so we can force symlink creation - # to fail. - with cd(self.proj.projdir): - # Set to read-only to force symlink to fail. - os.chmod(self.proj.projdir, S_IRUSR | S_IXUSR) - - # Use the clonedir from TestClone.rnclone - with self.assertRaises(EnvironmentError): - # Verify that this throws an exception. - self.clone=Clone(self.proj,clonedir=TestClone.rnclone.clonedir()) - - with cd(self.proj.projdir): - # Reset to writable so we can remove the projdir - os.chmod(self.proj.projdir, S_IWUSR | S_IXUSR) + # We'll make the projdir read-only so we can force symlink creation + # to fail. + with cd(self.proj.projdir): + # Set to read-only to force symlink to fail. + os.chmod(self.proj.projdir, S_IRUSR | S_IXUSR) + + # Use the clonedir from TestClone.rnclone + with self.assertRaises(EnvironmentError): + # Verify that this throws an exception. + self.clone = Clone( + self.proj, clonedir=TestClone.rnclone.clonedir()) + + with cd(self.proj.projdir): + # Reset to writable so we can remove the projdir + os.chmod(self.proj.projdir, S_IWUSR | S_IXUSR) def test_clone_failure_due_to_write_permissions(self): - with cd(self.proj.projdir): - # Set to read-only to force the git clone to fail. - os.chmod(self.proj.projdir, S_IRUSR | S_IXUSR) + with cd(self.proj.projdir): + # Set to read-only to force the git clone to fail. + os.chmod(self.proj.projdir, S_IRUSR | S_IXUSR) - with self.assertRaises(EnvironmentError): - self.clone=Clone(self.proj,remote=TestClone.rnremote) + with self.assertRaises(EnvironmentError): + self.clone = Clone(self.proj, remote=TestClone.rnremote) - with cd(self.proj.projdir): - # Reset to writable so we can remove the projdir - os.chmod(self.proj.projdir, S_IWUSR | S_IXUSR) + with cd(self.proj.projdir): + # Reset to writable so we can remove the projdir + os.chmod(self.proj.projdir, S_IWUSR | S_IXUSR) def test_nonexistant_clonedir(self): - with self.assertRaises(EnvironmentError): - self.clone_one=Clone(self.proj, clonedir="/a/nonexistant/directory/") + with self.assertRaises(EnvironmentError): + self.clone_one = Clone( + self.proj, clonedir="/a/nonexistant/directory/") def test_not_gitdir(self): - # Verify that an exception is raised when attempting to clone something - # that's not a git repository. - nongitdir=self.proj.projdir + "/nongitdir" - with cd (self.proj.projdir): - os.mkdir(nongitdir) + # Verify that an exception is raised when attempting to clone something + # that's not a git repository. + nongitdir = self.proj.projdir + "/nongitdir" + with cd(self.proj.projdir): + os.mkdir(nongitdir) - with self.assertRaises(EnvironmentError): - self.clone=Clone(self.proj,remote="", clonedir=nongitdir) + with self.assertRaises(EnvironmentError): + self.clone = Clone(self.proj, remote="", clonedir=nongitdir) def test_not_gitdir_but_with_dot_git(self): - # Verify that an exception is raised when attempting to clone a - # directory that has a .git file but is NOT a git repository. - nongitdir=self.proj.projdir + "/nongitdir" - with cd (self.proj.projdir): - os.mkdir(nongitdir) - # Create and empty .git file. - with open(".git", 'a'): - os.utime(".git", None) - - with self.assertRaises(EnvironmentError): - self.clone=Clone(self.proj,remote="", clonedir=nongitdir) + # Verify that an exception is raised when attempting to clone a + # directory that has a .git file but is NOT a git repository. + nongitdir = self.proj.projdir + "/nongitdir" + with cd(self.proj.projdir): + os.mkdir(nongitdir) + # Create and empty .git file. + with open(".git", 'a'): + os.utime(".git", None) + + with self.assertRaises(EnvironmentError): + self.clone = Clone(self.proj, remote="", clonedir=nongitdir) def test_incorrect_input_proj_type(self): - # Clone requires a valid Proj type as an input parameter. Verify that - # it throws an exception. - proj='stringtypeonpurpose' - with self.assertRaises(TypeError): - self.clone=Clone(proj,remote=TestClone.rnremote) + # Clone requires a valid Proj type as an input parameter. Verify that + # it throws an exception. + proj = 'stringtypeonpurpose' + with self.assertRaises(TypeError): + self.clone = Clone(proj, remote=TestClone.rnremote) def test_non_destructive_cleanup(self): - # Make sure that the file removal method in proj.cleanup() doesn't - # follow and remove symlinks. - self.clone_one=Clone(self.proj,remote=TestClone.rnremote) - self.proj_two=Proj(prefix=TestClone.testdirprefix) - # Use the clonedir from the first project as the clonedir for the - # second project. - self.clone_two=Clone(self.proj_two,clonedir=self.clone_one.clonedir()) + # Make sure that the file removal method in proj.cleanup() doesn't + # follow and remove symlinks. + self.clone_one = Clone(self.proj, remote=TestClone.rnremote) + self.proj_two = Proj(prefix=TestClone.testdirprefix) + # Use the clonedir from the first project as the clonedir for the + # second project. + self.clone_two = Clone( + self.proj_two, clonedir=self.clone_one.clonedir()) self.assertTrue(os.path.islink(self.clone_two.clonedir())) - # Cleanup proj_two - self.proj_two.cleanup() + # Cleanup proj_two + self.proj_two.cleanup() - # Make sure clone_one.clonedir wasn't removed when proj_two was removed - # which is a concern since proj_two used a clone directory from - # proj. + # Make sure clone_one.clonedir wasn't removed when proj_two was removed + # which is a concern since proj_two used a clone directory from + # proj. self.assertTrue(os.path.isdir(self.clone_one.clonedir())) def test_get_branch_clone(self): - self.clone=Clone(self.proj,remote=TestClone.rnremote) - self.assertEqual(TestClone.startbranch, self.clone.getbranch()) + self.clone = Clone(self.proj, remote=TestClone.rnremote) + self.assertEqual(TestClone.startbranch, self.clone.getbranch()) def test_checkoutbranch_clone(self): - self.clone=Clone(self.proj,remote=TestClone.rnremote) + self.clone = Clone(self.proj, remote=TestClone.rnremote) - # Test a new branch - with self.clone.checkoutbranch("TestClone", "origin/HEAD"): - self.assertEqual("TestClone", self.clone.getbranch()) + # Test a new branch + with self.clone.checkoutbranch("TestClone", "origin/HEAD"): + self.assertEqual("TestClone", self.clone.getbranch()) - self.assertEqual(TestClone.startbranch, self.clone.getbranch()) + self.assertEqual(TestClone.startbranch, self.clone.getbranch()) # Test being able to switch to a branch that already exists. - with self.clone.checkoutbranch("TestClone"): - self.assertEqual("TestClone", self.clone.getbranch()) + with self.clone.checkoutbranch("TestClone"): + self.assertEqual("TestClone", self.clone.getbranch()) - self.assertEqual(TestClone.startbranch, self.clone.getbranch()) + self.assertEqual(TestClone.startbranch, self.clone.getbranch()) - #TODO test a non-default 'track' passed to checkoutbranch. + # TODO test a non-default 'track' passed to checkoutbranch. def test_checkoutbranch_clone_with_local_changes(self): - self.clone=Clone(self.proj,remote=TestClone.rnremote) + self.clone = Clone(self.proj, remote=TestClone.rnremote) - # create an empty file and add it to the repository. - with cd (self.clone.repodir): - # Create and empty file. - with open("checkouttest", 'a'): - os.utime("checkouttest", None) + # create an empty file and add it to the repository. + with cd(self.clone.repodir): + # Create and empty file. + with open("checkouttest", 'a'): + os.utime("checkouttest", None) - self.clone.add(self.clone.repodir + '/checkouttest') + self.clone.add(self.clone.repodir + '/checkouttest') - with self.clone.checkoutbranch("TestClone", "origin/HEAD"): - self.assertEqual("TestClone", self.clone.getbranch()) + with self.clone.checkoutbranch("TestClone", "origin/HEAD"): + self.assertEqual("TestClone", self.clone.getbranch()) # Verify there's no file name 'checkouttest' when we switch branch. - with cd (self.clone.repodir): - self.assertFalse(os.path.isfile(self.clone.repodir + '/checkouttest')) + with cd(self.clone.repodir): + self.assertFalse(os.path.isfile( + self.clone.repodir + '/checkouttest')) - # Verify that we've returned to the correct branch. - self.assertEqual(TestClone.startbranch, self.clone.getbranch()) + # Verify that we've returned to the correct branch. + self.assertEqual(TestClone.startbranch, self.clone.getbranch()) - # Show that checkouttest does exist once were out of the - # checkoutbranch context. - with cd (self.clone.repodir): - self.assertTrue(os.path.isfile(self.clone.repodir + '/checkouttest')) + # Show that checkouttest does exist once were out of the + # checkoutbranch context. + with cd(self.clone.repodir): + self.assertTrue(os.path.isfile( + self.clone.repodir + '/checkouttest')) if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/git/gitrepo.py b/linaropy/git/gitrepo.py index d885a75..dc94ea1 100644 --- a/linaropy/git/gitrepo.py +++ b/linaropy/git/gitrepo.py @@ -19,189 +19,202 @@ from contextlib import contextmanager # specified here. You must instantiate a subclass in order to use/test these # operations. This is because 'clones' and 'workdirs' are created differently # but you operate on them in the exact same way. + + class GitRepo(object): + def __init__(self, proj): - self.repodir=u"" - if isinstance(proj, Proj): - self.proj=proj + self.repodir = u"" + if isinstance(proj, Proj): + self.proj = proj else: - raise TypeError('proj input parameter is not of type Proj') + raise TypeError('proj input parameter is not of type Proj') def branchexists(self, branch): logging.info("Checking to see if branch %s exists" % branch) - with cd(self.repodir): - try: + with cd(self.repodir): + try: # Quote the branchname because it might have strange # characters in it. - br="%s" % branch + br = "%s" % branch git("rev-parse", "--verify", br) - except ErrorReturnCode_128: + except ErrorReturnCode_128: logging.info("Couldn't find branch %s" % branch) - return False - return True + return False + return True def getbranch(self): - try: - with cd(self.repodir): - branch=git("rev-parse", "--abbrev-ref", "HEAD").stdout.rstrip() + try: + with cd(self.repodir): + branch = git("rev-parse", "--abbrev-ref", + "HEAD").stdout.rstrip() except ErrorReturnCode: - raise EnvironmentError("Unable to get the current branch") - return branch + raise EnvironmentError("Unable to get the current branch") + return branch # TODO make this a bit more sophisticated because the user might not be # using 'origin' as their remote name. def remote_branchname(self, branchname): - return "remotes/origin/" + branchname + return "remotes/origin/" + branchname # TODO: Fully test this. # Stash current changes and change to new branch. # Return to previous branch when context is exited. @contextmanager def checkoutbranch(self, branch, track=""): - with cd(self.repodir): - # The stashid will remain empty if there were no changes in the - # directory to stash. - stashid=u"" + with cd(self.repodir): + # The stashid will remain empty if there were no changes in the + # directory to stash. + stashid = u"" - try: - self.prevbranch=git("rev-parse", "--abbrev-ref", "HEAD").stdout.rstrip() + try: + self.prevbranch = git( + "rev-parse", "--abbrev-ref", "HEAD").stdout.rstrip() except ErrorReturnCode: - raise EnvironmentError("Unable to get the current branch") - - try: - # TODO: do we want to do a blanket git add *? - stashid=git("stash", "create").stdout.rstrip() - # If there's no stash then there's no reason to save. - if stashid!="": - git("stash", "save") + raise EnvironmentError("Unable to get the current branch") + + try: + # TODO: do we want to do a blanket git add *? + stashid = git("stash", "create").stdout.rstrip() + # If there's no stash then there's no reason to save. + if stashid != "": + git("stash", "save") except ErrorReturnCode: - raise EnvironmentError("Unable to get the current branch") + raise EnvironmentError("Unable to get the current branch") - try: - # TODO This is a nop as it is. - git("rev-parse", "--verify", branch) - # if the branch exists the previous statement won't cause an - # exception so we know we can just check it out. + try: + # TODO This is a nop as it is. + git("rev-parse", "--verify", branch) + # if the branch exists the previous statement won't cause an + # exception so we know we can just check it out. git("checkout", branch) except ErrorReturnCode: - try: - # if it doesn't exist we need to checkout a new branch + try: + # if it doesn't exist we need to checkout a new branch git("checkout", "-b", branch, track).stdout.rstrip() except ErrorReturnCode as exc: - raise EnvironmentError("Unable to checkout -b %s %s" % (branch, track)) + raise EnvironmentError( + "Unable to checkout -b %s %s" % (branch, track)) try: yield finally: - try: - with cd(self.repodir): + try: + with cd(self.repodir): git("checkout", self.prevbranch) - # If there's no stashid then there were no files stashed, - # so don't stash apply. - if stashid!="": + # If there's no stashid then there were no files stashed, + # so don't stash apply. + if stashid != "": git("stash", "apply", stashid) except ErrorReturnCode, exc: - raise EnvironmentError("Unable to return to the previous branch: %s" % exc.stderr) + raise EnvironmentError( + "Unable to return to the previous branch: %s" % exc.stderr) # TODO: Write a unit test for this. def add(self, filetogitadd): - # TODO: Determine if filetogitadd is relative or absolute. - # TODO: verify that filetogitadd is in self.repodir - try: - with cd(self.repodir): - git("add", filetogitadd) + # TODO: Determine if filetogitadd is relative or absolute. + # TODO: verify that filetogitadd is in self.repodir + try: + with cd(self.repodir): + git("add", filetogitadd) except ErrorReturnCode: - raise EnvironmentError("Unable to git add " + filetogitadd) + raise EnvironmentError("Unable to git add " + filetogitadd) # TODO: Write a unit test for this. # TODO: fix the default def commit(self, message="default"): - logging.info("Attempting to commit changes to %s" % self.repodir ) - try: - with cd(self.repodir): - # Git commit first with a boiler plate message and then allow the user - # to amend. - if git("status", "--porcelain"): - # using python sh will suppress the git editor - subprocess.call(["git", "commit", "-m", message]) - subprocess.call(["git", "commit", "--amend"]) - else: - logging.info("Nothing to commit.") - return False + logging.info("Attempting to commit changes to %s" % self.repodir) + try: + with cd(self.repodir): + # Git commit first with a boiler plate message and then allow the user + # to amend. + if git("status", "--porcelain"): + # using python sh will suppress the git editor + subprocess.call(["git", "commit", "-m", message]) + subprocess.call(["git", "commit", "--amend"]) + else: + logging.info("Nothing to commit.") + return False except ErrorReturnCode: - raise EnvironmentError("Unable to git commit ") + raise EnvironmentError("Unable to git commit ") return False # Something was committed. return True def log(self, number): - try: - with cd(self.repodir): - print git("log", "-n %d" % number) + try: + with cd(self.repodir): + print git("log", "-n %d" % number) except ErrorReturnCode: - raise EnvironmentError("Unable to git add " + filetogitadd) + raise EnvironmentError("Unable to git add " + filetogitadd) # TODO: Does this need to 'cd' first? def edit(self, toedit): - editor = os.getenv('EDITOR') - if not editor: - editor='/usr/bin/vim' - os.system(editor + ' ' + self.repodir + '/' + toedit) + editor = os.getenv('EDITOR') + if not editor: + editor = '/usr/bin/vim' + os.system(editor + ' ' + self.repodir + '/' + toedit) - self.add(toedit) + self.add(toedit) - return + return # TODO: Test this function with both dryrun=True and dryrun=False def pushToBranch(self, tobranch, dryrun=True): - try: - # TODO: Check for un-merged commits. - with cd(self.repodir): - branch=self.getbranch() - if dryrun: - git("push", "--dry-run", branch, tobranch) - else: - git("push", branch, tobranch) + try: + # TODO: Check for un-merged commits. + with cd(self.repodir): + branch = self.getbranch() + if dryrun: + git("push", "--dry-run", branch, tobranch) + else: + git("push", branch, tobranch) except ErrorReturnCode: - raise EnvironmentError("Unable to push branch %s to %s" % (branch, tobranch)) + raise EnvironmentError( + "Unable to push branch %s to %s" % (branch, tobranch)) def tag_exists(self, tag): - try: - with cd(self.repodir): - tagref="refs/tags/%s" % tag + try: + with cd(self.repodir): + tagref = "refs/tags/%s" % tag git("rev-parse", "-q", "--verify", tagref) - except ErrorReturnCode_128: + except ErrorReturnCode_128: logging.info("Couldn't find tag %s" % tag) return False - return True + return True def __str__(self): - return self.repodir + return self.repodir # TestGitRepo is an abstract baseclass. Verify that the constructor # will throw an exception if you try to run operations without # defining a subclass. + + class TestGitRepo(unittest.TestCase): - repoprefix="GitRepoUT" + repoprefix = "GitRepoUT" # This class is only used to test the GitRepo functions since, as an, # abstract-baseclass, GitRepo doesn't define repodir, and we need an # actual repository to test git based functions. class DerivedGitRepo(GitRepo): + def __init__(self, proj): - super(TestGitRepo.DerivedGitRepo,self).__init__(proj) - self.remote=u'http://git.linaro.org/toolchain/release-notes.git' - dgr_dirname="release-notes" - self.repodir=self.proj.projdir + "/" + dgr_dirname - try: - with cd(self.proj.projdir): - git("clone", self.remote, dgr_dirname, _err_to_out=True, _out="/dev/null") + super(TestGitRepo.DerivedGitRepo, self).__init__(proj) + self.remote = u'http://git.linaro.org/toolchain/release-notes.git' + dgr_dirname = "release-notes" + self.repodir = self.proj.projdir + "/" + dgr_dirname + try: + with cd(self.proj.projdir): + git("clone", self.remote, dgr_dirname, + _err_to_out=True, _out="/dev/null") except ErrorReturnCode: - raise EnvironmentError("Git unable to clone into " + self.repodir) + raise EnvironmentError( + "Git unable to clone into " + self.repodir) @classmethod def setUpClass(cls): - cls.proj=Proj(prefix=TestGitRepo.repoprefix, persist=False) - cls.dgr=TestGitRepo.DerivedGitRepo(cls.proj) + cls.proj = Proj(prefix=TestGitRepo.repoprefix, persist=False) + cls.dgr = TestGitRepo.DerivedGitRepo(cls.proj) @classmethod def tearDownClass(cls): @@ -210,32 +223,34 @@ class TestGitRepo(unittest.TestCase): # Test that the abstract baseclass throws an exception if one of the # functions are called from the baseclass without a derived class. def test_repo(self): - self.repo=GitRepo(self.proj) - with self.assertRaises(OSError): + self.repo = GitRepo(self.proj) + with self.assertRaises(OSError): # We haven't set a repodir so this should throw an exception. - branch=self.repo.getbranch() + branch = self.repo.getbranch() # TODO: Create a test-branch in the repo so it's always there. def test_tag_exists(self): with cd(self.dgr.repodir): - git("tag", "-a", "linaro-99.9-2099.08-rc1", "-m", "This is a test tag") + git("tag", "-a", "linaro-99.9-2099.08-rc1", "-m", "This is a test tag") self.assertTrue(self.dgr.tag_exists("linaro-99.9-2099.08-rc1")) - + def test_not_branchexists(self): - self.assertFalse(self.dgr.branchexists("foobar")) + self.assertFalse(self.dgr.branchexists("foobar")) def test_getbranch(self): with cd(self.dgr.repodir): - try: - git("checkout", "-b", "master_test", "origin/master").stdout.rstrip() + try: + git("checkout", "-b", "master_test", + "origin/master").stdout.rstrip() except ErrorReturnCode as exc: - raise EnvironmentError("Unable to checkout -b %s %s" % (branch, track)) - self.assertEquals(self.dgr.getbranch(), "master_test") + raise EnvironmentError( + "Unable to checkout -b %s %s" % (branch, track)) + self.assertEquals(self.dgr.getbranch(), "master_test") # TODO: Test checkoutbranch with various combinations of polluted # directories. if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/git/workdir.py b/linaropy/git/workdir.py index dcb2b15..db125e4 100644 --- a/linaropy/git/workdir.py +++ b/linaropy/git/workdir.py @@ -17,93 +17,103 @@ from sh import ErrorReturnCode # TODO: Set the git repo pushurl. + class Workdir(GitRepo): # @ clone - clone this workdir from this Clone. # @ workdir - name of the proposed workdir. # @ track - derive the workdir from the branch designated by the string # in 'track'. # @ branchname - the name of the local branch + def __init__(self, proj, clone=None, workdir="", track=None, branchname=""): - super(Workdir,self).__init__(proj) - - # TODO: The Clone can be in a different project dir than proj. if - # clone.clonedir is not in proj.projdir then create a symlink in the - # current projdir. - - if not isinstance(clone, Clone): - raise TypeError('Clone input parameter is not of type Clone') - - if not isinstance(workdir, str): - raise TypeError('Workdir workdir parameter must be a string') - - # An empty workdir would result in an empty variable expansion - # and a malformed git new-workdir expression. - if workdir=="": - raise EnvironmentError('You must specify a workdir directory when creating a Workdir') - - if branchname=="": - raise EnvironmentError('You must specify a branchname when creating a Workdir') - - try: - with cd(self.proj.projdir): - logging.info("Workdir(): going to call git new-workdir tracking %s" % track) - if track: - logging.info("Workdir(): Calling git new-workdir for workdir %s, tracking %s" % (workdir, track)) - #TODO: Do we want to prevalidate that 'track' is a valid branch or tag? - # If we don't this will just throw an exception. - print git_new_workdir(clone.clonedir(), workdir, track, _err_to_out=True, _out="/dev/null") - else: - logging.info("Workdir(): Calling git new-workdir for workdir %s, tracking %s" % (workdir, "origin/HEAD")) - # Always just checkout HEAD if the track is not specified. - print git_new_workdir(clone.clonedir(), workdir, "origin/HEAD", _err_to_out=True, _out="/dev/null") + super(Workdir, self).__init__(proj) + + # TODO: The Clone can be in a different project dir than proj. if + # clone.clonedir is not in proj.projdir then create a symlink in the + # current projdir. + + if not isinstance(clone, Clone): + raise TypeError('Clone input parameter is not of type Clone') + + if not isinstance(workdir, str): + raise TypeError('Workdir workdir parameter must be a string') + + # An empty workdir would result in an empty variable expansion + # and a malformed git new-workdir expression. + if workdir == "": + raise EnvironmentError( + 'You must specify a workdir directory when creating a Workdir') + + if branchname == "": + raise EnvironmentError( + 'You must specify a branchname when creating a Workdir') + + try: + with cd(self.proj.projdir): + logging.info( + "Workdir(): going to call git new-workdir tracking %s" % track) + if track: + logging.info( + "Workdir(): Calling git new-workdir for workdir %s, tracking %s" % (workdir, track)) + # TODO: Do we want to prevalidate that 'track' is a valid branch or tag? + # If we don't this will just throw an exception. + print git_new_workdir(clone.clonedir(), workdir, track, _err_to_out=True, _out="/dev/null") + else: + logging.info( + "Workdir(): Calling git new-workdir for workdir %s, tracking %s" % (workdir, "origin/HEAD")) + # Always just checkout HEAD if the track is not specified. + print git_new_workdir(clone.clonedir(), workdir, "origin/HEAD", _err_to_out=True, _out="/dev/null") except ErrorReturnCode as exc: - # if 'workdir' is None - # If 'workdir' already exists. - # If clone.clonedir() doesn't exist. - # If track isn't a valid branch. - raise EnvironmentError("Unable to create a git workdir ") + # if 'workdir' is None + # If 'workdir' already exists. + # If clone.clonedir() doesn't exist. + # If track isn't a valid branch. + raise EnvironmentError("Unable to create a git workdir ") - self.repodir=self.proj.projdir + '/' + workdir + self.repodir = self.proj.projdir + '/' + workdir - try: - with cd(self.repodir): - git("checkout", "-b", branchname) + try: + with cd(self.repodir): + git("checkout", "-b", branchname) except ErrorReturnCode as exc: - raise EnvironmentError("Unable to checkout branch %s in workdir %s" % (branchname, self.repodir)) + raise EnvironmentError( + "Unable to checkout branch %s in workdir %s" % (branchname, self.repodir)) - - #TODO: Verify that self.repodir exists or 'raise' exception? + # TODO: Verify that self.repodir exists or 'raise' exception? # TODO: write this function or the workdir will remain in detached # head state if it's not checked out into a branch. # def checkout(self, ): def workdir(self): - return self.repodir + return self.repodir + class TestWorkdir(unittest.TestCase): - testdirprefix="WorkdirUT" + testdirprefix = "WorkdirUT" @classmethod def setUpClass(cls): - # We need a Proj dir to store the necessary Clone in. - cls.proj=Proj(prefix=TestWorkdir.testdirprefix) + # We need a Proj dir to store the necessary Clone in. + cls.proj = Proj(prefix=TestWorkdir.testdirprefix) - #TODO: Perform a connectivity test to determine online or offline - # testing mode. + # TODO: Perform a connectivity test to determine online or offline + # testing mode. - # We'll create a Clone to be used by all the Workdir tests in order to - # be nice to the git server. - cls.rnclone=Clone(cls.proj,remote=u'http://git.linaro.org/toolchain/release-notes.git') - #OFFLINE: cls.rnclone=Clone(cls.proj,remote=u'/var/run/media/ryanarn/sidecar/reldir/release-notes') + # We'll create a Clone to be used by all the Workdir tests in order to + # be nice to the git server. + cls.rnclone = Clone( + cls.proj, remote=u'http://git.linaro.org/toolchain/release-notes.git') + # OFFLINE: + # cls.rnclone=Clone(cls.proj,remote=u'/var/run/media/ryanarn/sidecar/reldir/release-notes') - # All further tests will use this as the remote if they need to - # create more clones. - cls.rnremote=cls.rnclone.repodir + # All further tests will use this as the remote if they need to + # create more clones. + cls.rnremote = cls.rnclone.repodir - # A common name to use for the workdir for all of the Workdir tests. - cls.workdir="testworkdir" + # A common name to use for the workdir for all of the Workdir tests. + cls.workdir = "testworkdir" @classmethod def tearDownClass(cls): @@ -111,79 +121,92 @@ class TestWorkdir(unittest.TestCase): # Every instance of TestWorkdir requires its own proj directory. def setUp(self): - self.proj=Proj(prefix=TestWorkdir.testdirprefix) - self.branchname="testworkdir-" + str(uuid.uuid4()) + self.proj = Proj(prefix=TestWorkdir.testdirprefix) + self.branchname = "testworkdir-" + str(uuid.uuid4()) def tearDown(self): - self.proj.cleanup() + self.proj.cleanup() def test_workdir(self): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track=None, branchname=self.branchname) + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, track=None, branchname=self.branchname) self.assertTrue(os.path.isdir(self.workdir.workdir())) - + def test_workdir_with_default_track(self): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, branchname=self.branchname) + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, branchname=self.branchname) self.assertTrue(os.path.isdir(self.workdir.workdir())) - + def test_workdir_with_track(self): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) self.assertTrue(os.path.isdir(self.workdir.workdir())) def test_workdir_with_checkoutbranch(self): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, branchname="startbranch") + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, branchname="startbranch") self.assertTrue(os.path.isdir(self.workdir.workdir())) - # Test a new branch (derived from the existing branch) - with self.workdir.checkoutbranch("TestWorkdir", self.workdir.getbranch()): - self.assertEqual("TestWorkdir", self.workdir.getbranch()) + # Test a new branch (derived from the existing branch) + with self.workdir.checkoutbranch("TestWorkdir", self.workdir.getbranch()): + self.assertEqual("TestWorkdir", self.workdir.getbranch()) - # Verify that leaving the context restored the original branch. - self.assertEqual(self.workdir.getbranch(), "startbranch") + # Verify that leaving the context restored the original branch. + self.assertEqual(self.workdir.getbranch(), "startbranch") # Test being able to switch to a branch that already exists. - with self.workdir.checkoutbranch("TestWorkdir"): - self.assertEqual("TestWorkdir", self.workdir.getbranch()) + with self.workdir.checkoutbranch("TestWorkdir"): + self.assertEqual("TestWorkdir", self.workdir.getbranch()) - self.assertEqual(self.workdir.getbranch(), "startbranch") + self.assertEqual(self.workdir.getbranch(), "startbranch") def test_workdir_already_exists(self): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, branchname=self.branchname) + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, branchname=self.branchname) - # Should fail because TestWorkdir.workdir should already exist. - with self.assertRaises(EnvironmentError): - self.workdir2=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, branchname=self.branchname + '_2') + # Should fail because TestWorkdir.workdir should already exist. + with self.assertRaises(EnvironmentError): + self.workdir2 = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, branchname=self.branchname + '_2') def test_workdir_exceptions(self): - with self.assertRaises(TypeError): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=None, branchname=self.branchname) + with self.assertRaises(TypeError): + self.workdir = Workdir( + self.proj, clone=TestWorkdir.rnclone, workdir=None, branchname=self.branchname) - with self.assertRaises(EnvironmentError): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track="someinvalidbranchname", branchname=self.branchname) + with self.assertRaises(EnvironmentError): + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, + track="someinvalidbranchname", branchname=self.branchname) - # Test if clone.clonedir() doesn't exist by breaking repodir. - brokenclone=Clone(TestWorkdir.proj,TestWorkdir.rnremote) - brokenclone.repodir="/breakthisrepodir" + # Test if clone.clonedir() doesn't exist by breaking repodir. + brokenclone = Clone(TestWorkdir.proj, TestWorkdir.rnremote) + brokenclone.repodir = "/breakthisrepodir" - # Verify that a Clone with a broken repodir/clonedir results in an - # exception. - with self.assertRaises(EnvironmentError): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, branchname=self.branchname) + # Verify that a Clone with a broken repodir/clonedir results in an + # exception. + with self.assertRaises(EnvironmentError): + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, branchname=self.branchname) - # 'clone' isn't a valid Clone type. - with self.assertRaises(TypeError): - self.workdir=Workdir(self.proj, clone="foobar", workdir=TestWorkdir.workdir, branchname=self.branchname) + # 'clone' isn't a valid Clone type. + with self.assertRaises(TypeError): + self.workdir = Workdir( + self.proj, clone="foobar", workdir=TestWorkdir.workdir, branchname=self.branchname) def test_workdir_exceptions(self): - #TODO: branchname is empty. - with self.assertRaises(EnvironmentError): - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track="origin/HEAD", branchname="") - + # TODO: branchname is empty. + with self.assertRaises(EnvironmentError): + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, track="origin/HEAD", branchname="") + def test_workdir_exceptions(self): - #TODO: branchname already exists. - self.workdir=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) - with self.assertRaises(EnvironmentError): - self.workdir2=Workdir(self.proj, clone=TestWorkdir.rnclone, workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) + # TODO: branchname already exists. + self.workdir = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) + with self.assertRaises(EnvironmentError): + self.workdir2 = Workdir(self.proj, clone=TestWorkdir.rnclone, + workdir=TestWorkdir.workdir, track="origin/HEAD", branchname=self.branchname) if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/proj.py b/linaropy/proj.py index 26f6d36..3d05dba 100644 --- a/linaropy/proj.py +++ b/linaropy/proj.py @@ -6,116 +6,121 @@ import tempfile # Execute shell commands with the 'sh' package. from sh import rm + class Proj(object): """ Create a project temporary directory in /tmp. """ + def __init__(self, prefix="", persist=False): - """ - Create a /tmp project dir. + """ + Create a /tmp project dir. Parameters - ---------- - prefix : str - Optional prefix appended to /tmp projdir directory name. - - persist=False : bool - The projdir should persist after the cleanup function is called - only if persist=True. - """ - # This allows string or bool inputs. - if str(persist).lower() == "true": - self.persist=True - longevity="persistent" + ---------- + prefix : str + Optional prefix appended to /tmp projdir directory name. + + persist=False : bool + The projdir should persist after the cleanup function is called + only if persist=True. + """ + # This allows string or bool inputs. + if str(persist).lower() == "true": + self.persist = True + longevity = "persistent" else: - self.persist=False - longevity="temporary" + self.persist = False + longevity = "temporary" - self.projdir=unicode(tempfile.mkdtemp(prefix=prefix), "utf-8") - logging.info("Created %s project directory in %s" % (longevity, self.projdir)) + self.projdir = unicode(tempfile.mkdtemp(prefix=prefix), "utf-8") + logging.info("Created %s project directory in %s" % + (longevity, self.projdir)) def cleanup(self): """Perform cleanup (removal) of the proj directory if Proj persist==False.""" - if not self.persist and self.projdir != "/" and self.projdir != "/home": + if not self.persist and self.projdir != "/" and self.projdir != "/home": logging.info("Removing project dir %s" % self.projdir) - #TODO: Test whether we need to trap an exception if the directory - # has already been removed when cleanup is called. + # TODO: Test whether we need to trap an exception if the directory + # has already been removed when cleanup is called. rm("-rf", "--preserve-root", self.projdir) - self.projdir=None - else: + self.projdir = None + else: logging.info("Project dir %s will persist" % self.projdir) + class TestProj(unittest.TestCase): """Test the Proj class.""" + def setUp(self): - self.persistdir="" + self.persistdir = "" def test_create(self): - self.proj=Proj() + self.proj = Proj() self.assertNotEqual(self.proj.projdir, "") def test_create_dir(self): - self.proj=Proj() + self.proj = Proj() self.assertTrue(os.path.isdir(self.proj.projdir)) def test_create_with_prefix(self): - self.proj=Proj("testprefix") + self.proj = Proj("testprefix") self.assertTrue("testprefix" in self.proj.projdir) def test_create_with_persist_bool(self): - self.proj=Proj(persist=True) + self.proj = Proj(persist=True) self.assertTrue(self.proj.persist) - self.persistdir=self.proj.projdir + self.persistdir = self.proj.projdir def test_create_with_persist_str(self): - self.proj=Proj(persist="true") + self.proj = Proj(persist="true") self.assertTrue(self.proj.persist) - self.persistdir=self.proj.projdir + self.persistdir = self.proj.projdir def test_create_with_persist_false_str(self): - self.proj=Proj(persist="false") + self.proj = Proj(persist="false") self.assertFalse(self.proj.persist) - # Just in-case it wasn't set properly - self.persistdir=self.proj.projdir + # Just in-case it wasn't set properly + self.persistdir = self.proj.projdir def test_create_with_persist_false_bool(self): - self.proj=Proj(persist=False) + self.proj = Proj(persist=False) self.assertFalse(self.proj.persist) - # Just in-case it wasn't removed properly - self.persistdir=self.proj.projdir + # Just in-case it wasn't removed properly + self.persistdir = self.proj.projdir def test_create_with_persist_capstr(self): - self.proj=Proj(persist="TRUE") + self.proj = Proj(persist="TRUE") self.assertTrue(self.proj.persist) - self.persistdir=self.proj.projdir + self.persistdir = self.proj.projdir def test_cleanup(self): - self.proj=Proj() - projdir=self.proj.projdir - self.proj.cleanup() - # Verify that the directory has been removed. + self.proj = Proj() + projdir = self.proj.projdir + self.proj.cleanup() + # Verify that the directory has been removed. self.assertFalse(os.path.isdir(projdir)) def test_cleanup_with_persist(self): - self.proj=Proj(persist=True) - projdir=self.proj.projdir - self.proj.cleanup() + self.proj = Proj(persist=True) + projdir = self.proj.projdir + self.proj.cleanup() self.assertTrue(os.path.isdir(projdir)) - self.persistdir=self.proj.projdir + self.persistdir = self.proj.projdir def test_cleanup_with_persist_and_prefix(self): - self.proj=Proj(persist=True, prefix="thingy") - projdir=self.proj.projdir - self.proj.cleanup() + self.proj = Proj(persist=True, prefix="thingy") + projdir = self.proj.projdir + self.proj.cleanup() self.assertTrue(os.path.isdir(projdir)) - self.persistdir=self.proj.projdir + self.persistdir = self.proj.projdir def tearDown(self): - # if persistdir is set and isdir then remove it or we'll pollute /tmp. - if os.path.isdir(self.persistdir): - if self.persistdir != "/" and self.persistdir != "/home": - rm("-rf", "--preserve-root", self.persistdir) + # if persistdir is set and isdir then remove it or we'll pollute /tmp. + if os.path.isdir(self.persistdir): + if self.persistdir != "/" and self.persistdir != "/home": + rm("-rf", "--preserve-root", self.persistdir) if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/rn/custom_wordwrap.py b/linaropy/rn/custom_wordwrap.py index 4ed3e25..0a92efe 100644 --- a/linaropy/rn/custom_wordwrap.py +++ b/linaropy/rn/custom_wordwrap.py @@ -1,9 +1,10 @@ -#from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ +# from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ # unicode_urlencode from jinja2.runtime import Undefined #from jinja2.exceptions import FilterArgumentError #from jinja2._compat import imap, string_types, text_type, iteritems + def environmentfilter(f): """Decorator for marking environment dependent filters. The current :class:`Environment` is passed to the filter as first argument. @@ -11,9 +12,10 @@ def environmentfilter(f): f.environmentfilter = True return f + @environmentfilter def do_customwordwrap(environment, s, width=79, break_long_words=True, - wrapstring=None, break_on_hyphens=False): + wrapstring=None, break_on_hyphens=False): """ Return a copy of the string passed to the filter wrapped after ``79`` characters. You can override this default using the first @@ -26,6 +28,6 @@ def do_customwordwrap(environment, s, width=79, break_long_words=True, wrapstring = environment.newline_sequence import textwrap return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False, - replace_whitespace=False, - break_long_words=break_long_words, - break_on_hyphens=break_on_hyphens)) + replace_whitespace=False, + break_long_words=break_long_words, + break_on_hyphens=break_on_hyphens)) diff --git a/linaropy/rn/gccclone.py b/linaropy/rn/gccclone.py index 8647eaa..bd82ebf 100644 --- a/linaropy/rn/gccclone.py +++ b/linaropy/rn/gccclone.py @@ -4,26 +4,29 @@ from sh import git from ..git.clone import Clone from ..cd import cd + class GCCClone(Clone): - def __init__(self, proj, clonedir=None, remote=None ): - super(GCCClone,self).__init__(proj, clonedir, remote) + + def __init__(self, proj, clonedir=None, remote=None): + super(GCCClone, self).__init__(proj, clonedir, remote) logging.info("Changing directory to clonedir %s." % clonedir) with cd(clonedir): try: - with open('gcc/BASE-VER', 'r') as f: - self.basever = f.readline().strip() + with open('gcc/BASE-VER', 'r') as f: + self.basever = f.readline().strip() except: - raise IOError('gcc/BASE-VER not found in ' + clonedir) + raise IOError('gcc/BASE-VER not found in ' + clonedir) - log=git("log", "-n 1", "--grep=Merge branch") - for logline in log: - if logline.lstrip().startswith("Merge"): - # For some reason rsplit('.') isn't working. - self.fsfrev=logline.lstrip().rsplit(None,1)[1].split('.',1)[0] + log = git("log", "-n 1", "--grep=Merge branch") + for logline in log: + if logline.lstrip().startswith("Merge"): + # For some reason rsplit('.') isn't working. + self.fsfrev = logline.lstrip().rsplit(None, 1)[ + 1].split('.', 1)[0] def get_base_version(self): - return self.basever + return self.basever def get_fsf_revision(self): - return self.fsfrev + return self.fsfrev diff --git a/linaropy/rn/linaroseries.py b/linaropy/rn/linaroseries.py index 9344789..e798f5c 100644 --- a/linaropy/rn/linaroseries.py +++ b/linaropy/rn/linaroseries.py @@ -32,14 +32,17 @@ from ..series import series_from_tag # Inherit Series in order to provide Linaro specific rules on transitions # between series types. The baseclass Series doesn't have the toNext* # functions defined. + + class LinaroSeries(Series): + def __init__(self, seriestype, vendor=None, package=None, date=datetime.today(), spin=None, rc=None, strict=True): - # This is a dispatch table so that we can use a 'toNext' function based - # on an input type and it will call the correct toNextFoo function. - # This will work if the key is an integer or a string. Ideally this - # would be added to Series and we wouldn't need to derive, but I - # couldn't figure out how to get the pointer tables correct. + # This is a dispatch table so that we can use a 'toNext' function based + # on an input type and it will call the correct toNextFoo function. + # This will work if the key is an integer or a string. Ideally this + # would be added to Series and we wouldn't need to derive, but I + # couldn't figure out how to get the pointer tables correct. self.dispatchnext = { Series.series.index("candidate"): self.toNextCandidate, 'candidate': self.toNextCandidate, @@ -49,99 +52,108 @@ class LinaroSeries(Series): 'release': self.toNextRelease, } - super(LinaroSeries,self).__init__(seriestype, vendor, package, date,spin,rc, strict) + super(LinaroSeries, self).__init__(seriestype, + vendor, package, date, spin, rc, strict) def toNextCandidate(self, date=None, strict=False): - logging.info('from %s toNextCandidate' % self.longlowertype()) + logging.info('from %s toNextCandidate' % self.longlowertype()) if self.seriestype < 0 or self.seriestype >= len(Series.series): - raise TypeError('toNextCandidate on an unknown series type.') + raise TypeError('toNextCandidate on an unknown series type.') - candidate=copy.deepcopy(self) - candidate.seriestype = Series.series.index("candidate") + candidate = copy.deepcopy(self) + candidate.seriestype = Series.series.index("candidate") if date: - if not isinstance(date,datetime): - raise TypeError('date is not of type datetime.') - candidate.date=date - - if self.seriestype == Series.series.index("candidate"): - candidate.rc.increment() - elif self.seriestype == Series.series.index("release"): - rc=Rc(1) - candidate.rc=rc - candidate.spin.increment() - elif self.seriestype == Series.series.index("snapshot"): - spin=Spin(None) - rc=Rc(1) - candidate.rc=rc - candidate.spin=spin - - # If the user hasn't specified a date, the implicit behavior is to - # increment the date by 1 month when moving from a snapshot to a - # candidate. + if not isinstance(date, datetime): + raise TypeError('date is not of type datetime.') + candidate.date = date + + if self.seriestype == Series.series.index("candidate"): + candidate.rc.increment() + elif self.seriestype == Series.series.index("release"): + rc = Rc(1) + candidate.rc = rc + candidate.spin.increment() + elif self.seriestype == Series.series.index("snapshot"): + spin = Spin(None) + rc = Rc(1) + candidate.rc = rc + candidate.spin = spin + + # If the user hasn't specified a date, the implicit behavior is to + # increment the date by 1 month when moving from a snapshot to a + # candidate. if not date: - candidate.incrementMonth() - # If the user did specify a date and we're in strict mode we need to - # verify that the date they chose is exactly one month difference. - elif strict: - if candidate.date != self.date + relativedelta(months=1): - raise ValueError('toNextCandidate invoked with strict=True. Snapshot date to candidate date can only be +1 month difference.') - return candidate + candidate.incrementMonth() + # If the user did specify a date and we're in strict mode we need to + # verify that the date they chose is exactly one month difference. + elif strict: + if candidate.date != self.date + relativedelta(months=1): + raise ValueError( + 'toNextCandidate invoked with strict=True. Snapshot date to candidate date can only be +1 month difference.') + return candidate - if strict and candidate.date != self.date: - raise ValueError('Candidate date can only change if current series is a Snapshot when toNextCandidate is invoked with strict=True.') + if strict and candidate.date != self.date: + raise ValueError( + 'Candidate date can only change if current series is a Snapshot when toNextCandidate is invoked with strict=True.') - return candidate + return candidate def toNextRelease(self, date=None, strict=False): - logging.info('from %s toNextRelease' % self.longlowertype()) + logging.info('from %s toNextRelease' % self.longlowertype()) if self.seriestype < 0 or self.seriestype >= len(Series.series): - raise TypeError('toNextRelease called on an unknown series type.') - elif self.seriestype == Series.series.index("release"): - raise TypeError('A release series can not be the basis for another release. Move to a release candidate first.') - elif self.seriestype == Series.series.index("snapshot"): - raise TypeError('A snapshot series can not be the basis for a release. Move to a release candidate first.') - - # Only a candidate can turn into a release. - release=copy.deepcopy(self) + raise TypeError('toNextRelease called on an unknown series type.') + elif self.seriestype == Series.series.index("release"): + raise TypeError( + 'A release series can not be the basis for another release. Move to a release candidate first.') + elif self.seriestype == Series.series.index("snapshot"): + raise TypeError( + 'A snapshot series can not be the basis for a release. Move to a release candidate first.') + + # Only a candidate can turn into a release. + release = copy.deepcopy(self) # if we have a candidate and ask for a release rc needs to be None. - rc=Rc() - release.rc=rc - release.seriestype = Series.series.index("release") + rc = Rc() + release.rc = rc + release.seriestype = Series.series.index("release") if date: - if not isinstance(date,datetime): - raise TypeError('date is not of type datetime.') - release.date=date + if not isinstance(date, datetime): + raise TypeError('date is not of type datetime.') + release.date = date - if strict and release.date != self.date: - raise ValueError('Release date can not change as toNextRelease was invoked with strict=True') + if strict and release.date != self.date: + raise ValueError( + 'Release date can not change as toNextRelease was invoked with strict=True') - return release + return release def toNextSnapshot(self, date=None, strict=False): - logging.info('from %s toNextSnapshot' % self.longlowertype()) + logging.info('from %s toNextSnapshot' % self.longlowertype()) if self.seriestype < 0 or self.seriestype >= len(Series.series): - raise TypeError('toNextRelease called on an unknown series type.') - elif self.seriestype == Series.series.index("candidate"): - raise TypeError('Series of type candidate can not be the basis for a snapshot.') - if self.seriestype == Series.series.index("release"): - raise TypeError('Series of type release can not be the basis for a snapshot.') + raise TypeError('toNextRelease called on an unknown series type.') + elif self.seriestype == Series.series.index("candidate"): + raise TypeError( + 'Series of type candidate can not be the basis for a snapshot.') + if self.seriestype == Series.series.index("release"): + raise TypeError( + 'Series of type release can not be the basis for a snapshot.') # Only snapshots can be snapshots next. - snapshot=copy.deepcopy(self) - snapshot.seriestype = Series.series.index("snapshot") - snapshot.spin.increment() + snapshot = copy.deepcopy(self) + snapshot.seriestype = Series.series.index("snapshot") + snapshot.spin.increment() if date: - if not isinstance(date,datetime): - raise TypeError('date is not of type datetime.') - snapshot.date=date + if not isinstance(date, datetime): + raise TypeError('date is not of type datetime.') + snapshot.date = date - if strict and snapshot.date != self.date: - raise ValueError('Snapshot date can not change as toNextSnapshot was invoked with strict=True') + if strict and snapshot.date != self.date: + raise ValueError( + 'Snapshot date can not change as toNextSnapshot was invoked with strict=True') - return snapshot + return snapshot # toNext will take a 'key' as either a string representing the # Series.series type or the index of the Series.series type, e.g., @@ -151,221 +163,279 @@ class LinaroSeries(Series): def toNext(self, seriestype, date=None, strict=False): return self.dispatchnext[seriestype](date, strict) + def linaro_series_from_tag(tag=None): - series=series_from_tag(tag) - linaroseries=LinaroSeries(Series.series[series.seriestype], vendor="linaro", package=series.package ,date=series.date , spin=series.spin, rc=series.rc, strict=True ) + series = series_from_tag(tag) + linaroseries = LinaroSeries(Series.series[series.seriestype], vendor="linaro", + package=series.package, date=series.date, spin=series.spin, rc=series.rc, strict=True) return linaroseries # Helper function which creates a LinaroSeries from a properly formed branch name # input string. + + def linaroSeriesFromBranchname(branch=None): # Create a Series using the helper function and then populate a # LinaroSeries. TODO: There's probably a better way to do this such # as a SeriesFactory that is overridden. - series=series_from_branchname(branch) - linaroseries=LinaroSeries(Series.series[series.seriestype], vendor="linaro", package=series.package ,date=series.date , spin=series.spin, rc=series.rc, strict=True ) + series = series_from_branchname(branch) + linaroseries = LinaroSeries(Series.series[series.seriestype], vendor="linaro", + package=series.package, date=series.date, spin=series.spin, rc=series.rc, strict=True) return linaroseries + class TestLinaroSeries(unittest.TestCase): def test_candidate_to_candidate(self): - candidate=LinaroSeries("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - candidate2=candidate.toNextCandidate() - self.assertEqual(candidate2.branchname(), "releases/linaro-5.3-2016.05-1-rc2") - self.assertEqual(candidate2.seriestype, Series.series.index("candidate")) - self.assertEqual(candidate.date, candidate2.date) + candidate = LinaroSeries( + "candidate", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1", rc="1") + candidate2 = candidate.toNextCandidate() + self.assertEqual(candidate2.branchname(), + "releases/linaro-5.3-2016.05-1-rc2") + self.assertEqual(candidate2.seriestype, + Series.series.index("candidate")) + self.assertEqual(candidate.date, candidate2.date) - #TODO test date and strict=True + # TODO test date and strict=True def test_release_to_candidate(self): - # Test where spin is None and needs to be incremented. - release=LinaroSeries("release", package="GCC-5.3.1", date=datetime(2016,05,15)) - candidate=release.toNextCandidate() - self.assertEqual(candidate.branchname(), "releases/linaro-5.3-2016.05-1-rc1") - self.assertEqual(candidate.seriestype, Series.series.index("candidate")) - self.assertEqual(candidate.date, release.date) - - # Now test where spin is already non-zero. - release2=LinaroSeries("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - candidate2=release2.toNextCandidate() - self.assertEqual(candidate2.branchname(), "releases/linaro-5.3-2016.05-2-rc1") - self.assertEqual(candidate2.seriestype, Series.series.index("candidate")) - - #TODO test date and strict=True + # Test where spin is None and needs to be incremented. + release = LinaroSeries( + "release", package="GCC-5.3.1", date=datetime(2016, 05, 15)) + candidate = release.toNextCandidate() + self.assertEqual(candidate.branchname(), + "releases/linaro-5.3-2016.05-1-rc1") + self.assertEqual(candidate.seriestype, + Series.series.index("candidate")) + self.assertEqual(candidate.date, release.date) + + # Now test where spin is already non-zero. + release2 = LinaroSeries( + "release", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + candidate2 = release2.toNextCandidate() + self.assertEqual(candidate2.branchname(), + "releases/linaro-5.3-2016.05-2-rc1") + self.assertEqual(candidate2.seriestype, + Series.series.index("candidate")) + + # TODO test date and strict=True def test_snapshot_to_candidate(self): - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="6") - candidate=snapshot.toNextCandidate() - self.assertEqual(candidate.branchname(), "releases/linaro-5.3-2016.06-rc1") - self.assertEqual(candidate.seriestype, Series.series.index("candidate")) - self.assertNotEqual(candidate.date, snapshot.date) - # Verify that it's one month apart. - self.assertEqual(candidate.date, snapshot.date + relativedelta(months=1)) - - # Make sure that the default date increment is just one month. - candidate2=snapshot.toNextCandidate(strict=True) - self.assertEqual(candidate2.date, snapshot.date + relativedelta(months=1)) - - # whether strict=True or not. - candidate3=snapshot.toNextCandidate(strict=False) - self.assertEqual(candidate3.date, snapshot.date + relativedelta(months=1)) - - # If the user passed a date and strict=yes, make sure the increment is only one month. - candidate4=snapshot.toNextCandidate(date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) - plusonem=snapshot.date + relativedelta(months=1) - self.assertEqual(candidate4.date,plusonem) - - # Make sure the date can be set without error when strict is False - candidate5=snapshot.toNextCandidate(date=datetime.strptime("2016.07.15", "%Y.%m.%d"), strict=False) - self.assertEqual(candidate5.date, snapshot.date + relativedelta(months=2)) - - with self.assertRaises(ValueError): - # Attempting to increment the date when strict=True should raise an exception. - candidate6=snapshot.toNextCandidate(date=datetime.strptime("2016.07.15", "%Y.%m.%d"), strict=True) + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="6") + candidate = snapshot.toNextCandidate() + self.assertEqual(candidate.branchname(), + "releases/linaro-5.3-2016.06-rc1") + self.assertEqual(candidate.seriestype, + Series.series.index("candidate")) + self.assertNotEqual(candidate.date, snapshot.date) + # Verify that it's one month apart. + self.assertEqual(candidate.date, snapshot.date + + relativedelta(months=1)) + + # Make sure that the default date increment is just one month. + candidate2 = snapshot.toNextCandidate(strict=True) + self.assertEqual(candidate2.date, snapshot.date + + relativedelta(months=1)) + + # whether strict=True or not. + candidate3 = snapshot.toNextCandidate(strict=False) + self.assertEqual(candidate3.date, snapshot.date + + relativedelta(months=1)) + + # If the user passed a date and strict=yes, make sure the increment is + # only one month. + candidate4 = snapshot.toNextCandidate( + date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) + plusonem = snapshot.date + relativedelta(months=1) + self.assertEqual(candidate4.date, plusonem) + + # Make sure the date can be set without error when strict is False + candidate5 = snapshot.toNextCandidate( + date=datetime.strptime("2016.07.15", "%Y.%m.%d"), strict=False) + self.assertEqual(candidate5.date, snapshot.date + + relativedelta(months=2)) + + with self.assertRaises(ValueError): + # Attempting to increment the date when strict=True should raise an + # exception. + candidate6 = snapshot.toNextCandidate( + date=datetime.strptime("2016.07.15", "%Y.%m.%d"), strict=True) def test_unknown_to_candidate(self): - unknown=LinaroSeries("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - # Purposely override with an incorrect seriestype. - unknown.seriestype=99 - with self.assertRaises(IndexError): - candidate=unknown.toNextCandidate() + unknown = LinaroSeries( + "candidate", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1", rc="1") + # Purposely override with an incorrect seriestype. + unknown.seriestype = 99 + with self.assertRaises(IndexError): + candidate = unknown.toNextCandidate() def test_candidate_to_release(self): - candidate=LinaroSeries("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - release=candidate.toNextRelease() - self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-1") - self.assertEqual(release.seriestype, Series.series.index("release")) - self.assertEqual(candidate.date, release.date) - - release2=candidate.toNextRelease(strict=True) - self.assertEqual(release2.branchname(), "releases/linaro-5.3-2016.05-1") - self.assertEqual(release2.date, candidate.date) - - with self.assertRaises(ValueError): - # Attempting to increment the date when strict=True should raise an exception. - release3=candidate.toNextRelease(date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) - - # If strict=False and the date is changed, go ahead and change it. - release4=candidate.toNextRelease(date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=False) - self.assertEqual(release4.branchname(), "releases/linaro-5.3-2016.06-1") - self.assertNotEqual(release4.date, release.date) - - with self.assertRaises(TypeError): - release5=candidate.toNextRelease("2016.06", strict=False) + candidate = LinaroSeries( + "candidate", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1", rc="1") + release = candidate.toNextRelease() + self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-1") + self.assertEqual(release.seriestype, Series.series.index("release")) + self.assertEqual(candidate.date, release.date) + + release2 = candidate.toNextRelease(strict=True) + self.assertEqual(release2.branchname(), + "releases/linaro-5.3-2016.05-1") + self.assertEqual(release2.date, candidate.date) + + with self.assertRaises(ValueError): + # Attempting to increment the date when strict=True should raise an + # exception. + release3 = candidate.toNextRelease( + date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) + + # If strict=False and the date is changed, go ahead and change it. + release4 = candidate.toNextRelease( + date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=False) + self.assertEqual(release4.branchname(), + "releases/linaro-5.3-2016.06-1") + self.assertNotEqual(release4.date, release.date) + + with self.assertRaises(TypeError): + release5 = candidate.toNextRelease("2016.06", strict=False) def test_snapshot_to_release(self): - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="6") - with self.assertRaises(TypeError): - release=snapshot.toNextRelease() + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="6") + with self.assertRaises(TypeError): + release = snapshot.toNextRelease() def test_release_to_release(self): - release=LinaroSeries("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="6") - with self.assertRaises(TypeError): - release2=release.toNextRelease() + release = LinaroSeries( + "release", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="6") + with self.assertRaises(TypeError): + release2 = release.toNextRelease() def test_unknown_to_release(self): - unknown=LinaroSeries("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - # Purposely override with an incorrect seriestype. - unknown.seriestype=99 - with self.assertRaises(IndexError): - release=unknown.toNextRelease() + unknown = LinaroSeries( + "release", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + # Purposely override with an incorrect seriestype. + unknown.seriestype = 99 + with self.assertRaises(IndexError): + release = unknown.toNextRelease() def test_candidate_to_snapshot(self): - candidate=LinaroSeries("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - with self.assertRaises(TypeError): - snapshot=candidate.toNextSnapshot() - # This would/should be the case if this wasn't and invalid option. - # self.assertEqual(snapshot.seriestype, "snapshot") + candidate = LinaroSeries( + "candidate", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1", rc="1") + with self.assertRaises(TypeError): + snapshot = candidate.toNextSnapshot() + # This would/should be the case if this wasn't and invalid option. + # self.assertEqual(snapshot.seriestype, "snapshot") def test_release_to_snapshot(self): - release=LinaroSeries("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - with self.assertRaises(TypeError): - snapshot=release.toNextSnapshot() + release = LinaroSeries( + "release", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + with self.assertRaises(TypeError): + snapshot = release.toNextSnapshot() def test_snapshot_to_snapshot(self): - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="6") - snapshot2=snapshot.toNextSnapshot() - - self.assertEqual(snapshot2.branchname(), "snapshots/linaro-5.3-2016.05-7") - self.assertEqual(snapshot2.seriestype, Series.series.index("snapshot")) - self.assertEqual(snapshot.date, snapshot2.date) - - # Verify that the original hasn't changed. This verifies that a - # deepcopy is used on the toNext* functions. - self.assertEqual(snapshot.branchname(), "snapshots/linaro-5.3-2016.05-6") - - snapshot3=snapshot.toNextSnapshot(strict=True) - self.assertEqual(snapshot3.branchname(), "snapshots/linaro-5.3-2016.05-7") - self.assertEqual(snapshot3.seriestype, Series.series.index("snapshot")) - self.assertEqual(snapshot.date, snapshot3.date) - - with self.assertRaises(ValueError): - # Attempting to increment the date when strict=True should raise an exception. - snapshot4=snapshot.toNextSnapshot(date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) - - # If strict=False and the date is changed, go ahead and change it. - snapshot5=snapshot.toNextSnapshot(date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=False) - self.assertEqual(snapshot5.branchname(), "snapshots/linaro-5.3-2016.06-7") - self.assertNotEqual(snapshot5.date, snapshot.date) - - # Verify that a date as a string generates an exception. - with self.assertRaises(TypeError): - snapshot6=snapshot.toNextSnapshot("2016.06.15", strict=False) + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="6") + snapshot2 = snapshot.toNextSnapshot() + + self.assertEqual(snapshot2.branchname(), + "snapshots/linaro-5.3-2016.05-7") + self.assertEqual(snapshot2.seriestype, Series.series.index("snapshot")) + self.assertEqual(snapshot.date, snapshot2.date) + + # Verify that the original hasn't changed. This verifies that a + # deepcopy is used on the toNext* functions. + self.assertEqual(snapshot.branchname(), + "snapshots/linaro-5.3-2016.05-6") + + snapshot3 = snapshot.toNextSnapshot(strict=True) + self.assertEqual(snapshot3.branchname(), + "snapshots/linaro-5.3-2016.05-7") + self.assertEqual(snapshot3.seriestype, Series.series.index("snapshot")) + self.assertEqual(snapshot.date, snapshot3.date) + + with self.assertRaises(ValueError): + # Attempting to increment the date when strict=True should raise an + # exception. + snapshot4 = snapshot.toNextSnapshot( + date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=True) + + # If strict=False and the date is changed, go ahead and change it. + snapshot5 = snapshot.toNextSnapshot( + date=datetime.strptime("2016.06.15", "%Y.%m.%d"), strict=False) + self.assertEqual(snapshot5.branchname(), + "snapshots/linaro-5.3-2016.06-7") + self.assertNotEqual(snapshot5.date, snapshot.date) + + # Verify that a date as a string generates an exception. + with self.assertRaises(TypeError): + snapshot6 = snapshot.toNextSnapshot("2016.06.15", strict=False) def test_unknown_to_snapshot(self): - unknown=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - # Purposely override with an incorrect seriestype. - unknown.seriestype=99 - with self.assertRaises(IndexError): - snapshot=unknown.toNextSnapshot() + unknown = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + # Purposely override with an incorrect seriestype. + unknown.seriestype = 99 + with self.assertRaises(IndexError): + snapshot = unknown.toNextSnapshot() def test_snapshot_toNext(self): - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - self.assertEqual(snapshot.branchname(), "snapshots/linaro-5.3-2016.05-1") - - candidate=snapshot.toNext("candidate") - # A Snapshot -> Candidate traversal always results in spin being set to zero - # and the first release candidate being created. - self.assertEqual(candidate.branchname(), "releases/linaro-5.3-2016.06-rc1") - self.assertEqual(candidate.seriestype, Series.series.index("candidate")) - - # Make sure toNext works with 'index' as well as the type string. - candidate2=snapshot.toNext(Series.series.index("candidate")) - # A Snapshot -> Candidate traversal always results in spin being set to zero - # and the first release candidate being created. - self.assertEqual(candidate2.branchname(), "releases/linaro-5.3-2016.06-rc1") - self.assertEqual(candidate2.seriestype, Series.series.index("candidate")) - - with self.assertRaises(TypeError): - candidate=snapshot.toNext("release") - candidate=snapshot.toNext(Series.series.index("release")) + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + self.assertEqual(snapshot.branchname(), + "snapshots/linaro-5.3-2016.05-1") + + candidate = snapshot.toNext("candidate") + # A Snapshot -> Candidate traversal always results in spin being set to zero + # and the first release candidate being created. + self.assertEqual(candidate.branchname(), + "releases/linaro-5.3-2016.06-rc1") + self.assertEqual(candidate.seriestype, + Series.series.index("candidate")) + + # Make sure toNext works with 'index' as well as the type string. + candidate2 = snapshot.toNext(Series.series.index("candidate")) + # A Snapshot -> Candidate traversal always results in spin being set to zero + # and the first release candidate being created. + self.assertEqual(candidate2.branchname(), + "releases/linaro-5.3-2016.06-rc1") + self.assertEqual(candidate2.seriestype, + Series.series.index("candidate")) + + with self.assertRaises(TypeError): + candidate = snapshot.toNext("release") + candidate = snapshot.toNext(Series.series.index("release")) def test_toNext_incorrect_keys(self): - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - self.assertEqual(snapshot.branchname(), "snapshots/linaro-5.3-2016.05-1") - with self.assertRaises(KeyError): - candidate=snapshot.toNext("candidat") - candidate=snapshot.toNext("snapsho") - candidate=snapshot.toNext("releas") - candidate=snapshot.toNext(-1) - candidate=snapshot.toNext(len(Series.series)+1) - # Index out of range of the Series.series array. + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + self.assertEqual(snapshot.branchname(), + "snapshots/linaro-5.3-2016.05-1") + with self.assertRaises(KeyError): + candidate = snapshot.toNext("candidat") + candidate = snapshot.toNext("snapsho") + candidate = snapshot.toNext("releas") + candidate = snapshot.toNext(-1) + candidate = snapshot.toNext(len(Series.series) + 1) + # Index out of range of the Series.series array. # Test to see if the objects returned from the toNext* functions are # new instances and not references to the input Series. def test_toNextFOO_return_new_objects(self): - candidate=LinaroSeries("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - candidate2=candidate.toNext("candidate") - release=candidate.toNext("release") + candidate = LinaroSeries( + "candidate", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1", rc="1") + candidate2 = candidate.toNext("candidate") + release = candidate.toNext("release") + + self.assertIsNot(candidate, candidate2) + self.assertIsNot(candidate, release) - self.assertIsNot(candidate,candidate2) - self.assertIsNot(candidate,release) - - snapshot=LinaroSeries("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1") - snapshot2=snapshot.toNext("snapshot") - self.assertIsNot(snapshot,snapshot2) + snapshot = LinaroSeries( + "snapshot", package="GCC-5.3.1", date=datetime(2016, 05, 15), spin="1") + snapshot2 = snapshot.toNext("snapshot") + self.assertIsNot(snapshot, snapshot2) if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/rn/rngen.py b/linaropy/rn/rngen.py index 1818d3e..9119714 100644 --- a/linaropy/rn/rngen.py +++ b/linaropy/rn/rngen.py @@ -2,7 +2,8 @@ # vim: set tw=78 expandtab tabstop=4 shiftwidth=4 autoindent smartindent: import csv -import sys, getopt +import sys +import getopt reload(sys) sys.setdefaultencoding('utf8') @@ -37,14 +38,17 @@ from gccclone import GCCClone from ..rninput import finput + def get_gcc_version(gccclone): - dct= {} - (dct["major"],dct["minor"],dct["revision"]) = gccclone.get_base_version().split(".") - return dct + dct = {} + (dct["major"], dct["minor"], dct["revision"] + ) = gccclone.get_base_version().split(".") + return dct + def rngen(rn_series, gccclone, history): - trackseries=rn_series.track_series - nextseries=rn_series.next_series + trackseries = rn_series.track_series + nextseries = rn_series.next_series print "toNext: " + nextseries.branchname() print "toNext: " + format(nextseries, '%N/%d') @@ -52,48 +56,49 @@ def rngen(rn_series, gccclone, history): # TODO: What if 'track' is not a snapshot branch? To do this right we'd # probably have to preserve basedon information in the release notes # repository as a yaml file. - basedon='http://snapshots.linaro.org/components/toolchain/gcc-linaro/' - basedon=basedon + trackseries.get_dir() + basedon = 'http://snapshots.linaro.org/components/toolchain/gcc-linaro/' + basedon = basedon + trackseries.get_dir() print "basedon: " + basedon - basis_url=basedon + basis_url = basedon # print 'gccbaseversion is ' + gccclone.get_base_version() # dct= {} # (dct["major"],dct["minor"],dct["revision"]) = gccclone.get_base_version().split(".") # print 'fsf revision is ' + gccclone.get_fsf_revision() - ver=get_gcc_version(gccclone) + ver = get_gcc_version(gccclone) print 'gcc major ' + ver['major'] print 'gcc minor ' + ver['minor'] - fsf=gccclone.get_fsf_revision() + fsf = gccclone.get_fsf_revision() # The version numbering scheme changed with GCC 5. Now, every new release # has the major version incremented. Prior to version five the minor was # incremented per-release. # TODO: read stable and maintenance information from a config file. - if int(ver['major']) <= 4: - gcc_version_path= u'' + ver['major'] + '.' + ver['minor'] - stab_maint='Maintenance' + if int(ver['major']) <= 4: + gcc_version_path = u'' + ver['major'] + '.' + ver['minor'] + stab_maint = 'Maintenance' else: - gcc_version_path=ver['major'] - stab_maint='Stable' + gcc_version_path = ver['major'] + stab_maint = 'Stable' print "This is a %s RNSeries for GCC version %s" % (stab_maint, - gcc_version_path) + gcc_version_path) print "Using the following .csv file: " + history #month_year=format(nextseries, '%D') - month_year=nextseries.date + month_year = nextseries.date - outfile=u'GCC-' + ver['major'] + u'.' + ver['minor'] + u'-' + month_year.strftime("%Y.%m") + outfile = u'GCC-' + ver['major'] + u'.' + \ + ver['minor'] + u'-' + month_year.strftime("%Y.%m") # if spin != "": # outfile=outfile + u'-' + spin # # if rc != "": # outfile=outfile + u'-rc' + rc - outfile=outfile + str(nextseries.spin) + str(nextseries.rc) + outfile = outfile + str(nextseries.spin) + str(nextseries.rc) print "outfile: " + outfile with open(history, mode='r') as backports: @@ -101,20 +106,21 @@ def rngen(rn_series, gccclone, history): backports_content = backports.read() in_memory_backports = StringIO(backports_content) - backportsDict = csv.DictReader(in_memory_backports, fieldnames=['rev', 'fsf', 'linaro', 'summary', 'target', 'type', 'notes', 'backport', 'owner', 'author'], delimiter=',') - backports.close(); + backportsDict = csv.DictReader(in_memory_backports, fieldnames=[ + 'rev', 'fsf', 'linaro', 'summary', 'target', 'type', 'notes', 'backport', 'owner', 'author'], delimiter=',') + backports.close() + + release_type = nextseries.longuppertype() - release_type=nextseries.longuppertype() - - spin=str(nextseries.spin).strip('-') - rc=str(nextseries.rc).strip("-rc") + spin = str(nextseries.spin).strip('-') + rc = str(nextseries.rc).strip("-rc") - template_dir=rn_series.rn_template.workdir() - series_dir=rn_series.rn_series.workdir() + template_dir = rn_series.rn_template.workdir() + series_dir = rn_series.rn_series.workdir() # Verify that the basis url is actually valid, otherwise the release notes # will contain erroneous information. - url=urllib2 + url = urllib2 try: ret = urllib2.urlopen(basis_url) except url.URLError as e: @@ -122,45 +128,46 @@ def rngen(rn_series, gccclone, history): exit(1) # TODO verify that the basis_url is a valid url and warn if not. - basis=u'' - basis_ver=basis_url.strip("/") - basis_ver=basis_ver.rsplit("/",1)[1] + basis = u'' + basis_ver = basis_url.strip("/") + basis_ver = basis_ver.rsplit("/", 1)[1] if basis_url.find("releases") == 1: - basis="Linaro Release GCC " + basis_ver + basis = "Linaro Release GCC " + basis_ver elif basis_url.find("-rc") == 1: - basis="Linaro Release-Candidate GCC " + basis_ver + basis = "Linaro Release-Candidate GCC " + basis_ver else: - basis="Linaro Snapshot GCC " + basis_ver + basis = "Linaro Snapshot GCC " + basis_ver + + release_string = "Linaro GCC %s.%s-%s.%s %s" % (ver['major'], ver[ + 'minor'], month_year.strftime("%Y"), month_year.strftime("%m"), release_type) - release_string="Linaro GCC %s.%s-%s.%s %s" % (ver['major'],ver['minor'],month_year.strftime("%Y"), month_year.strftime("%m"),release_type) - print "The release notes for this %s will be generated based on: %s" % (release_string, basis) # Get ready to do the rendering of the jinja2 templates into .textile # format. # relative path to the README.textile templates. - src_readme_path=u'/components/toolchain/gcc-linaro/%s/README.textile' % gcc_version_path - bin_readme_path=u'/components/toolchain/binaries/README.textile' - + src_readme_path = u'/components/toolchain/gcc-linaro/%s/README.textile' % gcc_version_path + bin_readme_path = u'/components/toolchain/binaries/README.textile' + # absolute path to README.textile templates. - template_src_readme=template_dir + src_readme_path - template_bin_readme=template_dir + bin_readme_path + template_src_readme = template_dir + src_readme_path + template_bin_readme = template_dir + bin_readme_path # relative path to the README.textile.series templates. # Note, the src templates don't have an extends (.series) file. - src_extends_path=u'/components/toolchain/gcc-linaro/%s/README.textile' % gcc_version_path - bin_extends_path=u'/components/toolchain/binaries/README.textile.series' + src_extends_path = u'/components/toolchain/gcc-linaro/%s/README.textile' % gcc_version_path + bin_extends_path = u'/components/toolchain/binaries/README.textile.series' # absolute path to README.textile.series template overrides. These are # what are passed to the jinja2 rendering engine because they might # override the default templates with version specific information. - series_src_extends=series_dir + src_extends_path - series_bin_extends=series_dir + bin_extends_path + series_src_extends = series_dir + src_extends_path + series_bin_extends = series_dir + bin_extends_path # These are the README.textile files that exist in the series directory. - series_src_readme=series_dir + src_readme_path - series_bin_readme=series_dir + bin_readme_path + series_src_readme = series_dir + src_readme_path + series_bin_readme = series_dir + bin_readme_path # Copy the template README.textile over the series README.textile file # because the jinja2 engine will need access to the parent template. This @@ -170,12 +177,12 @@ def rngen(rn_series, gccclone, history): # After the script runs the *_series_template_path files are overwritten # with the generated README.textile files. - src_readme=series_src_readme - bin_readme=series_bin_readme - + src_readme = series_src_readme + bin_readme = series_bin_readme - # Setting lstrip_blocks=True lets us use indenting in jinja2 templates. - env = Environment(loader=FileSystemLoader(series_dir), lstrip_blocks=True, trim_blocks=True) + # Setting lstrip_blocks=True lets us use indenting in jinja2 templates. + env = Environment(loader=FileSystemLoader(series_dir), + lstrip_blocks=True, trim_blocks=True) # We need to use a custom wordwrap filter that doesn't line-break urls. env.filters['customwordwrap'] = do_customwordwrap @@ -187,7 +194,8 @@ def rngen(rn_series, gccclone, history): # Generate the toolchain GCC source archive release notes. source_textile_rendering = source_archive_template.render( backports=backportsDict, - GCC_base_version=ver['major'] + u'.' + ver['minor'] + u'.' + ver['revision'], + GCC_base_version=ver['major'] + u'.' + + ver['minor'] + u'.' + ver['revision'], FSF_rev=fsf, basis=basis, basis_url=basis_url, @@ -203,11 +211,11 @@ def rngen(rn_series, gccclone, history): source_textile_rendering = source_textile_rendering.encode('utf-8') - out_source=u'' + outfile - out_binary=u'Linaro-' + outfile + out_source = u'' + outfile + out_binary = u'Linaro-' + outfile try: - with open(out_source + u'.textile','w') as f: + with open(out_source + u'.textile', 'w') as f: f.write(source_textile_rendering) print 'Wrote textile rendering to file %s' % os.getcwd() + u'/' + out_source + u'.textile' except IOError as e: @@ -216,7 +224,7 @@ def rngen(rn_series, gccclone, history): source_html_rendering = textile.textile(source_textile_rendering) try: - with open(out_source + u'.html','w') as f: + with open(out_source + u'.html', 'w') as f: f.write(source_html_rendering) print 'Wrote html rendering to file %s' % os.getcwd() + u'/' + out_source + u'.html' except IOError as e: @@ -233,24 +241,24 @@ def rngen(rn_series, gccclone, history): minor=ver['minor'], stab_maint=stab_maint, snap_rc_release=release_type) - + binary_textile_rendering = binary_textile_rendering.encode('utf-8') try: - with open(out_binary + u'.textile','w') as f: + with open(out_binary + u'.textile', 'w') as f: f.write(binary_textile_rendering) print 'Wrote textile rendering to file %s' % os.getcwd() + u'/' + out_binary + u'.textile' except IOError as e: sys.exit('Error rendering textile binary archive release notes.') - + binary_html_rendering = textile.textile(binary_textile_rendering) - + try: - with open(out_binary + u'.html','w') as f: + with open(out_binary + u'.html', 'w') as f: f.write(binary_html_rendering) print 'Wrote html rendering to file %s' % os.getcwd() + u'/' + out_binary + u'.html' except IOError as e: sys.exit('Error rendering html release notes.') - + # Generate the binary toolchain announce message. announce_rendering = announce_template.render( announce='yes', @@ -264,29 +272,29 @@ def rngen(rn_series, gccclone, history): snap_rc_release=release_type) announce_rendering = announce_rendering.encode('utf-8') - announce_file=u'announce-' + out_binary + u'.txt' + announce_file = u'announce-' + out_binary + u'.txt' try: - with open(announce_file,'w') as f: + with open(announce_file, 'w') as f: f.write(announce_rendering) print 'Wrote text rendering to file %s' % os.getcwd() + u'/' + announce_file except IOError as e: sys.exit('Error rendering text announce message.') - # Copy the generated .textile file over the # readme_series_dir/README.textile template file. # WARNING: This must be done AFTER you generate the announce message # because it uses the same README.textile template as the textile rendered # release notes. - copyfile(out_binary + u'.textile' ,bin_readme) + copyfile(out_binary + u'.textile', bin_readme) print 'Wrote generated file ' + out_binary + u'.textile' + " to " + bin_readme # Copy the generated .textile file over the # readme_series_dir/README.textile template file. - copyfile(out_source + u'.textile' ,src_readme ) + copyfile(out_source + u'.textile', src_readme) print 'Wrote generated file ' + out_source + u'.textile' + " to " + src_readme rn_series.rn_series.add(bin_readme) rn_series.rn_series.add(src_readme) - rn_series.rn_series.commit("Generated Release Notes for %s." % nextseries.label()) + rn_series.rn_series.commit( + "Generated Release Notes for %s." % nextseries.label()) rn_series.rn_series.log(1) diff --git a/linaropy/rn/rnseries.py b/linaropy/rn/rnseries.py index 4b5a7ba..3b6769a 100644 --- a/linaropy/rn/rnseries.py +++ b/linaropy/rn/rnseries.py @@ -11,7 +11,7 @@ from ..git.clone import Clone from ..git.workdir import Workdir from ..series import Series from linaroseries import LinaroSeries -from linaroseries import linaroSeriesFromBranchname +from linaroseries import linaroSeriesFromBranchname from template import RNTemplate from ..rninput import yninput @@ -19,83 +19,86 @@ from ..rninput import yninput # Abstract base class for a release-notes series # Every RNSeries has a templateRN instance and a workdir. The template # instance is used for the base template. + + class RNSeries(object): - #rnremote=u'http://git.linaro.org/toolchain/release-notes.git' + # rnremote=u'http://git.linaro.org/toolchain/release-notes.git' # use ssh:// so that we can push to the remote. - rnremote=u'ssh://git@git.linaro.org/toolchain/release-notes.git' - _series='components/toolchain/binaries/README.textile.series' + rnremote = u'ssh://git@git.linaro.org/toolchain/release-notes.git' + _series = 'components/toolchain/binaries/README.textile.series' # @rnrepo - path to the existing releases notes repository if there is one. # If there isn't one a new one will be cloned. # @track_series - an instance of a LinaroSeries to track. # @next_series - an instance of a LinaroSeries that is the next series. + def __init__(self, proj, rnrepo=None, track_series=None, next_series=None, headless=False): - self.proj=proj - # Create the release-notes repository clone. The Clone constructor - # will throw an exception if proj is not a Proj. That is an - # unrecoverable error so don't catch it here. The Clone constructor - # will also throw and exception if rnrepo is not a string. - - if rnrepo: - logging.info('RNSeries() clone already exists. Using existing.') - self.rn_clone=Clone(proj, clonedir=rnrepo) - else: - self.rn_clone=Clone(proj, remote=RNSeries.rnremote) - - # TODO: Write a testcase that exposes this. + self.proj = proj + # Create the release-notes repository clone. The Clone constructor + # will throw an exception if proj is not a Proj. That is an + # unrecoverable error so don't catch it here. The Clone constructor + # will also throw and exception if rnrepo is not a string. + + if rnrepo: + logging.info('RNSeries() clone already exists. Using existing.') + self.rn_clone = Clone(proj, clonedir=rnrepo) + else: + self.rn_clone = Clone(proj, remote=RNSeries.rnremote) + + # TODO: Write a testcase that exposes this. if not track_series: - raise TypeError("Input variable track_series is required.") + raise TypeError("Input variable track_series is required.") - # TODO: Write a testcase that exposes this. - if not isinstance(track_series, LinaroSeries): - raise TypeError("Input variable track_series not of type Series.") + # TODO: Write a testcase that exposes this. + if not isinstance(track_series, LinaroSeries): + raise TypeError("Input variable track_series not of type Series.") - # TODO: Write a testcase that exposes this. + # TODO: Write a testcase that exposes this. if not next_series: - raise TypeError("Input variable next_series is required.") + raise TypeError("Input variable next_series is required.") - # TODO: Write a testcase that exposes this. - if not isinstance(next_series, LinaroSeries): - raise TypeError("Input variable next_series not of type Series.") + # TODO: Write a testcase that exposes this. + if not isinstance(next_series, LinaroSeries): + raise TypeError("Input variable next_series not of type Series.") - self.track_series=track_series - self.next_series=next_series + self.track_series = track_series + self.next_series = next_series # Default to None, as this is set in update_template_readmes - self.rn_template=None - self.rn_series=None + self.rn_template = None + self.rn_series = None def update_templ_readmes(self, headless=False): - """ + """ Prompt the user to update the Template README.textile files. - The first time this is called it creates the Template repository. + The first time this is called it creates the Template repository. - This must be called before update_rnseries_reamdes(). + This must be called before update_rnseries_reamdes(). - Parameters - ---------- - headless=False : bool + Parameters + ---------- + headless=False : bool Automatically decline to edit any of the README.textile files. - This is useful for automated testing. If headless==True then - the template readmes will not be updated. Only the template - repository will be created. - """ - templ_branchname=self.next_series.shorttype() - templ_branchname + templ_branchname + "_" + self.next_series.get_dir() - if not self.rn_template: - logging.info("Creating the RNTemplate instance.") - self.rn_template=RNTemplate( - self.proj, - self.rn_clone, - branchname_suffix=templ_branchname) + This is useful for automated testing. If headless==True then + the template readmes will not be updated. Only the template + repository will be created. + """ + templ_branchname = self.next_series.shorttype() + templ_branchname + templ_branchname + "_" + self.next_series.get_dir() + if not self.rn_template: + logging.info("Creating the RNTemplate instance.") + self.rn_template = RNTemplate( + self.proj, + self.rn_clone, + branchname_suffix=templ_branchname) logging.info( "Requesting updates to the TemplateReadme and series files.") - self.rn_template.update_readme(headless=headless) - self.rn_template.update_series(headless=headless) + self.rn_template.update_readme(headless=headless) + self.rn_template.update_series(headless=headless) - logging.info( + logging.info( "Commiting README.textile and README.textile.series files to" "template repository.") @@ -105,10 +108,10 @@ class RNSeries(object): """ Prompt the user to update the series README.textile.series file. - The first time this is called it creates the series workdir + The first time this is called it creates the series workdir repository. - The update_template_reamdes() function must be called before this + The update_template_reamdes() function must be called before this is called. Exceptions @@ -116,84 +119,87 @@ class RNSeries(object): RuntimeError Returned if update_template_readmes() hasn't been called yet. - Parameters - ---------- - headless=False : bool + Parameters + ---------- + headless=False : bool Automatically decline to edit any of the README.textile files. - This is useful for automated testing. If headless==True then - the template readmes will not be updated. Only the template - repository will be created. + This is useful for automated testing. If headless==True then + the template readmes will not be updated. Only the template + repository will be created. """ # The RNTemplate instance is necessary as we might need to derive # the SeriesRN from it. - if not self.rn_template: - raise RuntimeError( - "The rn_template doesn't yet exist. Call" - " update_template_readmes() first.") + if not self.rn_template: + raise RuntimeError( + "The rn_template doesn't yet exist. Call" + " update_template_readmes() first.") - remote_track=self.rn_clone.remote_branchname(self.track_series.branchname()) + remote_track = self.rn_clone.remote_branchname( + self.track_series.branchname()) if not self.rn_series: - print("Looking for branch %s" % self.track_series.branchname()) - # The workdir for the first candidate series will be derived from - # the changes made to the master branch templates. The workdir for - # subsequent candidates and releases will be made based on the - # existing candidate or release branch. - #if not self.rn_clone.branchexists(self.track_series.branchname()): - if not self.rn_clone.branchexists(remote_track): - logging.info( - "Creating RNSeries based on branch " - + self.rn_template.getbranch()) - - self.rn_series=Workdir( - proj=self.proj, + print("Looking for branch %s" % self.track_series.branchname()) + # The workdir for the first candidate series will be derived from + # the changes made to the master branch templates. The workdir for + # subsequent candidates and releases will be made based on the + # existing candidate or release branch. + # if not + # self.rn_clone.branchexists(self.track_series.branchname()): + if not self.rn_clone.branchexists(remote_track): + logging.info( + "Creating RNSeries based on branch " + + self.rn_template.getbranch()) + + self.rn_series = Workdir( + proj=self.proj, clone=self.rn_clone, workdir=self.next_series.shorttype(), track=self.rn_template.getbranch(), branchname=self.next_series.branchname()) - else: - logging.info( + else: + logging.info( "MARK Creating RNSeries based on branch " - + remote_track) - # + self.track_series.branchname()) + + remote_track) + # + self.track_series.branchname()) - self.rn_series=Workdir( + self.rn_series = Workdir( proj=self.proj, clone=self.rn_clone, workdir=self.next_series.shorttype(), track=remote_track, branchname=self.next_series.branchname()) - #track=self.track_series.branchname(), + # track=self.track_series.branchname(), - logging.warning( + logging.warning( "If you updated the template README.textile.series file" " the changes will not be reflected in this series" " README.textile.series as this series is derived from %s." " Please make the changes to the series" " README.textile.series file as well." % remote_track) - # self.track_series.branchname()) + # self.track_series.branchname()) - # TODO: Ask if the user would like to merge the changes in - # the template README.textile.series file instead of the + # TODO: Ask if the user would like to merge the changes in + # the template README.textile.series file instead of the # long-winded warning above. if not headless: - answer=yninput( + answer = yninput( "Would you like to update the %s README.textile.series" " file?" % self.next_series.longlowertype(), "N") - if answer == "y": - self.rn_series.edit(self._series) + if answer == "y": + self.rn_series.edit(self._series) return self.rn_series.commit( - "Added NEWS items for %s." % self.next_series.branchname()) + "Added NEWS items for %s." % self.next_series.branchname()) def push_readme_updates(self): pass # TODO: Don't forget to push template and workdir changes. - # self.rn_template.pushToBranch("origin/master") - # TODO: Should the workdir know where to push to? - # self.rn_series.pushToBranch(self.next_series.branchname()) + # self.rn_template.pushToBranch("origin/master") + # TODO: Should the workdir know where to push to? + # self.rn_series.pushToBranch(self.next_series.branchname()) + class TestSeriesRN(unittest.TestCase): pass diff --git a/linaropy/rn/template.py b/linaropy/rn/template.py index b5d0f59..dd6323c 100644 --- a/linaropy/rn/template.py +++ b/linaropy/rn/template.py @@ -10,95 +10,101 @@ from ..git.clone import Clone from ..git.workdir import Workdir from ..rninput import yninput + class RNTemplate(Workdir): - _readme='components/toolchain/binaries/README.textile' - _series='components/toolchain/binaries/README.textile.series' + _readme = 'components/toolchain/binaries/README.textile' + _series = 'components/toolchain/binaries/README.textile.series' def __init__(self, proj, rnclone, branchname_suffix=None): - if branchname_suffix: - branchname='template_' + branchname_suffix - else: - branchname='template_' + str(uuid.uuid4()) - super(RNTemplate, self).__init__(proj, rnclone, "template", track="origin/master", branchname=branchname) - # Todo move template workdir out of detached head state. + if branchname_suffix: + branchname = 'template_' + branchname_suffix + else: + branchname = 'template_' + str(uuid.uuid4()) + super(RNTemplate, self).__init__(proj, rnclone, "template", + track="origin/master", branchname=branchname) + # Todo move template workdir out of detached head state. # TODO: Allow the user to edit BOTH the gcc-linaro/ and binaries/ # README.textile file as currently this function only does the binary one. # TODO: Create Unit Test # TODO: test headless def update_readme(self, headless=False): - if headless: - return False + if headless: + return False - answer=yninput("Would you like to update the Template README.textile file?", "N") - if answer != "y": - print "The Template README.textile file has not been updated." - return False + answer = yninput( + "Would you like to update the Template README.textile file?", "N") + if answer != "y": + print "The Template README.textile file has not been updated." + return False - editor = os.getenv('EDITOR') - if not editor: - editor='/usr/bin/vim' - print "Edit the README.textile template fragment if changes are needed." - os.system(editor + ' ' + self.repodir + '/' + RNTemplate._readme) + editor = os.getenv('EDITOR') + if not editor: + editor = '/usr/bin/vim' + print "Edit the README.textile template fragment if changes are needed." + os.system(editor + ' ' + self.repodir + '/' + RNTemplate._readme) - self.add(RNTemplate._readme) - return True + self.add(RNTemplate._readme) + return True # TODO: Create Unit Test # TODO: test headless def update_series(self, headless=False): if headless: - return False + return False - answer=yninput("Would you like to update the Template README.textile.series file?", "N") - if answer != "y": - print "The Template README.textile.series file has not been updated." - return False + answer = yninput( + "Would you like to update the Template README.textile.series file?", "N") + if answer != "y": + print "The Template README.textile.series file has not been updated." + return False - editor = os.getenv('EDITOR') - if not editor: - editor='/usr/bin/vim' - print "Edit the README.textile.series template fragment if changes are needed." - os.system(editor + ' ' + self.repodir + '/' + RNTemplate._series) + editor = os.getenv('EDITOR') + if not editor: + editor = '/usr/bin/vim' + print "Edit the README.textile.series template fragment if changes are needed." + os.system(editor + ' ' + self.repodir + '/' + RNTemplate._series) - self.add(RNTemplate._series) - return True + self.add(RNTemplate._series) + return True # TODO: Do we need this? def get_readme(self): - return self.repodir + '/' + RNTemplate._readme + return self.repodir + '/' + RNTemplate._readme # TODO: Do we need this? def get_series(self): - return self.repodir + '/' + RNTemplate._series + return self.repodir + '/' + RNTemplate._series + class TestRNTemplate(unittest.TestCase): - testdirprefix="RNTemplateUT" + testdirprefix = "RNTemplateUT" # Every instance of TestClass requires its own proj directory. def setUp(self): - self.proj=Proj(prefix=TestRNTemplate.testdirprefix, persist=True) + self.proj = Proj(prefix=TestRNTemplate.testdirprefix, persist=True) def tearDown(self): - self.proj.cleanup() + self.proj.cleanup() def test_getREADME(self): - self.rnrepo=Clone(self.proj,remote=u'http://git.linaro.org/toolchain/release-notes.git') - self.rn_template=RNTemplate(self.proj,self.rnrepo) - compare=self.proj.projdir + '/template/' + RNTemplate._readme - self.assertEqual(self.rn_template.get_readme(),compare) - self.assertTrue(os.path.isfile(self.rn_template.get_readme())) + self.rnrepo = Clone( + self.proj, remote=u'http://git.linaro.org/toolchain/release-notes.git') + self.rn_template = RNTemplate(self.proj, self.rnrepo) + compare = self.proj.projdir + '/template/' + RNTemplate._readme + self.assertEqual(self.rn_template.get_readme(), compare) + self.assertTrue(os.path.isfile(self.rn_template.get_readme())) def test_getSERIES(self): - self.rnrepo=Clone(self.proj,remote=u'http://git.linaro.org/toolchain/release-notes.git') - self.rn_template=RNTemplate(self.proj,self.rnrepo) - compare=self.proj.projdir + '/template/' + RNTemplate._series - self.assertEqual(self.rn_template.get_series(),compare) - self.assertTrue(os.path.isfile(self.rn_template.get_series())) - + self.rnrepo = Clone( + self.proj, remote=u'http://git.linaro.org/toolchain/release-notes.git') + self.rn_template = RNTemplate(self.proj, self.rnrepo) + compare = self.proj.projdir + '/template/' + RNTemplate._series + self.assertEqual(self.rn_template.get_series(), compare) + self.assertTrue(os.path.isfile(self.rn_template.get_series())) # TODO: Test branchname_suffix if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/rninput.py b/linaropy/rninput.py index 86d3d90..d440a5b 100644 --- a/linaropy/rninput.py +++ b/linaropy/rninput.py @@ -6,30 +6,35 @@ import os.path # @accept - The list of valid responses. # @retry - Whether to retry on a malformed input. # Returns 'y' or 'no' + + def yninput(message, default="n", accept=['yes', 'y', 'no', 'n'], retry=True): # TODO: Test this if default.lower() not in accept: - raise TypeError('Default as %s is not in list of accepted responses.' % default) + raise TypeError( + 'Default as %s is not in list of accepted responses.' % default) - default_msg=" [y/N]: " + default_msg = " [y/N]: " if default.lower() == "y" or default.lower() == "yes": - default_msg=" [Y/n]: " + default_msg = " [Y/n]: " while(1): - answer=raw_input(message + default_msg) or default.lower() - if answer.lower() not in accept and retry: - print "'%s' is an invalid response. Please try again." % answer.lower() - continue + answer = raw_input(message + default_msg) or default.lower() + if answer.lower() not in accept and retry: + print "'%s' is an invalid response. Please try again." % answer.lower() + continue else: if answer.lower() == "yes" or answer.lower() == "y": - return "y" + return "y" return "n" # TODO: Test with a directory returned as the answer. -def finput(message,orval): + + +def finput(message, orval): while(1): - answer=raw_input(message) or orval - if os.path.exists(answer) and os.path.isfile(answer): - return answer + answer = raw_input(message) or orval + if os.path.exists(answer) and os.path.isfile(answer): + return answer - print "%s doesn't exist or isn't a regular file. Try again." % answer + print "%s doesn't exist or isn't a regular file. Try again." % answer diff --git a/linaropy/series.py b/linaropy/series.py index 93452d9..ca0a11b 100644 --- a/linaropy/series.py +++ b/linaropy/series.py @@ -36,110 +36,111 @@ class Series(object): # This will make sure snapshot doesn't have an rc and release doesn't have # an rc for instance. def __init__(self, seriestype, vendor=None, package=None, date=datetime.today(), spin=None, rc=None, strict=True): - """ - Create a Series to store the details on a package release, snapshot, - or release-candidate. + """ + Create a Series to store the details on a package release, snapshot, + or release-candidate. - Parameters - ---------- - seriestype : str + Parameters + ---------- + seriestype : str "candidate", "release", or "snapshot" - vendor : str - A String representing the vendor for the series. The default is - inherited from the Vendor class. + vendor : str + A String representing the vendor for the series. The default is + inherited from the Vendor class. - package : str or Package - Designate the package that this Series represents, for example, - 'gcc'. The default is inherited from the Package class. + package : str or Package + Designate the package that this Series represents, for example, + 'gcc'. The default is inherited from the Package class. - date : str or datetime - "YYYY.MM", "YY.MM", or a datetime object representing the Series. + date : str or datetime + "YYYY.MM", "YY.MM", or a datetime object representing the Series. - spin : Spin - A spin number for the Series. + spin : Spin + A spin number for the Series. - rc : Rc - An rc number for the Series. + rc : Rc + An rc number for the Series. - strict=True : bool - Enforce rules regarding whether candidates can/cannot have Rcs. - """ + strict=True : bool + Enforce rules regarding whether candidates can/cannot have Rcs. + """ if isinstance(spin, Spin): - self.spin=spin + self.spin = spin else: - # Spin will raise an exception if spin is the wrong type. - # A None parameter will create a Spin with an internal value of None. - self.spin=Spin(spin) + # Spin will raise an exception if spin is the wrong type. + # A None parameter will create a Spin with an internal value of + # None. + self.spin = Spin(spin) if isinstance(rc, Rc): - self.rc=rc + self.rc = rc else: - # Rc will raise an exception if rc is the wrong type. A None parameter - # will create an Rc with an internal value of None. - self.rc=Rc(rc) - - if isinstance(date, datetime): - # Force all of the days of the month to 15 to unify comparisons. - date.replace(day=15) - self.date=date + # Rc will raise an exception if rc is the wrong type. A None parameter + # will create an Rc with an internal value of None. + self.rc = Rc(rc) + + if isinstance(date, datetime): + # Force all of the days of the month to 15 to unify comparisons. + date.replace(day=15) + self.date = date else: - # 'date' is a string. If the input date can't be parsed by datetime - # it will throw an exception. We can't recover from it so just pass - # it up. - if len(date) < 10: - tmpdate=datetime.strptime(date, "%Y.%m") - else: - tmpdate=datetime.strptime(date, "%Y.%m.%d") - # Force all of the days of the month to 15 to unify comparisons. - self.date=tmpdate.replace(day=15) - - # If the input vendor=None just instantiate the default vendor. + # 'date' is a string. If the input date can't be parsed by datetime + # it will throw an exception. We can't recover from it so just pass + # it up. + if len(date) < 10: + tmpdate = datetime.strptime(date, "%Y.%m") + else: + tmpdate = datetime.strptime(date, "%Y.%m.%d") + # Force all of the days of the month to 15 to unify comparisons. + self.date = tmpdate.replace(day=15) + + # If the input vendor=None just instantiate the default vendor. if not vendor: - self.vendor=Vendor() - else: - self.vendor=vendor + self.vendor = Vendor() + else: + self.vendor = vendor if not package: - raise TypeError('Series requires an input package.') + raise TypeError('Series requires an input package.') elif isinstance(package, Package): - self.package=package + self.package = package elif isinstance(package, basestring): - self.package=packageFromStr(package) - else: - # There can't be a defaut package because it requires a version. - raise TypeError("Series 'package' unrecognized type " + str(type(package))) + self.package = packageFromStr(package) + else: + # There can't be a defaut package because it requires a version. + raise TypeError( + "Series 'package' unrecognized type " + str(type(package))) - # We might want to uniquely identify a particular Series object. - self.uniqueid=str(uuid.uuid4()) + # We might want to uniquely identify a particular Series object. + self.uniqueid = str(uuid.uuid4()) # We store a seriestype as an integer into an enumeration array - # so that the names can be changed as desired. + # so that the names can be changed as desired. try: - self.seriestype = Series.series.index(seriestype.lower()) - except ValueError: - self.seriestype = -1 # no match - raise TypeError('Invalid series type %s.' % seriestype) - - # rc can only be non-None for release-candidates. - if strict: - if self.seriestype == Series.series.index("snapshot"): - if self.rc.val != 0: - raise ValueError('A snapshot series cannot have an rc.') - elif self.seriestype == Series.series.index("release"): - if self.rc.val != 0: - raise ValueError('A release series cannot have an rc.') - - - if self.seriestype == Series.series.index("candidate") and self.rc.val is 0: - raise TypeError('A candidate series must have an rc specified.') + self.seriestype = Series.series.index(seriestype.lower()) + except ValueError: + self.seriestype = -1 # no match + raise TypeError('Invalid series type %s.' % seriestype) + + # rc can only be non-None for release-candidates. + if strict: + if self.seriestype == Series.series.index("snapshot"): + if self.rc.val != 0: + raise ValueError('A snapshot series cannot have an rc.') + elif self.seriestype == Series.series.index("release"): + if self.rc.val != 0: + raise ValueError('A release series cannot have an rc.') + + if self.seriestype == Series.series.index("candidate") and self.rc.val is 0: + raise TypeError('A candidate series must have an rc specified.') # We need an OrderedDict because we want to parse/capture -%X and .%X # before %X and a regular dict won't guarantee that iterkeys returns in # the inserted order.. This dict starts out empty and we'll populate it # in the same way we will udpate it later. This is used for the # __format__ function for quick formatting. - self.fmt=OrderedDict() + self.fmt = OrderedDict() self.fmt['%N'] = None self.fmt['-%L'] = None self.fmt['.%L'] = None @@ -154,8 +155,8 @@ class Series(object): self.fmt['%m'] = None self.fmt['%p'] = None self.fmt['%D'] = None - self.fmt['%h'] = None - self.fmt['%d'] = None + self.fmt['%h'] = None + self.fmt['%d'] = None # Match and strip the key '-' as Spin might be empty. self.fmt['-%S'] = None # Match and strip the key '.' as Spin might be empty. @@ -168,7 +169,7 @@ class Series(object): self.fmt['%R'] = None # Fill in the values. - for key in self.fmt.iterkeys(): + for key in self.fmt.iterkeys(): self.update_fmtdict(key) def update_fmtdict(self, key): @@ -180,7 +181,7 @@ class Series(object): elif key == '.%L': # Only prepend '.' if there's actually a series label. label = self.serieslabel() - self.fmt['.%L'] = string.replace(label,'-','.') + self.fmt['.%L'] = string.replace(label, '-', '.') return elif key == '%L': self.fmt['%L'] = self.serieslabel().strip('-') @@ -206,29 +207,29 @@ class Series(object): elif key == '%D': self.fmt['%D'] = self.date.strftime("%Y.%m") elif key == '%h': - self.fmt['%h'] = self.get_server() + self.fmt['%h'] = self.get_server() elif key == '%d': - self.fmt['%d'] = self.get_dir() + self.fmt['%d'] = self.get_dir() elif key == '-%S': # This will include the '-' if present. self.fmt['-%S'] = str(self.spin) elif key == '.%S': - spin=str(self.spin) - self.fmt['.%S'] = string.replace(spin,'-','.') + spin = str(self.spin) + self.fmt['.%S'] = string.replace(spin, '-', '.') elif key == '%S': self.fmt['%S'] = str(self.spin).strip('-') elif key == '-%R': # This will include the '-' is present. self.fmt['-%R'] = str(self.rc) elif key == '.%R': - rc=str(self.rc) - self.fmt['.%R'] = string.replace(rc,'-','.') + rc = str(self.rc) + self.fmt['.%R'] = string.replace(rc, '-', '.') elif key == '%R': self.fmt['%R'] = str(self.rc).strip('-') else: raise KeyError('Unknown format key.') - def __format__(self,format_spec): + def __format__(self, format_spec): """ Format an output string based on format spec. @@ -239,9 +240,9 @@ class Series(object): "%V released this product" This would be formatted as "Linaro released this product" - + call using: - + formattedstr=format(series_instance, 'string_with_delimiters') delimiters @@ -257,7 +258,7 @@ class Series(object): Note: This is special. If -%L or .%L is in the format_spec and there is no series label (for release and candidates) then the leading '-' or '.' will be stripped as well. - + %P : package name %l : lowercase package name @@ -291,71 +292,72 @@ class Series(object): Note: This is special. If -%S or .%S is in the format_spec and there is no Spin then the leading '-' or '.' will be stripped as well. - + %R : Rc number Note: This is special. If -%R or .%R is in the format_spec and there is no Rc then the leading '-' or '.' will be stripped as well. """ - ret='' - # Iterate across the dictionary and for each key found replace the key + ret = '' + # Iterate across the dictionary and for each key found replace the key # with the contents of the fmt dictionary. - ret=format_spec - for key in self.fmt.iterkeys(): + ret = format_spec + for key in self.fmt.iterkeys(): if key in ret: # Update the relevant keys everytime through because the user # might have changed things. self.update_fmtdict(key) - replac=self.fmt[key] - ret=string.replace(ret,key,replac) - return ret + replac = self.fmt[key] + ret = string.replace(ret, key, replac) + return ret def serieslabel(self): - # Only the 'snapshot-' is used in a label. - if self.seriestype == Series.series.index("snapshot"): - return u'-' + Series.series[self.seriestype] + # Only the 'snapshot-' is used in a label. + if self.seriestype == Series.series.index("snapshot"): + return u'-' + Series.series[self.seriestype] else: - return u'' + return u'' def shorttype(self): - return Series.series[self.seriestype] + return Series.series[self.seriestype] def longlowertype(self): - return Series.serieslongupper[self.seriestype].lower() + return Series.serieslongupper[self.seriestype].lower() def longuppertype(self): - return Series.serieslongupper[self.seriestype] + return Series.serieslongupper[self.seriestype] def __str__(self): - return Series.series[self.seriestype] + "_" + self.uniqueid + return Series.series[self.seriestype] + "_" + self.uniqueid def label(self): - label=str(self.vendor) + self.serieslabel() + u'-' + str(self.package) - label=label + u'-' + self.date.strftime("%Y.%m") - label=label + str(self.spin) + str(self.rc) - return label + label = str(self.vendor) + self.serieslabel() + \ + u'-' + str(self.package) + label = label + u'-' + self.date.strftime("%Y.%m") + label = label + str(self.spin) + str(self.rc) + return label def incrementMonth(self): - self.date = self.date + relativedelta(months=1) + self.date = self.date + relativedelta(months=1) def get_dir(self): - dirstr=self.package.version.strfversion("%M%m") - dirstr=dirstr + u'-' + self.date.strftime("%Y.%m") - dirstr=dirstr + str(self.spin) - dirstr=dirstr + str(self.rc) - return dirstr + dirstr = self.package.version.strfversion("%M%m") + dirstr = dirstr + u'-' + self.date.strftime("%Y.%m") + dirstr = dirstr + str(self.spin) + dirstr = dirstr + str(self.rc) + return dirstr def get_server(self): - namespace=u'snapshots' - if self.seriestype == Series.series.index("release"): - namespace=u'releases' - return namespace + namespace = u'snapshots' + if self.seriestype == Series.series.index("release"): + namespace = u'releases' + return namespace def get_namespace(self): - namespace=u'releases' - if self.seriestype == Series.series.index("snapshot"): - namespace=u'snapshots' - return namespace + namespace = u'releases' + if self.seriestype == Series.series.index("snapshot"): + namespace = u'snapshots' + return namespace # TODO: Document what a conformant branch name looks like. # Return a conformant branch name from the Series information. @@ -369,19 +371,21 @@ class Series(object): ------------ string represensting the branch name. """ - branchname=u'' - if self.seriestype == Series.series.index("snapshot"): - branchname=branchname + u'snapshots/' - else: - branchname=branchname + u'releases/' + branchname = u'' + if self.seriestype == Series.series.index("snapshot"): + branchname = branchname + u'snapshots/' + else: + branchname = branchname + u'releases/' - branchname=branchname + self.vendor.lower() - branchname=branchname + u'-' + self.package.version.strfversion("%M%m") - branchname=branchname + u'-' + self.date.strftime("%Y.%m") - branchname=branchname + str(self.spin) - branchname=branchname + str(self.rc) + branchname = branchname + self.vendor.lower() + branchname = branchname + u'-' + \ + self.package.version.strfversion("%M%m") + branchname = branchname + u'-' + self.date.strftime("%Y.%m") + branchname = branchname + str(self.spin) + branchname = branchname + str(self.rc) + + return branchname - return branchname def series_from_branchname(branch=None): """ @@ -392,114 +396,124 @@ def series_from_branchname(branch=None): branch : str The branchname of a package as it lives in a git repository. A properly formed - branch name has the following elements, where options in brackets are optional: + branch name has the following elements, where options in brackets are optional: - <namespace>/<package-version>-<YYYY>.<MM>[-spin][-rcN] + <namespace>/<package-version>-<YYYY>.<MM>[-spin][-rcN] - Snapshot - -------- - snapshots/<foo>[!-rcN] + Snapshot + -------- + snapshots/<foo>[!-rcN] - Candidate - --------- - releases/<foo>-rcN + Candidate + --------- + releases/<foo>-rcN - Release - ------- - releases/<foo>[!-rcN] + Release + ------- + releases/<foo>[!-rcN] """ logging.info("Branch is %s." % branch) if not isinstance(branch, basestring): - raise TypeError('series_from_branchname requires a basestring as input') + raise TypeError( + 'series_from_branchname requires a basestring as input') if not branch: - raise TypeError('series_from_branchname requires a non-empty string as input') + raise TypeError( + 'series_from_branchname requires a non-empty string as input') # Get the part before the '/'. That's the namespace try: - namespace=branch.rsplit('/', 1)[0] + namespace = branch.rsplit('/', 1)[0] except IndexError: - raise ValueError('string must have a namespace, e.g., <namespace>/<everything_else>') + raise ValueError( + 'string must have a namespace, e.g., <namespace>/<everything_else>') # Get everything after the '/'. try: - seriesstr=branch.rsplit('/', 1)[1] + seriesstr = branch.rsplit('/', 1)[1] except IndexError: - raise ValueError( + raise ValueError( "string must delimit the namespace from the right branch with a" " '/' char, e.g., <namespace>/<vendor>-<package_version>") # TODO: Are these necessary or did the previous cases cover it? - #if namespace == u'': + # if namespace == u'': # raise ValueError("Couldn't parse a namespace from input string") # This will catch where there's a namespace/ but no right hand value after # the /. if seriesstr == u'': - raise ValueError("Couldn't parse a series from input string. Missing a branch name.") + raise ValueError( + "Couldn't parse a series from input string. Missing a branch name.") - keys=['vendor', 'version', 'date', 'spin', 'rc'] + keys = ['vendor', 'version', 'date', 'spin', 'rc'] # This might generate key errors, depending on whether anything can be # parsed from the right-hand values. - values=seriesstr.split('-') - dictionary=dict(zip(keys, values)) + values = seriesstr.split('-') + dictionary = dict(zip(keys, values)) # if there is no spin but there is an 'rcX' in the spin key:value pair # it means that there's really no spin but should be in the rc key:value # pair. if dictionary.has_key("spin") and "rc" in dictionary["spin"]: - dictionary["rc"]=dictionary["spin"] - dictionary.pop("spin", None) + dictionary["rc"] = dictionary["spin"] + dictionary.pop("spin", None) # We need to have None fields in the missing keys for when we call the # Series constructor. if not dictionary.has_key("rc"): - dictionary["rc"]=None + dictionary["rc"] = None else: - # strip the "rc" and just leave the int. + # strip the "rc" and just leave the int. if dictionary["rc"].startswith("rc"): try: - dictionary["rc"]=int(dictionary["rc"][2:]) + dictionary["rc"] = int(dictionary["rc"][2:]) except ValueError: - raise TypeError("The rc value must be an integer.") + raise TypeError("The rc value must be an integer.") # We need to have None fields in the missing keys for when we call the # Series constructor. if not dictionary.has_key("spin"): - dictionary["spin"]=None + dictionary["spin"] = None else: - if not dictionary["spin"].isnumeric(): - raise TypeError("The spin must be numeric.") + if not dictionary["spin"].isnumeric(): + raise TypeError("The spin must be numeric.") - seriesdate=datetime.today + seriesdate = datetime.today if dictionary["date"]: - datekeys=['year', 'month', 'day'] - datevalues=dictionary["date"].split('.') - datefields=dict(zip(datekeys, datevalues)) - if not datefields.has_key("day"): - datefields["day"]="15" - seriesdate=datetime(int(datefields["year"]), int(datefields["month"]), int(datefields["day"])) + datekeys = ['year', 'month', 'day'] + datevalues = dictionary["date"].split('.') + datefields = dict(zip(datekeys, datevalues)) + if not datefields.has_key("day"): + datefields["day"] = "15" + seriesdate = datetime(int(datefields["year"]), int( + datefields["month"]), int(datefields["day"])) if "snapshots" in namespace and dictionary["rc"]: - raise ValueError('A snapshots namespace can not have an rc. This is a non-conforming input.') + raise ValueError( + 'A snapshots namespace can not have an rc. This is a non-conforming input.') elif "releases" not in namespace and dictionary["rc"]: - raise ValueError('An rc must have a "releases" namespace. This is a non-conforming input.') + raise ValueError( + 'An rc must have a "releases" namespace. This is a non-conforming input.') elif dictionary["rc"]: - seriesname="candidate" + seriesname = "candidate" elif "snapshots" in namespace: - seriesname="snapshot" + seriesname = "snapshot" elif "releases" in namespace: - seriesname="release" + seriesname = "release" elif "snapshot" in namespace: - raise ValueError('"snapshot" is not a complete namespace. The conforming namespace is "snapshots".') + raise ValueError( + '"snapshot" is not a complete namespace. The conforming namespace is "snapshots".') else: # TODO test for unknown namespace. raise ValueError('Unknown namespace in input string.') - package=Package(package="GCC", version=dictionary["version"]) - series=Series(seriesname, package=package, date=seriesdate, spin=dictionary["spin"], rc=dictionary["rc"], strict=True) + package = Package(package="GCC", version=dictionary["version"]) + series = Series(seriesname, package=package, date=seriesdate, spin=dictionary[ + "spin"], rc=dictionary["rc"], strict=True) return series + def series_from_tag(tag=None): """ Create a Series from a git tag name @@ -511,519 +525,544 @@ def series_from_tag(tag=None): The git tag of a package as it lives in a git repository. A properly formed tag will take the following form: - Snapshot - -------- - linaro-snapshot-Maj.min-YYYY.MM[-spin] + Snapshot + -------- + linaro-snapshot-Maj.min-YYYY.MM[-spin] - Candidate - --------- - linaro-Maj.min-YYYY.MM[-spin]-rcN + Candidate + --------- + linaro-Maj.min-YYYY.MM[-spin]-rcN - Release - ------- - linaro-Maj.min-YYYY.MM[-spin] + Release + ------- + linaro-Maj.min-YYYY.MM[-spin] """ # TODO Test this. if not tag: - raise ValueError('series_from_tag requires a tag') + raise ValueError('series_from_tag requires a tag') # TODO Test this. if not isinstance(tag, basestring): - raise TypeError('series_from_tag requires a basestring as input') + raise TypeError('series_from_tag requires a basestring as input') # This is default, we'll replace with 'snapshots' if we detect that the # tag is indeed a snapshot. - namespace="releases" + namespace = "releases" # since 'snapshots' tags aren't the same as release and rc tags we need # to force conformance, i.e., remove "-snapshot", but record the # namespace as snapshots while we're at it. if "snapshot" in tag: - tag=string.replace(tag,"-snapshot",'') - namespace="snapshots" + tag = string.replace(tag, "-snapshot", '') + namespace = "snapshots" # Now we're going to cheat and fabricate a false branchname. - branchname=namespace + '/' + tag + branchname = namespace + '/' + tag # ... in which case we can reuse this function. return series_from_branchname(branchname) from vers import versionFromStr + class TestSeries(unittest.TestCase): """Test the Series class using the unittest framework.""" + def test_missing_seriestype(self): - with self.assertRaises(TypeError): - spin=Spin() - rc=Rc() - candidate=Series(package="GCC-5.3.1", spin=spin, rc=rc) + with self.assertRaises(TypeError): + spin = Spin() + rc = Rc() + candidate = Series(package="GCC-5.3.1", spin=spin, rc=rc) def test_no_match(self): - with self.assertRaises(TypeError): - candidate=Series("foobar", package="GCC-5.3.1") + with self.assertRaises(TypeError): + candidate = Series("foobar", package="GCC-5.3.1") def test_partial_seriestype_match(self): - with self.assertRaises(TypeError): - candidate=Series("candid", package="GCC-5.3.1") + with self.assertRaises(TypeError): + candidate = Series("candid", package="GCC-5.3.1") def test_excessive_seriestype_match(self): - with self.assertRaises(TypeError): - candidate=Series("candidate2", package="GCC-5.3.1") + with self.assertRaises(TypeError): + candidate = Series("candidate2", package="GCC-5.3.1") def test_match_release(self): - release=Series("release", package="GCC-5.3.1") - self.assertEqual(str(release).split("_")[0], "release") + release = Series("release", package="GCC-5.3.1") + self.assertEqual(str(release).split("_")[0], "release") def test_match_candidate_wrongcase(self): - candidate=Series("Candidate", package="GCC-5.3.1",rc="1") - self.assertEqual(str(candidate).split("_")[0], "candidate") + candidate = Series("Candidate", package="GCC-5.3.1", rc="1") + self.assertEqual(str(candidate).split("_")[0], "candidate") def test_match_snapshot_wrongcase(self): - snapshot=Series("SNAPSHOT", package="GCC-5.3.1") - self.assertEqual(str(snapshot).split("_")[0], "snapshot") + snapshot = Series("SNAPSHOT", package="GCC-5.3.1") + self.assertEqual(str(snapshot).split("_")[0], "snapshot") def test_longlowertype_candidate(self): - candidate=Series("candidate", package="GCC-5.3.1", rc="1") - self.assertEqual(candidate.longlowertype(), "release-candidate") + candidate = Series("candidate", package="GCC-5.3.1", rc="1") + self.assertEqual(candidate.longlowertype(), "release-candidate") def test_longuppertype_candidate(self): - candidate=Series("candidate", package="GCC-5.3.1", rc="4") - self.assertEqual(candidate.longuppertype(), "Release-Candidate") + candidate = Series("candidate", package="GCC-5.3.1", rc="4") + self.assertEqual(candidate.longuppertype(), "Release-Candidate") def test_shorttype_candidate(self): - candidate=Series("candidate", package="GCC-5.3.1", rc="1") - self.assertEqual(candidate.shorttype(), "candidate") + candidate = Series("candidate", package="GCC-5.3.1", rc="1") + self.assertEqual(candidate.shorttype(), "candidate") def test_serieslabel_candidate(self): - candidate=Series("candidate", package="GCC-5.3.1", rc="1") - self.assertEqual(candidate.serieslabel(), "") + candidate = Series("candidate", package="GCC-5.3.1", rc="1") + self.assertEqual(candidate.serieslabel(), "") def test_serieslabel_release(self): - candidate=Series("release", package="GCC-5.3.1") - self.assertEqual(candidate.serieslabel(), "") + candidate = Series("release", package="GCC-5.3.1") + self.assertEqual(candidate.serieslabel(), "") def test_serieslabel_snapshot(self): - candidate=Series("snapshot", package="GCC-5.3.1") - self.assertEqual(candidate.serieslabel(), "-snapshot") + candidate = Series("snapshot", package="GCC-5.3.1") + self.assertEqual(candidate.serieslabel(), "-snapshot") def test_empty_rc(self): - rc=Rc(7) - candidate=Series("candidate", package="GCC-5.3.1", rc=rc) - self.assertEqual(candidate.rc.vers, 7) - self.assertEqual(str(candidate.rc), "FOO") + rc = Rc(7) + candidate = Series("candidate", package="GCC-5.3.1", rc=rc) + self.assertEqual(candidate.rc.vers, 7) + self.assertEqual(str(candidate.rc), "FOO") def test_empty_rc(self): - rc=Rc() - release=Series("release", package="GCC-5.3.1", rc=rc) - self.assertEqual(str(release.rc), "") + rc = Rc() + release = Series("release", package="GCC-5.3.1", rc=rc) + self.assertEqual(str(release.rc), "") - release2=Series("release", package="GCC-5.3.1") - self.assertEqual(str(release2.rc), "") + release2 = Series("release", package="GCC-5.3.1") + self.assertEqual(str(release2.rc), "") def test_specified_rc(self): - rc=Rc(7) - candidate=Series("candidate", package="GCC-5.3.1", rc=rc) - self.assertEqual(candidate.rc.val, 7) - self.assertEqual(str(candidate.rc), "-rc7") + rc = Rc(7) + candidate = Series("candidate", package="GCC-5.3.1", rc=rc) + self.assertEqual(candidate.rc.val, 7) + self.assertEqual(str(candidate.rc), "-rc7") def test_candidate_with_no_rc(self): - with self.assertRaises(TypeError): - candidate=Series("candidate", package="GCC-5.3.1") + with self.assertRaises(TypeError): + candidate = Series("candidate", package="GCC-5.3.1") - with self.assertRaises(TypeError): - rc=Rc() - candidate2=Series("candidate", package="GCC-5.3.1", rc=rc) + with self.assertRaises(TypeError): + rc = Rc() + candidate2 = Series("candidate", package="GCC-5.3.1", rc=rc) def test_rc_as_string(self): - candidate=Series("candidate", package="GCC-5.3.1", rc="7") - self.assertEqual(candidate.rc.val, 7) - self.assertEqual(str(candidate.rc), "-rc7") + candidate = Series("candidate", package="GCC-5.3.1", rc="7") + self.assertEqual(candidate.rc.val, 7) + self.assertEqual(str(candidate.rc), "-rc7") def test_rc_as_int(self): - candidate=Series("candidate", package="GCC-5.3.1", rc=7) - self.assertEqual(candidate.rc.val, 7) - self.assertEqual(str(candidate.rc), "-rc7") + candidate = Series("candidate", package="GCC-5.3.1", rc=7) + self.assertEqual(candidate.rc.val, 7) + self.assertEqual(str(candidate.rc), "-rc7") def test_rc_as_typeerror(self): - floatrc=7.0 - with self.assertRaises(TypeError): - snapshot=Series("snapshot", package="GCC-5.3.1", rc=floatrc) + floatrc = 7.0 + with self.assertRaises(TypeError): + snapshot = Series("snapshot", package="GCC-5.3.1", rc=floatrc) def test_rc_as_negative(self): - with self.assertRaises(ValueError): - snapshot=Series("snapshot", package="GCC-5.3.1", rc="-1") + with self.assertRaises(ValueError): + snapshot = Series("snapshot", package="GCC-5.3.1", rc="-1") def test_missing_spin(self): - snapshot=Series("snapshot", package="GCC-5.3.1") - self.assertEqual(snapshot.spin.val, 0) - self.assertEqual(str(snapshot.spin), "") + snapshot = Series("snapshot", package="GCC-5.3.1") + self.assertEqual(snapshot.spin.val, 0) + self.assertEqual(str(snapshot.spin), "") def test_specified_spin(self): - spin=Spin(7) - snapshot=Series("snapshot", package="GCC-5.3.1", spin=spin) - self.assertEqual(snapshot.spin.val, 7) - self.assertEqual(str(snapshot.spin), "-7") + spin = Spin(7) + snapshot = Series("snapshot", package="GCC-5.3.1", spin=spin) + self.assertEqual(snapshot.spin.val, 7) + self.assertEqual(str(snapshot.spin), "-7") def test_empty_spin(self): - spin=Spin() - snapshot=Series("snapshot", package="GCC-5.3.1", spin=spin) - self.assertEqual(str(snapshot.spin), "") + spin = Spin() + snapshot = Series("snapshot", package="GCC-5.3.1", spin=spin) + self.assertEqual(str(snapshot.spin), "") def test_spin_as_string(self): - snapshot=Series("snapshot", spin="7", package="GCC-5.3.1") - self.assertEqual(snapshot.spin.val, 7) - self.assertEqual(str(snapshot.spin), "-7") + snapshot = Series("snapshot", spin="7", package="GCC-5.3.1") + self.assertEqual(snapshot.spin.val, 7) + self.assertEqual(str(snapshot.spin), "-7") def test_spin_as_int(self): - snapshot=Series("snapshot", spin=7, package="GCC-5.3.1") - self.assertEqual(snapshot.spin.val, 7) - self.assertEqual(str(snapshot.spin), "-7") + snapshot = Series("snapshot", spin=7, package="GCC-5.3.1") + self.assertEqual(snapshot.spin.val, 7) + self.assertEqual(str(snapshot.spin), "-7") def test_spin_as_typeerror(self): - floatspin=7.0 - with self.assertRaises(TypeError): - snapshot=Series("snapshot", spin=floatspin, package="GCC-5.3.1") + floatspin = 7.0 + with self.assertRaises(TypeError): + snapshot = Series("snapshot", spin=floatspin, package="GCC-5.3.1") def test_spin_as_negative(self): - with self.assertRaises(ValueError): - snapshot=Series("snapshot", spin="-1", package="GCC-5.3.1") + with self.assertRaises(ValueError): + snapshot = Series("snapshot", spin="-1", package="GCC-5.3.1") def test_empty_spin_and_rc(self): - release=Series("release", package="GCC-5.3.1") - self.assertEqual(release.spin.val, 0) - self.assertEqual(release.rc.val, 0) - self.assertEqual(str(release.spin), "") - self.assertEqual(str(release.rc), "") + release = Series("release", package="GCC-5.3.1") + self.assertEqual(release.spin.val, 0) + self.assertEqual(release.rc.val, 0) + self.assertEqual(str(release.spin), "") + self.assertEqual(str(release.rc), "") def test_package_as_Package(self): - package = Package("GCC", "5.3.1") - release=Series("release", package) - self.assertEqual(str(release.package), "GCC-5.3.1") + package = Package("GCC", "5.3.1") + release = Series("release", package) + self.assertEqual(str(release.package), "GCC-5.3.1") def test_package_as_Package(self): - # Create a Version instead of a package - package = versionFromStr("5.3.1") - with self.assertRaises(TypeError): - candidate=Series("candidate", package) + # Create a Version instead of a package + package = versionFromStr("5.3.1") + with self.assertRaises(TypeError): + candidate = Series("candidate", package) def test_package_as_None(self): - package=None - with self.assertRaises(TypeError): - candidate=Series("candidate", package) + package = None + with self.assertRaises(TypeError): + candidate = Series("candidate", package) def test_getbranchname(self): - candidate=Series("candidate", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") - self.assertEqual(candidate.branchname(), "releases/linaro-5.3-2016.05-1-rc1") - release=Series("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc=None) - self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-1") + candidate = Series("candidate", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1") + self.assertEqual(candidate.branchname(), + "releases/linaro-5.3-2016.05-1-rc1") + release = Series("release", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc=None) + self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-1") def test_date_string(self): - candidate=Series("candidate", package="GCC-5.3.1", date="2016.05.27", spin="1", rc="1") - self.assertEqual(datetime(2016,05,15),candidate.date) + candidate = Series("candidate", package="GCC-5.3.1", + date="2016.05.27", spin="1", rc="1") + self.assertEqual(datetime(2016, 05, 15), candidate.date) - candidate2=Series("candidate", package="GCC-5.3.1", date="2016.05", spin="1", rc="1") - self.assertEqual(datetime(2016,05,15),candidate2.date) + candidate2 = Series("candidate", package="GCC-5.3.1", + date="2016.05", spin="1", rc="1") + self.assertEqual(datetime(2016, 05, 15), candidate2.date) - with self.assertRaises(TypeError): - candidate3=Series("candidate", package="GCC-5.3.1", date=datetime("20161034234"), spin="1", rc="1") + with self.assertRaises(TypeError): + candidate3 = Series("candidate", package="GCC-5.3.1", + date=datetime("20161034234"), spin="1", rc="1") def test_series_strict_true(self): - with self.assertRaises(ValueError): - snapshot=Series("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1", strict=True) + with self.assertRaises(ValueError): + snapshot = Series("snapshot", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1", strict=True) - with self.assertRaises(ValueError): - snapshot=Series("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") + with self.assertRaises(ValueError): + snapshot = Series("snapshot", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1") - with self.assertRaises(ValueError): - release=Series("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1", strict=True) + with self.assertRaises(ValueError): + release = Series("release", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1", strict=True) - with self.assertRaises(ValueError): - release=Series("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1") + with self.assertRaises(ValueError): + release = Series("release", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1") def test_series_strict_false(self): - snapshot=Series("snapshot", package="GCC-5.3.1", date=datetime(2016,05,15), spin="6", rc="1", strict=False) - self.assertEqual(snapshot.branchname(), "snapshots/linaro-5.3-2016.05-6-rc1") + snapshot = Series("snapshot", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="6", rc="1", strict=False) + self.assertEqual(snapshot.branchname(), + "snapshots/linaro-5.3-2016.05-6-rc1") - release=Series("release", package="GCC-5.3.1", date=datetime(2016,05,15), spin="1", rc="1", strict=False) - self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-1-rc1") + release = Series("release", package="GCC-5.3.1", + date=datetime(2016, 05, 15), spin="1", rc="1", strict=False) + self.assertEqual(release.branchname(), + "releases/linaro-5.3-2016.05-1-rc1") - release=Series("release", package="GCC-5.3.1", date=datetime(2016,05,15), rc="1", strict=False) - self.assertEqual(release.branchname(), "releases/linaro-5.3-2016.05-rc1") + release = Series("release", package="GCC-5.3.1", + date=datetime(2016, 05, 15), rc="1", strict=False) + self.assertEqual(release.branchname(), + "releases/linaro-5.3-2016.05-rc1") # These tests will verify that a branchname can be read, a series created, # and then the same branch name recreated. def test_series_from_branchname(self): - branch2=u'snapshots/linaro-5.3-2016.05-6' - series2=series_from_branchname(branch=branch2) - self.assertEqual(series2.branchname(),u'snapshots/linaro-5.3-2016.05-6') + branch2 = u'snapshots/linaro-5.3-2016.05-6' + series2 = series_from_branchname(branch=branch2) + self.assertEqual(series2.branchname(), + u'snapshots/linaro-5.3-2016.05-6') - branch3=u'snapshots/linaro-5.3-2016.05' - series3=series_from_branchname(branch=branch3) - self.assertEqual(series3.branchname(),u'snapshots/linaro-5.3-2016.05') + branch3 = u'snapshots/linaro-5.3-2016.05' + series3 = series_from_branchname(branch=branch3) + self.assertEqual(series3.branchname(), u'snapshots/linaro-5.3-2016.05') - branch4=u'releases/linaro-5.3-2016.05-6-rc1' - series4=series_from_branchname(branch=branch4) - self.assertEqual(series4.branchname(),u'releases/linaro-5.3-2016.05-6-rc1') + branch4 = u'releases/linaro-5.3-2016.05-6-rc1' + series4 = series_from_branchname(branch=branch4) + self.assertEqual(series4.branchname(), + u'releases/linaro-5.3-2016.05-6-rc1') - branch5=u'releases/linaro-5.3-2016.05-rc1' - series5=series_from_branchname(branch=branch5) - self.assertEqual(series5.branchname(),u'releases/linaro-5.3-2016.05-rc1') + branch5 = u'releases/linaro-5.3-2016.05-rc1' + series5 = series_from_branchname(branch=branch5) + self.assertEqual(series5.branchname(), + u'releases/linaro-5.3-2016.05-rc1') - branch6=u'releases/linaro-5.3-2016.05-6' - series6=series_from_branchname(branch=branch6) - self.assertEqual(series6.branchname(),u'releases/linaro-5.3-2016.05-6') + branch6 = u'releases/linaro-5.3-2016.05-6' + series6 = series_from_branchname(branch=branch6) + self.assertEqual(series6.branchname(), + u'releases/linaro-5.3-2016.05-6') - branch7=u'releases/linaro-5.3-2016.05' - series7=series_from_branchname(branch=branch7) - self.assertEqual(series7.branchname(),u'releases/linaro-5.3-2016.05') + branch7 = u'releases/linaro-5.3-2016.05' + series7 = series_from_branchname(branch=branch7) + self.assertEqual(series7.branchname(), u'releases/linaro-5.3-2016.05') - # -rc1 is invalid with a snapshots namespace. - branch8=u'snapshots/linaro-5.3-2016.05-6-rc1' - with self.assertRaises(ValueError): - series8=series_from_branchname(branch=branch8) + # -rc1 is invalid with a snapshots namespace. + branch8 = u'snapshots/linaro-5.3-2016.05-6-rc1' + with self.assertRaises(ValueError): + series8 = series_from_branchname(branch=branch8) # Wrong branchname.. it should be 'snapshots' - branch9=u'snapshot/linaro-5.3-2016.05-6-rc1' - with self.assertRaises(ValueError): - series9=series_from_branchname(branch=branch9) + branch9 = u'snapshot/linaro-5.3-2016.05-6-rc1' + with self.assertRaises(ValueError): + series9 = series_from_branchname(branch=branch9) # Wrong branchname.. it should be 'snapshots' - branch10=u'snapshot/linaro-5.3-2016.05-6' - with self.assertRaises(ValueError): - series10=series_from_branchname(branch=branch10) + branch10 = u'snapshot/linaro-5.3-2016.05-6' + with self.assertRaises(ValueError): + series10 = series_from_branchname(branch=branch10) # namespace required. - branch11=u'linaro-5.3-2016.05-6' - with self.assertRaises(ValueError): - series11=series_from_branchname(branch=branch11) - - # it should complain about missing the right-hand values. - branch12=u'snapshots/' - with self.assertRaises(ValueError): - series12=series_from_branchname(branch=branch12) - - # It won't parse because of a missing namespace / - branch13=u'snapshots' - with self.assertRaises(ValueError): - series13=series_from_branchname(branch=branch13) - - branch14=u'snapshots/foo' - with self.assertRaises(KeyError): - series14=series_from_branchname(branch=branch14) - - # unknown namespace. - branch15=u'foobarnamespace/linaro-5.3-2016.05-6' - with self.assertRaises(ValueError): - series15=series_from_branchname(branch=branch15) - - # This will fail on a non-datetime input. - branch16=u'snapshots/linaro-5.3-asdf' - with self.assertRaises(ValueError): - series16=series_from_branchname(branch=branch16) - - # This will fail with an invalid spin. - branch17=u'snapshots/linaro-5.3-2016.05-a' - with self.assertRaises(TypeError): - series17=series_from_branchname(branch=branch17) - - # This will fail with an invalid rc. - branch18=u'snapshots/linaro-5.3-2016.05-rcasdfn' - with self.assertRaises(TypeError): - series18=series_from_branchname(branch=branch18) - - # This will fail with an invalid rc. - branch19=u'snapshots/linaro-5.3-2016.05-9-rcasdfn' - with self.assertRaises(TypeError): - series19=series_from_branchname(branch=branch19) + branch11 = u'linaro-5.3-2016.05-6' + with self.assertRaises(ValueError): + series11 = series_from_branchname(branch=branch11) + + # it should complain about missing the right-hand values. + branch12 = u'snapshots/' + with self.assertRaises(ValueError): + series12 = series_from_branchname(branch=branch12) + + # It won't parse because of a missing namespace / + branch13 = u'snapshots' + with self.assertRaises(ValueError): + series13 = series_from_branchname(branch=branch13) + + branch14 = u'snapshots/foo' + with self.assertRaises(KeyError): + series14 = series_from_branchname(branch=branch14) + + # unknown namespace. + branch15 = u'foobarnamespace/linaro-5.3-2016.05-6' + with self.assertRaises(ValueError): + series15 = series_from_branchname(branch=branch15) + + # This will fail on a non-datetime input. + branch16 = u'snapshots/linaro-5.3-asdf' + with self.assertRaises(ValueError): + series16 = series_from_branchname(branch=branch16) + + # This will fail with an invalid spin. + branch17 = u'snapshots/linaro-5.3-2016.05-a' + with self.assertRaises(TypeError): + series17 = series_from_branchname(branch=branch17) + + # This will fail with an invalid rc. + branch18 = u'snapshots/linaro-5.3-2016.05-rcasdfn' + with self.assertRaises(TypeError): + series18 = series_from_branchname(branch=branch18) + + # This will fail with an invalid rc. + branch19 = u'snapshots/linaro-5.3-2016.05-9-rcasdfn' + with self.assertRaises(TypeError): + series19 = series_from_branchname(branch=branch19) # TODO: Test series.label (as there was a runtime bug) def test_snapshot_series_from_tag(self): - tag=u'linaro-snapshot-5.3-2016.05-6' - series=series_from_tag(tag=tag) - self.assertEqual(series.branchname(),u'snapshots/linaro-5.3-2016.05-6') + tag = u'linaro-snapshot-5.3-2016.05-6' + series = series_from_tag(tag=tag) + self.assertEqual(series.branchname(), + u'snapshots/linaro-5.3-2016.05-6') def test_invalid_snapshot_series_from_tag(self): # We can't have -rc1 on a snapshot. - tag=u'linaro-snapshot-5.3-2016.05-6-rc1' - with self.assertRaises(ValueError): - series=series_from_tag(tag=tag) + tag = u'linaro-snapshot-5.3-2016.05-6-rc1' + with self.assertRaises(ValueError): + series = series_from_tag(tag=tag) def test_candidate_series_from_tag(self): - tag=u'linaro-5.3-2016.05-6-rc1' - series=series_from_tag(tag=tag) - self.assertEqual(series.branchname(),u'releases/linaro-5.3-2016.05-6-rc1') + tag = u'linaro-5.3-2016.05-6-rc1' + series = series_from_tag(tag=tag) + self.assertEqual(series.branchname(), + u'releases/linaro-5.3-2016.05-6-rc1') def test_release_series_from_tag(self): - tag=u'linaro-5.3-2016.05-6' - series=series_from_tag(tag=tag) - self.assertEqual(series.branchname(),u'releases/linaro-5.3-2016.05-6') + tag = u'linaro-5.3-2016.05-6' + series = series_from_tag(tag=tag) + self.assertEqual(series.branchname(), u'releases/linaro-5.3-2016.05-6') def test_series_from_tag_invalid_spin(self): - tag=u'linaro-5.3-2016.05-abc' - with self.assertRaises(TypeError): - series=series_from_tag(tag=tag) + tag = u'linaro-5.3-2016.05-abc' + with self.assertRaises(TypeError): + series = series_from_tag(tag=tag) def test_series_from_tag_invalid_rc(self): - tag=u'linaro-5.3-2016.05-rcabf' - with self.assertRaises(TypeError): - series=series_from_tag(tag=tag) + tag = u'linaro-5.3-2016.05-rcabf' + with self.assertRaises(TypeError): + series = series_from_tag(tag=tag) def test_series_from_tag_invalid_rc_with_valid_spin(self): - tag=u'linaro-5.3-2016.05-9-rcabf' - with self.assertRaises(TypeError): - series=series_from_tag(tag=tag) + tag = u'linaro-5.3-2016.05-9-rcabf' + with self.assertRaises(TypeError): + series = series_from_tag(tag=tag) + class TestSeriesFormat(unittest.TestCase): @classmethod def setUpClass(cls): - snaptag=u'linaro-snapshot-5.3-2016.05-6' - reltag=u'linaro-5.3-2016.05-6' - rctag=u'linaro-5.3-2016.05-6-rc1' - cls.snapseries=series_from_tag(tag=snaptag) - cls.relseries=series_from_tag(tag=reltag) - cls.rcseries=series_from_tag(tag=rctag) + snaptag = u'linaro-snapshot-5.3-2016.05-6' + reltag = u'linaro-5.3-2016.05-6' + rctag = u'linaro-5.3-2016.05-6-rc1' + cls.snapseries = series_from_tag(tag=snaptag) + cls.relseries = series_from_tag(tag=reltag) + cls.rcseries = series_from_tag(tag=rctag) def test_format_N_snap(self): - f=format(self.snapseries, '%N') - self.assertEquals(f,'snapshots') + f = format(self.snapseries, '%N') + self.assertEquals(f, 'snapshots') def test_format_N_rel(self): - f=format(self.relseries, '%N') - self.assertEquals(f,'releases') + f = format(self.relseries, '%N') + self.assertEquals(f, 'releases') def test_format_N_rc(self): - f=format(self.rcseries, '%N') - self.assertEquals(f,'releases') + f = format(self.rcseries, '%N') + self.assertEquals(f, 'releases') def test_format_dashL_snap(self): - f=format(self.snapseries, 'foo-%L-bar') - self.assertEquals(f,'foo-snapshot-bar') + f = format(self.snapseries, 'foo-%L-bar') + self.assertEquals(f, 'foo-snapshot-bar') def test_format_dashL_rel(self): - f=format(self.relseries, 'foo-%L-bar') - self.assertEquals(f,'foo-bar') - + f = format(self.relseries, 'foo-%L-bar') + self.assertEquals(f, 'foo-bar') + def test_format_dashL_rc(self): - f=format(self.rcseries, 'foo-%L-bar') - self.assertEquals(f,'foo-bar') - + f = format(self.rcseries, 'foo-%L-bar') + self.assertEquals(f, 'foo-bar') + def test_format_dotL_snap(self): - f=format(self.snapseries, 'foo.%L.bar') - self.assertEquals(f,'foo.snapshot.bar') - + f = format(self.snapseries, 'foo.%L.bar') + self.assertEquals(f, 'foo.snapshot.bar') + def test_format_dotL_rel(self): - f=format(self.relseries, 'foo.%L.bar') - self.assertEquals(f,'foo.bar') - + f = format(self.relseries, 'foo.%L.bar') + self.assertEquals(f, 'foo.bar') + def test_format_dotL_rc(self): - f=format(self.rcseries, 'foo.%L.bar') - self.assertEquals(f,'foo.bar') - + f = format(self.rcseries, 'foo.%L.bar') + self.assertEquals(f, 'foo.bar') + def test_format_L_snap(self): - f=format(self.snapseries, 'foo%Lbar') - self.assertEquals(f,'foosnapshotbar') - + f = format(self.snapseries, 'foo%Lbar') + self.assertEquals(f, 'foosnapshotbar') + def test_format_L_rel(self): - f=format(self.relseries, 'foo%Lbar') - self.assertEquals(f,'foobar') - + f = format(self.relseries, 'foo%Lbar') + self.assertEquals(f, 'foobar') + def test_format_L_rc(self): - f=format(self.rcseries, 'foo%Lbar') - self.assertEquals(f,'foobar') + f = format(self.rcseries, 'foo%Lbar') + self.assertEquals(f, 'foobar') def test_format_dashP(self): - f=format(self.snapseries, 'foo-%P-bar') - self.assertEquals(f,'foo-GCC-bar') + f = format(self.snapseries, 'foo-%P-bar') + self.assertEquals(f, 'foo-GCC-bar') def test_format_dotP(self): - f=format(self.snapseries, 'foo.%P.bar') - self.assertEquals(f,'foo.GCC.bar') + f = format(self.snapseries, 'foo.%P.bar') + self.assertEquals(f, 'foo.GCC.bar') def test_format_P(self): - f=format(self.snapseries, 'foo%Pbar') - self.assertEquals(f,'fooGCCbar') + f = format(self.snapseries, 'foo%Pbar') + self.assertEquals(f, 'fooGCCbar') def test_format_dashl(self): - f=format(self.snapseries, 'foo-%l-bar') - self.assertEquals(f,'foo-gcc-bar') + f = format(self.snapseries, 'foo-%l-bar') + self.assertEquals(f, 'foo-gcc-bar') def test_format_dotl(self): - f=format(self.snapseries, 'foo.%l.bar') - self.assertEquals(f,'foo.gcc.bar') + f = format(self.snapseries, 'foo.%l.bar') + self.assertEquals(f, 'foo.gcc.bar') def test_format_l(self): - f=format(self.snapseries, 'foo%lbar') - self.assertEquals(f,'foogccbar') + f = format(self.snapseries, 'foo%lbar') + self.assertEquals(f, 'foogccbar') def test_format_V(self): - f=format(self.snapseries, 'foo.%V.bar') - self.assertEquals(f,'foo.Linaro.bar') + f = format(self.snapseries, 'foo.%V.bar') + self.assertEquals(f, 'foo.Linaro.bar') def test_format_v(self): - f=format(self.snapseries, 'foo.%v.bar') - self.assertEquals(f,'foo.linaro.bar') + f = format(self.snapseries, 'foo.%v.bar') + self.assertEquals(f, 'foo.linaro.bar') def test_format_E(self): - f=format(self.snapseries, 'gcc-%E') - self.assertEquals(f,'gcc-5.3') + f = format(self.snapseries, 'gcc-%E') + self.assertEquals(f, 'gcc-5.3') # This shouldn't show a trailing - after the minor because of a point. def test_format_E_with_fabricated_minor(self): - minorseries=copy.deepcopy(self.snapseries) - minorseries.package.version.point=9 - f=format(minorseries, 'gcc-%E') - self.assertEquals(f,'gcc-5.3') + minorseries = copy.deepcopy(self.snapseries) + minorseries.package.version.point = 9 + f = format(minorseries, 'gcc-%E') + self.assertEquals(f, 'gcc-5.3') def test_format_e(self): - f=format(self.snapseries, 'gcc-%e') - self.assertEquals(f,'gcc-5.3') + f = format(self.snapseries, 'gcc-%e') + self.assertEquals(f, 'gcc-5.3') def test_format_e_fabricate_minor(self): - minorseries=copy.deepcopy(self.snapseries) - minorseries.package.version.point=9 - f=format(minorseries, 'gcc-%e') - self.assertEquals(f,'gcc-5.3.9') - + minorseries = copy.deepcopy(self.snapseries) + minorseries.package.version.point = 9 + f = format(minorseries, 'gcc-%e') + self.assertEquals(f, 'gcc-5.3.9') + def test_format_M(self): - f=format(self.snapseries, 'gcc-%M') - self.assertEquals(f,'gcc-5') - + f = format(self.snapseries, 'gcc-%M') + self.assertEquals(f, 'gcc-5') + def test_format_m(self): - f=format(self.snapseries, 'gcc-X.%m') - self.assertEquals(f,'gcc-X.3') - + f = format(self.snapseries, 'gcc-X.%m') + self.assertEquals(f, 'gcc-X.3') + def test_format_p(self): - f=format(self.snapseries, 'gcc-X.Y.%p') - self.assertEquals(f,'gcc-X.Y.') + f = format(self.snapseries, 'gcc-X.Y.%p') + self.assertEquals(f, 'gcc-X.Y.') def test_format_p_fabricate_minor(self): - minorseries=copy.deepcopy(self.snapseries) - minorseries.package.version.point=9 - f=format(minorseries, 'gcc-X.Y.%p') - self.assertEquals(f,'gcc-X.Y.9') + minorseries = copy.deepcopy(self.snapseries) + minorseries.package.version.point = 9 + f = format(minorseries, 'gcc-X.Y.%p') + self.assertEquals(f, 'gcc-X.Y.9') def test_format_D(self): - f=format(self.snapseries, 'foo-%D-bar') - self.assertEquals(f,'foo-2016.05-bar') + f = format(self.snapseries, 'foo-%D-bar') + self.assertEquals(f, 'foo-2016.05-bar') def test_format_snap_h(self): - f=format(self.snapseries, 'http://%h.') - self.assertEquals(f,'http://snapshots.') - + f = format(self.snapseries, 'http://%h.') + self.assertEquals(f, 'http://snapshots.') + def test_format_release_h(self): - f=format(self.relseries, 'http://%h.') - self.assertEquals(f,'http://releases.') - + f = format(self.relseries, 'http://%h.') + self.assertEquals(f, 'http://releases.') + def test_format_snap_h(self): - f=format(self.snapseries, 'http://%h.') - self.assertEquals(f,'http://snapshots.') - + f = format(self.snapseries, 'http://%h.') + self.assertEquals(f, 'http://snapshots.') + def test_format_snap_d(self): - f=format( + f = format( self.snapseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1032,7 +1071,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rel_d(self): - f=format( + f = format( self.relseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1041,7 +1080,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rc_d(self): - f=format( + f = format( self.rcseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1050,7 +1089,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6-rc1') def test_format_snap_d(self): - f=format( + f = format( self.snapseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1059,7 +1098,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rel_d(self): - f=format( + f = format( self.relseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1068,7 +1107,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rc_d(self): - f=format( + f = format( self.rcseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1077,7 +1116,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6-rc1') def test_format_snap_d(self): - f=format( + f = format( self.snapseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1086,7 +1125,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rel_d(self): - f=format( + f = format( self.relseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1095,7 +1134,7 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6') def test_format_rc_d(self): - f=format( + f = format( self.rcseries, 'http://%h.linaro.org/components/toolchain/binaries/%d') self.assertEquals( @@ -1104,65 +1143,65 @@ class TestSeriesFormat(unittest.TestCase): 'toolchain/binaries/5.3-2016.05-6-rc1') def test_format_dashS(self): - f=format(self.snapseries, 'foo-%S-bar') - self.assertEquals(f,'foo-6-bar') - + f = format(self.snapseries, 'foo-%S-bar') + self.assertEquals(f, 'foo-6-bar') + def test_format_dashS_no_spin(self): - nospinseries=copy.deepcopy(self.snapseries) - nospinseries.spin=Spin() - f=format(nospinseries, 'foo-%S-bar') - self.assertEquals(f,'foo-bar') + nospinseries = copy.deepcopy(self.snapseries) + nospinseries.spin = Spin() + f = format(nospinseries, 'foo-%S-bar') + self.assertEquals(f, 'foo-bar') def test_format_dotS(self): - f=format(self.snapseries, 'foo.%S.bar') - self.assertEquals(f,'foo.6.bar') + f = format(self.snapseries, 'foo.%S.bar') + self.assertEquals(f, 'foo.6.bar') def test_format_dotS_no_spin(self): - nospinseries=copy.deepcopy(self.snapseries) - nospinseries.spin=Spin() - f=format(nospinseries, 'foo.%S.bar') - self.assertEquals(f,'foo.bar') + nospinseries = copy.deepcopy(self.snapseries) + nospinseries.spin = Spin() + f = format(nospinseries, 'foo.%S.bar') + self.assertEquals(f, 'foo.bar') def test_format_S(self): - f=format(self.snapseries, 'foo%Sbar') - self.assertEquals(f,'foo6bar') + f = format(self.snapseries, 'foo%Sbar') + self.assertEquals(f, 'foo6bar') def test_format_S_no_spin(self): - nospinseries=copy.deepcopy(self.snapseries) - nospinseries.spin=Spin() - f=format(nospinseries, 'foo%Sbar') - self.assertEquals(f,'foobar') - + nospinseries = copy.deepcopy(self.snapseries) + nospinseries.spin = Spin() + f = format(nospinseries, 'foo%Sbar') + self.assertEquals(f, 'foobar') + def test_format_dashR(self): - f=format(self.rcseries, '2016.05-6-%R') - self.assertEquals(f,'2016.05-6-rc1') + f = format(self.rcseries, '2016.05-6-%R') + self.assertEquals(f, '2016.05-6-rc1') def test_format_dashR_fabricate_norc(self): - norcseries=copy.deepcopy(self.rcseries) - norcseries.rc=Rc() - f=format(norcseries, '2016.05-6-%R') - self.assertEquals(f,'2016.05-6') + norcseries = copy.deepcopy(self.rcseries) + norcseries.rc = Rc() + f = format(norcseries, '2016.05-6-%R') + self.assertEquals(f, '2016.05-6') def test_format_dotR(self): - f=format(self.rcseries, '2016.05-6.%R') - self.assertEquals(f,'2016.05-6.rc1') + f = format(self.rcseries, '2016.05-6.%R') + self.assertEquals(f, '2016.05-6.rc1') def test_format_dotR_fabricate_norc(self): - norcseries=copy.deepcopy(self.rcseries) - norcseries.rc=Rc() - f=format(norcseries, '2016.05-6.%R') - self.assertEquals(f,'2016.05-6') - + norcseries = copy.deepcopy(self.rcseries) + norcseries.rc = Rc() + f = format(norcseries, '2016.05-6.%R') + self.assertEquals(f, '2016.05-6') + def test_format_R(self): - f=format(self.rcseries, '2016.05-6-%R') - self.assertEquals(f,'2016.05-6-rc1') + f = format(self.rcseries, '2016.05-6-%R') + self.assertEquals(f, '2016.05-6-rc1') def test_format_R_fabricate_norc(self): - norcseries=copy.deepcopy(self.rcseries) - norcseries.rc=Rc() - f=format(norcseries, '2016.05-6#%R') - self.assertEquals(f,'2016.05-6#') + norcseries = copy.deepcopy(self.rcseries) + norcseries.rc = Rc() + f = format(norcseries, '2016.05-6#%R') + self.assertEquals(f, '2016.05-6#') if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() diff --git a/linaropy/vers.py b/linaropy/vers.py index 7e8c2f1..45d4e3b 100644 --- a/linaropy/vers.py +++ b/linaropy/vers.py @@ -1,20 +1,23 @@ import unittest import logging + class Vendor(object): + def __init__(self, vendor="Linaro"): - if not vendor: - raise TypeError("Vendor requires a vendor string.") + if not vendor: + raise TypeError("Vendor requires a vendor string.") if isinstance(vendor, basestring): - self.vendor=vendor + self.vendor = vendor else: - raise TypeError("Input 'vendor' must be of type basestring.") + raise TypeError("Input 'vendor' must be of type basestring.") def __str__(self): - return self.vendor + return self.vendor def lower(self): - return self.vendor.lower() + return self.vendor.lower() + class Version(object): # @major - required int or str representation of int. @@ -22,43 +25,45 @@ class Version(object): # If None, then minor will not be output. # @point - optional int or str representation of int, otherwise None. # If None, then point will not be output. + def __init__(self, major, minor=None, point=None): if isinstance(major, int) or isinstance(major, basestring): - # This will throw an exception if 'major' is an empty string. - self.major=int(major) - else: - raise TypeError("major must be of type int, string.") + # This will throw an exception if 'major' is an empty string. + self.major = int(major) + else: + raise TypeError("major must be of type int, string.") if isinstance(minor, int) or isinstance(minor, basestring): - # This will throw an exception if 'minor' is an empty string. - self.minor=int(minor) + # This will throw an exception if 'minor' is an empty string. + self.minor = int(minor) elif not minor: - self.minor=None - else: - raise TypeError("minor must be of type int, string, or None.") + self.minor = None + else: + raise TypeError("minor must be of type int, string, or None.") if isinstance(point, int) or isinstance(point, basestring): - # This is illegal, as it'd mess up the output and make it look like - # there's a minor that's really a point. - if not minor and point: - raise RuntimeError("minor must be specified if point is specified.") + # This is illegal, as it'd mess up the output and make it look like + # there's a minor that's really a point. + if not minor and point: + raise RuntimeError( + "minor must be specified if point is specified.") - # This will throw an exception if 'minor' is an empty string. - self.point=int(point) + # This will throw an exception if 'minor' is an empty string. + self.point = int(point) elif not point: - self.point=None - else: - raise TypeError("point must be of type int, string, or None.") + self.point = None + else: + raise TypeError("point must be of type int, string, or None.") def __str__(self): - ver=str(self.major) - if self.minor: - ver=ver + u'.' + str(self.minor) - if self.point: - ver=ver + u'.' + str(self.point) - return ver + ver = str(self.major) + if self.minor: + ver = ver + u'.' + str(self.minor) + if self.point: + ver = ver + u'.' + str(self.point) + return ver # TODO: I'm sure there's a more pythonic way to do this but this is # quick and dirty. @@ -68,115 +73,121 @@ class Version(object): # delimiter - Delimiter character to use in output: space or dash. # TODO: Use a dictionary with replace def strfversion(self, formatstr, delimiter='.'): - toks=[str(x) for x in formatstr.split('%') if x.strip()] + toks = [str(x) for x in formatstr.split('%') if x.strip()] - delstoks=len(toks) - verstoks=0 + delstoks = len(toks) + verstoks = 0 - if self.major: - verstoks=verstoks+1 - if self.minor: - verstoks=verstoks+1 - if self.point: - verstoks=verstoks+1 + if self.major: + verstoks = verstoks + 1 + if self.minor: + verstoks = verstoks + 1 + if self.point: + verstoks = verstoks + 1 - if delstoks > verstoks: - numtoks=verstoks - 1 + if delstoks > verstoks: + numtoks = verstoks - 1 else: - numtoks=delstoks - 1 - - vers=u'' - for tok in toks: - if tok == 'M': - vers=vers + str(self.major) - elif tok == 'm': - vers=vers + str(self.minor) - elif tok == 'p': + numtoks = delstoks - 1 + + vers = u'' + for tok in toks: + if tok == 'M': + vers = vers + str(self.major) + elif tok == 'm': + vers = vers + str(self.minor) + elif tok == 'p': if self.point: - vers=vers + str(self.point) - if numtoks > 0: - vers=vers + delimiter - numtoks=numtoks-1 - return vers + vers = vers + str(self.point) + if numtoks > 0: + vers = vers + delimiter + numtoks = numtoks - 1 + return vers # Helper function which returns a Version. + + def versionFromStr(version): if not isinstance(version, basestring): raise TypeError('input must be of type basestring') - major=version.split('.', 1)[0] + major = version.split('.', 1)[0] # split('.',1) will return index error on "5" but will return empty string on "5." # Any empty string is not a valid input into Version. if major == u'': - major=None + major = None try: - minor=version.split('.', 2)[1] + minor = version.split('.', 2)[1] except IndexError: - minor=None + minor = None if minor == u'': - minor=None + minor = None try: - point=version.split('.', 3)[2] + point = version.split('.', 3)[2] except IndexError: - point=None + point = None if point == u'': - point=None + point = None + + return Version(major, minor, point) - return Version(major, minor, point) class Package(object): # @package - default = GCC # @version - required. Either a string representing a version or a Version # instance. + def __init__(self, package="GCC", version=None): - if not package or package == u'': - raise TypeError("Package requires 'package' as a non-empty string") + if not package or package == u'': + raise TypeError("Package requires 'package' as a non-empty string") if isinstance(package, basestring): - self.package=package + self.package = package else: - raise TypeError("Input 'package' must be of type basestring.") + raise TypeError("Input 'package' must be of type basestring.") if not version: - raise RuntimeError("Package requires a version.") + raise RuntimeError("Package requires a version.") elif isinstance(version, Version): - self.version=version + self.version = version else: - self.version=versionFromStr(version) + self.version = versionFromStr(version) def get_package(self): - return self.package + return self.package def get_version(self): - return str(self.version) + return str(self.version) def __str__(self): - return self.package + u'-' + str(self.version) + return self.package + u'-' + str(self.version) def lower(self): - return self.package.lower() + u'-' + str(self.version) + return self.package.lower() + u'-' + str(self.version) + + # TODO: Create format function which can change the separator to ' ' or to + # '-'. - #TODO: Create format function which can change the separator to ' ' or to '-'. def packageFromStr(package=None): if not isinstance(package, basestring): - raise TypeError('packageFromStr requires a string as input') + raise TypeError('packageFromStr requires a string as input') # Get the part before the version numbers. That's the package try: - package_name=package.rsplit('-', 1)[0] + package_name = package.rsplit('-', 1)[0] except IndexError: - raise RuntimeError('string must be <package_name>-<package_version>') + raise RuntimeError('string must be <package_name>-<package_version>') try: - package_version=package.rsplit('-', 1)[1] + package_version = package.rsplit('-', 1)[1] except IndexError: - raise ValueError('string must be <package_name>-<package_version>') + raise ValueError('string must be <package_name>-<package_version>') if package_name == u'': raise TypeError("Couldn't parse a package name from input string") @@ -184,432 +195,447 @@ def packageFromStr(package=None): raise TypeError("Couldn't parse a package version from input string") # This will throw exceptions if the input are malformed. - package=Package(package_name, package_version) + package = Package(package_name, package_version) return package + class Vers(object): + def __init__(self, val=None): - if val is None: - self.val=0 - return + if val is None: + self.val = 0 + return if isinstance(val, int) or isinstance(val, basestring): - # This should raise an exception if the string can't be converted - # to an int. If val is already an int it's a nop. - intval=int(val) - - if intval < 0: - raise ValueError('Input val must not be negative') - self.val=intval - else: - raise TypeError("Input val must be of type int or string.") + # This should raise an exception if the string can't be converted + # to an int. If val is already an int it's a nop. + intval = int(val) + + if intval < 0: + raise ValueError('Input val must not be negative') + self.val = intval + else: + raise TypeError("Input val must be of type int or string.") def increment(self): - self.val=self.val+1 + self.val = self.val + 1 # Return the "-<val>" string or an empty string. def __str__(self): - # Don't return - if self.val is None or self.val == 0: - return "" + # Don't return + if self.val is None or self.val == 0: + return "" else: - return "-" + str(self.val) + return "-" + str(self.val) + class Spin(Vers): + def __init__(self, spin=None): try: - super(Spin,self).__init__(spin) - except ValueError: - raise ValueError('Input spin must not be negative') + super(Spin, self).__init__(spin) + except ValueError: + raise ValueError('Input spin must not be negative') + class Rc(Vers): + def __init__(self, rc=None): try: - super(Rc,self).__init__(rc) - except ValueError: - raise ValueError('Input rc must not be negative') + super(Rc, self).__init__(rc) + except ValueError: + raise ValueError('Input rc must not be negative') # The string representation differs slighty from Spin def __str__(self): - # Don't return - if self.val is None or self.val == 0: - return "" + # Don't return + if self.val is None or self.val == 0: + return "" else: - return "-rc" + str(self.val) + return "-rc" + str(self.val) + class TestVersion(unittest.TestCase): + def test_no_major(self): with self.assertRaises(TypeError): - version=Version(major=None) + version = Version(major=None) with self.assertRaises(TypeError): - version=Version() + version = Version() def test_empty_major(self): with self.assertRaises(ValueError): - version=Version(major="") + version = Version(major="") def test_empty_minor(self): with self.assertRaises(ValueError): - version=Version(major=5, minor="") + version = Version(major=5, minor="") def test_empty_point(self): with self.assertRaises(ValueError): - version=Version(major=5, minor=3, point="") + version = Version(major=5, minor=3, point="") def test_non_int_major(self): with self.assertRaises(ValueError): - version=Version('A') + version = Version('A') def test_int_major(self): - version=Version(5) - self.assertEqual(str(version), "5") - version2=Version(major=5) - self.assertEqual(str(version2), "5") + version = Version(5) + self.assertEqual(str(version), "5") + version2 = Version(major=5) + self.assertEqual(str(version2), "5") def test_intstr_major(self): - version=Version("5") - self.assertEqual(str(version), "5") - version2=Version(major="5") - self.assertEqual(str(version2), "5") + version = Version("5") + self.assertEqual(str(version), "5") + version2 = Version(major="5") + self.assertEqual(str(version2), "5") def test_non_int_minor(self): with self.assertRaises(ValueError): - version=Version(major="5", minor="A") + version = Version(major="5", minor="A") def test_int_minor(self): - version=Version(major=5, minor=3) - self.assertEqual(str(version), "5.3") + version = Version(major=5, minor=3) + self.assertEqual(str(version), "5.3") def test_intstr_minor(self): - version=Version(major="5", minor="3") - self.assertEqual(str(version), "5.3") + version = Version(major="5", minor="3") + self.assertEqual(str(version), "5.3") def test_no_minor(self): - version=Version(major="5", minor=None) - self.assertEqual(str(version), "5") + version = Version(major="5", minor=None) + self.assertEqual(str(version), "5") def test_point_no_minor(self): with self.assertRaises(RuntimeError): - version=Version(major=5, minor=None, point=1) + version = Version(major=5, minor=None, point=1) def test_int_point(self): - version=Version(major=5, minor=3, point=1) - self.assertEqual(str(version), "5.3.1") + version = Version(major=5, minor=3, point=1) + self.assertEqual(str(version), "5.3.1") def test_non_int_point(self): with self.assertRaises(ValueError): - version=Version(major=5, minor=3, point="A") + version = Version(major=5, minor=3, point="A") def test_intstr_point(self): - version=Version(major="5", minor="3", point="1") - self.assertEqual(str(version), "5.3.1") + version = Version(major="5", minor="3", point="1") + self.assertEqual(str(version), "5.3.1") def test_no_point(self): - version=Version(major="5", minor="3", point=None) - self.assertEqual(str(version), "5.3") + version = Version(major="5", minor="3", point=None) + self.assertEqual(str(version), "5.3") def test_strfversion(self): - version=Version(major="5", minor="3", point="1") - self.assertEqual(version.strfversion("%M%m%p", delimiter='-'),"5-3-1") - self.assertEqual(version.strfversion("%M%m%p"),"5.3.1") + version = Version(major="5", minor="3", point="1") + self.assertEqual(version.strfversion("%M%m%p", delimiter='-'), "5-3-1") + self.assertEqual(version.strfversion("%M%m%p"), "5.3.1") + class TestVendor(unittest.TestCase): + def test_vendor_default(self): - vendor=Vendor() + vendor = Vendor() self.assertEqual(str(vendor), "Linaro") self.assertEqual(vendor.lower(), "linaro") def test_none_input(self): with self.assertRaises(TypeError): - vendor=Vendor(vendor=None) + vendor = Vendor(vendor=None) def test_nonstring_input(self): with self.assertRaises(TypeError): - vendor=Vendor(vendor=int(1)) + vendor = Vendor(vendor=int(1)) def test_str_input(self): - vendor=Vendor("TestVendor") + vendor = Vendor("TestVendor") self.assertEqual(str(vendor), "TestVendor") self.assertEqual(vendor.lower(), "testvendor") + class TestPackage(unittest.TestCase): def test_package_no_version(self): with self.assertRaises(RuntimeError): - # We require a version. - package=Package() + # We require a version. + package = Package() def test_package_default(self): - package=Package(version="5.3.1") + package = Package(version="5.3.1") self.assertEqual(str(package), "GCC-5.3.1") self.assertEqual(package.lower(), "gcc-5.3.1") - self.assertEqual(package.package, "GCC") + self.assertEqual(package.package, "GCC") def test_none_package(self): with self.assertRaises(TypeError): - package=Package(package=None, version="5.3.1") + package = Package(package=None, version="5.3.1") def test_none_version(self): with self.assertRaises(RuntimeError): - package=Package(package="GCC", version=None) + package = Package(package="GCC", version=None) def test_with_Version(self): - version=Version(5,3,1) - package=Package(version=version) + version = Version(5, 3, 1) + package = Package(version=version) self.assertEqual(str(package), "GCC-5.3.1") self.assertEqual(package.lower(), "gcc-5.3.1") def test_package_version(self): - version=Version(5,3,1) - package=Package(version=version) + version = Version(5, 3, 1) + package = Package(version=version) self.assertEqual(str(package.version), "5.3.1") self.assertEqual(package.get_version(), "5.3.1") self.assertEqual(package.get_package(), "GCC") - + def test_str_input(self): - package=Package("TestPackage", version="5.3.1") + package = Package("TestPackage", version="5.3.1") self.assertEqual(str(package), "TestPackage-5.3.1") self.assertEqual(package.lower(), "testpackage-5.3.1") def test_empty_package_name(self): with self.assertRaises(TypeError): - package=Package(package="", version="5.3.1") + package = Package(package="", version="5.3.1") + class TestSpin(unittest.TestCase): def test_spin_val(self): - spin=Spin(1) - self.assertEqual(spin.val, 1) + spin = Spin(1) + self.assertEqual(spin.val, 1) def test_spin_val_str(self): - spin=Spin(1) - self.assertEqual(str(spin), "-1") - + spin = Spin(1) + self.assertEqual(str(spin), "-1") + def test_spin_increment_val(self): - spin=Spin(1) - spin.increment() - self.assertEqual(spin.val, 2) + spin = Spin(1) + spin.increment() + self.assertEqual(spin.val, 2) def test_spin_increment_str(self): - spin=Spin(1) - spin.increment() - self.assertEqual(str(spin), "-2") + spin = Spin(1) + spin.increment() + self.assertEqual(str(spin), "-2") def test_zero_spin(self): - spin=Spin(0) - self.assertEqual(spin.val, 0) + spin = Spin(0) + self.assertEqual(spin.val, 0) def test_zero_spin_str(self): - spin=Spin(0) - self.assertEqual(str(spin), "") + spin = Spin(0) + self.assertEqual(str(spin), "") def test_none_spin(self): - spin=Spin(None) - self.assertEqual(spin.val, 0) + spin = Spin(None) + self.assertEqual(spin.val, 0) def test_none_spin_increment(self): - spin=Spin(None) - spin.increment() - self.assertEqual(spin.val, 1) + spin = Spin(None) + spin.increment() + self.assertEqual(spin.val, 1) def test_none_spin_str(self): - spin=Spin(None) - self.assertEqual(str(spin), "") + spin = Spin(None) + self.assertEqual(str(spin), "") def test_default_spin(self): - spin=Spin() - self.assertEqual(spin.val, 0) + spin = Spin() + self.assertEqual(spin.val, 0) def test_default_spin_str(self): - spin=Spin() - self.assertEqual(str(spin), "") + spin = Spin() + self.assertEqual(str(spin), "") def test_negative_val(self): with self.assertRaises(ValueError): - spin=Spin(-1) + spin = Spin(-1) def test_default_spin_str(self): - spin=Spin() - self.assertEqual(str(spin), "") + spin = Spin() + self.assertEqual(str(spin), "") def test_spin_string_input(self): - spin=Spin("9") - self.assertEqual(spin.val, 9) - self.assertEqual(str(spin), "-9") + spin = Spin("9") + self.assertEqual(spin.val, 9) + self.assertEqual(str(spin), "-9") def test_spin_negative_string_input(self): with self.assertRaises(ValueError): - spin=Spin("-9") + spin = Spin("-9") def test_float_type(self): with self.assertRaises(TypeError): - spin=Spin(7.0) + spin = Spin(7.0) + class TestRc(unittest.TestCase): + def test_rc_val(self): - rc=Rc(1) - self.assertEqual(rc.val, 1) + rc = Rc(1) + self.assertEqual(rc.val, 1) def test_rc_str(self): - rc=Rc(1) - self.assertEqual(str(rc), "-rc1") + rc = Rc(1) + self.assertEqual(str(rc), "-rc1") def test_negative_val(self): with self.assertRaises(ValueError): - rc=Rc(-1) + rc = Rc(-1) def test_zero_rc_str(self): - rc=Rc(0) - self.assertEqual(str(rc), "") + rc = Rc(0) + self.assertEqual(str(rc), "") def test_none_rc_str(self): - rc=Rc(None) - self.assertEqual(str(rc), "") + rc = Rc(None) + self.assertEqual(str(rc), "") def test_default_rc_str(self): - rc=Rc() - self.assertEqual(str(rc), "") + rc = Rc() + self.assertEqual(str(rc), "") def test_rc_increment_val(self): - rc=Rc(1) - rc.increment() - self.assertEqual(rc.val, 2) + rc = Rc(1) + rc.increment() + self.assertEqual(rc.val, 2) def test_rc_increment_str(self): - rc=Rc(1) - rc.increment() - self.assertEqual(str(rc), "-rc2") + rc = Rc(1) + rc.increment() + self.assertEqual(str(rc), "-rc2") def test_none_rc_increment_str(self): - rc=Rc(None) - rc.increment() - self.assertEqual(str(rc), "-rc1") + rc = Rc(None) + rc.increment() + self.assertEqual(str(rc), "-rc1") def test_default_rc_str(self): - rc=Rc() - self.assertEqual(str(rc), "") + rc = Rc() + self.assertEqual(str(rc), "") def test_rc_string_input(self): - rc=Rc("9") - self.assertEqual(rc.val, 9) - self.assertEqual(str(rc), "-rc9") + rc = Rc("9") + self.assertEqual(rc.val, 9) + self.assertEqual(str(rc), "-rc9") def test_rc_negative_string_input(self): with self.assertRaises(ValueError): - rc=Rc("-9") + rc = Rc("-9") def test_float_type(self): with self.assertRaises(TypeError): - rc=Rc(7.0) + rc = Rc(7.0) + class TestPackageFromString(unittest.TestCase): def test_none(self): with self.assertRaises(TypeError): - package=packageFromStr(package=None) + package = packageFromStr(package=None) def test_empty_str_package(self): with self.assertRaises(ValueError): - package=packageFromStr(package=u"") + package = packageFromStr(package=u"") def test_with_package(self): - package=Package("GCC", "5.3.1") + package = Package("GCC", "5.3.1") with self.assertRaises(TypeError): - package=packageFromStr(package=package) + package = packageFromStr(package=package) def test_with_no_package_name(self): with self.assertRaises(TypeError): - package=packageFromStr(package="-5.3.1") + package = packageFromStr(package="-5.3.1") with self.assertRaises(ValueError): - package=packageFromStr(package="5.3.1") + package = packageFromStr(package="5.3.1") def test_with_no_package_version(self): with self.assertRaises(TypeError): - package=packageFromStr(package="GCC-") + package = packageFromStr(package="GCC-") with self.assertRaises(ValueError): - package=packageFromStr(package="GCC") + package = packageFromStr(package="GCC") def test_with_space(self): with self.assertRaises(ValueError): - package=packageFromStr(package="GCC 5.3.1") + package = packageFromStr(package="GCC 5.3.1") def test_correct_usage(self): - package=packageFromStr(package="GCC-5.3.1") + package = packageFromStr(package="GCC-5.3.1") self.assertEqual(str(package), "GCC-5.3.1") self.assertEqual(package.lower(), "gcc-5.3.1") - self.assertEqual(package.package, "GCC") - self.assertEqual(str(package.version), "5.3.1") - self.assertEqual(package.version.major, 5) - self.assertEqual(package.version.minor, 3) - self.assertEqual(package.version.point, 1) + self.assertEqual(package.package, "GCC") + self.assertEqual(str(package.version), "5.3.1") + self.assertEqual(package.version.major, 5) + self.assertEqual(package.version.minor, 3) + self.assertEqual(package.version.point, 1) + class TestVersionFromStr(unittest.TestCase): def test_extra_dot(self): - version=versionFromStr("5.3.1.4") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, 3) - self.assertEqual(version.point, 1) + version = versionFromStr("5.3.1.4") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, 1) def test_major_minor_point(self): - version=versionFromStr("5.3.1") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, 3) - self.assertEqual(version.point, 1) + version = versionFromStr("5.3.1") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, 1) def test_major_minor_dot(self): - version=versionFromStr("5.3.") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, 3) - self.assertEqual(version.point, None) + version = versionFromStr("5.3.") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, None) def test_major_minor(self): - version=versionFromStr("5.3") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, 3) - self.assertEqual(version.point, None) + version = versionFromStr("5.3") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, 3) + self.assertEqual(version.point, None) def test_major_dot(self): - version=versionFromStr("5.") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, None) - self.assertEqual(version.point, None) + version = versionFromStr("5.") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, None) + self.assertEqual(version.point, None) def test_major(self): - version=versionFromStr("5") - self.assertEqual(version.major, 5) - self.assertEqual(version.minor, None) - self.assertEqual(version.point, None) + version = versionFromStr("5") + self.assertEqual(version.major, 5) + self.assertEqual(version.minor, None) + self.assertEqual(version.point, None) def test_empty(self): with self.assertRaises(TypeError): - version=versionFromStr("") + version = versionFromStr("") def test_non_int_major(self): with self.assertRaises(ValueError): - version=versionFromStr("a.b.c") + version = versionFromStr("a.b.c") def test_non_int_minor(self): with self.assertRaises(ValueError): - version=versionFromStr("5.b.1") + version = versionFromStr("5.b.1") def test_non_int_point(self): with self.assertRaises(ValueError): - version=versionFromStr("5.3.a") + version = versionFromStr("5.3.a") def test_non_string(self): - version=Version(5,3,1) + version = Version(5, 3, 1) with self.assertRaises(TypeError): - version=versionFromStr(version) + version = versionFromStr(version) def test_none(self): with self.assertRaises(TypeError): - version=versionFromStr(version=None) + version = versionFromStr(version=None) if __name__ == '__main__': - #logging.basicConfig(level="INFO") + # logging.basicConfig(level="INFO") unittest.main() - @@ -28,17 +28,20 @@ from linaropy.rninput import finput from jinja2.exceptions import TemplateSyntaxError import traceback -rnProj=[] +rnProj = [] # Cleanup the temporary project directory if necessary. + + def rncleanup(): if not rnProj: - # This will be the case if the script is run via the test driver. + # This will be the case if the script is run via the test driver. print "No cleanup needed" else: - print "Cleaning up Proj dir %s if possible." % rnProj[0].projdir + print "Cleaning up Proj dir %s if possible." % rnProj[0].projdir rnProj[0].cleanup() + def generate(track, to_date, to_series, gccsource, persist): # Delay creating the Proj directory until now so that the parser (and # parser validation functions) can be tested in the unittests without @@ -47,36 +50,38 @@ def generate(track, to_date, to_series, gccsource, persist): print "proj dir is: %s with persist=%s" % (rnProj[0].projdir, str(persist)) # This will raise an exception if gccsource is not a git repository. - gccclone=GCCClone(rnProj[0], clonedir=gccsource) + gccclone = GCCClone(rnProj[0], clonedir=gccsource) - #use gccsource to figure out the GCC Base Version and the FSF Version from the git commit history. + # use gccsource to figure out the GCC Base Version and the FSF Version + # from the git commit history. print 'gccbaseversion is ' + gccclone.get_base_version() print 'fsf revision is ' + gccclone.get_fsf_revision() if gccclone.tag_exists(track): - logging.info("%s is a tag. Creating Series from tag.") - track_series=linaro_series_from_tag(track) + logging.info("%s is a tag. Creating Series from tag.") + track_series = linaro_series_from_tag(track) else: - logging.info("%s is a branch? Creating Series from branchname.") - track_series=linaroSeriesFromBranchname(track) + logging.info("%s is a branch? Creating Series from branchname.") + track_series = linaroSeriesFromBranchname(track) try: - next_series=track_series.toNext(to_series) + next_series = track_series.toNext(to_series) except TypeError: print( "Next series '%s' from '%s' in an invalid progression" - % (LinaroSeries.series[to_series], track_series.shorttype())) - print("If this is a release series try tracking the release-candidate tag instead of the release branch.") - sys.exit(2) + % (LinaroSeries.series[to_series], track_series.shorttype())) + print("If this is a release series try tracking the release-candidate tag instead of the release branch.") + sys.exit(2) if to_date != next_series.date: - raise RuntimeError('The date passed to this driver does not equal the date computed by LinaroSeries.toNext()') + raise RuntimeError( + 'The date passed to this driver does not equal the date computed by LinaroSeries.toNext()') - rnclone=Clone( + rnclone = Clone( rnProj[0], remote=u'ssh://git@git.linaro.org/toolchain/release-notes.git') - next_rn=RNSeries( + next_rn = RNSeries( rnProj[0], rnrepo=rnclone.clonedir(), track_series=track_series, @@ -86,76 +91,93 @@ def generate(track, to_date, to_series, gccsource, persist): print "Please verify that your changes have been committed on the template branch:" next_rn.rn_template.log(1) - ans=True - history=finput('Please enter the location of the changelog csv file: ', "6.1-2016.06.csv") + ans = True + history = finput( + 'Please enter the location of the changelog csv file: ', "6.1-2016.06.csv") next_rn.update_series_readmes() - while ans==True: + while ans == True: # Generate the temporary output files to the projdir. - with cd(rnProj[0].projdir): + with cd(rnProj[0].projdir): try: rngen(next_rn, gccclone, history) except TemplateSyntaxError: traceback.print_exc(file=sys.stdout) print "Please correct the template and try again." - print "Please direct your browser to the rendered .html files in" - print "%s and make sure that they look correct." % rnProj[0].projdir - ans=next_rn.update_series_readmes() + print "Please direct your browser to the rendered .html files in" + print "%s and make sure that they look correct." % rnProj[0].projdir + ans = next_rn.update_series_readmes() # Verify that the GCC Source is located where it says it is. + + class VerifyGCCSourceAction(argparse.Action): + def __init__(self, option_strings, dest, nargs=None, **kwargs): if nargs is not None: raise ValueError("nargs not allowed") - super(VerifyGCCSourceAction, self).__init__(option_strings, dest, **kwargs) + super(VerifyGCCSourceAction, self).__init__( + option_strings, dest, **kwargs) + def __call__(self, parser, namespace, values, option_string=None): print('%r %r %r' % (namespace, values, option_string)) setattr(namespace, self.dest, values) - print "gccsource: " + values - # We simply want to test that the directory exists. We'll prove that - # it is a git directory in a later step. - if not os.path.isdir(values): - sys.exit(2) + print "gccsource: " + values + # We simply want to test that the directory exists. We'll prove that + # it is a git directory in a later step. + if not os.path.isdir(values): + sys.exit(2) + def str_to_datetime(datestr): # strptime will throw an exception if the input date is not a string or is # not parsable. if len(datestr) < 10: - inputdate=datetime.strptime(datestr, "%Y.%m") + inputdate = datetime.strptime(datestr, "%Y.%m") else: - inputdate=datetime.strptime(datestr, "%Y.%m.%d") + inputdate = datetime.strptime(datestr, "%Y.%m.%d") # Force the 'day' to 15 to unify comparisons. - return inputdate.replace(day=15) + return inputdate.replace(day=15) + def create_parser(): parser = argparse.ArgumentParser( prog="rn.py", - description='''Generate release notes.''' + description='''Generate release notes.''' ) # Positionals are required by default. - parser.add_argument('track', help='branchname or tag name of series to track.') + parser.add_argument( + 'track', help='branchname or tag name of series to track.') - parser.add_argument('-g', '--gccsource', dest='gccsource', required=True, action=VerifyGCCSourceAction, help='location of the gcc source') + parser.add_argument('-g', '--gccsource', dest='gccsource', required=True, + action=VerifyGCCSourceAction, help='location of the gcc source') - parser.add_argument('-d', '--date', dest='to_date', required=True, help='the next series date in "YYYY.MM" form.', type=str_to_datetime) + parser.add_argument('-d', '--date', dest='to_date', required=True, + help='the next series date in "YYYY.MM" form.', type=str_to_datetime) - parser.add_argument('-n', '--nopersist', dest='persist', default=True, action='store_false', help='The proj dir will not persist once this program has executed.') + parser.add_argument('-n', '--nopersist', dest='persist', default=True, action='store_false', + help='The proj dir will not persist once this program has executed.') # At least one of the following arguments are required. group = parser.add_mutually_exclusive_group(required=True) - group.add_argument('-c', '--candidate', dest='to_series', action='store_const', const=LinaroSeries.series.index("candidate")) - group.add_argument('-r', '--release', dest='to_series', action='store_const', const=LinaroSeries.series.index("release")) - group.add_argument('-s', '--snapshot', dest='to_series', action='store_const', const=LinaroSeries.series.index("snapshot")) + group.add_argument('-c', '--candidate', dest='to_series', + action='store_const', const=LinaroSeries.series.index("candidate")) + group.add_argument('-r', '--release', dest='to_series', + action='store_const', const=LinaroSeries.series.index("release")) + group.add_argument('-s', '--snapshot', dest='to_series', + action='store_const', const=LinaroSeries.series.index("snapshot")) return parser + def main(): - parser=create_parser() + parser = create_parser() args = parser.parse_args() - generate(args.track, args.to_date, args.to_series, args.gccsource, args.persist) + generate(args.track, args.to_date, args.to_series, + args.gccsource, args.persist) if __name__ == '__main__': logging.basicConfig(level="INFO") @@ -1,24 +1,28 @@ from unittest from rn import create_parser + class TestRn(TestCase): """ Base TestCase class, sets up a CLI parser """ + + @classmethod def setUpClass(cls): parser = create_parser() cls.parser = parser + def test_foo(self): -# args = self.parser.parse_args(['foo', '-R', '', '-A', 'idbs81839']) -# result = ping(args.tags, args.region, args.ami) -# self.assertIsNotNone(result) - -# TODO: test %Y.%m.%d dates -# TODO: test %Y.%m dates -# TODO: test non-conformant dates -# TODO: snapshots/linaro-5.3-2016.05-6 -c -d "2016.06." --strict + # args = self.parser.parse_args(['foo', '-R', '', '-A', 'idbs81839']) + # result = ping(args.tags, args.region, args.ami) + # self.assertIsNotNone(result) + + # TODO: test %Y.%m.%d dates + # TODO: test %Y.%m dates + # TODO: test non-conformant dates + # TODO: snapshots/linaro-5.3-2016.05-6 -c -d "2016.06." --strict if __name__ == '__main__': unittest.main() |