Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #4 from twitter/fixup

Fixup
  • Loading branch information...
commit 3bea47b076cbcf932effd24af35ed3a3a614faab 2 parents 30937d4 + 511fd10
Kyle Maxwell authored
View
1  HACKING
@@ -0,0 +1 @@
+When you make changes to this project, please test by bootstrapping a new project and running `sbt update test` there.
View
47 README.rdoc
@@ -1,8 +1,47 @@
This creates a standard environment for your twitter-centric sbt/scala thrift service.
+Building:
+
+ :$ rake build
+ :$ gem install pkg/scala-bootstrapper-*.gem
+
Usage:
- :$ mkdir foo
- :$ cd foo
- :$ scala-bootstrapper foo
- :$ sbt update test
+ :$ mkdir birdname
+ :$ cd birdname
+ :$ scala-bootstrapper birdname
+ :$ sbt update test
+
+Tutorial:
+
+ :$ less TUTORIAL.md
+
+== Git support
+
+You can track files generated by scala-bootstrapper in a Git branch,
+and later merge changes from the branch (e.g. to rename a project, or
+to upgrade to a newer version of scala-bootstrapper.
+
+To get started:
+
+ :$ scala-bootstrapper --git foo
+
+For a brand-new project (no <tt>.git</tt> directory) this will
+initialize a Git repo in the directory, generate files into the
+<tt>scala-bootstrapper</tt> branch, and merge the branch to
+<tt>master</tt>.
+
+For an existing project, this will generate files into the
+<tt>scala-bootstrapper</tt> branch, and merge it to the current branch
+*without* actually taking the changes (just making
+<tt>scala-bootstrapper</tt> a parent of the current branch to anchor
+future merges). This is to avoid clobbering files if you had
+previously run <tt>scala-bootstrapper</tt> without the <tt>--git</tt>
+option (or created files some other way). If you want to merge the
+changes and manually resolve any conflicts, do
+
+ :$ git cherry-pick --no-commit scala-bootstrapper
+
+Once the <tt>scala-bootstrapper</tt> branch is created, subsequent
+runs will generate files into the branch and merge it to the current
+branch; if there are conflicts you can resolve them in the usual way.
View
2  VERSION
@@ -1 +1 @@
-0.7.1
+0.9.2
View
2  bin/sbt
@@ -1,2 +0,0 @@
-#!/usr/bin/env ruby
-exec "java","-Xmx2g", "-XX:+CMSClassUnloadingEnabled", "-XX:MaxPermSize=256m", "-jar", File.dirname(__FILE__) + "/../vendor/sbt-launch-0.7.4.jar", *ARGV
View
81 bin/scala-bootstrapper
@@ -7,6 +7,7 @@ opts = Trollop::options do
opt :public, "Use the public twitter maven repo"
opt :namespace, "Use something besides com.twitter", :type => :string
+ opt :git, "Use Git to track updates to generated files"
end
@@ -34,12 +35,16 @@ end
def gsub_birds(haystack, name, namespace)
haystack.
+ gsub("com.twitter.birdname", "#{namespace}.#{name.downcase}").
+ gsub("com/twitter/birdname", "#{namespace.gsub('.', '/')}/#{name.downcase}").
gsub("BirdName", name).
gsub("birdname", name.downcase).
gsub("bird_name", name.underscore).
- gsub("birdName", name.camelize).
- gsub("com.twitter", namespace).
- gsub("com/twitter", namespace.gsub(".", "/"))
+ gsub("birdName", name.camelize)
+end
+
+def sys(cmd, abort_on_fail=true)
+ system(cmd + " &> /dev/null") || abort_on_fail && abort("failed: #{cmd}")
end
require "erb"
@@ -49,6 +54,35 @@ include FileUtils
project_name = ARGV.pop.camelize(true)
is_public = opts[:public]
namespace = opts[:namespace] || "com.twitter"
+git = opts[:git]
+$overwrite_all = true if git
+$ex_post_facto = false
+$branch = 'master'
+$files = []
+
+if git
+ if !File.exists?('.git')
+ if `ls -l` != ''
+ abort('files in directory, no git repo.')
+ end
+ sys('git init')
+ sys('touch README.md')
+ sys('git add .')
+ sys("git commit -m'first commit'")
+ sys('git checkout -b scala-bootstrapper')
+
+ else
+ if `git status -s` != ''
+ abort('uncommitted files in directory.')
+ end
+ $branch = `git branch`.grep(/^\*/).first.chomp.gsub(/^\* (.+)$/, '\1')
+
+ if !sys('git checkout scala-bootstrapper', false)
+ $ex_post_facto = true
+ sys('git checkout -b scala-bootstrapper')
+ end
+ end
+end
root = File.expand_path(File.dirname(__FILE__) + "/../lib/template")
@@ -72,8 +106,47 @@ Dir["#{root}/**/*"].select{|path| File.file?(path)}.each do |path|
puts "writing #{target_path}"
mkdir_p(File.dirname(target_path))
File.open(target_path, "w") {|f| f.print(gsub_birds(template.result(binding), project_name, namespace)) }
+ $files << target_path
end
if File.exists?("src/scripts/startup.sh")
- `mv src/scripts/startup.sh src/scripts/#{project_name.downcase}.sh`
+ startup = "src/scripts/#{project_name.downcase}.sh"
+ `mv src/scripts/startup.sh #{startup}`
+ $files << startup
+end
+
+[ "src/scripts/#{project_name.downcase}.sh", "src/scripts/console", "run" ].each do |executable|
+ `chmod +x #{executable}` if File.exists?(executable)
+end
+
+if git
+ $files.each { |file| sys("git add #{file}") if File.exists?(file) }
+ sys("git commit -m'scala-bootstrapper'", false) # fails if no change
+ sys("git checkout #{$branch}")
+ sys('git merge --no-ff --no-commit scala-bootstrapper')
+
+ if $ex_post_facto
+ # don't commit anything, just make scala-bootstrapper head a parent
+ sys('rm .git/index')
+ sys('git checkout HEAD .')
+ sys('git clean -fdx')
+ end
+
+ sys("git commit -m'merged scala-bootstrapper'", false) # fails if no change
+end
+
+if $ex_post_facto
+ puts <<EOF
+Found existing .git directory; scala-bootstrapper branch created but
+generated files not merged to #{$branch}. To manually merge changes,
+run
+
+ git cherry-pick --no-commit scala-bootstrapper
+
+then
+
+ git commit
+
+once you have resolved any conflicts.
+EOF
end
View
0  lib/template/.gitignore → lib/template/.gitignore.erb
File renamed without changes
View
8 lib/template/Gemfile
@@ -1,6 +1,8 @@
+# use "bundle install" to update gems; "gem install bundler" to install bundler.
source :rubygems
source "http://gems.local.twitter.com"
-gem "thrift_client", "0.6"
-gem "thrift", "0.5"
+gem "thrift_client", "0.6.2"
+gem "thrift", "0.6"
gem "railsless-deploy"
-gem "twitter-cap-utils", "~>0.8.0"
+gem "capistrano"
+gem "twitter-cap-utils", "~>0.8.0"
View
24 lib/template/README.md
@@ -0,0 +1,24 @@
+# Project BirdName
+
+Welcome to your birdname project! To make sure things are working
+properly, you may want to:
+
+ $ sbt update test
+
+There is a tutorial for what to do next, which you can find in the
+scala-bootstrapper README.rdoc file.
+
+# Configuring Intellij
+
+If you want to setup Intellij, it has to happen off to the side:
+
+ $ sbt
+ > *sbtIdeaRepo at http://mpeltonen.github.com/maven/
+ > *idea is com.github.mpeltonen sbt-idea-processor 0.4.0
+ > update
+ > idea
+
+# Documenting your project
+
+Add documentation here! Eventually, you'll be able to publish this to
+a web site for the world to easily find and read.
View
187 lib/template/TUTORIAL.md
@@ -0,0 +1,187 @@
+# Welcome to BirdName!
+
+## Setup
+
+Scala-bootstrapper has created a fully-functional Scala service for
+you. You can verify that things are set up correctly by doing:
+
+ $ sbt update test
+
+## Tutorial
+
+### Run your service!
+
+There are two ways to start your service. You can build a runnable
+jar and tell java to run it directly:
+
+ $ sbt package-dist
+ $ java -Dstage=development -jar ./dist/birdname/birdname-1.0.0-SNAPSHOT.jar
+
+or you can ask sbt to run your service:
+
+ $ sbt 'run -f config/development.scala'
+
+### Verify that the service is running
+
+The java/sbt command-lines will "hang" because the server is running in the
+foreground. (In production, we use libslack-daemon to wrap java processes into
+unix daemons.) Go to another terminal and check for a logfile. If your server
+is named "birdname", there should be a `birdname.log` with contents like this:
+
+ INF [20110615-14:05:41.656] stats: Starting JsonStatsLogger
+ INF [20110615-14:05:41.674] admin: Starting TimeSeriesCollector
+ DEB [20110615-14:05:41.792] nio: Using the autodetected NIO constraint level: 0
+
+That's your indication that the server is running. :)
+
+### View the Thrift IDL for your service
+
+The IDL for your service is in `src/main/thrift/birdname.thrift`. The
+Thrift compiler uses the IDL to generate bindings for various
+languages, making it easy for scripts in those languages to talk to
+your service. More information about Thrift and how to write an IDL
+for your service can be found [here](http://wiki.apache.org/thrift/Tutorial).
+
+### Call your service from ruby
+
+Your service implements simple get() and put() methods. Once you have
+your server running, as above, bring up a different shell and:
+
+ $ cd birdname
+ $ bundle install
+ $ ./dist/birdname/scripts/console
+ >> $client
+ >> $client.put("key1", "valueForKey")
+ >> $client.get("key1")
+
+### Look at the stats for your service
+
+By default, your project is configured to use
+[Ostrich](https://github.com/twitter/ostrich), a library for service
+configuration, administration, and stats reporting. Your config file
+in `config/development.scala` defines which port ostrich uses for admin
+requests. You can view the stats via that port:
+
+ $ curl localhost:9900/stats.txt
+ counters:
+ BirdName/connects: 1
+ BirdName/requests: 2
+ BirdName/success: 2
+ ...
+
+Ostrich also stores historial stats data and can build
+[graphs](http://localhost:9900/graph/) for you.
+
+### Stop the service
+
+You can ask the server to shutdown over the admin port also:
+
+ $ curl localhost:9900/shutdown.txt
+ ok
+
+### View the implementation of get() and put()
+
+In `src/main/scala`, take a look at `BirdNameServiceImpl.scala`. (This may
+have a different name, based on what you called your server.)
+
+The base interface is specified by thrift. Additionally, we're using Twitter's
+async I/O framework: finagle. Finagle (and a lot of great documentation about
+it) is hosted here: https://github.com/twitter/finagle
+
+### Try adding some timers and counters
+
+At the top of BirdNameServiceImpl.scala, add:
+
+ import com.twitter.ostrich.stats.Stats
+
+Then inside get():
+
+ Stats.incr("birdname.gets")
+
+and inside put():
+
+ Stats.incr("birdname.puts")
+
+Then restart your server, talk to the server via console, and check
+your stats:
+
+ $ curl localhost:9900/stats.txt
+ counters:
+ BirdName/connects: 1
+ BirdName/requests: 2
+ BirdName/success: 2
+ birdname.gets: 1
+ birdname.puts: 1
+
+You can also time various things that your server is doing, for
+example:
+
+ Stats.time("birdname.put.latency") {
+ Thread.sleep(10) // so you can see it
+ database(key) = value
+ }
+
+### Specs: let's add some tests
+
+[Specs](http://code.google.com/p/specs/) is a Behavior-Driven Design
+framework that allows you to write semi-human-readable descriptions of
+how your service should behave and test that those descriptions are
+valid. You already have some Specs code for your project in
+src/test/scala/com/twitter/birdname/BirdNameServiceSpec.scala. Check
+out the existing test and add a new one for the counter functionality
+we just added.
+
+ import com.twitter.ostrich.stats.Stats
+
+ ...
+
+ "verify stats" in {
+ val counters = Stats.getCounters
+ foofa.put("name", "bluebird")()
+ foofa.get("name")() mustEqual "bluebird"
+ counters.getOrElse("foofa.gets", 1) must_==1
+ counters.getOrElse("foofa.puts", 1) must_==1
+ }
+
+TODO: add link to scala school lesson on Specs
+
+### Automatically compile and test your server when you change code
+
+By now you've had to Ctrl-C your server and restart it to get changes
+to show up. This gets a little tiresome. The build tool we are
+using,
+[SBT (simple build tool)](http://code.google.com/p/simple-build-tool/)
+has a console that you can access by just running "sbt" from the
+command line.
+
+ $ sbt
+ [info] Standard project rules 0.11.4 loaded (2011-03-18).
+ [warn] No .svnrepo file; no svn repo will be configured.
+ [info] Building project birdname 1.0.0-SNAPSHOT against Scala 2.8.1
+ [info] using BirdNameProject with sbt 0.7.4 and Scala 2.7.7
+
+SBT has a wide array of features, but a useful one right now is to
+use the "~ test" command.
+
+ > ~ test
+
+The tilde tells SBT to look for changes to your source files and
+re-execute the command when it detects a change.
+
+TODO: add link to scala school lesson on SBT
+
+### Add an admin / dashboard page.
+
+### Add a new dependency to your project, perhaps twitter/util?
+
+### Take a tour of the logs our service is producing.
+
+### Add command-line parameters for your service.
+-D foo=bar
+runtime.arguments.get("foo")
+
+### Storage: let's persist the data in Cassandra!
+
+### Twitter API: let's listen to the Firehose!
+
+### Twitter API: let's fetch some statuses & users & stuff.
View
10 lib/template/config/development.scala.erb
@@ -5,9 +5,9 @@ import com.twitter.birdname.config._
// development mode.
new BirdNameServiceConfig {
-
+
// Add your own config here
-
+
// Where your service will be exposed.
thriftPort = 9999
@@ -15,9 +15,9 @@ new BirdNameServiceConfig {
admin.httpPort = 9900
// End user configuration
-
- // Expert-only: Ostrich stats and logger configuration.
-
+
+ // Expert-only: Ostrich stats and logger configuration.
+
admin.statsNodes = new StatsConfig {
reporters = new JsonStatsLoggerConfig {
loggerName = "stats"
View
6 lib/template/config/production.scala.erb
@@ -5,9 +5,9 @@ import com.twitter.birdname.config._
// production mode.
new BirdNameServiceConfig {
-
+
// Add your own config here
-
+
// Where your service will be exposed.
thriftPort = 9999
@@ -15,7 +15,7 @@ new BirdNameServiceConfig {
admin.httpPort = 9900
// End user configuration
-
+
// Expert-only: Ostrich stats and logger configuration.
admin.statsNodes = new StatsConfig {
reporters = new JsonStatsLoggerConfig {
View
6 lib/template/config/staging.scala.erb
@@ -5,9 +5,9 @@ import com.twitter.birdname.config._
// staging mode.
new BirdNameServiceConfig {
-
+
// Add your own config here
-
+
// Where your service will be exposed.
thriftPort = 9999
@@ -15,7 +15,7 @@ new BirdNameServiceConfig {
admin.httpPort = 9900
// End user configuration
-
+
// Expert-only: Ostrich stats and logger configuration.
admin.statsNodes = new StatsConfig {
reporters = new JsonStatsLoggerConfig {
View
6 lib/template/config/test.scala.erb
@@ -5,9 +5,9 @@ import com.twitter.birdname.config._
// test mode.
new BirdNameServiceConfig {
-
+
// Add your own config here
-
+
// Where your service will be exposed.
thriftPort = 9999
@@ -15,7 +15,7 @@ new BirdNameServiceConfig {
admin.httpPort = 9900
// End user configuration
-
+
// Expert-only: Ostrich stats and logger configuration.
admin.statsNodes = new StatsConfig {
reporters = new JsonStatsLoggerConfig {
View
10 lib/template/project/build/BirdNameProject.scala.erb
@@ -14,18 +14,22 @@ class BirdNameProject(info: ProjectInfo) extends StandardServiceProject(info)
with NoisyDependencies
with DefaultRepos
with SubversionPublisher
+ with PublishSourcesAndJavadocs
+ with PublishSite
{
- val finagleVersion = "1.2.1"
+ val finagleVersion = "1.8.4"
+
val finagleC = "com.twitter" % "finagle-core" % finagleVersion
val finagleT = "com.twitter" % "finagle-thrift" % finagleVersion
val finagleO = "com.twitter" % "finagle-ostrich4" % finagleVersion
// thrift
val libthrift = "thrift" % "libthrift" % "0.5.0"
+ val util = "com.twitter" % "util" % "1.11.2"
override def originalThriftNamespaces = Map("BirdName" -> "com.twitter.birdname.thrift")
- val scalaThriftTargetNamespace = "com.twitter.birdname"
-
+ override val scalaThriftTargetNamespace = "com.twitter.birdname"
+
val slf4jVersion = "1.5.11"
val slf4jApi = "org.slf4j" % "slf4j-api" % slf4jVersion withSources() intransitive()
val slf4jBindings = "org.slf4j" % "slf4j-jdk14" % slf4jVersion withSources() intransitive()
View
23 lib/template/project/plugins/Plugins.scala.erb
@@ -1,7 +1,24 @@
import sbt._
class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
- val twitterMaven = "twitter.com" at "http://maven.twttr.com/"
- val standardProject = "com.twitter" % "standard-project" % "0.11.1"
- val sbtThrift = "com.twitter" % "sbt-thrift" % "1.1.0"
+ import scala.collection.jcl
+ val environment = jcl.Map(System.getenv())
+ def isSBTOpenTwitter = environment.get("SBT_OPEN_TWITTER").isDefined
+ def isSBTTwitter = environment.get("SBT_TWITTER").isDefined
+
+ override def repositories = if (isSBTOpenTwitter) {
+ Set("twitter.artifactory" at "http://artifactory.local.twitter.com/open-source/")
+ } else if (isSBTTwitter) {
+ Set("twitter.artifactory" at "http://artifactory.local.twitter.com/repo/")
+ } else {
+ super.repositories ++ Set(
+ "twitter.com" at "http://maven.twttr.com/",
+ "scala-tools" at "http://scala-tools.org/repo-releases/",
+ "freemarker" at "http://freemarker.sourceforge.net/maven2/"
+ )
+ }
+ override def ivyRepositories = Seq(Resolver.defaultLocal(None)) ++ repositories
+
+ val standardProject = "com.twitter" % "standard-project" % "0.12.7"
+ val sbtThrift = "com.twitter" % "sbt-thrift" % "1.4.4"
}
View
15 lib/template/src/main/scala/com/twitter/birdname/BirdNameServiceImpl.scala.erb
@@ -8,23 +8,24 @@ import config._
class BirdNameServiceImpl(config: BirdNameServiceConfig) extends BirdNameServiceServer {
val serverName = "BirdName"
val thriftPort = config.thriftPort
-
+
/**
- * These services are based on finagle, which implements a nonblocking server. If you
+ * These services are based on finagle, which implements a nonblocking server. If you
* are making blocking rpc calls, it's really important that you run these actions in
* a thread pool, so that you don't block the main event loop. This thread pool is only
* needed for these blocking actions. The code looks like:
*
* // Depends on com.twitter.util >= 1.6.10
* val futurePool = new FuturePool(Executors.newFixedThreadPool(config.threadPoolSize))
- *
+ *
* def hello() = futurePool {
* someService.blockingRpcCall
* }
- *
- */
+ *
+ */
- val database = new mutable.HashMap[String, String]()
+ val database = new mutable.HashMap[String, String]
+ with mutable.SynchronizedMap[String, String]
def get(key: String) = {
database.get(key) match {
@@ -38,7 +39,7 @@ class BirdNameServiceImpl(config: BirdNameServiceConfig) extends BirdNameService
}
def put(key: String, value: String) = {
- log.debug("put %s")
+ log.debug("put %s", key)
database(key) = value
Future.void
}
View
11 lib/template/src/scripts/startup.sh
@@ -17,10 +17,11 @@ JAR_NAME="$APP_NAME-$VERSION.jar"
STAGE="production"
HEAP_OPTS="-Xmx4096m -Xms4096m -XX:NewSize=768m"
-GC_OPTS="-verbosegc -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+UseConcMarkSweepGC -XX:+UseParNewGC"
+GC_OPTS="-XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy -XX:MaxGCPauseMillis=1000 -XX:GCTimeRatio=99"
+GC_LOG_OPTS="-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC"
GC_LOG="-Xloggc:/var/log/$APP_NAME/gc.log"
DEBUG_OPTS="-XX:ErrorFile=/var/log/$APP_NAME/java_error%p.log"
-JAVA_OPTS="-server -Dstage=$STAGE $GC_OPTS $GC_LOG $HEAP_OPTS $DEBUG_OPTS"
+JAVA_OPTS="-server -Dstage=$STAGE $GC_OPTS $GC_LOG_OPTS $GC_LOG $HEAP_OPTS $DEBUG_OPTS"
pidfile="/var/run/$APP_NAME/$APP_NAME.pid"
daemon_pidfile="/var/run/$APP_NAME/$APP_NAME-daemon.pid"
@@ -64,7 +65,7 @@ case "$1" in
echo "already running."
exit 0
fi
-
+
ulimit -c unlimited || echo -n " (no coredump)"
$DAEMON $daemon_args $daemon_start_args -- sh -c "echo "'$$'" > $pidfile; exec ${JAVA_HOME}/bin/java ${JAVA_OPTS} -jar ${APP_HOME}/${JAR_NAME}"
tries=0
@@ -86,7 +87,7 @@ case "$1" in
exit 0
fi
- curl -s http://localhost:${ADMIN_PORT}/shutdown.txt > /dev/null
+ curl -m 5 -s http://localhost:${ADMIN_PORT}/shutdown.txt > /dev/null
tries=0
while running; do
tries=$((tries + 1))
@@ -112,7 +113,7 @@ case "$1" in
done
echo "done."
;;
-
+
status)
if running; then
echo "$APP_NAME is running."
View
2  lib/template/src/test/scala/com/twitter/birdname/AbstractSpec.scala.erb
@@ -9,7 +9,7 @@ abstract class AbstractSpec extends Specification {
val env = RuntimeEnvironment(this, Array("-f", "config/test.scala"))
lazy val birdName = {
val out = env.loadRuntimeConfig[BirdNameService]
-
+
// You don't really want the thrift server active, particularly if you
// are running repetitively via ~test
ServiceTracker.shutdown // all services
View
73 scala-bootstrapper.gemspec
@@ -0,0 +1,73 @@
+# Generated by jeweler
+# DO NOT EDIT THIS FILE DIRECTLY
+# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = %q{scala-bootstrapper}
+ s.version = "0.9.2"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Kyle Maxwell"]
+ s.date = %q{2011-08-23}
+ s.default_executable = %q{scala-bootstrapper}
+ s.description = %q{Twitter scala project init}
+ s.email = %q{kmaxwell@twitter.com}
+ s.executables = ["scala-bootstrapper"]
+ s.extra_rdoc_files = [
+ "LICENSE",
+ "README.rdoc"
+ ]
+ s.files = [
+ ".document",
+ ".gitignore",
+ "HACKING",
+ "LICENSE",
+ "README.rdoc",
+ "Rakefile",
+ "VERSION",
+ "bin/scala-bootstrapper",
+ "lib/template/.gitignore.erb",
+ "lib/template/Capfile",
+ "lib/template/Gemfile",
+ "lib/template/README.md",
+ "lib/template/TUTORIAL.md",
+ "lib/template/config/development.scala.erb",
+ "lib/template/config/production.scala.erb",
+ "lib/template/config/staging.scala.erb",
+ "lib/template/config/test.scala.erb",
+ "lib/template/project/build.properties",
+ "lib/template/project/build/BirdNameProject.scala.erb",
+ "lib/template/project/plugins/Plugins.scala.erb",
+ "lib/template/run",
+ "lib/template/src/main/scala/com/twitter/birdname/BirdNameServiceImpl.scala.erb",
+ "lib/template/src/main/scala/com/twitter/birdname/Main.scala.erb",
+ "lib/template/src/main/scala/com/twitter/birdname/config/BirdNameServiceConfig.scala.erb",
+ "lib/template/src/main/thrift/birdname.thrift.erb",
+ "lib/template/src/scripts/console.erb",
+ "lib/template/src/scripts/startup.sh",
+ "lib/template/src/test/scala/com/twitter/birdname/AbstractSpec.scala.erb",
+ "lib/template/src/test/scala/com/twitter/birdname/BirdNameServiceSpec.scala.erb",
+ "scala-bootstrapper.gemspec",
+ "vendor/trollop.rb"
+ ]
+ s.homepage = %q{http://github.com/fizx/scala-bootstrapper}
+ s.rdoc_options = ["--charset=UTF-8"]
+ s.require_paths = ["lib"]
+ s.rubygems_version = %q{1.3.7}
+ s.summary = %q{Twitter scala project init}
+
+ if s.respond_to? :specification_version then
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
+ else
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
+ end
+ else
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
+ end
+end
+
View
BIN  vendor/sbt-launch-0.7.4.jar
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.