easily deploy JWS and applets with Scar

I’ve posted about Scar before, so I’ll just give a quick summary. I hate Ant, XML programming is an abomination. I hate Maven, though I like the idea of an artifact repo but only for large projects with many dependencies. I want to build my own stuff without any nonsense. If Java could be used to build Java projects, naturally every Java programmer wouldn’t have any trouble. Scar is a collection of utilities that make it easier to do build related tasks using Java code.

http://code.google.com/p/scar/

That out of the way, I recently reorganized Scar. Here are the parts:

  • The Scar class has static utility methods. They usually take some strings that point to files or directories and do something useful, like zip, unzip, compile source files, etc.
  • The Paths class comes from my wildcard project. It uses globs (asterisks) or regex to collect file paths. The globs are very efficient, eg they don’t traverse into directories that can’t potentially match the glob pattern. This makes collecting paths to compile, zip, etc very easy.
  • The Project class is intended to be a project descriptor. It is loaded from a YAML document and has a project directory. It has utility methods to get paths relative to the project directory and get data out of the YAML in various formats, such as strings, floats, and Paths relative to the project directory. Nothing is assumed about how you’ll use the Project class, it is only a data container with utility methods. You don’t have to even use it at all.
  • The Build class takes a Project instance and does Java build tasks on it. It uses conventions for the data in the Project, eg it expects the YAML to have “name” for projcet name, “source” to list Java source files, “dependencies” to list paths to dependency projects, etc. It can compile and JAR a project and all dependent projects just by reading the Project file. You don’t have to use this at all, you can just make use of Scar utility methods and go your own route to build your project.

Previously, the Scar class had a bunch of stuff that is now in the Build class. Now, the Scar class isn’t cluttered with that optional stuff, and all the utilities like compiling, LZMAing, etc can be used by people who don’t want to bother with the Build stuff.

So, what are some examples for common tasks already!? I’m getting there! First, it is easy enough to get a directory that contains your application as a bunch of JARs. In Eclipse you can right click, export, and click runnable JAR. Now that you have that, here is how you can run your app for JWS, just create a new class with a main method and this code:


String keystore = "keystore";
String alias = "alias";
String password = "password";
String company = "Company";
String title = "Title";
String inputDir = "C:/example/jars";
String outputDir = "C:/example/jws";
Scar.keystore(keystore, alias, password, company, title);
Scar.jws(inputDir, outputDir, true, keystore, alias, password);
Scar.jnlp(outputDir, "com.example.MainClass", "name-of-jar-with-mainclass.jar",
	"http://example.com/applet/run.jnlp", company, title, "splash.jpg");

This generates a keystore file (if it doesn’t exist), generates a JNLP file, and signs all your JARs to work with JWS. Put your JARs and the JNLP file on the internet and you are done!

Specifically, for each JAR it removes any previous signing, does pack200 and unpack200 to normalize the JAR, signs it with your keystore, does pack200, and then GZIP. It skips the last two steps for JARs containing “native”. When generating the JNLP, it puts JARs containing “native” in the appropriate native section, based on if they contain “win”, “mac”, “linux”, or “solaris”.

Here’s another example, this time to package an LWJGL applet:


Scar.keystore(keystore, alias, password, company, title);
Scar.lwjglApplet(inputDir, outputDir, keystore, alias, password);
Scar.lwjglAppletHtml(outputDir, "com.example.MainClass");

This generates a keystore file (if it doesn’t exist), generates an HTML file, and signs all your JARs to work as an LWJGL applet. Put your JARs and the HTML file on the internet and you are done!

Specifically, for each JAR it removes any previous signing, does pack200 and unpack200 to normalize the JAR, signs it with your keystore, does pack200, and then LZMA. It skips the LZMA and packing for the LWJGL JARs “lwjgl_util_applet.jar” and “lzma.jar”. It skips the pack200 for JARs containing “native”. When generating the HTML, it puts JARs containing “native” in the appropriate native section, based on if they contain “win”, “mac”, “linux”, or “solaris”.

