From a369b06115c8fbbae4fc89b05eb8094e2b012c86 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Sat, 13 Feb 2010 06:31:28 -0600 Subject: [PATCH] Split into classes. Created build file and formal project. --- .hgignore | 1 + build.xml | 55 ++++++ pit.groovy | 185 ------------------ project.properties | 8 + src/com/jdbernard/pit/Category.groovy | 14 ++ src/com/jdbernard/pit/Filter.groovy | 28 +++ src/com/jdbernard/pit/Issue.groovy | 24 +++ .../jdbernard/pit/PersonalIssueTracker.groovy | 51 +++++ src/com/jdbernard/pit/Project.groovy | 73 +++++++ 9 files changed, 254 insertions(+), 185 deletions(-) create mode 100644 build.xml delete mode 100755 pit.groovy create mode 100644 project.properties create mode 100644 src/com/jdbernard/pit/Category.groovy create mode 100644 src/com/jdbernard/pit/Filter.groovy create mode 100644 src/com/jdbernard/pit/Issue.groovy create mode 100644 src/com/jdbernard/pit/PersonalIssueTracker.groovy create mode 100644 src/com/jdbernard/pit/Project.groovy diff --git a/.hgignore b/.hgignore index 6f3cc06..b0b9510 100644 --- a/.hgignore +++ b/.hgignore @@ -1 +1,2 @@ +build/ \..*sw[op] diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..a6041da --- /dev/null +++ b/build.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pit.groovy b/pit.groovy deleted file mode 100755 index 58b3c90..0000000 --- a/pit.groovy +++ /dev/null @@ -1,185 +0,0 @@ -#!/usr/bin/groovy - -def cli = new CliBuilder(usage: '') -cli.h(longOpt: 'help', 'Show help information.') -cli.v(longOpt: 'verbose', 'Show verbose task information') -cli.l(longOpt: 'list', 'List issues. Unless otherwise specified it lists all ' - + 'sub projects and all unclosed issue categories.') -cli.i(argName: 'id', longOpt: 'id', args: 1, - 'Filter issues by id. Accepts a comma-delimited list.') -cli.c(argName: 'category', longOpt: 'category', args: 1, - 'Filter issues by category (bug, feature, task, closed). Accepts a ' - + 'comma-delimited list.') -cli.p(argName: 'priority', longOpt: 'priority', args: 1, - 'Filter issues by priority. This acts as a threshhold, listing all issues ' - + 'greater than or equal to the given priority.') -cli.r(argName: 'project', longOpt: 'project', args: 1, - 'Filter issues by project (relative to the current directory). Accepts a ' - + 'comma-delimited list.') -cli.s(longOpt: 'show-subprojects', - 'Include sup projects in listing (default behaviour)') -cli.S(longOpt: 'no-subprojects', 'Do not list subprojects.') - -def opts = cli.parse(args) -def issuedb = [:] - -if (!opts) System.exit(1) // better solution? - -if (opts.h) cli.usage() - -def categories = ['bug','feature','task'] -if (opts.c) categories = opts.c.split(/[,\s]/) -categories = categories.collect { Category.toCategory(it) } - -// build issue list -issuedb = new Project(new File('.'), - new Filter('categories': categories, - 'priority': (opts.p ? opts.p.toInteger() : 9), - 'projects': (opts.r ? opts.r.toLowerCase().split(/[,\s]/).asType(List.class) : []), - 'ids': (opts.i ? opts.i.split(/[,\s]/).asType(List.class) : []), - 'acceptProjects': (opts.s || !opts.S))) - -// list first -if (opts.l) issuedb.list('verbose': opts.v) - -// change priority second -//else if (opts.cp) - -// change category third -//else if (opts.cc) - -// new entry last - -enum Category { - BUG, - FEATURE, - TASK, - CLOSED - - public static Category toCategory(String s) { - for(c in Category.values()) - if (c.toString().startsWith(s.toUpperCase())) return c - throw new IllegalArgumentException("No category matches ${s}.") - } -} - -class Project { - - String name - Map issues = [:] - Map projects = [:] - - Project(File dir, Filter filter = null) { - dir.eachFile { child -> - - // add sub projects - if (child.isDirectory()) { - if ( child.name ==~ /\d{4}/ || // just an issue folder - (filter && !filter.accept(child.name))) - return - - // otherwise build and add to list - projects[(child.name)] = new Project(child, filter) - } else if (child.isFile()) { - def issue - - // if exception, then not an issue - try { issue = new Issue(child) } catch (all) { return } - - if (filter && !filter.accept(issue)) return - - issues[(issue.id)] = issue - } - } - } - - public void eachIssue(Closure c) { - for (i in issues.values()) c.call(i) - for (p in projects.values()) p.eachIssue(c) - } - - public void each(Filter filter = null, Closure c) { - def is = filter?.issueSorter ?: { it.id.toInteger() } - def ps = filter?.projectSorter ?: { it.name } - - for (issue in issues.values().sort(is)) { - if (filter && !filter.accept(issue)) - return - - c.call(issue) - } - - for (project in projects.values().sort(ps)) { - if (filter && !filter.accept(project)) - return - - c.call(project) - project.each(c) - } - } - - public void list(Map options = [:]) { - if (!options.offset) options.offset = "" - if (!options.verbose) options.verbose = false - - each(options.filter) { - if (it instanceof Project) { - println "\n${options.offset}${it.name}" - println "${options.offset}${'-'.multiply(p.name.length())}" - } else { - println "${options.offset}${it.id}(${it.priority}): " + - "${it.category} ${it.title}" - if (options.verbose) println "\n${it.text}" - } - } - } -} - -class Issue { - - String id - Category category - int priority - String title - String text - - Issue(File file) { - - def matcher = file.name =~ /(\d{4})([bftc])(\d).*/ - if (!matcher) return null - - id = matcher[0][1] - category = Category.toCategory(matcher[0][2]) - priority = matcher[0][3].toInteger() - - file.withReader { title = it.readLine() } - text = file.text - } -} - -class Filter { - - List categories = null - List projects = null - List ids = null - int priority = 9 - boolean acceptProjects = true - Closure projectSorter - Closure issueSorter - - public boolean accept(Issue i) { - return (i.priority <= priority && - (!categories || categories.contains(i.category)) && - (!ids || ids.contains(i.id))) - } - - public boolean accept(Project p) { - return (acceptProjects && - (!projects || projects.contains(p.name))) - } - - public boolean accept(String name) { - return (acceptProjects && - (!projects || projects.contains(name))) - } -} diff --git a/project.properties b/project.properties new file mode 100644 index 0000000..7acec89 --- /dev/null +++ b/project.properties @@ -0,0 +1,8 @@ +app.version=1.0 +build.dir=build +build.jar=pit-${app.version}.jar +build.lib.jar=lib${build.jar} +groovy.home=/usr/share/groovy +lib.dir=lib +main.class=com.jdbernard.pit.PersonalIssueTracker +src.dir=src diff --git a/src/com/jdbernard/pit/Category.groovy b/src/com/jdbernard/pit/Category.groovy new file mode 100644 index 0000000..f6edd51 --- /dev/null +++ b/src/com/jdbernard/pit/Category.groovy @@ -0,0 +1,14 @@ +package com.jdbernard.pit + +public enum Category { + BUG, + FEATURE, + TASK, + CLOSED + + public static Category toCategory(String s) { + for(c in Category.values()) + if (c.toString().startsWith(s.toUpperCase())) return c + throw new IllegalArgumentException("No category matches ${s}.") + } +} diff --git a/src/com/jdbernard/pit/Filter.groovy b/src/com/jdbernard/pit/Filter.groovy new file mode 100644 index 0000000..70eadd9 --- /dev/null +++ b/src/com/jdbernard/pit/Filter.groovy @@ -0,0 +1,28 @@ +package com.jdbernard.pit + +class Filter { + + List categories = null + List projects = null + List ids = null + int priority = 9 + boolean acceptProjects = true + Closure projectSorter + Closure issueSorter + + public boolean accept(Issue i) { + return (i.priority <= priority && + (!categories || categories.contains(i.category)) && + (!ids || ids.contains(i.id))) + } + + public boolean accept(Project p) { + return (acceptProjects && + (!projects || projects.contains(p.name))) + } + + public boolean accept(String name) { + return (acceptProjects && + (!projects || projects.contains(name))) + } +} diff --git a/src/com/jdbernard/pit/Issue.groovy b/src/com/jdbernard/pit/Issue.groovy new file mode 100644 index 0000000..f4d104b --- /dev/null +++ b/src/com/jdbernard/pit/Issue.groovy @@ -0,0 +1,24 @@ +package com.jdbernard.pit + +public class Issue { + + String id + Category category + int priority + String title + String text + + Issue(File file) { + + def matcher = file.name =~ /(\d{4})([bftc])(\d).*/ + if (!matcher) return null + + id = matcher[0][1] + category = Category.toCategory(matcher[0][2]) + priority = matcher[0][3].toInteger() + + file.withReader { title = it.readLine() } + text = file.text + } + +} diff --git a/src/com/jdbernard/pit/PersonalIssueTracker.groovy b/src/com/jdbernard/pit/PersonalIssueTracker.groovy new file mode 100644 index 0000000..8dce79b --- /dev/null +++ b/src/com/jdbernard/pit/PersonalIssueTracker.groovy @@ -0,0 +1,51 @@ +package com.jdbernard.pit + +def cli = new CliBuilder(usage: '') +cli.h(longOpt: 'help', 'Show help information.') +cli.v(longOpt: 'verbose', 'Show verbose task information') +cli.l(longOpt: 'list', 'List issues. Unless otherwise specified it lists all ' + + 'sub projects and all unclosed issue categories.') +cli.i(argName: 'id', longOpt: 'id', args: 1, + 'Filter issues by id. Accepts a comma-delimited list.') +cli.c(argName: 'category', longOpt: 'category', args: 1, + 'Filter issues by category (bug, feature, task, closed). Accepts a ' + + 'comma-delimited list.') +cli.p(argName: 'priority', longOpt: 'priority', args: 1, + 'Filter issues by priority. This acts as a threshhold, listing all issues ' + + 'greater than or equal to the given priority.') +cli.r(argName: 'project', longOpt: 'project', args: 1, + 'Filter issues by project (relative to the current directory). Accepts a ' + + 'comma-delimited list.') +cli.s(longOpt: 'show-subprojects', + 'Include sup projects in listing (default behaviour)') +cli.S(longOpt: 'no-subprojects', 'Do not list subprojects.') + +def opts = cli.parse(args) +def issuedb = [:] + +if (!opts) System.exit(1) // better solution? + +if (opts.h) cli.usage() + +def categories = ['bug','feature','task'] +if (opts.c) categories = opts.c.split(/[,\s]/) +categories = categories.collect { Category.toCategory(it) } + +// build issue list +issuedb = new Project(new File('.'), + new Filter('categories': categories, + 'priority': (opts.p ? opts.p.toInteger() : 9), + 'projects': (opts.r ? opts.r.toLowerCase().split(/[,\s]/).asType(List.class) : []), + 'ids': (opts.i ? opts.i.split(/[,\s]/).asType(List.class) : []), + 'acceptProjects': (opts.s || !opts.S))) + +// list first +if (opts.l) issuedb.list('verbose': opts.v) + +// change priority second +//else if (opts.cp) + +// change category third +//else if (opts.cc) + +// new entry last diff --git a/src/com/jdbernard/pit/Project.groovy b/src/com/jdbernard/pit/Project.groovy new file mode 100644 index 0000000..717669f --- /dev/null +++ b/src/com/jdbernard/pit/Project.groovy @@ -0,0 +1,73 @@ +package com.jdbernard.pit + +class Project { + + String name + Map issues = [:] + Map projects = [:] + + Project(File dir, Filter filter = null) { + dir.eachFile { child -> + + // add sub projects + if (child.isDirectory()) { + if ( child.name ==~ /\d{4}/ || // just an issue folder + (filter && !filter.accept(child.name))) + return + + // otherwise build and add to list + projects[(child.name)] = new Project(child, filter) + } else if (child.isFile()) { + def issue + + // if exception, then not an issue + try { issue = new Issue(child) } catch (all) { return } + + if (filter && !filter.accept(issue)) return + + issues[(issue.id)] = issue + } + } + } + + public void eachIssue(Closure c) { + for (i in issues.values()) c.call(i) + for (p in projects.values()) p.eachIssue(c) + } + + public void each(Filter filter = null, Closure c) { + def is = filter?.issueSorter ?: { it.id.toInteger() } + def ps = filter?.projectSorter ?: { it.name } + + for (issue in issues.values().sort(is)) { + if (filter && !filter.accept(issue)) + return + + c.call(issue) + } + + for (project in projects.values().sort(ps)) { + if (filter && !filter.accept(project)) + return + + c.call(project) + project.each(c) + } + } + + public void list(Map options = [:]) { + if (!options.offset) options.offset = "" + if (!options.verbose) options.verbose = false + + each(options.filter) { + if (it instanceof Project) { + println "\n${options.offset}${it.name}" + println "${options.offset}${'-'.multiply(p.name.length())}" + } else { + println "${options.offset}${it.id}(${it.priority}): " + + "${it.category} ${it.title}" + if (options.verbose) println "\n${it.text}" + } + } + } +}