aboutsummaryrefslogtreecommitdiffhomepage
path: root/gbp/pq.py
diff options
context:
space:
mode:
Diffstat (limited to 'gbp/pq.py')
-rw-r--r--gbp/pq.py137
1 files changed, 137 insertions, 0 deletions
diff --git a/gbp/pq.py b/gbp/pq.py
new file mode 100644
index 00000000..39eb6a07
--- /dev/null
+++ b/gbp/pq.py
@@ -0,0 +1,137 @@
+# vim: set fileencoding=utf-8 :
+#
+# (C) 2011 Guido Guenther <agx@sigxcpu.org>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+import os
+import re
+from errors import GbpError
+
+class Patch(object):
+ """
+ A patch in a patchqueue
+
+ @ivar path: path to the patch
+ @type path: string
+ @ivar topic: the topic of the patch
+ @type topic: string
+ @ivar strip: path components to strip (think patch -p<strip>)
+ @type strip: integer
+ """
+ def __init__(self, path, topic=None, strip=None):
+ self.path = path
+ self.topic = topic
+ self.strip = strip
+
+ def __repr__(self):
+ repr = "<gbp.pq.Patch path='%s' " % self.path
+ if self.topic:
+ repr += "topic='%s' " % self.topic
+ if self.strip != None:
+ repr += "strip=%d " % self.strip
+ repr += ">"
+ return repr
+
+
+class PatchQueue(list):
+ @classmethod
+ def read_series_file(klass, seriesfile):
+ """Read a series file into gbp.pq.Patch objects"""
+ patch_dir = os.path.dirname(seriesfile)
+ try:
+ s = file(seriesfile)
+ except Exception, err:
+ raise GbpError("Cannot open series file: %s" % err)
+
+ queue = klass._read_series(s, patch_dir)
+ s.close()
+ return queue
+
+ @classmethod
+ def _read_series(klass, series, patch_dir):
+ """
+ Read patch series
+ @param series: series of patches in quilt format
+ @type series: iterable of strings
+ @param patch_dir: path prefix to prepend to each patch path
+ @type patch_dir: string
+
+ >>> PatchQueue._read_series(['a/b', \
+ 'a -p1', \
+ 'a/b -p2'], '.') # doctest:+NORMALIZE_WHITESPACE
+ [<gbp.pq.Patch path='./a/b' topic='a' >,
+ <gbp.pq.Patch path='./a' strip=1 >,
+ <gbp.pq.Patch path='./a/b' topic='a' strip=2 >]
+ """
+
+ queue = PatchQueue()
+ for line in series:
+ queue.append(klass._parse_line(line, patch_dir))
+ return queue
+
+ @staticmethod
+ def _get_topic(line):
+ """
+ Get the topic from the path's path
+ >>> PatchQueue._get_topic("a/b c")
+ 'a'
+ >>> PatchQueue._get_topic("asdf")
+ >>> PatchQueue._get_topic("/asdf")
+ """
+ topic = os.path.dirname(line)
+ if topic in [ '', '/' ]:
+ topic = None
+ return topic
+
+ @staticmethod
+ def _split_strip(line):
+ """
+ Separate the -p<num> option from the patch name
+
+ >>> PatchQueue._split_strip("asdf -p1")
+ ('asdf', 1)
+ >>> PatchQueue._split_strip("a/nice/patch")
+ ('a/nice/patch', None)
+ >>> PatchQueue._split_strip("asdf foo")
+ ('asdf foo', None)
+ """
+ patch = line
+ strip = None
+
+ split = line.rsplit(None, 1)
+ if len(split) > 1:
+ m = re.match('-p(?P<level>[0-9]+)', split[1])
+ if m:
+ patch = split[0]
+ strip = int(m.group('level'))
+
+ return (patch, strip)
+
+ @classmethod
+ def _parse_line(klass, line, patch_dir):
+ """
+ Parse a single line from a patch file
+
+ >>> PatchQueue._parse_line("a/b -p1", '/tmp/patches')
+ <gbp.pq.Patch path='/tmp/patches/a/b' topic='a' strip=1 >
+ >>> PatchQueue._parse_line("a/b", '.')
+ <gbp.pq.Patch path='./a/b' topic='a' >
+ """
+ line = line.rstrip()
+ topic = klass._get_topic(line)
+ (patch, split) = klass._split_strip(line)
+ return Patch(os.path.join(patch_dir, patch), topic, split)
+
+