3 Commits
0.3 ... 0.6

Author SHA1 Message Date
e296e87003 Version 1.6: Added help section, bugfix, updated build process.
* Build now includes config and bin resources.
* Build new builds an executable jar.
* Added help section.
* Bugfix for working directory.
2013-09-13 09:16:08 -05:00
269a9b9125 Version 0.5: Added support for syncing timelines.
* Added missing libraries required by timeline-lib to support syncable
  timelines.
* Added code to shutdown sync threads upon exit.
2013-09-13 08:57:45 -05:00
76bf676c2c 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.
2013-08-10 01:40:02 -05:00
27 changed files with 134 additions and 14 deletions

View File

@ -4,4 +4,20 @@
<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}">
<fileset dir="${resources.dir}/bin"/>
</copy>
<copy todir="${package.dir}/lib">
<fileset dir="${build.dir}/lib/runtime/jar"/>
<fileset dir="${resources.dir}/config"/>
</copy>
<zip basedir="${build.dir}" includes="${name}-${version}/"
destfile="${build.dir}/${name}-${version}.zip"/>
</target>
</project>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,7 @@
#Fri, 09 Aug 2013 11:44:57 -0500
#Fri, 13 Sep 2013 09:05:06 -0500
lib.local=true
name=timestamper-cli
version=0.3
build.number=1
version=0.6
build.number=4
main.class=com.jdblabs.timestamper.cli.TimeStamperCLI
executable.jar=true

4
resources/bin/ts Executable file
View File

@ -0,0 +1,4 @@
curdir="`pwd`"
cd ~/programs/timestamper-cli-0.4
java -cp "lib:lib/*:./*" com.jdblabs.timestamper.cli.TimeStamperCLI -d "$curdir" "$@"
cd "$curdir"

View File

View File

@ -23,12 +23,14 @@ public class TimeStamperCLI {
protected TimelineProperties timelineProperties
protected Timeline timeline
public static final String VERSION = "0.1"
public static final String VERSION = "0.6"
protected static def cli = [
'h': [longOpt: 'help'],
'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 +43,26 @@ 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.h) println USAGE
if (opts.v) {
println "TimeStamperCLI v${VERSION}"
println "By JDB Labs (https://www.jdb-labs.com)"
return }
if (opts.t) {
File propFile = new File(workingDir, opts.t)
inst.showTimeline(propFile, sin, out, err) }
File propFile = new File(opts.t)
if (!propFile.isAbsolute()) propFile = new File(workingDir, opts.t)
inst.showTimeline(propFile, sin, out, err, ttyDevice) }
else if (inst.timeline == null) {
// Look for .timestamperrc user config file
File cfgFile = new File(
@ -61,13 +72,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 +90,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 +147,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 +179,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)
@ -187,6 +213,8 @@ public class TimeStamperCLI {
}
}
this.timelineProperties.syncTargets.each { it.shutdown() }
if (readerThread.isAlive()) {
readerThread.interrupt();
readerThread.join(500);
@ -195,6 +223,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).
@ -219,4 +292,29 @@ public class TimeStamperCLI {
return sb.toString() }
public static final String USAGE = """\
TimeStamperCLI v${VERSION}
By JDB Labs (https://www.jdb-labs.com)
Usage:
ts <OPTIONS>
where OPTIONS is one or more of:
-h, --help Print this usage information.
-v, --version Print version information.
-d, --working-directory Set the application's working direcotry (defaults to
the current directory of the executing process).
-t, --timeline-config Set the timeline configuration file to use to access
the timeline. By default, the value of the
`lastUsed` property in the \$HOME/.timestamperrc
file is used to find the timeline configuration file
to use.
--tty Manually set the name of the TTY device to use. This
defaults to `/dev/tty`.
"""
}