Scar can do other useful stuff, like “one JAR” or FTP your files, but I think the above is particularily relevant to JGO. If you give it a try, please run Scar from source as I just refactored some things tonight and haven’t released an up to date JAR. If someone could do some testing that would be great. :slight_smile:

Where do we find it? The link in your signature gives me a 404 :S

googlecode search: Scar -> http://code.google.com/p/scar/

This business of Paths, Projects, and Builds looks somewhat inspired by SBT. It wouldn’t be a bad idea to read SBT’s docs and mine it for further ideas, such as the Setting/Task concept.

You might not want to duplicate SBT’s complexity (the “Simple” in “Simple Build Tool” is increasingly ironic), but you can probably drop SBT’s pure functional model of key updates and make it unabashedly stateful, which I imagine would simplify things quite a bit.

I hate ANT so much, particularly for generating a classpath string, that I’ll immediately try to switch to your library for all my projects. Thanks for making this, it looks very interesting.

I had not looked at SBT before. I see it is a build system for Scala written in Scala. It unsurprisingly seems very Scala like, and by that I mean really freaking complicated. :stuck_out_tongue: I read through Settings and it’s hard for me to tell if the complexity is warranted. By the time I got to the .scala build definition I was completely lost. I do see the similarities though.

Scar (the class) is really a collection of utilities for common build tasks. Project is a generic project descriptor. Build imposes conventions on Project and uses Scar (the class) to do various tasks on the project. You could just use Scar methods on their own and ignore the other isht. If you do use the Build class and it doesn’t do things quite how you like, presumably you would just copy and paste and make it yours. So, rather than a complicated tool that caters to all needs, it is a simple tool that lets you get done what you need in a simple, straightforward way.

I have mixed feelings about including Java code in the project descriptor. Scar supports this, but without an IDE it isn’t very convenient. Then again, writing a main method in an IDE is inconvenient for running from the command line. Possibly a file separate from and referenced by the project descriptor would easily do both.

Sweet! :smiley: If your project setup matches the Scar Project defaults (source in src or src/main/java, dependency JARs in lib or libs, resources in assets or resources or src/main/resources, etc) then you can just do “java -jar scar.jar” and it will compile and JAR your stuff. I just posted a new scar.jar on the Google code site. If not, you can create a project.yaml file in the project root and override the defaults. You might want a project.yaml to set a main class. Quick example:


