“Leiningen教程中文版”的版本间的差异

来自Dennis的知识库
跳转到: 导航搜索
本教程覆盖了哪些
本教程覆盖范围
第31行: 第31行:
  
 
对于那些从来没有接触过Ant或者Maven的JVM初哥,(忠告是):不要惊慌失措。Leiningen也是为了你们而设计。这个教程
 
对于那些从来没有接触过Ant或者Maven的JVM初哥,(忠告是):不要惊慌失措。Leiningen也是为了你们而设计。这个教程
会帮助你快速开始,并解释Leiningen如何处理项目自动化以及JVM世界的依赖管理。
+
会帮助你快速开始,并解释Leiningen如何处理项目自动化以及JVM的依赖管理。
  
 
== 获得帮助 ==
 
== 获得帮助 ==

2012年12月9日 (日) 14:00的版本

目录

Leiningen教程

声明

  • 本Wiki上的任何文字信息均在GNU自由文档许可证1.3或更高版本下发布,如果用于任何商业用途都需经本人同意。任何转载都请注明出处。
  • 本Wiki上的内容来自本人的学习笔记,来源可能包括原创、书籍、网页、链接等,如果侵犯了您的知识产权,请与本人联系,我将及时删除。
  • 我的联系方式 killme2008@gmail.com

Leiningen是什么

Leiningen是一个用于自动化(构建)clojure项目的工具,使你免于心急火燎的窘境。

它处理各种各样项目相关的任务,可以做到:

  • 创建新项目
  • 管理你的项目的依赖关系
  • 运行测试
  • 运行一个REPL(你不需要再关心如何将依赖加入classpath)
  • 编译java源码(如果有的话)
  • 运行项目(如果项目是一个app的话)
  • 为项目产生一个maven风格的pom文件
  • 为部署编译和打包项目
  • 发行类库到maven仓库,例如Clojars
  • 运行clojure编写的自定义的自动化任务(称为leiningen插件)

如果你来自Java世界,Leiningen就是Maven和Ant的无痛结合。如果你是Ruby或者Python世界的人们,则Leiningen 就是那个组合了RubyGems/Bundler/Rake和pip/Fabric等功能的一个单一工具。

本教程覆盖范围

本教程主要覆盖了项目结构、依赖管理、运行测试、REPL以及跟部署相关的话题。

对于那些从来没有接触过Ant或者Maven的JVM初哥,(忠告是):不要惊慌失措。Leiningen也是为了你们而设计。这个教程 会帮助你快速开始,并解释Leiningen如何处理项目自动化以及JVM的依赖管理。

获得帮助

Also keep in mind that Leiningen ships with fairly comprehensive help; `lein help` gives a list of tasks while `lein help task` provides details. Further documentation such as the readme, sample configuration, and even this tutorial are also provided.

另外,记住Leiningen发行附带了相当全面的帮助;lein help可以获得一个task列表,同时lein help task可以获取任务的详细信息。 更多的文档,例如readme,示范配置以及本教程也同时提供给您。

Leiningen项目

Leiningen works with *projects*. A project is a directory containing a group of Clojure (and, possibly, Java) source files, along with a bit of metadata about them. The metadata is stored in a file named `project.clj` (by convention) in the project's root directory. The `project.clj` file is how you tell Leiningen about things like

Leiningen处理的是项目。一个项目就是一个包含了一组Clojure(可能也有Java)源码文件的目录,同时附带一些元信息。 元信息存在一个在根目录的称为project.clj(默认名称)的文件。project.clj就是用来告诉Leiningen 项目是什么样的,包括:

  • 项目名称
  • 项目描述
  • 依赖哪些类库
  • 使用的Clojure版本是什么
  • 哪里找到(项目)源码
  • App的main namespace是什么
* Project name
* Project description
* What libraries the project depends on
* What Clojure version to use
* Where to find source files
* What's the main namespace of the app

and more.

等等。

Most Leiningen tasks only make sense in the context of a project. Some (for example, `lein repl`) can also work globally, from any directory.

