Added edit and delete commands.
* Added `edit` which uses the program in $EDITOR to allow the user to edit the current timeline marker. * Added `delete` to remove the current timeline marker from the timeline. * Added support for using a named TTY device in order to use an interactive program ($EDITOR in this case) to take over interaction with the user. There is still a problem with this, in that a process by default only has access to its controlling TTY device. This mean, for example, that redirecting the subprocess input and output to the TTY will fail to work properly if the timestamper CLI process is not part of the same process group as the process owning the TTY the user is interacting with. This is the case when using nailgun: the java process running TimeStamperCLI is not part of the same process group as the user's client shell. I think TTY device permissions may be alterable, and we can work around this by changing the permissions for the current TTY in the launcher script that invokes the nailgun client. Needs more investigation. * Added package build target to create a zip of the CLI standalone installation.
This commit is contained in:
parent
284a4159d1
commit
76bf676c2c
12
build.xml
12
build.xml
@ -4,4 +4,16 @@
|
||||
<property file="project.properties"/>
|
||||
<import file="jdb-build-1.10.xml"/>
|
||||
|
||||
<target name="package" depends="build">
|
||||
<property name="package.dir" value="${build.dir}/${name}-${version}"/>
|
||||
<mkdir dir="${package.dir}/lib"/>
|
||||
<copy file="${build.dir}/${name}-${version}.${build.number}.jar"
|
||||
tofile="${package.dir}/${name}-${version}.jar"/>
|
||||
<copy todir="${package.dir}/lib">
|
||||
<fileset dir="${build.dir}/lib/runtime/jar"/>
|
||||
</copy>
|
||||
<zip basedir="${build.dir}" includes="${name}-${version}/"
|
||||
destfile="${build.dir}/${name}-${version}.zip"/>
|
||||
|
||||
</target>
|
||||
</project>
|
||||
|
Binary file not shown.
BIN
lib/compile/jar/jdb-util-2.0.jar
Normal file
BIN
lib/compile/jar/jdb-util-2.0.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
lib/runtime/jar/jdb-util-2.0.jar
Normal file
BIN
lib/runtime/jar/jdb-util-2.0.jar
Normal file
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
#Fri, 09 Aug 2013 11:44:57 -0500
|
||||
#Sat, 10 Aug 2013 01:38:31 -0500
|
||||
lib.local=true
|
||||
name=timestamper-cli
|
||||
version=0.3
|
||||
build.number=1
|
||||
version=0.4
|
||||
build.number=13
|
||||
|
@ -23,12 +23,13 @@ public class TimeStamperCLI {
|
||||
protected TimelineProperties timelineProperties
|
||||
protected Timeline timeline
|
||||
|
||||
public static final String VERSION = "0.1"
|
||||
public static final String VERSION = "0.4"
|
||||
|
||||
protected static def cli = [
|
||||
'v': [longOpt: 'version'],
|
||||
'd': [longOpt: 'working-directory', arguments: 1],
|
||||
't': [longOpt: 'timeline-config', arguments: 1] ]
|
||||
't': [longOpt: 'timeline-config', arguments: 1],
|
||||
'tty': [longOpt: 'tty', arguments: 1]]
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
@ -41,17 +42,22 @@ public class TimeStamperCLI {
|
||||
|
||||
doMain(nailgunInst, context.args, context.in, context.out, context.err) }
|
||||
|
||||
protected static doMain(TimeStamperCLI inst, String[] args,
|
||||
protected static void doMain(TimeStamperCLI inst, String[] args,
|
||||
def sin, def out, def err) {
|
||||
|
||||
//out = new PrintStream(AnsiConsole.wrapOutputStream(out))
|
||||
def opts = LightOptionParser.parseOptions(cli, args as List)
|
||||
|
||||
File workingDir = new File(opts.d ?: '.')
|
||||
String ttyDevice = opts.tty ?: '/dev/tty'
|
||||
|
||||
if (opts.v) {
|
||||
println "TimeStamperCLI v${VERSION}"
|
||||
return }
|
||||
|
||||
if (opts.t) {
|
||||
File propFile = new File(workingDir, opts.t)
|
||||
inst.showTimeline(propFile, sin, out, err) }
|
||||
inst.showTimeline(propFile, sin, out, err, ttyDevice) }
|
||||
else if (inst.timeline == null) {
|
||||
// Look for .timestamperrc user config file
|
||||
File cfgFile = new File(
|
||||
@ -61,13 +67,13 @@ public class TimeStamperCLI {
|
||||
cfgFile.canonicalPath
|
||||
else {
|
||||
def cfg = new SmartConfig(cfgFile)
|
||||
inst.showTimeline(new File(cfg.lastUsed), sin, out, err) } }
|
||||
else { inst.showTimeline(sin, out, err) } }
|
||||
inst.showTimeline(new File(cfg.lastUsed), sin, out, err, ttyDevice) } }
|
||||
else { inst.showTimeline(sin, out, err, ttyDevice) } }
|
||||
|
||||
public TimeStamperCLI() { }
|
||||
|
||||
public void showTimeline(File timelinePropertiesFile,
|
||||
def sin, def out, def err) {
|
||||
def sin, def out, def err, String ttyDevice) {
|
||||
if (!timelinePropertiesFile.exists() ||
|
||||
!timelinePropertiesFile.isFile()) {
|
||||
|
||||
@ -79,9 +85,9 @@ public class TimeStamperCLI {
|
||||
this.timelineProperties = new TimelineProperties(timelinePropertiesFile)
|
||||
this.timeline = timelineProperties.timeline
|
||||
|
||||
showTimeline(sin, out, err) }
|
||||
showTimeline(sin, out, err, ttyDevice) }
|
||||
|
||||
public void showTimeline(final def sin, def out, def err) {
|
||||
public void showTimeline(final def sin, def out, def err, String ttyDevice) {
|
||||
|
||||
//out.println ""
|
||||
def currentMarker = timeline.getLastMarker(new Date())
|
||||
@ -136,7 +142,7 @@ public class TimeStamperCLI {
|
||||
case ~/n|new/:
|
||||
|
||||
// Read mark
|
||||
out.println(ansi().fg(YELLOW).a("New timestamp:").reset())
|
||||
out.println(ansi().fg(YELLOW).a("New timestamp mark:").reset())
|
||||
String mark = blockingReadLine()
|
||||
|
||||
// Read notes
|
||||
@ -168,6 +174,21 @@ public class TimeStamperCLI {
|
||||
currentMarker = timeline.getLastMarker(new Date())
|
||||
break
|
||||
|
||||
case ~/e|ed|edit/:
|
||||
reader.pause()
|
||||
out.println(ansi().fg(YELLOW).
|
||||
a("Press ENTER to launch an editor for the current marker..."))
|
||||
out.flush()
|
||||
blockingReadLine()
|
||||
currentMarker = edit(currentMarker, ttyDevice)
|
||||
reader.resume()
|
||||
break
|
||||
|
||||
case ~/d|del|delete/:
|
||||
timeline.removeMarker(currentMarker)
|
||||
currentMarker = timeline.getLastMarker(new Date())
|
||||
break
|
||||
|
||||
default:
|
||||
String notes = readNotes()
|
||||
currentMarker = new TimelineMarker(new Date(), line, notes)
|
||||
@ -195,6 +216,51 @@ public class TimeStamperCLI {
|
||||
out.println ""
|
||||
}
|
||||
|
||||
protected TimelineMarker edit(TimelineMarker tm, String ttyDevice) {
|
||||
File temp = File.createTempFile('timestamp-mark-', '.txt')
|
||||
temp.withPrintWriter { fout ->
|
||||
fout.println("""\
|
||||
# Edit the time, mark, and notes below. Any lines starting with '#' will be
|
||||
# ignored. When done, save the file and close the editor.""")
|
||||
fout.println(Timeline.longFormat.format(tm.timestamp))
|
||||
fout.println(tm.mark)
|
||||
fout.println("""\
|
||||
# Everything from the line below to the end of the file will be considered
|
||||
# notes for this timeline mark.""")
|
||||
fout.println(tm.notes) }
|
||||
|
||||
['sh', '-c', "\$EDITOR ${temp.canonicalPath} <${ttyDevice} >${ttyDevice}"].execute().waitFor()
|
||||
|
||||
Thread.sleep(200)
|
||||
|
||||
String newTimeStr
|
||||
String newMark
|
||||
String newNotes = ""
|
||||
|
||||
temp.eachLine { line ->
|
||||
if (line =~ /^\s*#/) return
|
||||
|
||||
if (!newTimeStr) newTimeStr = line
|
||||
else if (!newMark) newMark = line
|
||||
else newNotes += line + EOL }
|
||||
|
||||
Date newTime
|
||||
try { newTime = Timeline.longFormat.parse(newTimeStr) }
|
||||
catch(Exception e) {
|
||||
out.println(ansi().fg(RED).a("Invalid timestamp format. The " +
|
||||
"previous timestamp value will be retained."))
|
||||
newTime = currentMark.timestamp }
|
||||
|
||||
timeline.removeMarker(tm)
|
||||
def newMarker = new TimelineMarker(newTime, newMark, newNotes)
|
||||
timeline.addMarker(newMarker)
|
||||
if (timelineProperties.persistOnUpdate)
|
||||
timelineProperties.save()
|
||||
|
||||
return newMarker
|
||||
|
||||
}
|
||||
|
||||
protected static String formatMarker(TimelineMarker tm) {
|
||||
return ansi().fgBright(CYAN).
|
||||
a(Timeline.shortFormat.format(tm.timestamp) + " ").fg(GREEN).
|
||||
|
Loading…
x
Reference in New Issue
Block a user