lix-pm / lix.client

A dependable package manager for your Haxe projects
The Unlicense
119 stars 23 forks source link

Gitter

lix - a dependable package manager for your Haxe projects

lix is a package manager that makes it easy for you to track dependencies used in your Haxe project, and to make sure everyone always has the right versions when they build your app.

The core proposition of lix is that all dependencies should be fully locked down and versioned, so that every state can be reliably replicated.

To track dependencies, lix leverages the conventions put forth by haxeshim. This means that for each dependency, there is a <libName>.hxml in the project's haxe_libraries folder. In addition to putting all required compiler arguments into a library's hxml, lix also leaves behind installation instructions that allow to redownload the exact same version on another machine. If you check out any particular state of a project, then lix download will download any missing library versions.

You can depend on lix to manage your haxe dependencies.


Contents


Haxe Shim

Before we get started: lix is made to work on top of Haxe Shim. You can read more about it here, but essentially, you can think of it just normal Haxe with a slightly tweaked cli. What it does is to replace the tight coupling in the haxe toolchain in favor of simple conventions:

Installation

lix is installed through npm (or yarn). If you don't have one of these installed, you can find out how to install NodeJS and NPM here.

To install lix:

npm install -g lix

After this you will have the commands lix, haxe, haxelib and neko available.

For each project you want to use lix for, you should create a "scope":

lix scope create
lix use haxe stable

This will create a ".haxerc" in the cwd, saying we should use the current stable Haxe version for this project. It will also tell Haxe Shim that this project should expect to find information about haxelibs in the "haxe_libraries" folder.

Usage

Downloading all dependencies

lix download

This will make sure all dependencies are installed and on the right versions. It will also fetch neko and the project specific haxe version.

You should use this after using git clone, git pull, git checkout and similar commands.

Adding a new dependency

lix install <scheme>:<library>

The schemes you can use include haxelib, github, gitlab, and http/https:

Note that for github and gitlab you can specify credentials using the --gh-credentials and --gl-private-token parameters respectively. Be warned though that these credentials are then baked into the hxmls as well. Be very careful about using this option.

Because haxelib is a prominent source for stable versions, a shortcut is available: lix +lib <libname>. e.g. lix +lib hxcpp#3.4.188 is equivalent for lix install haxelib:hxcpp#3.4.188.

Removing a dependency

To remove a dependency simply delete the related .hxml file from your haxe_libraries folder.

This however won't remove the downloaded sources from the global cache. To do that you would have to delete it from ~/haxe/haxe_libraries or %AppData%\haxe\haxe_libraries.

Aliasing

You can always download a library under a different name and version, example:

lix install haxelib:tink_core as othername#1.2.3

You will find something like the following othername.hxml in your haxe_libraries:

# @install: lix --silent download "haxelib:tink_core#1.16.1" into tink_core/1.16.1/haxelib
-D othername=1.2.3
-cp ${HAXESHIM_LIBCACHE}/tink_core/1.16.1/haxelib/src

Hxml files

Once you've installed a dependency with lix and it exists in your haxe_libraries folder, you can add it to your haxe build (hxml file) with:

-lib mylibrary

where "mylibrary" has a valid file in haxe_libraries/mylibrary.hxml.

It's worth noting that we don't include the haxelib version in the hxml anymore, so doing this:

-lib mylibrary:1.0.0

is no longer accepted.

Version control

We recommend you add the entire haxe_libraries folder to your version control. For example, if you're using git:

git add haxe_libraries

Then every time you change a dependency with lix, you should commit those changes to git.

Every time you switch branches, pull, merge, or clone a new repo, if the files in "haxe_libraries" have changed, you should re-run:

lix download

(A fun fact: despite the name, lix download often doesn't have to download anything, especially if you've used those dependencies before, as they will be cached. This makes switching branches and syncing dependencies incredibly fast and painless).

Local development

If you develop your own haxelibs, you might be used to using haxelib dev to tell haxelib to use a local folder rather than a downloaded library while you develop your library, so that changes you make in the local folder are always used in the next build.

With lix, there is no command to do this, you just edit the relevant hxml file.

For example, change haxe_libraries/tink_core.hxml from:

# @install: lix --silent download "haxelib:tink_core#1.15.0" into tink_core/1.15.0/haxelib
-D tink_core=1.15.0
-cp ${HAXESHIM_LIBCACHE}/tink_core/1.15.0/haxelib/src

to:

# @install: lix --silent download "haxelib:tink_core#1.15.0" into tink_core/1.15.0/haxelib
-D tink_core=1.15.0
-cp /home/jason/workspace/tink_core/src/

When you do this, it will show up as a modified file in git. You should avoid commiting this change, as it won't work for anyone else who wants to use your project but doesn't have the exact same project in the exact same location.