大多数Leiningen的任务仅在项目的上下文里才有意义(译者注:也就是大多数任务只能在一个项目里使用)。但是有些任务如 lein repl也可以从任何目录全局地工作。

Next lets take a look at how projects are created.

接下来,让我们看看项目是如何创建的。


创建一个项目

We'll assume you've got Leiningen installed as per the [README](https://github.com/technomancy/leiningen/blob/master/README.md). Generating a new project is easy:

我们假设你已经按照README安装了Leiningen。 创建一个项目很简单:

   $ lein new my-stuff
   Generating a project called my-stuff based on the 'default' template.

生成了一个名为my-stuff的项目,基于'default'模板:

   $ cd my-stuff
   $ tree
   .
   |-- project.clj
   |-- README.md
   |-- src
   |   `-- my_stuff
   |       `-- core.clj
   `-- test
       `-- my_stuff
           `-- core_test.clj

目录层次

Here we've got your project's README, a `src/` directory containing the code, a `test/` directory, and a `project.clj` file which describes your project to Leiningen. The `src/my_stuff/core.clj` file corresponds to the `my-stuff.core` namespace.

到这一步,我们得到了项目的README,一个包含了代码的src/目录,一个 test/目录,以及一个向Leiningen描述项目的project.clj文件。 src/my_stuff/core.clj文件对应于my-stuff.core命名空间。


Even though most pure Clojure projects never need to customize directory layout, it is possible with Leiningen.

尽管大多数纯Clojure项目都不需要定制目录层次,但是Leiningen允许你这样做。

文件名-到-命名空间的映射惯例

Note that we use `my-stuff.core` instead of just `my-stuff` since single-segment namespaces are discouraged in Clojure. Also note that namespaces with dashes in the name will have the corresponding file named with underscores instead since the JVM has trouble loading files with dashes in the name. The intricacies of namespaces are a common source of confusion for newcomers, and while they are mostly outside the scope of this tutorial, you can [read up on them elsewhere](http://blog.8thlight.com/colin-jones/2010/12/05/clojure-libs-and-namespaces-require-use-import-and-ns.html).

注意到我们使用my-stuff.core作为命名空间,而不只是my-sutff, 这是因为Clojure不鼓励只有一段(single-segment,译者注:意思是没有"."连接的的单一名称)的命名空间。 另外我们也注意到含有波折号(也就是减号)的命名空间,会被映射到波折号被下划线替换的文件,这是因为 JVM加载含有波折号的文件会遇到问题。命名空间的错综复杂是新手通常感到困扰的一个来源,虽然我们已经偏离本 教程的范围,你可以在别处阅读到它们

project.clj

A default project.clj file will start off looking something like the this: 一个默认的project.clj文件初始看起来类似这样:

   (defproject my-stuff "0.1.0-SNAPSHOT"
     :description "FIXME: write description"
     :url "http://example.com/FIXME"
     :license {:name "Eclipse Public License"
               :url "http://www.eclipse.org/legal/epl-v10.html"}
     :dependencies org.clojure/clojure "1.4.0")

If you don't fill in the `:description` with a short sentence, your project will be harder to find in search results, so start there. Be sure to fix the `:url` as well. At some point you'll need to flesh out the README too, but for now let's skip ahead to setting `:dependencies`. Note that Clojure is just another dependency here. Unlike most languages, it's easy to swap out any version of Clojure.

如果你没有为description填写一个简短的(描述)句子,你的项目 会难于被搜索,所以请填写一下。也请填写下:url(译注:项目地址URL)。 有时候,你也需要充实下README文件,但是现在让我们略过(这一步)去设置下:dependencies。 注意到,不像其他语言那样,Clojure在这里也只是另一个依赖罢了,你可以很容易地转换Clojure版本。


依赖

概览

Clojure is a hosted language and Clojure libraries are distributed the same way as in other JVM languages: as JARs.

Clojure是一门寄宿语言(译注:寄宿于JVM之上),并且Clojure的类库也像其他JVM语言那样作为JAR发布。

JARs (`.jar` files) are basically just `.zip` files with a little extra JVM-specific metadata. They usually contain `.class` files (JVM bytecode) and `.clj` source files, but they can also contain other things like config files, JavaScript files or text files with static data.

JAR(jar文件)仅仅是是一些附加了JVM特有元信息的.zip文件。 它们通常包含有.class文件(JVM字节码),和.clj源码文件, 但是它们也可以包含其他一些东西,例如配置文件、JavaScript文件或者含有静态数据的文本文件。


已发布的JVM类库拥有identifiers(artifact group, artifact id)和versions

Artifact IDs, Groups和Versions

You can [search Clojars](http://clojars.org/search?q=clj-http) using its web interface. On the page for `clj-http` it shows this:

你可以使用web接口搜索Clojars,搜索clj-http的结果页显示为:

   [clj-http "0.5.5"]

There are two different ways of specifying a dependency on the latest stable version of the `clj-http` library, one in Leiningen format shown above and one in Maven format. We'll skip the Maven one for now, though you'll need to learn to read it for Java libraries from [Central](http://search.maven.org). You can copy the Leiningen version directly into the `:dependencies` vector in `project.clj`.

有两种途径来设置依赖clj-http类库的最新版本,一种是类似于上面所展示 的Leiningen格式,另一种是Maven格式。我们现在略过Maven的方式,但是你需要为学习(使用) 来自Maven central的Java类库读一下。你可以直接拷贝Leiningen版本 到project.clj里的:dependencies vector。

Within the vector, "clj-http" is referred to as the "artifact id". "0.5.5" is the version. Some libraries will also have "group ids", which are displayed like this:

在vector里,"clj-http"被称为"artifact id"(译者注:还记得Maven吗)。"0.5.5"就是版本号。 一些类库还会有"group id",显示成这样:

   [com.cedarsoft.utils.legacy/hibernate "1.3.4"]

The group-id is the part before the slash. Especially for Java libraries, it's often a reversed domain name. Clojure libraries often use the same group-id and artifact-id (as with clj-http), in which case you can omit the group-id. If there is a library that's part of a larger group (such as `ring-jetty-adapter` being part of the `ring` project), the group-id is often the same across all the sub-projects.

group-id就是斜杠之前的部分。特别是对于Java类库来说,它通常是倒序的域名。而Clojure类库 通常使用相同的group-id和artifact-id(例如clj-http),这种情况下你可以忽略group-id。 如果某个类库从属于一个很大的分组(例如ring-jetty-adapterring项目的一部分), 那么通常所有子项目的group-id保持一样。

Snapshot版本

Sometimes versions will end in "-SNAPSHOT". This means that it is not an official release but a development build. Relying on snapshot dependencies is discouraged but is sometimes necessary if you need bug fixes, etc. that have not made their way into a release yet. However, snapshot versions are not guaranteed to stick around, so it's important that non-development releases never depend upon snapshot versions that you don't control. Adding a snapshot dependency to your project will cause Leiningen to actively go seek out the latest version of the dependency daily (whereas normal release versions are cached in the local repository) so if you have a lot of snapshots it will slow things down.

有时候版本号会以 "-SNAPSHOT"结尾。这意味着这不是一个正式的release版本,而是一个开发构建(版本)。 不鼓励依赖snapshot版本,但是有时候也是必须的,例如你需要bug fix等还没有将它们发布。尽管如此, snapshot版本不被保证停留,所以很重要的一点是非开发中的release绝不依赖你无法控制的snapshot版本。 添加一个snapshot依赖到你的项目里,会导致Leiningen每天主动查找该依赖的最新版本(而正常的release版本 会缓存在本地仓库),所以如果你使用了很多snapshot版本,可能会拖慢一些。


Note that some libraries make their group-id and artifact-id correspond with the namespace they provide inside the jar, but this is just a convention. There is no guarantee they will match up at all, so consult the library's documentation before writing your `:require` and `:import` clauses.

请注意,有一些类库会让它们的group-id和artifact-id对应到它们jar里提供的命名空间,但是这一点 仅是惯例。并不保证总是能匹配起来,所以在你写下:require:import语句之前翻阅 下类库的文档。

仓库

Dependencies are stored in a *maven repository* (or, more formally, "maven artifact repository", or just "repository" if there's little chance of ambiguity).

If you are familiar with Perl's CPAN, Python's Cheeseshop (aka PyPi), Ruby's rubygems.org, or Node.js's NPM, it's the same thing. Leiningen reuses existing JVM repositories infrastructure. There are several popular open source repositories. Leiningen by default will use two of them: [clojars.org](http://clojars.org) and [Maven Central](http://search.maven.org/).

[Clojars](https://clojars.org/) is the Clojure community's centralized maven repository, while [Central](http://search.maven.org/) is for the wider JVM community.

You can add third-party repositories by setting the `:repositories` key in project.clj. See the [sample.project.clj](https://github.com/technomancy/leiningen/blob/rc/sample.project.clj).

检查依赖

Sometimes it is necessary to develop two projects in parallel but it is very inconvenient to run `lein install` and restart your repl all the time to get your changes picked up. Leiningen provides a solution called *checkout dependencies* (or just *checkouts*). To use it, create a directory called `checkouts` in the project root, like so:

   .
   |-- project.clj
   |-- README.md
   |-- checkouts
   |-- src
   |   `-- my_stuff
   |       `-- core.clj
   `-- test
       `-- my_stuff
           `-- core_test.clj

Then, under the checkouts directory, create symlinks to projects you need.

   .
   |-- project.clj
   |-- README.md
   |-- checkouts
   |   `-- superlib2 [link to ~/code/oss/superlib2]
   |   `-- superlib3 [link to ~/code/megacorp/superlib3]
   |-- src
   |   `-- my_stuff
   |       `-- core.clj
   `-- test
       `-- my_stuff
           `-- core_test.clj

Libraries located under the `checkouts` directory take precedence over libraries pulled from repositories, but this is not a replacement for listing the project in your main project's `:dependencies`; it simply supplements that for convenience.

The checkouts feature is not transitive: in other words, Leiningen will not find checkout dependencies of a checkout dependency.

运行代码

Enough setup; let's see some code running. Start with a REPL (read-eval-print loop):

   $ lein repl
   nREPL server started on port 40612
   Welcome to REPL-y!
   Clojure 1.4.0
       Exit: Control+D or (exit) or (quit)
   Commands: (user/help)
       Docs: (doc function-name-here)
             (find-doc "part-of-name-here")
     Source: (source function-name-here)
             (user/sourcery function-name-here)
    Javadoc: (javadoc java-object-or-class-here)
   Examples from clojuredocs.org: [clojuredocs or cdoc]
             (user/clojuredocs name-here)
             (user/clojuredocs "ns-here" "name-here")
   user=>

The REPL is an interactive prompt where you can enter arbitrary code to run in the context of your project. Since we've added `clj-http` to `:dependencies`, we are able to load it here along with code from the `my-stuff.core` namespace in your project's own `src/` directory:

   user=> (require 'my-stuff.core)
   nil
   user=> (my-stuff.core/-main)
   Hello, World!
   nil
   user=> (require '[clj-http.client :as http])
   nil
   user=> (def response (http/get "http://leiningen.org"))
   #'user/response
   user=> (keys response)
   (:trace-redirects :status :headers :body)

The call to `-main` shows both println output ("Hello, World!") and the return value (nil) together.

Built-in documentation is available via `doc`, while `clojuredocs` offers more thorough examples from the [ClojureDocs](http://clojuredocs.org) site:

   user=> (doc reduce)
   -------------------------
   clojure.core/reduce
   ([f coll] [f val coll])
     f should be a function of 2 arguments. If val is not supplied,
     returns the result of applying f to the first 2 items in coll, then
     applying f to that result and the 3rd item, etc. If coll contains no
     items, f must accept no arguments as well, and reduce returns the
     result of calling f with no arguments.  If coll has only 1 item, it
     is returned and f is not called.  If val is supplied, returns the
     result of applying f to val and the first item in coll, then
     applying f to that result and the 2nd item, etc. If coll contains no
     items, returns val and f is not called.
   user=> (user/clojuredocs pprint)
   Loading clojuredocs-client...
   ========== vvv Examples ================
     user=> (def *map* (zipmap
                         [:a :b :c :d :e]
                         (repeat
                           (zipmap [:a :b :c :d :e]
                             (take 5 (range))))))
     #'user/*map*
     user=> *map*
     {:e {:e 4, :d 3, :c 2, :b 1, :a 0}, :d {:e 4, :d 3, :c 2, :b 1, :a 0}, :c {:e 4, :d 3, :c 2, :b 1, :a 0}, :b {:e 4, :d 3, :c 2, :b 1, :a 0}, :a {:e 4, :d 3, :c 2, :b 1, :a 0}}
     user=> (clojure.pprint/pprint *map*)
     {:e {:e 4, :d 3, :c 2, :b 1, :a 0},
      :d {:e 4, :d 3, :c 2, :b 1, :a 0},
      :c {:e 4, :d 3, :c 2, :b 1, :a 0},
      :b {:e 4, :d 3, :c 2, :b 1, :a 0},
      :a {:e 4, :d 3, :c 2, :b 1, :a 0}}
     nil
   ========== ^^^ Examples ================
   1 example found for clojure.pprint/pprint

You can even examine the source of functions:

   user=> (source my-stuff.core/-main)
   (defn -main
     "I don't do a whole lot."
     [& args]
     (println "Hello, World!"))
   user=> ; use control+d to exit

If you already have code in a `-main` function ready to go and don't need to enter code interactively, the `run` task is simpler:

   $ lein run -m my-stuff.core
   Hello, World!

Providing an alternate `-m` argument will tell Leiningen to look for the `-main` function in another namespace. Setting a default `:main` in `project.clj` lets you omit `-m`.

For long-running `lein run` processes, you may wish to save memory with the higher-order trampoline task, which allows the Leiningen JVM process to exit before launching your project's JVM.

   $ lein trampoline run -m my-stuff.server 5000

测试

We haven't written any tests yet, but we can run the failing tests included from the project template:

   $ lein test
   lein test my.test.stuff
   FAIL in (a-test) (stuff.clj:7)
   FIXME, I fail.
   expected: (= 0 1)
     actual: (not (= 0 1))
   Ran 1 tests containing 1 assertions.
   1 failures, 0 errors.

Once we fill it in the test suite will become more useful. Sometimes if you've got a large test suite you'll want to run just one or two namespaces at a time; `lein test my.test.stuff` will do that. You also might want to break up your tests using test selectors; see `lein help test` for more details.

Running `lein test` from the command-line is suitable for regression testing, but the slow startup time of the JVM makes it a poor fit for testing styles that require tighter feedback loops. In these cases, either keep a repl open for running the appropriate call to [clojure.test/run-tests](http://clojuredocs.org/clojure_core/1.3.0/clojure.test/run-tests) or look into editor integration such as [clojure-test-mode](https://github.com/technomancy/clojure-mode).

Keep in mind that while keeping a running process around is convenient, it's easy for that process to get into a state that doesn't reflect the files on disk—functions that are loaded and then deleted from the file will remain in memory, making it easy to miss problems arising from missing functions (often referred to as "getting slimed"). Because of this it's advised to do a `lein test` run with a fresh instance periodically in any case, perhaps before you commit.

使用项目

Generally speaking, there are three different goals that are typical of Leiningen projects:

  • An application you can distribute to end-users
  • A server-side application
  • A library for other Clojure projects to consume

For the first, you typically build an uberjar. For libraries, you will want to have them published to a repository like Clojars or a private repository. For server-side applications it varies as described below. Generating a project with `lein new app myapp` will start you out with a few extra defaults suitable for non-library projects.

Uberjar

The simplest thing to do is to distribute an uberjar. This is a single standalone executable jar file most suitable for giving to nontechnical users. For this to work you'll need to specify a namespace as your `:main` in `project.clj`. By this point our `project.clj` file should look like this:

```clj (defproject my-stuff "0.1.0-SNAPSHOT"

 :description "FIXME: write description"
 :url "http://example.com/FIXME"
 :license {:name "Eclipse Public License"
           :url "http://www.eclipse.org/legal/epl-v10.html"}
 :dependencies [[org.clojure/clojure "1.3.0"]
                [org.apache.lucene/lucene-core "3.0.2"]
                [clj-http "0.4.1"]]
 :profiles {:dev {:dependencies midje "1.3.1"}}
 :test-selectors {:default (complement :integration)
                 :integration :integration
                 :all (fn [_] true)}
 :main my.stuff)

```

The namespace you specify will need to contain a `-main` function that will get called when your standalone jar is run. This namespace should have a `(:gen-class)` declaration in the `ns` form at the top. The `-main` function will get passed the command-line arguments. Let's try something simple in `src/my/stuff.clj`:

```clj (ns my.stuff

 (:gen-class))

(defn -main [& args]

 (println "Welcome to my project! These are your args:" args))

```

Now we're ready to generate your uberjar:

   $ lein uberjar
   Compiling my.stuff
   Compilation succeeded.
   Created /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jar
   Including my-stuff-0.1.0-SNAPSHOT.jar
   Including clj-http-0.4.1.jar
   Including clojure-1.3.0.jar
   Including lucene-core-3.0.2.jar
   Created /home/phil/src/leiningen/my-stuff/target/my-stuff-0.1.0-SNAPSHOT-standalone.jar

This creates a single jar file that contains the contents of all your dependencies. Users can run it with a simple `java` invocation, or on some systems just by double-clicking the jar file.

   $ java -jar my-stuff-0.1.0-standalone.jar Hello world.
   Welcome to my project! These are your args: (Hello world.)

You can run a regular (non-uber) jar with the `java` command-line tool, but that requires constructing the classpath yourself, so it's not a good solution for end-users.

Of course if your users already have Leiningen installed, you can instruct them to use `lein run` as described above.

框架 (Uber)jars

Many Java frameworks expect deployment of a jar file or derived archive sub-format containing a subset of the application's necessary dependencies. The framework expects to provide the missing dependencies itself at run-time. Dependencies which are provided by a framework in this fashion may be specified in the `:provided` profile. Such dependencies will be available during compilation, testing, etc., but won't be included by default by the `uberjar` task or plugin tasks intended to produce stable deployment artifacts.

For example, Hadoop job jars may be just regular (uber)jar files containing all dependencies except the Hadoop libraries themselves:

```clj (project example.hadoop "0.1.0"

 ...
 :profiles {:provided
            {:dependencies
             org.apache.hadoop/hadoop-core "0.20.2-dev"}}
 :main example.hadoop)

```

   $ lein uberjar
   Compiling example.hadoop
   Created /home/xmpl/src/example.hadoop/example.hadoop-0.1.0.jar
   Including example.hadoop-0.1.0.jar
   Including clojure-1.4.0.jar
   Created /home/xmpl/src/example.hadoop/example.hadoop-0.1.0-standalone.jar
   $ hadoop jar example.hadoop-0.1.0-standalone.jar
   12/08/24 08:28:30 INFO util.Util: resolving application jar from found main method on: example.hadoop
   12/08/24 08:28:30 INFO flow.MultiMapReducePlanner: using application jar: /home/xmpl/src/example.hadoop/./example.hadoop-0.1.0-standalone.jar
   ...

Plugins are required to generate framework deployment jar derivatives (such as WAR files) which include additional metadata, but the `:provided` profile provides a general mechanism for handling the framework dependencies.

服务端项目

There are many ways to get your project deployed as a server-side application. Aside from the obvious uberjar approach, simple programs can be packaged up as tarballs with accompanied shell scripts using the [lein-tar plugin](https://github.com/technomancy/lein-tar) and then deployed using [pallet](http://hugoduncan.github.com/pallet/), [chef](http://opscode.com/chef/), or other mechanisms. Web applications may be deployed as uberjars using embedded Jetty with `ring-jetty-adapter` or as .war (web application archive) files created by the [lein-ring plugin](https://github.com/weavejester/lein-ring). For things beyond uberjars, server-side deployments are so varied that they are better-handled using plugins rather than tasks that are built-in to Leiningen itself.

If you do end up involving Leiningen in production via something like `lein trampoline run`, it's very important to ensure you take steps to freeze all the dependencies before deploying, otherwise it could be easy to end up with [unrepeatable deployments](https://github.com/technomancy/leiningen/wiki/Repeatability). Consider including `~/.m2/repository` in your unit of deployment along with your project code. It's recommended to use Leiningen to create a deployable artifact in a continuous integration setting. For example, you could have a [Jenkins](http://jenkins-ci.org) CI server run your project's full test suite, and if it passes, upload a tarball to S3. Then deployment is just a matter of pulling down and extracting the known-good tarball on your production servers.

Also remember that the `run` task defaults to including the `user`, `dev`, and `default` profiles, which are not suitable for production. Using `lein trampoline with-profile production run -m myapp.main` is recommended. By default the production profile is empty, but if your deployment includes the `~/.m2/repository` directory from the CI run that generated the tarball, then you should add its path as `:local-repo` along with `:offline? true` to the `:production` profile. Staying offline prevents the deployed project from diverging at all from the version that was tested in the CI environment.

发行类库

If your project is a library and you would like others to be able to use it as a dependency in their projects, you will need to get it into a public repository. While it's possible to [maintain your own private repository](https://github.com/technomancy/leiningen/blob/rc/doc/DEPLOY.md) or get it into [Central](http://search.maven.org), the easiest way is to publish it at [Clojars](http://clojars.org). Once you have [created an account](https://clojars.org/register) there, publishing is easy:

   $ lein deploy clojars
   Created ~/src/my-stuff/target/my-stuff-0.1.0-SNAPSHOT.jar
   Wrote ~/src/my-stuff/pom.xml
   No credentials found for clojars
   See `lein help deploying` for how to configure credentials.
   Username: me
   Password: 
   Retrieving my-stuff/my-stuff/0.1.0-SNAPSHOT/maven-metadata.xml (1k)
       from https://clojars.org/repo/
   Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/my-stuff-0.1.0-20120531.032047-14.jar (5k)
       to https://clojars.org/repo/
   Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/my-stuff-0.1.0-20120531.032047-14.pom (3k)
       to https://clojars.org/repo/
   Retrieving my-stuff/my-stuff/maven-metadata.xml (1k)
       from https://clojars.org/repo/
   Sending my-stuff/my-stuff/0.1.0-SNAPSHOT/maven-metadata.xml (1k)
       to https://clojars.org/repo/
   Sending my-stuff/my-stuff/maven-metadata.xml (1k)
       to https://clojars.org/repo/

Once that succeeds it will be available as a package on which other projects may depend. For instructions on storing your credentials so they don't have to be re-entered every time, see `lein help deploying`. When deploying a release that's not a snapshot, Leiningen will attempt to sign it using [GPG](http://gnupg.org) to prove your authorship of the release. See the [deploy guide](https://github.com/technomancy/leiningen/blob/rc/doc/DEPLOY.md). for details of how to set that up. The deploy guide includes instructions for deploying to other repositories as well.

== That's It!

Now go start coding your next project! 现在可以开始编码你的下一个项目了!

个人工具
名字空间

变换
操作
导航
工具箱