dependencies:
- ../arcanetactics
- ../appletloader
resources:
- myresources
classpath:
- lib|**/*.jar
- ../../libgdx/target/dist|gdx-backend-lwjgl.jar
main: com.example.MainClass

Or of course you can ignore the Build crap and write a main method that does your build.

I updated the Scar documentation on the homepage.
http://code.google.com/p/scar/
I think it is clearer and easier to see how the hell one might use the project. Feedback is welcome!

Actually I follow your way of thinking. Why NOT do your build ‘scripts’ in Java? The alternative is usually horrendously verbose configuration files to make the “flexible” tool adhere to your specific needs. Just use the facilities of the JDK and some standardization. Heck, your build scripts can even be easily debugged.

I am actually introducing that way of thinking into the company I work for where everyone thinks in nothing else but Oracle databases (sigh). For example today a problem arose where a file was in UTF-16 format and the Oracle loader tool couldn’t work with that, it had to be UTF-8. People were discussing for 10 minutes how to fix that until I had enough: in a mere five minutes I put together a simple command line thing in Java which can take a source encoding and a destination encoding and then converts the file using only a simple inputstreamreader and a printstream. The problem was solved.

When people asked me what magic tool I used, I answered: “Java”. You should have seen the blank stares, it was glorious. And 15 minutes later I had transformed it into a full user friendly Swing GUI. More blank stares.

I hate Maven, though I like the idea of an artifact repo but only for large projects with many dependencies.

Note that for example Play Framework actually utilizes the Maven repositories for its internal dependency management, but it doesn’t actually use Maven. In stead it uses a simple text file format to define the dependency groupId, artifactId and version and it has simple scripts to actually manage the dependencies. Something to think about.

Yeah, something like that could easily be done in Java code. The Scar project descriptor is generic, so you could just add a “mavenRepos” and “mavenDependencies” section that are lists of URLs and group/artifactid/versions. Unfortunately it isn’t as simple as just downloading JARs, to make it useful it would have to download and parse the POM so it could also download dependent maven JARs, recursively. And once you are parsing POMs you would need to parse any parent POMs they inherit from, recursively. It becomes too much of a PITA for me to want to bother really. If you are using Maven, you should be punished! :stuck_out_tongue:

Actually I took a minute to look into it. Apparently this…
mvn -DrepoUrl=http://blah -DgroupId=commons-io -DartifactId=commons-io -Dversion=1.4 dependency:get
…can be used to download JARs into the local repo, and dependency:copy-dependencies could be used to copy them into a directory where Scar could find them. However, don’t you need these JARs for your IDE to develop your app? In that case you are probably already using Maven start to finish and you don’t need Scar, or you already have a directory full of JARs and you can use Scar as normal without any Maven crap.

Hey Nate your sig is still broken :point:

Apache Ivy can fetch from maven repos and has an actual API for it – it’s what SBT uses. So you don’t need maven installed to use maven dependencies. Then again Ivy is also the biggest source of grumbling from SBT devs, so maybe it’s not the best idea to use it. Might want to see what tools like grape and gradle are doing and see if that’s easier to work with.

Some people would like to use managed dependencies without either using maven or going back to the stone age of doing it all by hand. If you’re against the concept of managed deps, probably best to be up front about it.

You don’t need to parse any poms. You manually manage transient dependencies when you’re not using Maven, you just keep doing that. As you stated earlier, the (transient) dependency management features of Maven are only really useful for large multi-module projects such as JEE applications. The point is to have a centralized point to download them from, not to mimic what Maven does. But that would actually only matter if you want to take Scar beyond the scope of game development. When your focus is game projects you will hardly ever change the libraries you use except for maybe an update of LWJGL. Would be a shame to waste time on such a feature when nobody using the tool will actually ever need it. Plus in my opinion tools should stay small, simple and to the point :slight_smile: Why did I bring this up again?

Grr, just you wait. I’ll come up with an awesome idea some day :wink:

I don’t get this attitude of “games=simplistic”. Not just simple, but simplistic, as in dumb and incapable. I want to distribute a demo as source, and I neither want to bundle a bunch of jars with it, nor force people to chase down every dependency by hand.

But if I want to use something like TWL, I have no choice but to bundle it, because the idea of automatic, versioned dependencies is good enough for Perl with CPAN, or Python with PyPi, but not for Java, because it’s a game? Huh.

I could add something that takes URLs from the project descriptor and downloads the JARs. You could point it at Maven repos if you want, or at your own hosting. Worth it? It would only be a couple lines of code to add.

Sig work now? Google does something fancy with links to a user’s projects…

So, judging from that signature, you’re just like a lot of us - spend more time writing tools than you do actual games? ;D

Yes, of course! I’m just trying to fit in! :emo: I’ve shipped a couple games, but I also spend tons of time on libs. I dunno, it’s just more fun sometimes, probably because of the smaller scope. I have a backlog filled with “real” work, products, games, and libs. I’m trying to get some closure by finishing my (soul robbing) RTS… :’(

I don’t get what caused this rant, nor what it is about really. I can comment about the distributing of jars: you could use one-jar to wrap everything into one.

http://one-jar.sourceforge.net/

You could even package the LWJGL natives using it apparently.

EDIT:

oops, Scar already has that built in apparently :slight_smile: Some day!

Beware of one-jar and lgpl libraries…
Besides that, what is the problem with shipping jar libraries with the game executable ? Every AAA title comes with a load of dll files and resources, exposing all the stuff to the user.

Agreed, I personally have no problems with dumping all dependency libraries in a /lib subdirectory (to separate from the main executable jar to prevent confusion) and just distribute like that. Heck, I tend to keep resources (graphics, sounds, music) out of the game jar as well, makes it easier to tinker with them during development without having to rebuild.