Instead, once you've finished the work on your dependency, (even if it's a work in progress), push your changes to Github, and then use that:

lix install github:haxetink/tink_core#my_work_in_progress_branch

This way if anyone else wants to use your work-in-progress, they'll be able to.

Scripting

Lix supports running "haxe scripts" on either the interpreter or nodejs. The first argument must be something that looks like a class name (i.e. a dot path where the last part starts with an upper case letter, e.g. ExportAssets or tasks.export.Assets).

The class name resolution is as follows:

With the file and class paths being established, lix will read the file. A leading #!-line will be ignored. It will scan lines so long as they are empty or start with //!, the latter ones being allowed to pass additional args to the compiler.

Example:

//! -lib foo -D something=somevalue
class ExportAssets {
  static function main() {
    trace('Look at me, I am exporting ${Sys.args().join(', ')}!');
  }
}

Any additional arguments are passed to the script. Suppose ExportAssets were in the scripts directory, then the invokation would look like this:

Input:

  lix ExportAssets sword shield axe

Becomes:

  haxe -lib foo -D something=somevalue -cp scripts --run ExportAssets sword shield axe

Outputs:

  ExportAssets.hx:4: Look at me, I am exporting sword, shield, axe!

NodeJS scripting

A special case occurs when compiling with -lib hxnodejs. Let's slightly adjust the above example:

//! -lib hxnodejs
class ExportAssets {
  static function main() {
    js.Node.console.log('Look at me, I am import ${Sys.args().join(', ')}!');
  }
}
Input:

  lix ExportAssets sword shield axe

Becomes:

  haxe -lib hxnodejs -cp scripts -main ExportAssets -js scripts/ExportAssets.js
  node scripts/ExportAssets.js sword shield axe

Outputs:

  Look at me, I am exporting sword, shield, axe!

Note that the JS script will attempt to delete itself when run.

Concepts

lix was designed based on a few key concepts that we believe have helped package managers for other languages be successful. Understanding these concepts can help you understand the way lix works.

FAQ

What does this do differently to haxelib?

Haxelib was built many years ago, before npm even existed. It was great at first, but suffers from a few limitations:

How does this compare to hmm?

Hmm is another tool that aims to improve package management for haxe projects. It does this by storing version information and installation instructions in "hmm.json", allowing you to restore state based on those instructions.

It's a big step forward from Haxelib, but we think lix is a step forward again.

Reasons you might prefer hmm:

Reasons you might prefer lix:

Is this similar to npm / yarn / cargo / $packageManager?

lix has taken inspiration from each of these package managers, and tries to learn lessons from each. It is not exactly the same in its implementation as any other package manager.

For example, like npm lix will know how to install dependencies from GitHub, which is great for using unreleased development versions.

Like yarn, lix will cache the exact versions installed, including the exact versions of all dependencies, the exact commit SHAs for any dependencies loaded from Github, and more, meaning you have a reproducible build.

Unlike either, lix does not make a local copy of each library inside a folder in your project, preferring instead to keep the source code in a global folder, to save install time and disk space.

How to use non-minimized versions of the shims?

By default the shims generated as a jsnode target by this project are minimized to accelerate loading. For developing or debugging lix that can be a problem, here is how to unminimize them:

  1. In Build.hx find a line with ncc like cmd('npm run -- ncc -m build $file');,
  2. Remove the -m option as seen in ncc documentation and save the file,
  3. Reinstall using e.g. npm -g install . in the lix.client folder (possibly sudo is needed).

Can I use these tools without installing them globally?

Yes, assuming your project has a package.json. If not, you can create it by:

With that in place, install lix just skipping the "-g" option:

npm install lix --save

And then you can run each of the commands with:

npx lix
npx haxe
npx haxelib
npx neko

Not that npx requires you to either have npm >= 5.2.0 or installing it via npm i -g npx (use sudo as appropriate).

If you prefer yarn:

yarn add lix

And then

yarn lix
yarn haxe
yarn haxelib
yarn neko

Consider adding this to your package.json, for frictionless intallation:

"scripts": {
    "postinstall": "lix download"
}

This will make sure lix installs its packages every time npm or yarn installs their packages.

Help and support

If you find a bug or have an issue, please file an issue on GitHub.

If you would like to chat through an issue, you can often find someone helpful on our Gitter channel.

We try to be friendly!

Contributing

We welcome contributions - whether it's to help triage GitHub issues, write new features, support other users or improve documentation.

If you would like to know how to help, or would like to discuss a feature you're considering implementing, please reach out to us on Gitter.

Your help will be much appreciated!

Acknowledgements

Very special thanks to Geir who was kind to hand over the lix package on npm. From this point forward, that package is now available as lix-index.