Skip to content

Publishing and the "changing" attribute

Jason Wall edited this page Oct 26, 2019 · 1 revision

I had both of these things click for me at the same time. I'm going to get into what each refers to in a bit here but first I want to go over what I was trying to accomplish.

The Goal

I am designing hex in such a way that you can use as much or as little as you want. This requires separating a lot of the code into smaller modules that depend on each other. I also need a way to tie them all together in the example application as well as an "end user" application (when a developer decides to start creating a hex-app). For example hex_action depends on hex_routing. That means that when I create a dependency on hex_action in an application ivy.xml I would need to add hex_action, hex_routing, and all jars each of those library in turn depend on added to the compile or runtime classpath of my application. However I DO NOT want dependencies like JUnit or other dependencies that are JUST used for compilation like the servlet-api.jar.

I also need a way for these modules that depend on each other to notice changes immediately when I'm working on the framework itself. e.g. If I'm adding a feature to hex_action which requires an update in hex_routing I need to make the change in hex_routing and immediately have it reflected in the classpath of hex_action.

The Solution(s)

Publishing

I had the hardest time with publishing. So much so that it drove me to create the second command in the ivy-cli. I needed a way to remember the voodoo incantation for publishing a working copy to my local Ivy store (~/.ivy2/local).

This might be a good time to mention that Ivy DOES NOT publish directly to your local cache. This drove me CRAZY because I thought my publishing commands weren't working. Little did I know I was looking in the wrong directory. So keep the directory structure of ~/.ivy2/ in mind:

  • ~/.ivy2/cache - A local copy of all dependencies Ivy has downloaded through out it's career on your machine.
  • ~/.ivy2/local - An Ivy repository of artifacts that you have published to the "local" resolver. As far as I can tell a resolver is a way of describing a repository that can host artifacts. Check out the docs for more info.

Ivy will first check your local repository when resolving dependencies described in an ivy.xml file. If it finds them in local they will then be "downloaded" to the cache directory.

The following things are VERY IMPORTANT (if not required) when publishing your library:

  • publishpattern (CLI) or artifactspattern (Ant): This is the actual location of the physical files that are to be pushed up to the resolver. They seem to need to be described using the Ivy pattern elements. Like [artifact] and [ext]. e.g.: Currently I'm using IntelliJ IDEA to create the .jar files that I'm publishing. They are stored in a directory ../out/artifacts (relative to any individual module path). So my publishpattern would be ../out/artifacts/[artifact].[ext]. By default artifact is the value of the module attribute in your ivy.xml <info> element and ext is "jar". Otherwise Ivy will apply this pattern for each <artifact> element found in the <publications> element that match the confs you have selected for the publish command. e.g.:

      <publications>
          <artifact name="hex_routing"/>
          <artifact name="routing_guide" ext="html" conf="with_docs"/>
      </publications>
    

    Given the above section of an ivy.xml and the pattern ../out/artifacts/[artifact].[ext] Ivy will upload the following to the resolver:

    • A file ../out/artifacts/hex_routing.jar
    • Another file ../out/artifacts/routing_guide.html IF the conf with_docs was passed into this call to publish.
  • revision - If not provided Ivy will create a timestamped revision for you. If you're planning on overwriting frequently this can cause you to have several copies of a "working" version of your library pushed to your local. To avoid this I just provide an obvious revision like "working" or "snapshot" as the revision. I don't feel like this is optimal at this point, but I don't really know of a better way to deal with this right now.

The changing attribute

Once I had figured out how to push my snapshot to local, I spent a lot of time spinning my wheels on getting my cache to update every time I tried to resolve the dependencies of a module. For some reason I thought there was a way to do that via a setting on the publishing command. In retrospect I realize that was totally upside-down. If you want a dependency refreshed every time you resolve dependencies for a module why not say so on the dependency itself?

<dependency org="hex" name="hex_routing" rev="latest.integration" changing="true"/>

finally { }

In retrospect the hard part was figuring out how publishing worked. The changing attribute is easy to add once you have the right artifacts in your local. The short form of getting publishing to work is:

  1. Make sure your artifacts (jars) are where you think they are.
  2. Make sure your artifacts are named they way you think they are.
  3. Make sure your publish pattern points to where your physical artifacts are.