parent
3e39e3e80d
commit
25fe2cadb1
59 changed files with 14 additions and 8480 deletions
|
@ -370,7 +370,6 @@ SREQ$(1)_T_$(2)_H_$(3) = \
|
|||
# libraries
|
||||
CSREQ$(1)_T_$(2)_H_$(3) = \
|
||||
$$(TSREQ$(1)_T_$(2)_H_$(3)) \
|
||||
$$(HBIN$(1)_H_$(3))/rustpkg$$(X_$(3)) \
|
||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
|
||||
$$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep))
|
||||
|
|
|
@ -52,8 +52,8 @@ documentation.
|
|||
> options are also supported, pass `--help` for more information on them.
|
||||
|
||||
When complete, `make install` will place several programs into
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
|
||||
API-documentation tool, and `rustpkg`, the Rust package manager and build
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool.
|
||||
system.
|
||||
3. Read the [tutorial].
|
||||
4. Enjoy!
|
||||
|
|
|
@ -1,270 +0,0 @@
|
|||
% The Rust Packaging Guide
|
||||
|
||||
# Introduction
|
||||
|
||||
Sharing is caring. Rust comes with a tool, `rustpkg`, which allows you to
|
||||
package up your Rust code and share it with other people. This guide will
|
||||
get you started on all of the concepts and commands you need to give the gift
|
||||
of Rust code to someone else.
|
||||
|
||||
# Installing External Packages
|
||||
|
||||
First, let's try to use an external package somehow. I've made a sample package
|
||||
called `hello` to demonstrate how to do so. Here's how `hello` is used:
|
||||
|
||||
~~~~
|
||||
extern mod hello;
|
||||
|
||||
fn main() {
|
||||
hello::world();
|
||||
}
|
||||
~~~~
|
||||
|
||||
Easy! But if you try to compile this, you'll get an error:
|
||||
|
||||
~~~~ {.notrust}
|
||||
$ rustc main.rs
|
||||
main.rs:1:0: 1:17 error: can't find crate for `hello`
|
||||
main.rs:1 extern mod hello;
|
||||
^~~~~~~~~~~~~~~~~
|
||||
~~~~
|
||||
|
||||
This makes sense, as we haven't gotten it from anywhere yet! Luckily for us,
|
||||
`rustpkg` has an easy way to fetch others' code: the `install` command. It's
|
||||
used like this:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ rustpkg install PKG_ID
|
||||
~~~
|
||||
|
||||
This will install a package named `PKG_ID` into your current Rust environment.
|
||||
I called it `PKG_ID` in this example because `rustpkg` calls this a 'package
|
||||
identifier.' When using it with an external package like this, it's often a
|
||||
URI fragment. You see, Rust has no central authority for packages. You can
|
||||
build your own `hello` library if you want, and that's fine. We'd both host
|
||||
them in different places and different projects would rely on whichever version
|
||||
they preferred.
|
||||
|
||||
To install the `hello` library, simply run this in your terminal:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ rustpkg install github.com/steveklabnik/hello
|
||||
~~~
|
||||
|
||||
You should see a message that looks like this:
|
||||
|
||||
~~~ {.notrust}
|
||||
note: Installed package github.com/steveklabnik/hello-0.1 to /some/path/.rust
|
||||
~~~
|
||||
|
||||
Now, compiling our example should work:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ rustc main.rs
|
||||
$ ./main
|
||||
Hello, world.
|
||||
~~~
|
||||
|
||||
Simple! That's all it takes.
|
||||
|
||||
# Workspaces
|
||||
|
||||
Before we can talk about how to make packages of your own, you have to
|
||||
understand the big concept with `rustpkg`: workspaces. A 'workspace' is simply
|
||||
a directory that has certain sub-directories that `rustpkg` expects. Different
|
||||
Rust projects will go into different workspaces.
|
||||
|
||||
A workspace consists of any directory that has the following
|
||||
directories:
|
||||
|
||||
* `src`: The directory where all the source code goes.
|
||||
* `build`: This directory contains all of the build output.
|
||||
* `lib`: The directory where any libraries distributed with the package go.
|
||||
* `bin`: This directory holds any binaries distributed with the package.
|
||||
|
||||
There are also default file names you'll want to follow as well:
|
||||
|
||||
* `main.rs`: A file that's going to become an executable.
|
||||
* `lib.rs`: A file that's going to become a library.
|
||||
|
||||
# Building your own Package
|
||||
|
||||
Now that you've got workspaces down, let's build your own copy of `hello`. Go
|
||||
to wherever you keep your personal projects, and let's make all of the
|
||||
directories we'll need. I'll refer to this personal project directory as
|
||||
`~/src` for the rest of this guide.
|
||||
|
||||
## Creating our workspace
|
||||
|
||||
~~~ {.notrust}
|
||||
$ cd ~/src
|
||||
$ mkdir -p hello/src/hello
|
||||
$ cd hello
|
||||
~~~
|
||||
|
||||
Easy enough! Let's do one or two more things that are nice to do:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ git init .
|
||||
$ cat > README.md
|
||||
# hello
|
||||
|
||||
A simple package for Rust.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
$ rustpkg install github.com/YOUR_USERNAME/hello
|
||||
```
|
||||
^D
|
||||
$ cat > .gitignore
|
||||
.rust
|
||||
build
|
||||
^D
|
||||
$ git commit -am "Initial commit."
|
||||
~~~
|
||||
|
||||
If you're not familliar with the `cat >` idiom, it will make files with the
|
||||
text you type inside. Control-D (`^D`) ends the text for the file.
|
||||
|
||||
Anyway, we've got a README and a `.gitignore`. Let's talk about that
|
||||
`.gitignore` for a minute: we are ignoring two directories, `build` and
|
||||
`.rust`. `build`, as we discussed earlier, is for build artifacts, and we don't
|
||||
want to check those into a repository. `.rust` is a directory that `rustpkg`
|
||||
uses to keep track of its own settings, as well as the source code of any other
|
||||
external packages that this workspace uses. This is where that `rustpkg
|
||||
install` puts all of its files. Those are also not to go into our repository,
|
||||
so we ignore it all as well.
|
||||
|
||||
Next, let's add a source file:
|
||||
|
||||
~~~
|
||||
#[desc = "A hello world Rust package."];
|
||||
#[license = "MIT"];
|
||||
|
||||
pub fn world() {
|
||||
println!("Hello, world.");
|
||||
}
|
||||
~~~
|
||||
|
||||
Put this into `src/hello/lib.rs`. Let's talk about each of these attributes:
|
||||
|
||||
## Crate attributes for packages
|
||||
|
||||
`license` is equally simple: the license we want this code to have. I chose MIT
|
||||
here, but you should pick whatever license makes the most sense for you.
|
||||
|
||||
`desc` is a description of the package and what it does. This should just be a
|
||||
sentence or two.
|
||||
|
||||
## Building your package
|
||||
|
||||
Building your package is simple:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ rustpkg build hello
|
||||
~~~
|
||||
|
||||
This will compile `src/hello/lib.rs` into a library. After this process
|
||||
completes, you'll want to check out `build`:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ ls build/x86_64-unknown-linux-gnu/hello/
|
||||
libhello-ed8619dad9ce7d58-0.1.0.so
|
||||
~~~
|
||||
|
||||
This directory naming structure is called a 'build triple,' and is because I'm
|
||||
on 64 bit Linux. Yours may differ based on platform.
|
||||
|
||||
You'll also notice that `src/hello/lib.rs` turned into
|
||||
`libhello-ed8619dad9ce7d58-0.1.0.so`. This is a simple combination of the
|
||||
library name, a hash of its content, and the version.
|
||||
|
||||
Now that your library builds, you'll want to commit:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ git add src
|
||||
$ git commit -m "Adding source code."
|
||||
~~~
|
||||
|
||||
If you're using GitHub, after creating the project, do this:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ git remote add origin git@github.com:YOUR_USERNAME/hello.git
|
||||
$ git push origin -u master
|
||||
~~~
|
||||
|
||||
Now you can install and use it! Go anywhere else in your filesystem:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ cd ~/src/foo
|
||||
$ rustpkg install github.com/YOUR_USERNAME/hello
|
||||
WARNING: The Rust package manager is experimental and may be unstable
|
||||
note: Installed package github.com/YOUR_USERNAME/hello-0.1 to /home/yourusername/src/hello/.rust
|
||||
~~~
|
||||
|
||||
That's it!
|
||||
|
||||
# Testing your Package
|
||||
|
||||
Testing your package is simple as well. First, let's change `src/hello/lib.rs` to contain
|
||||
a function that can be sensibly tested:
|
||||
|
||||
~~~
|
||||
#[desc = "A Rust package for determining whether unsigned integers are even."];
|
||||
#[license = "MIT"];
|
||||
|
||||
pub fn is_even(i: uint) -> bool {
|
||||
i % 2 == 0
|
||||
}
|
||||
~~~
|
||||
|
||||
Once you've edited `lib.rs`, you can create a second crate file, `src/hello/test.rs`,
|
||||
to put tests in:
|
||||
|
||||
~~~
|
||||
#[license = "MIT"];
|
||||
extern mod hello;
|
||||
use hello::is_even;
|
||||
|
||||
#[test]
|
||||
fn test_is_even() {
|
||||
assert!(is_even(0));
|
||||
assert!(!is_even(1));
|
||||
assert!(is_even(2));
|
||||
}
|
||||
~~~
|
||||
|
||||
Note that you have to import the crate you just created in `lib.rs` with the
|
||||
`extern mod hello` directive. That's because you're putting the tests in a different
|
||||
crate from the main library that you created.
|
||||
|
||||
Now, you can use the `rustpkg test` command to build this test crate (and anything else
|
||||
it depends on) and run the tests, all in one step:
|
||||
|
||||
~~~ {.notrust}
|
||||
$ rustpkg test hello
|
||||
WARNING: The Rust package manager is experimental and may be unstable
|
||||
note: Installed package hello-0.1 to /Users/tjc/.rust
|
||||
|
||||
running 1 test
|
||||
test test_is_even ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
~~~
|
||||
|
||||
# More resources
|
||||
|
||||
There's a lot more going on with `rustpkg`, this is just to get you started.
|
||||
Check out [the rustpkg manual](rustpkg.html) for the full details on how to
|
||||
customize `rustpkg`.
|
||||
|
||||
A tag was created on GitHub specifically for `rustpkg`-related issues. You can
|
||||
[see all the Issues for rustpkg
|
||||
here](https://github.com/mozilla/rust/issues?direction=desc&labels=A-pkg&sort=created&state=open),
|
||||
with bugs as well as new feature plans. `rustpkg` is still under development,
|
||||
and so may be a bit flaky at the moment.
|
||||
|
||||
You may also want to check out [this blog
|
||||
post](http://tim.dreamwidth.org/1820526.html), which contains some of the early
|
||||
design decisions and justifications.
|
|
@ -1,112 +0,0 @@
|
|||
# Japanese translations for Rust package
|
||||
# Copyright (C) 2014 The Rust Project Developers
|
||||
# This file is distributed under the same license as the Rust package.
|
||||
# Automatically generated, 2014.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Rust 0.10-pre\n"
|
||||
"POT-Creation-Date: 2014-01-13 12:01+0900\n"
|
||||
"PO-Revision-Date: 2014-01-13 12:01+0900\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-conditions.md:4 doc/guide-ffi.md:4 doc/guide-lifetimes.md:4
|
||||
#: doc/guide-macros.md:4 doc/guide-rustpkg.md:4 doc/guide-tasks.md:4
|
||||
#: doc/rust.md:4 doc/rustpkg.md:4 doc/tutorial.md:4
|
||||
msgid "# Introduction"
|
||||
msgstr "# イントロダクション"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:2
|
||||
#, fuzzy
|
||||
#| msgid "% The Rust Language Tutorial"
|
||||
msgid "% The Rust Packaging Guide"
|
||||
msgstr "% Rust 言語チュートリアル"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:11
|
||||
#, fuzzy
|
||||
#| msgid "## Using other crates"
|
||||
msgid "# Installing External Packages"
|
||||
msgstr "## 他のクレートの利用"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:22
|
||||
#, fuzzy, no-wrap
|
||||
#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
|
||||
msgid ""
|
||||
"fn main() {\n"
|
||||
" hello::world();\n"
|
||||
"}\n"
|
||||
"~~~~\n"
|
||||
msgstr ""
|
||||
"~~~~ {.ignore}\n"
|
||||
"// main.rs\n"
|
||||
"extern mod world;\n"
|
||||
"fn main() { println(~\"hello \" + world::explore()); }\n"
|
||||
"~~~~"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:91
|
||||
#, fuzzy
|
||||
#| msgid "## Using other crates"
|
||||
msgid "# Building your own Package"
|
||||
msgstr "## 他のクレートの利用"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:98
|
||||
#, fuzzy
|
||||
#| msgid "## Using other crates"
|
||||
msgid "## Creating our workspace"
|
||||
msgstr "## 他のクレートの利用"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:115
|
||||
#, fuzzy
|
||||
#| msgid "# Introduction"
|
||||
msgid "## Installation"
|
||||
msgstr "# イントロダクション"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:149
|
||||
#, fuzzy, no-wrap
|
||||
#| msgid "~~~~ {.ignore} // main.rs extern mod world; fn main() { println(~\"hello \" + world::explore()); } ~~~~"
|
||||
msgid ""
|
||||
"pub fn world() {\n"
|
||||
" println!(\"Hello, world.\");\n"
|
||||
"}\n"
|
||||
"~~~\n"
|
||||
msgstr ""
|
||||
"~~~~ {.ignore}\n"
|
||||
"// main.rs\n"
|
||||
"extern mod world;\n"
|
||||
"fn main() { println(~\"hello \" + world::explore()); }\n"
|
||||
"~~~~"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:161
|
||||
#, fuzzy
|
||||
#| msgid "## Using other crates"
|
||||
msgid "## Building your package"
|
||||
msgstr "## 他のクレートの利用"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:209
|
||||
#, fuzzy
|
||||
#| msgid "## Using other crates"
|
||||
msgid "# Testing your Package"
|
||||
msgstr "## 他のクレートの利用"
|
||||
|
||||
#. type: Plain text
|
||||
#: doc/guide-rustpkg.md:257
|
||||
#, fuzzy
|
||||
#| msgid "## Managed boxes"
|
||||
msgid "# More resources"
|
||||
msgstr "## マネージドボックス"
|
|
@ -791,7 +791,7 @@ extern mod extra; // equivalent to: extern mod extra = "extra";
|
|||
|
||||
extern mod rustextra = "extra"; // linking to 'extra' under another name
|
||||
|
||||
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for rustpkg
|
||||
extern mod foo = "some/where/rust-foo#foo:1.0"; // a full package ID for external tools
|
||||
~~~~
|
||||
|
||||
##### Use declarations
|
||||
|
|
164
doc/rustpkg.md
164
doc/rustpkg.md
|
@ -1,164 +0,0 @@
|
|||
% Rustpkg Reference Manual
|
||||
|
||||
# Introduction
|
||||
|
||||
This document is the reference manual for the Rustpkg packaging and build tool for the Rust programming language.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
Rustpkg is a work in progress, as is this reference manual.
|
||||
If the actual behavior of rustpkg differs from the behavior described in this reference,
|
||||
that reflects either an incompleteness or a bug in rustpkg.
|
||||
|
||||
# Package searching
|
||||
|
||||
rustpkg searches for packages using the `RUST_PATH` environment variable,
|
||||
which is a colon-separated list (semicolon-separated on Windows) of directories.
|
||||
|
||||
Each directory in this list is a *workspace* for rustpkg.
|
||||
|
||||
`RUST_PATH` implicitly contains an entry for `./.rust` (as well as
|
||||
`../.rust`, `../../.rust`,
|
||||
and so on for every parent of `.` up to the filesystem root).
|
||||
That means that if `RUST_PATH` is not set,
|
||||
then rustpkg will still search for workspaces in `./.rust` and so on.
|
||||
`RUST_PATH` also implicitly contains an entry for the system path:
|
||||
`/usr/local` or the equivalent on Windows.
|
||||
This entry comes after the implicit entries for `./.rust` and so on.
|
||||
Finally, the last implicit entry in `RUST_PATH` is `~/.rust`
|
||||
or the equivalent on Windows.
|
||||
|
||||
Each workspace may contain one or more packages.
|
||||
|
||||
When building code that contains one or more directives of the form `extern mod P`,
|
||||
rustpkg automatically searches for packages named `P` in the `RUST_PATH` (as described above).
|
||||
It builds those dependencies if necessary.
|
||||
Thus, when using rustpkg,
|
||||
there is no need for `-L` flags to tell the linker where to find libraries for external crates.
|
||||
|
||||
# Package structure
|
||||
|
||||
A valid workspace must contain each of the following subdirectories:
|
||||
|
||||
* 'src/': contains one subdirectory per package. Each subdirectory contains source files for a given package.
|
||||
|
||||
For example, if `foo` is a workspace containing the package `bar`,
|
||||
then `foo/src/bar/main.rs` could be the `main` entry point for
|
||||
building a `bar` executable.
|
||||
* 'lib/': `rustpkg install` installs libraries into a target-specific subdirectory of this directory.
|
||||
|
||||
For example, on a 64-bit machine running Mac OS X,
|
||||
if `foo` is a workspace containing the package `bar`,
|
||||
rustpkg will install libraries for bar to `foo/lib/x86_64-apple-darwin/`.
|
||||
The libraries will have names of the form `foo/lib/x86_64-apple-darwin/libbar-[hash].dylib`,
|
||||
where [hash] is a hash of the package ID.
|
||||
* 'bin/': `rustpkg install` installs executable binaries into this directory.
|
||||
|
||||
For example, rustpkg will install executables for `bar` to
|
||||
`foo/bin`.
|
||||
The executables will have names of the form `foo/bin/bar`.
|
||||
* 'build/': `rustpkg build` stores temporary build artifacts in a target-specific subdirectory of this directory.
|
||||
|
||||
For example, on a 64-bit machine running Mac OS X,
|
||||
if `foo` is a workspace containing the package `bar` and `foo/src/bar/main.rs` exists,
|
||||
then `rustpkg build` will create `foo/build/x86_64-apple-darwin/bar/main.o`.
|
||||
|
||||
# Package identifiers
|
||||
|
||||
A package identifier identifies a package uniquely.
|
||||
A package can be stored in a workspace on the local file system,
|
||||
or on a remote Web server, in which case the package ID resembles a URL.
|
||||
For example, `github.com/mozilla/rust` is a package ID
|
||||
that would refer to the git repository browsable at `http://github.com/mozilla/rust`.
|
||||
A package ID can also specify a version, like:
|
||||
`github.com/mozilla/rust#0.3`.
|
||||
In this case, `rustpkg` will check that the repository `github.com/mozilla/rust` has a tag named `0.3`,
|
||||
and report an error otherwise.
|
||||
A package ID can also specify a particular revision of a repository, like:
|
||||
`github.com/mozilla/rust#release-0.7`.
|
||||
When the refspec (portion of the package ID after the `#`) can't be parsed as a decimal number,
|
||||
rustpkg passes the refspec along to the version control system without interpreting it.
|
||||
rustpkg also interprets any dependencies on such a package ID literally
|
||||
(as opposed to versions, where a newer version satisfies a dependency on an older version).
|
||||
Thus, `github.com/mozilla/rust#5c4cd30f80` is also a valid package ID,
|
||||
since git can deduce that 5c4cd30f80 refers to a revision of the desired repository.
|
||||
|
||||
A package identifier can name a subdirectory of another package.
|
||||
For example, if `foo` is a workspace, and `foo/src/bar/lib.rs` exists,
|
||||
as well as `foo/src/bar/extras/baz/lib.rs`,
|
||||
then both `bar` and `bar/extras/baz` are valid package identifiers
|
||||
in the workspace `foo`.
|
||||
|
||||
Because rustpkg uses generic source file names as the main inputs, you will
|
||||
need to specify the package identifier in them using the `crate_id` attribute
|
||||
on the crate.
|
||||
|
||||
## Source files
|
||||
|
||||
rustpkg searches for four different fixed filenames in order to determine the crates to build:
|
||||
|
||||
* `main.rs`: Assumed to be a main entry point for building an executable.
|
||||
* `lib.rs`: Assumed to be a library crate.
|
||||
* `test.rs`: Assumed to contain tests declared with the `#[test]` attribute.
|
||||
* `bench.rs`: Assumed to contain benchmarks declared with the `#[bench]` attribute.
|
||||
|
||||
## Versions
|
||||
|
||||
`rustpkg` packages do not need to declare their versions with an attribute inside one of the source files,
|
||||
because `rustpkg` infers it from the version control system.
|
||||
When building a package that is in a `git` repository,
|
||||
`rustpkg` assumes that the most recent tag specifies the current version.
|
||||
When building a package that is not under version control,
|
||||
or that has no tags, `rustpkg` assumes the intended version is 0.1.
|
||||
|
||||
> **Note:** A future version of rustpkg will support semantic versions.
|
||||
|
||||
# Dependencies
|
||||
|
||||
rustpkg infers dependencies from `extern mod` directives.
|
||||
Thus, there should be no need to pass a `-L` flag to rustpkg to tell it where to find a library.
|
||||
(In the future, it will also be possible to write an `extern mod` directive referring to a remote package.)
|
||||
|
||||
# Custom build scripts
|
||||
|
||||
A file called `pkg.rs` at the root level in a package directory is called a *package script*.
|
||||
If a package script exists, rustpkg executes it to build the package
|
||||
rather than inferring crates as described previously.
|
||||
|
||||
Inside `pkg.rs`, it's possible to call back into rustpkg to finish up the build.
|
||||
`rustpkg::api` contains functions to build, install, or clean libraries and executables
|
||||
in the way rustpkg normally would without custom build logic.
|
||||
|
||||
# Command reference
|
||||
|
||||
## build
|
||||
|
||||
`rustpkg build foo` searches for a package with ID `foo`
|
||||
and builds it in any workspace(s) where it finds one.
|
||||
Supposing such packages are found in workspaces X, Y, and Z,
|
||||
the command leaves behind files in `X`'s, `Y`'s, and `Z`'s `build` directories,
|
||||
but not in their `lib` or `bin` directories.
|
||||
(The exception is when rustpkg fetches a package `foo`'s sources from a remote repository.
|
||||
In that case, it stores both the sources *and* the build artifacts for `foo`
|
||||
in the workspace that `foo` will install to (see ##install below)).
|
||||
|
||||
## clean
|
||||
|
||||
`rustpkg clean foo` deletes the contents of `foo`'s `build` directory.
|
||||
|
||||
## install
|
||||
|
||||
`rustpkg install foo` builds the libraries and/or executables that are targets for `foo`.
|
||||
If `RUST_PATH` is declared as an environment variable, then rustpkg installs the
|
||||
libraries and executables into the `lib` and `bin` subdirectories
|
||||
of the first entry in `RUST_PATH`.
|
||||
Otherwise, if the current working directory CWD is a workspace,
|
||||
it installs them into CWD's `lib` and `bin` subdirectories.
|
||||
Otherwise, if the current working directory is CWD,
|
||||
it installs them into the .rust/lib and .rust/bin subdirectories of CWD
|
||||
(creating them if necessary).
|
||||
|
||||
## test
|
||||
|
||||
`rustpkg test foo` builds `foo`'s `test.rs` file if necessary,
|
||||
then runs the resulting test executable.
|
|
@ -117,8 +117,8 @@ can be adjusted by passing a `--prefix` argument to
|
|||
for more information on them.
|
||||
|
||||
When complete, `make install` will place several programs into
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the
|
||||
API-documentation tool; and `rustpkg`, the Rust package manager.
|
||||
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
|
||||
API-documentation tool.
|
||||
|
||||
[tarball]: http://static.rust-lang.org/dist/rust-0.9.tar.gz
|
||||
[win-exe]: http://static.rust-lang.org/dist/rust-0.9-install.exe
|
||||
|
@ -3087,15 +3087,6 @@ they model most closely what people expect to shadow.
|
|||
If you use `extern mod`, per default `rustc` will look for libraries in the library search path (which you can
|
||||
extend with the `-L` switch).
|
||||
|
||||
However, Rust also ships with rustpkg, a package manager that is able to automatically download and build
|
||||
libraries if you use it for building your crate. How it works is explained [here][rustpkg],
|
||||
but for this tutorial it's only important to know that you can optionally annotate an
|
||||
`extern mod` statement with a package id that rustpkg can use to identify it:
|
||||
|
||||
~~~ {.ignore}
|
||||
extern mod rust = "github.com/mozilla/rust"; // pretend Rust is a simple library
|
||||
~~~
|
||||
|
||||
## Crate metadata and settings
|
||||
|
||||
For every crate you can define a number of metadata items, such as link name, version or author.
|
||||
|
@ -3146,11 +3137,6 @@ or setting the crate type (library or executable) explicitly:
|
|||
# fn farm() {}
|
||||
~~~~
|
||||
|
||||
> ***Note:*** The rules regarding package IDs, both as attributes and as used
|
||||
in `extern mod`, as well as their interaction with `rustpkg` are
|
||||
currently not clearly defined and will likely change in the
|
||||
future.
|
||||
|
||||
## A minimal example
|
||||
|
||||
Now for something that you can actually compile yourself.
|
||||
|
@ -3253,7 +3239,8 @@ library. You can use them by linking to `extra` with an `extern mod extra;`.
|
|||
[extra library]: extra/index.html
|
||||
|
||||
Right now `extra` contains those definitions directly, but in the future it will likely just
|
||||
re-export a bunch of 'officially blessed' crates that get managed with `rustpkg`.
|
||||
re-export a bunch of 'officially blessed' crates that get managed with a
|
||||
package manager.
|
||||
|
||||
# What next?
|
||||
|
||||
|
@ -3267,7 +3254,6 @@ guides on individual topics.
|
|||
* [The foreign function interface][ffi]
|
||||
* [Containers and iterators][container]
|
||||
* [Error-handling and Conditions][conditions]
|
||||
* [Packaging up Rust code][rustpkg]
|
||||
* [Documenting Rust code][rustdoc]
|
||||
* [Testing Rust code][testing]
|
||||
* [The Rust Runtime][runtime]
|
||||
|
@ -3281,7 +3267,6 @@ There is further documentation on the [wiki], however those tend to be even more
|
|||
[ffi]: guide-ffi.html
|
||||
[container]: guide-container.html
|
||||
[conditions]: guide-conditions.html
|
||||
[rustpkg]: guide-rustpkg.html
|
||||
[testing]: guide-testing.html
|
||||
[runtime]: guide-runtime.html
|
||||
[rustdoc]: rustdoc.html
|
||||
|
|
|
@ -130,7 +130,7 @@ To build an executable with debug info (experimental):
|
|||
|
||||
.SH "SEE ALSO"
|
||||
|
||||
rustdoc, rustpkg
|
||||
rustdoc
|
||||
|
||||
.SH "BUGS"
|
||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
||||
|
|
|
@ -84,7 +84,7 @@ The generated HTML can be viewed with any standard web browser.
|
|||
|
||||
.SH "SEE ALSO"
|
||||
|
||||
rustc, rustpkg
|
||||
rustc
|
||||
|
||||
.SH "BUGS"
|
||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
||||
|
|
195
man/rustpkg.1
195
man/rustpkg.1
|
@ -1,195 +0,0 @@
|
|||
.TH RUSTPKG "1" "July 2013" "rustpkg 0.7" "User Commands"
|
||||
.SH NAME
|
||||
rustpkg \- package manager for Rust applications
|
||||
.SH SYNOPSIS
|
||||
.B rustpkg
|
||||
[\fICOMMAND\fR] [\fIOPTIONS\fR] \fIINPUT\fR
|
||||
|
||||
.SH DESCRIPTION
|
||||
|
||||
This tool is a package manager for applications written in the Rust language,
|
||||
available at <\fBhttps://www.rust-lang.org\fR>. It provides commands to build,
|
||||
install and test Rust programs.
|
||||
|
||||
\fBrustpkg\fR is still a work in progress. See \fBdoc/rustpkg.md\fR in the Rust source distribution for future plans.
|
||||
|
||||
.SH COMMANDS
|
||||
|
||||
.TP
|
||||
\fBbuild\fR
|
||||
Searches for a package with the specified name and builds it in the workspace in
|
||||
which it is found.
|
||||
.TP
|
||||
\fBclean\fR
|
||||
Remove all generated files from the \fIbuild\fR directory in the target's workspace.
|
||||
.TP
|
||||
\fBinstall\fR
|
||||
Builds the specified target, and all its dependencies, and then installs the
|
||||
build products into the \fIlib\fR and \fIbin\fR directories of their respective
|
||||
workspaces.
|
||||
.TP
|
||||
\fBinit\fR
|
||||
Initializes the current working directory into a workspace.
|
||||
|
||||
.SS "BUILD COMMAND"
|
||||
|
||||
rustpkg build \fI[pkgname]\fR
|
||||
|
||||
The \fBbuild\fR command searches for a package with specified package name and
|
||||
builds it in any workspace(s) where it finds one. Any dependent packages are
|
||||
also built. The output files produced by the build phase are stored in the
|
||||
\fIbuild\fR subdirectories of each package. The executables and libraries are
|
||||
not copied to the 'bin' or 'lib' directories; that is the purpose of the
|
||||
\fBinstall\fR command.
|
||||
|
||||
.SS "CLEAN COMMAND"
|
||||
|
||||
rustpkg clean \fI[pkgname]\fR
|
||||
|
||||
deletes the contents of package's build directory.
|
||||
|
||||
.SS "INSTALL COMMAND"
|
||||
|
||||
rustpkg install \fI[url]\fR
|
||||
|
||||
builds the libraries and/or executables that are targets for the specified
|
||||
package name or URL, and then installs them either into package's \fIlib\fR
|
||||
and \fIbin\fR directories, or into the \fIlib\fR and \fIbin\fR subdirectories
|
||||
of the first entry in RUST_PATH.
|
||||
|
||||
Examples:
|
||||
|
||||
$ rustpkg install github.com/mozilla/servo.git#1.2
|
||||
$ rustpkg install rust-glfw
|
||||
|
||||
.SS "INIT COMMAND"
|
||||
|
||||
rustpkg init
|
||||
|
||||
This will turn the current working directory into a workspace. The first
|
||||
command you run when starting off a new project.
|
||||
|
||||
Example:
|
||||
|
||||
$ rustpkg init
|
||||
|
||||
.SH "ENVIRONMENT"
|
||||
|
||||
.TP
|
||||
RUST_PATH
|
||||
A colon-separated (semicolon-separated) list of paths denoting workspaces
|
||||
to search for Rust source files. See the section \fBPATHS\fR for full details.
|
||||
|
||||
.SH "PATHS"
|
||||
|
||||
The \fBrustpkg\fR tool searches for packages in the folders specified by the
|
||||
\fBRUST_PATH\fR environment variable. Each folder constitutes a
|
||||
\fIworkspace\fR, which contains one or more modules available to import.
|
||||
|
||||
In addition to the RUST_PATH settings, the following implicit paths are
|
||||
\fIalways\fR searched, in the following order:
|
||||
|
||||
1. Any folders named ".rust" in the current directory, \fIand every parent\fR
|
||||
of the curent directory, up to the filesystem root;
|
||||
|
||||
2. The system path "/usr/local" on Unix-style systems, or the equivalent on
|
||||
Windows; and
|
||||
|
||||
3. A folder named ".rust" in the user's home directory (ie. "~/.rust" on Unix-
|
||||
style systems or the equivalent on Windows).
|
||||
|
||||
.SH "PACKAGE STRUCTURE"
|
||||
|
||||
A valid workspace must contain each of the following subdirectories:
|
||||
|
||||
.TP
|
||||
\fBsrc/\fR
|
||||
Contains the Rust source code, with one subdirectory per package. Each
|
||||
subdirectory contains source files for a given package.
|
||||
.TP
|
||||
\fBlib/\fR
|
||||
"rustpkg install" installs libraries into a target-specific subdirectory of this directory.
|
||||
.TP
|
||||
\fBbin/\fR
|
||||
"rustpkg install" installs executable binaries into a target-specific subdirectory of this directory.
|
||||
.TP
|
||||
\fBbuild/\fR
|
||||
"rustpkg build" stores temporary build artifacts in a target-specific subdirectory of this directory.
|
||||
|
||||
For example, if "foo" is a workspace containing the package "bar", then
|
||||
"foo/src/bar/main.rs" would be the "main" entry point for building a "bar"
|
||||
executable.
|
||||
|
||||
.SH "PACKAGE IDENTIFIERS"
|
||||
|
||||
A package identifier uniquely identifies a package. A package can be stored in
|
||||
a workspace on the local file system, or on a remote Web server, in which case
|
||||
the package ID resembles a URL.
|
||||
|
||||
For example, \fIgithub.com/mozilla/rust\fR is a package ID
|
||||
that would refer to the git repository browsable at \fIhttp://github.com/mozilla/rust\fR.
|
||||
|
||||
A package ID can also specify a version, like:
|
||||
\fIgithub.com/mozilla/rust#0.3\fR. In this case, \fBrustpkg\fR will check that
|
||||
the repository \fIgithub.com/mozilla/rust\fR has a tag named \fI0.3\fR, and
|
||||
report an error otherwise.
|
||||
|
||||
.SH "SPECIAL MODULES"
|
||||
|
||||
\fBrustpkg\fR searches for four different known filenames in the src directory
|
||||
in order to determine which crates to build:
|
||||
|
||||
.TP
|
||||
\fBmain.rs\fR
|
||||
Assumed to be a main entry point for building an executable (install destination is 'bin' directory).
|
||||
.TP
|
||||
\fBlib.rs\fR
|
||||
Assumed to be a library crate (install destination is 'lib' directory).
|
||||
.TP
|
||||
\fBtest.rs\fR
|
||||
Assumed to contain tests declared with the \fI#[test]\fR attribute.
|
||||
.TP
|
||||
\fBbench.rs\fR
|
||||
Assumed to contain benchmarks declared with the \fI#[bench]\fR attribute.
|
||||
|
||||
.SH "CRATE VERSIONS"
|
||||
|
||||
\fBrustpkg\fR packages do not need to declare their versions with an attribute
|
||||
inside one of the source files, because rustpkg infers it from the version
|
||||
control system. When building a package that is in a git repository,
|
||||
rustpkg assumes that the most recent tag specifies the current version. When
|
||||
building a package that is not under version control, or that has no tags,
|
||||
rustpkg defaults the version to 0.1.
|
||||
|
||||
.SH "DEPENDENCIES"
|
||||
|
||||
rustpkg infers dependencies from "extern mod" directives. Thus, there should
|
||||
be no need to pass a "-L" flag to rustpkg to tell it where to find a library.
|
||||
(In the future, it will also be possible to write an "extern mod" directive
|
||||
referring to a remote package.)
|
||||
|
||||
.SH "CUSTOM BUILD SCRIPTS"
|
||||
|
||||
A file called \fIpkg.rs\fR at the root level in a workspace is called a \fIpackage
|
||||
script\fR. If a package script exists, rustpkg executes it to build the
|
||||
package rather than inferring crates as described previously.
|
||||
|
||||
Inside \fIpkg.rs\fR, it's possible to call back into rustpkg to finish up the
|
||||
build. The \fIrustpkg::api\fR module contains functions to build, install, or
|
||||
clean libraries and executables in the way rustpkg normally would without
|
||||
custom build logic.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
|
||||
rustc, rustdoc
|
||||
|
||||
.SH "BUGS"
|
||||
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.
|
||||
|
||||
.SH "AUTHOR"
|
||||
See \fBAUTHORS.txt\fR in the Rust source distribution. Graydon Hoare
|
||||
<\fIgraydon@mozilla.com\fR> is the project leader.
|
||||
|
||||
.SH "COPYRIGHT"
|
||||
This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR
|
||||
file in the rust source distribution.
|
|
@ -50,9 +50,9 @@
|
|||
################################################################################
|
||||
|
||||
TARGET_CRATES := std extra green rustuv native flate arena glob
|
||||
HOST_CRATES := syntax rustc rustdoc rustpkg
|
||||
HOST_CRATES := syntax rustc rustdoc
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
TOOLS := compiletest rustpkg rustdoc rustc
|
||||
TOOLS := compiletest rustdoc rustc
|
||||
|
||||
DEPS_std := native:rustrt
|
||||
DEPS_extra := std
|
||||
|
@ -62,17 +62,14 @@ DEPS_native := std
|
|||
DEPS_syntax := std extra
|
||||
DEPS_rustc := syntax native:rustllvm flate arena
|
||||
DEPS_rustdoc := rustc native:sundown
|
||||
DEPS_rustpkg := rustc
|
||||
DEPS_flate := std native:miniz
|
||||
DEPS_arena := std extra
|
||||
DEPS_glob := std
|
||||
|
||||
TOOL_DEPS_compiletest := extra green rustuv
|
||||
TOOL_DEPS_rustpkg := rustpkg green rustuv
|
||||
TOOL_DEPS_rustdoc := rustdoc green rustuv
|
||||
TOOL_DEPS_rustc := rustc green rustuv
|
||||
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs
|
||||
TOOL_SOURCE_rustpkg := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs
|
||||
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ PKG_FILES := \
|
|||
$(addprefix $(S)src/, \
|
||||
README.txt \
|
||||
driver \
|
||||
librustpkg \
|
||||
librustc \
|
||||
compiletest \
|
||||
etc \
|
||||
|
|
12
mk/docs.mk
12
mk/docs.mk
|
@ -89,12 +89,6 @@ doc/rust.epub: rust.md
|
|||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@
|
||||
|
||||
DOCS += doc/rustpkg.html
|
||||
doc/rustpkg.html: rustpkg.md $(HTML_DEPS)
|
||||
@$(call E, pandoc: $@)
|
||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
||||
|
||||
DOCS += doc/rustdoc.html
|
||||
doc/rustdoc.html: rustdoc.md $(HTML_DEPS)
|
||||
@$(call E, pandoc: $@)
|
||||
|
@ -212,12 +206,6 @@ doc/guide-conditions.html: $(S)doc/guide-conditions.md $(HTML_DEPS)
|
|||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
||||
|
||||
DOCS += doc/guide-rustpkg.html
|
||||
doc/guide-rustpkg.html: $(S)doc/guide-rustpkg.md $(HTML_DEPS)
|
||||
@$(call E, pandoc: $@)
|
||||
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
|
||||
$(CFG_PANDOC) $(HTML_OPTS) --output=$@
|
||||
|
||||
DOCS += doc/guide-pointers.html
|
||||
doc/guide-pointers.html: $(S)doc/guide-pointers.md $(HTML_DEPS)
|
||||
@$(call E, pandoc: $@)
|
||||
|
|
13
mk/tests.mk
13
mk/tests.mk
|
@ -185,7 +185,6 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
|
|||
check-lite: cleantestlibs cleantmptestlogs \
|
||||
check-stage2-std check-stage2-extra check-stage2-rpass \
|
||||
check-stage2-rustuv check-stage2-native check-stage2-green \
|
||||
check-stage2-rustpkg \
|
||||
check-stage2-rfail check-stage2-cfail check-stage2-rmake
|
||||
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log
|
||||
|
||||
|
@ -423,18 +422,6 @@ $(foreach host,$(CFG_HOST), \
|
|||
$(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \
|
||||
))))))
|
||||
|
||||
# FIXME (#10104): Raise the stack size to work around rustpkg bypassing
|
||||
# the code in rustc that would take care of it.
|
||||
define DEF_RUSTPKG_STACK_FIX
|
||||
$$(call TEST_OK_FILE,$(1),$(2),$(3),rustpkg): export RUST_MIN_STACK=8000000
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(eval $(call DEF_RUSTPKG_STACK_FIX,$(stage),$(target),$(host))))))
|
||||
|
||||
|
||||
######################################################################
|
||||
# Rules for the compiletest tests (rpass, rfail, etc.)
|
||||
######################################################################
|
||||
|
|
|
@ -30,7 +30,6 @@ Source layout:
|
|||
| `test/auxiliary` | - Dependencies of tests |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `librustdoc/` | The Rust API documentation tool |
|
||||
| `librustpkg/` | The package manager and build system |
|
||||
| `libuv/` | The libuv submodule |
|
||||
| ------------------- | --------------------------------------------------------- |
|
||||
| `llvm/` | The LLVM submodule |
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[cfg(rustpkg)]
|
||||
extern mod this = "rustpkg";
|
||||
|
||||
#[cfg(rustdoc)]
|
||||
extern mod this = "rustdoc";
|
||||
|
||||
|
|
|
@ -150,8 +150,9 @@ pub struct Options {
|
|||
lint_opts: ~[(lint::Lint, lint::level)],
|
||||
save_temps: bool,
|
||||
output_type: back::link::OutputType,
|
||||
// This is mutable for rustpkg, which updates search paths based on the
|
||||
// parsed code.
|
||||
// This was mutable for rustpkg, which updates search paths based on the
|
||||
// parsed code. It remains mutable in case its replacements wants to use
|
||||
// this.
|
||||
addl_lib_search_paths: @RefCell<HashSet<Path>>,
|
||||
ar: Option<~str>,
|
||||
linker: Option<~str>,
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
Right now, commands that work are "build" and "clean".
|
||||
|
||||
`rustpkg build` and `rustpkg clean` should work
|
||||
|
||||
for example:
|
||||
$ cd ~/rust/src/librustpkg/testsuite/pass
|
||||
$ rustpkg build hello-world
|
||||
... some output ...
|
||||
$ rustpkg clean hello-world
|
||||
|
||||
-------------
|
||||
the following test packages in librustpkg/testsuite/pass:
|
||||
* hello-world
|
||||
* install-paths
|
||||
* simple-lib
|
||||
* deeply/nested/path
|
||||
* fancy-lib
|
||||
|
||||
It fails on the following test packages:
|
||||
* external-crate (no support for `extern mod` inference yet)
|
||||
|
||||
and should fail with proper error messages
|
||||
on all of the test packages in librustpkg/testsuite/fail
|
||||
* no-inferred-crates
|
|
@ -1,199 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use CtxMethods;
|
||||
use context::*;
|
||||
use crate::*;
|
||||
use package_source::*;
|
||||
use path_util::{platform_library_name, target_build_dir};
|
||||
use target::*;
|
||||
use workspace::pkg_parent_workspaces;
|
||||
use workcache_support::*;
|
||||
pub use path_util::default_workspace;
|
||||
|
||||
pub use source_control::{safe_git_clone, git_clone_url};
|
||||
|
||||
use std::run;
|
||||
use extra::arc::{Arc,RWArc};
|
||||
use extra::workcache;
|
||||
use extra::workcache::{Database, FreshnessMap};
|
||||
use extra::treemap::TreeMap;
|
||||
use syntax::crateid::CrateId;
|
||||
|
||||
// A little sad -- duplicated from rustc::back::*
|
||||
#[cfg(target_arch = "arm")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-marm"] }
|
||||
#[cfg(target_arch = "mips")]
|
||||
fn cc_args() -> ~[~str] { ~[] }
|
||||
#[cfg(target_arch = "x86")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-m32"] }
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn cc_args() -> ~[~str] { ~[~"-m64"] }
|
||||
|
||||
/// Convenience functions intended for calling from pkg.rs
|
||||
/// p is where to put the cache file for dependencies
|
||||
pub fn default_context(sysroot: Path, p: Path) -> BuildContext {
|
||||
new_default_context(new_workcache_context(&p), sysroot)
|
||||
}
|
||||
|
||||
pub fn new_default_context(c: workcache::Context, p: Path) -> BuildContext {
|
||||
BuildContext {
|
||||
context: Context {
|
||||
cfgs: ~[],
|
||||
rustc_flags: RustcFlags::default(),
|
||||
use_rust_path_hack: false,
|
||||
},
|
||||
sysroot: p,
|
||||
workcache_context: c
|
||||
}
|
||||
}
|
||||
|
||||
fn file_is_fresh(path: &str, in_hash: &str) -> bool {
|
||||
let path = Path::new(path);
|
||||
path.exists() && in_hash == digest_file_with_date(&path)
|
||||
}
|
||||
|
||||
fn binary_is_fresh(path: &str, in_hash: &str) -> bool {
|
||||
let path = Path::new(path);
|
||||
path.exists() && in_hash == digest_only_date(&path)
|
||||
}
|
||||
|
||||
pub fn new_workcache_context(p: &Path) -> workcache::Context {
|
||||
let db_file = p.join("rustpkg_db.json"); // ??? probably wrong
|
||||
debug!("Workcache database file: {}", db_file.display());
|
||||
let db = RWArc::new(Database::new(db_file));
|
||||
let cfg = Arc::new(TreeMap::new());
|
||||
let mut freshness: FreshnessMap = TreeMap::new();
|
||||
// Set up freshness functions for every type of dependency rustpkg
|
||||
// knows about
|
||||
freshness.insert(~"file", file_is_fresh);
|
||||
freshness.insert(~"binary", binary_is_fresh);
|
||||
workcache::Context::new_with_freshness(db, cfg, Arc::new(freshness))
|
||||
}
|
||||
|
||||
pub fn build_lib(sysroot: Path, root: Path, name: ~str, lib: Path) {
|
||||
build_lib_with_cfgs(sysroot, root, name, lib, ~[])
|
||||
}
|
||||
|
||||
pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, lib: Path, cfgs: ~[~str]) {
|
||||
let cx = default_context(sysroot, root.clone());
|
||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
||||
let pkg_src = PkgSrc {
|
||||
source_workspace: root.clone(),
|
||||
build_in_destination: false,
|
||||
destination_workspace: root.clone(),
|
||||
start_dir: root.join_many(["src", name.as_slice()]),
|
||||
id: crate_id,
|
||||
// n.b. This assumes the package only has one crate
|
||||
libs: ~[mk_crate(lib)],
|
||||
mains: ~[],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
};
|
||||
pkg_src.build(&cx, cfgs, []);
|
||||
}
|
||||
|
||||
pub fn build_exe(sysroot: Path, root: Path, name: ~str, main: Path) {
|
||||
build_exe_with_cfgs(sysroot, root, name, main, ~[])
|
||||
}
|
||||
|
||||
pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, main: Path, cfgs: ~[~str]) {
|
||||
let cx = default_context(sysroot, root.clone());
|
||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
||||
let pkg_src = PkgSrc {
|
||||
source_workspace: root.clone(),
|
||||
build_in_destination: false,
|
||||
destination_workspace: root.clone(),
|
||||
start_dir: root.join_many(["src", name.as_slice()]),
|
||||
id: crate_id,
|
||||
libs: ~[],
|
||||
// n.b. This assumes the package only has one crate
|
||||
mains: ~[mk_crate(main)],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
};
|
||||
|
||||
pkg_src.build(&cx, cfgs, []);
|
||||
}
|
||||
|
||||
pub fn install_pkg(cx: &BuildContext,
|
||||
workspace: Path,
|
||||
name: ~str,
|
||||
// For now, these inputs are assumed to be inputs to each of the crates
|
||||
more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
|
||||
let crate_id: CrateId = from_str(name).expect("valid crate id");
|
||||
cx.install(PkgSrc::new(workspace.clone(), workspace, false, crate_id),
|
||||
&WhatToBuild{ build_type: Inferred,
|
||||
inputs_to_discover: more_inputs,
|
||||
sources: Everything });
|
||||
}
|
||||
|
||||
/// Builds an arbitrary library whose short name is `output`,
|
||||
/// by invoking `tool` with arguments `args` plus "-o %s", where %s
|
||||
/// is the platform-specific library name for `output`.
|
||||
/// Returns that platform-specific name, or None if `tool` could not be started.
|
||||
pub fn build_library_in_workspace(exec: &mut workcache::Exec,
|
||||
context: &mut Context,
|
||||
package_name: &str,
|
||||
tool: &str,
|
||||
flags: &[~str],
|
||||
paths: &[~str],
|
||||
output: &str) -> Option<~str> {
|
||||
use command_failed = conditions::command_failed::cond;
|
||||
|
||||
let workspace = my_workspace(context, package_name);
|
||||
let workspace_build_dir = target_build_dir(&workspace);
|
||||
let out_name = workspace_build_dir.join_many([package_name.to_str(),
|
||||
platform_library_name(output)]);
|
||||
// make paths absolute
|
||||
let crateid: CrateId = from_str(package_name).expect("valid crate id");
|
||||
let absolute_paths = paths.map(|s| {
|
||||
let whatever = workspace.join_many([~"src",
|
||||
crateid.short_name_with_version(),
|
||||
s.to_owned()]);
|
||||
whatever.as_str().unwrap().to_owned()
|
||||
});
|
||||
|
||||
let cc_args = cc_args();
|
||||
|
||||
let all_args = flags + absolute_paths + cc_args +
|
||||
~[~"-o", out_name.as_str().unwrap().to_owned()];
|
||||
match run::process_status(tool, all_args) {
|
||||
Some(exit_process) => {
|
||||
if exit_process.success() {
|
||||
let out_name_str = out_name.as_str().unwrap().to_owned();
|
||||
exec.discover_output("binary",
|
||||
out_name_str,
|
||||
digest_only_date(&out_name));
|
||||
context.add_library_path(out_name.dir_path());
|
||||
Some(out_name_str)
|
||||
} else {
|
||||
Some(command_failed.raise((tool.to_owned(), all_args, exit_process)))
|
||||
}
|
||||
},
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn my_workspace(context: &Context, package_name: &str) -> Path {
|
||||
use bad_pkg_id = conditions::bad_pkg_id::cond;
|
||||
|
||||
// (this assumes no particular version is requested)
|
||||
let crateid = from_str(package_name).expect("valid crate id");
|
||||
let workspaces = pkg_parent_workspaces(context, &crateid);
|
||||
if workspaces.is_empty() {
|
||||
bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
|
||||
}
|
||||
workspaces[0]
|
||||
}
|
||||
|
||||
fn mk_crate(p: Path) -> Crate {
|
||||
Crate { file: p, flags: ~[], cfgs: ~[] }
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Useful conditions
|
||||
|
||||
pub use syntax::crateid::CrateId;
|
||||
pub use std::io::FileStat;
|
||||
pub use std::io::process::ProcessExit;
|
||||
pub use std::path::Path;
|
||||
|
||||
condition! {
|
||||
pub bad_path: (Path, ~str) -> Path;
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub nonexistent_package: (CrateId, ~str) -> Path;
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub missing_pkg_files: (CrateId) -> ();
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub bad_pkg_id: (Path, ~str) -> CrateId;
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub failed_to_create_temp_dir: (~str) -> Path;
|
||||
}
|
||||
|
||||
condition! {
|
||||
pub git_checkout_failed: (~str, Path) -> ();
|
||||
}
|
||||
|
||||
condition! {
|
||||
// str is output of applying the command (first component)
|
||||
// to the args (second component)
|
||||
pub command_failed: (~str, ~[~str], ProcessExit) -> ~str;
|
||||
}
|
|
@ -1,347 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Context data structure used by rustpkg
|
||||
|
||||
use extra::workcache;
|
||||
use rustc::driver::session;
|
||||
use rustc::metadata::filesearch::rustlibdir;
|
||||
|
||||
use std::hashmap::HashSet;
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct Context {
|
||||
// Config strings that the user passed in with --cfg
|
||||
cfgs: ~[~str],
|
||||
// Flags to pass to rustc
|
||||
rustc_flags: RustcFlags,
|
||||
// If use_rust_path_hack is true, rustpkg searches for sources
|
||||
// in *package* directories that are in the RUST_PATH (for example,
|
||||
// FOO/src/bar-0.1 instead of FOO). The flag doesn't affect where
|
||||
// rustpkg stores build artifacts.
|
||||
use_rust_path_hack: bool,
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct BuildContext {
|
||||
// Context for workcache
|
||||
workcache_context: workcache::Context,
|
||||
// Parsed command line options
|
||||
context: Context,
|
||||
// The root directory containing the Rust standard libraries
|
||||
sysroot: Path
|
||||
}
|
||||
|
||||
impl BuildContext {
|
||||
pub fn sysroot(&self) -> Path {
|
||||
self.sysroot.clone()
|
||||
}
|
||||
|
||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
||||
// or the host dir
|
||||
pub fn sysroot_to_use(&self) -> Path {
|
||||
if !in_target(&self.sysroot) {
|
||||
self.sysroot.clone()
|
||||
} else {
|
||||
let mut p = self.sysroot.clone();
|
||||
p.pop();
|
||||
p.pop();
|
||||
p.pop();
|
||||
p
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the flags to pass to rustc, as a vector of strings
|
||||
pub fn flag_strs(&self) -> ~[~str] {
|
||||
self.context.flag_strs()
|
||||
}
|
||||
|
||||
pub fn compile_upto(&self) -> StopBefore {
|
||||
self.context.compile_upto()
|
||||
}
|
||||
|
||||
pub fn add_library_path(&mut self, p: Path) {
|
||||
debug!("Adding library path: {}", p.display());
|
||||
self.context.add_library_path(p);
|
||||
}
|
||||
|
||||
pub fn additional_library_paths(&self) -> HashSet<Path> {
|
||||
self.context.rustc_flags.additional_library_paths.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Deliberately unsupported rustc flags:
|
||||
--bin, --lib inferred from crate file names
|
||||
-L inferred from extern mods
|
||||
--out-dir inferred from RUST_PATH
|
||||
--test use `rustpkg test`
|
||||
-v -h --ls don't make sense with rustpkg
|
||||
-W -A -D -F - use pragmas instead
|
||||
|
||||
rustc flags that aren't implemented yet:
|
||||
--passes
|
||||
--llvm-arg
|
||||
--target-feature
|
||||
--android-cross-path
|
||||
*/
|
||||
pub struct RustcFlags {
|
||||
compile_upto: StopBefore,
|
||||
// Linker to use with the --linker flag
|
||||
linker: Option<~str>,
|
||||
// Extra arguments to pass to rustc with the --link-args flag
|
||||
link_args: Option<~str>,
|
||||
// Optimization level. 0 = default. -O = 2.
|
||||
optimization_level: session::OptLevel,
|
||||
// True if the user passed in --save-temps
|
||||
save_temps: bool,
|
||||
// Target (defaults to rustc's default target)
|
||||
target: Option<~str>,
|
||||
// Target CPU (defaults to rustc's default target CPU)
|
||||
target_cpu: Option<~str>,
|
||||
// Additional library directories, which get passed with the -L flag
|
||||
// This can't be set with a rustpkg flag, only from package scripts
|
||||
additional_library_paths: HashSet<Path>,
|
||||
// Any -Z features
|
||||
experimental_features: Option<~[~str]>
|
||||
}
|
||||
|
||||
impl Clone for RustcFlags {
|
||||
fn clone(&self) -> RustcFlags {
|
||||
RustcFlags {
|
||||
compile_upto: self.compile_upto,
|
||||
linker: self.linker.clone(),
|
||||
link_args: self.link_args.clone(),
|
||||
optimization_level: self.optimization_level,
|
||||
save_temps: self.save_temps,
|
||||
target: self.target.clone(),
|
||||
target_cpu: self.target_cpu.clone(),
|
||||
additional_library_paths: self.additional_library_paths.clone(),
|
||||
experimental_features: self.experimental_features.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum StopBefore {
|
||||
Nothing, // compile everything
|
||||
Link, // --no-link
|
||||
LLVMCompileBitcode, // --emit-llvm without -S
|
||||
LLVMAssemble, // -S --emit-llvm
|
||||
Assemble, // -S without --emit-llvm
|
||||
Trans, // --no-trans
|
||||
Pretty, // --pretty
|
||||
Analysis, // --parse-only
|
||||
}
|
||||
|
||||
impl Context {
|
||||
|
||||
/// Returns the flags to pass to rustc, as a vector of strings
|
||||
pub fn flag_strs(&self) -> ~[~str] {
|
||||
self.rustc_flags.flag_strs()
|
||||
}
|
||||
|
||||
pub fn compile_upto(&self) -> StopBefore {
|
||||
self.rustc_flags.compile_upto
|
||||
}
|
||||
|
||||
pub fn add_library_path(&mut self, p: Path) {
|
||||
self.rustc_flags.additional_library_paths.insert(p);
|
||||
}
|
||||
}
|
||||
|
||||
/// We assume that if ../../rustlib exists, then we're running
|
||||
/// rustpkg from a Rust target directory. This is part of a
|
||||
/// kludgy hack used to adjust the sysroot.
|
||||
pub fn in_target(sysroot: &Path) -> bool {
|
||||
debug!("Checking whether {} is in target", sysroot.display());
|
||||
let mut p = sysroot.dir_path();
|
||||
p.pop();
|
||||
p.push(rustlibdir());
|
||||
p.is_dir()
|
||||
}
|
||||
|
||||
impl RustcFlags {
|
||||
fn flag_strs(&self) -> ~[~str] {
|
||||
let linker_flag = match self.linker {
|
||||
Some(ref l) => ~[~"--linker", l.clone()],
|
||||
None => ~[]
|
||||
};
|
||||
let link_args_flag = match self.link_args {
|
||||
Some(ref l) => ~[~"--link-args", l.clone()],
|
||||
None => ~[]
|
||||
};
|
||||
let save_temps_flag = if self.save_temps { ~[~"--save-temps"] } else { ~[] };
|
||||
let target_flag = match self.target {
|
||||
Some(ref l) => ~[~"--target", l.clone()],
|
||||
None => ~[]
|
||||
};
|
||||
let target_cpu_flag = match self.target_cpu {
|
||||
Some(ref l) => ~[~"--target-cpu", l.clone()],
|
||||
None => ~[]
|
||||
};
|
||||
let z_flags = match self.experimental_features {
|
||||
Some(ref ls) => ls.flat_map(|s| ~[~"-Z", s.clone()]),
|
||||
None => ~[]
|
||||
};
|
||||
linker_flag
|
||||
+ link_args_flag
|
||||
+ save_temps_flag
|
||||
+ target_flag
|
||||
+ target_cpu_flag
|
||||
+ z_flags + (match self.compile_upto {
|
||||
LLVMCompileBitcode => ~[~"--emit-llvm"],
|
||||
LLVMAssemble => ~[~"--emit-llvm", ~"-S"],
|
||||
Link => ~[~"-c"],
|
||||
Trans => ~[~"--no-trans"],
|
||||
Assemble => ~[~"-S"],
|
||||
// n.b. Doesn't support all flavors of --pretty (yet)
|
||||
Pretty => ~[~"--pretty"],
|
||||
Analysis => ~[~"--parse-only"],
|
||||
Nothing => ~[]
|
||||
})
|
||||
}
|
||||
|
||||
pub fn default() -> RustcFlags {
|
||||
RustcFlags {
|
||||
linker: None,
|
||||
link_args: None,
|
||||
compile_upto: Nothing,
|
||||
optimization_level: session::Default,
|
||||
save_temps: false,
|
||||
target: None,
|
||||
target_cpu: None,
|
||||
additional_library_paths: HashSet::new(),
|
||||
experimental_features: None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Command {
|
||||
BuildCmd,
|
||||
CleanCmd,
|
||||
DoCmd,
|
||||
HelpCmd,
|
||||
InfoCmd,
|
||||
InitCmd,
|
||||
InstallCmd,
|
||||
ListCmd,
|
||||
PreferCmd,
|
||||
TestCmd,
|
||||
UninstallCmd,
|
||||
UnpreferCmd,
|
||||
}
|
||||
|
||||
impl FromStr for Command {
|
||||
|
||||
fn from_str(s: &str) -> Option<Command> {
|
||||
match s {
|
||||
&"build" => Some(BuildCmd),
|
||||
&"clean" => Some(CleanCmd),
|
||||
&"do" => Some(DoCmd),
|
||||
&"help" => Some(HelpCmd),
|
||||
&"info" => Some(InfoCmd),
|
||||
&"install" => Some(InstallCmd),
|
||||
&"list" => Some(ListCmd),
|
||||
&"prefer" => Some(PreferCmd),
|
||||
&"test" => Some(TestCmd),
|
||||
&"init" => Some(InitCmd),
|
||||
&"uninstall" => Some(UninstallCmd),
|
||||
&"unprefer" => Some(UnpreferCmd),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true if any of the flags given are incompatible with the cmd
|
||||
pub fn flags_forbidden_for_cmd(flags: &RustcFlags,
|
||||
cfgs: &[~str],
|
||||
cmd: Command, user_supplied_opt_level: bool) -> bool {
|
||||
let complain = |s| {
|
||||
println!("The {} option can only be used with the `build` command:
|
||||
rustpkg [options..] build {} [package-ID]", s, s);
|
||||
};
|
||||
|
||||
if flags.linker.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The --linker option can only be used with the build or install commands.");
|
||||
return true;
|
||||
}
|
||||
if flags.link_args.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The --link-args option can only be used with the build or install commands.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if !cfgs.is_empty() && cmd != BuildCmd && cmd != InstallCmd && cmd != TestCmd {
|
||||
println!("The --cfg option can only be used with the build, test, or install commands.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if user_supplied_opt_level && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The -O and --opt-level options can only be used with the build \
|
||||
or install commands.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if flags.save_temps && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The --save-temps option can only be used with the build \
|
||||
or install commands.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if flags.target.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The --target option can only be used with the build \
|
||||
or install commands.");
|
||||
return true;
|
||||
}
|
||||
if flags.target_cpu.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The --target-cpu option can only be used with the build \
|
||||
or install commands.");
|
||||
return true;
|
||||
}
|
||||
if flags.experimental_features.is_some() && cmd != BuildCmd && cmd != InstallCmd {
|
||||
println!("The -Z option can only be used with the build or install commands.");
|
||||
return true;
|
||||
}
|
||||
|
||||
match flags.compile_upto {
|
||||
Link if cmd != BuildCmd => {
|
||||
complain("--no-link");
|
||||
true
|
||||
}
|
||||
Trans if cmd != BuildCmd => {
|
||||
complain("--no-trans");
|
||||
true
|
||||
}
|
||||
Assemble if cmd != BuildCmd => {
|
||||
complain("-S");
|
||||
true
|
||||
}
|
||||
Pretty if cmd != BuildCmd => {
|
||||
complain("--pretty");
|
||||
true
|
||||
}
|
||||
Analysis if cmd != BuildCmd => {
|
||||
complain("--parse-only");
|
||||
true
|
||||
}
|
||||
LLVMCompileBitcode if cmd != BuildCmd => {
|
||||
complain("--emit-llvm");
|
||||
true
|
||||
}
|
||||
LLVMAssemble if cmd != BuildCmd => {
|
||||
complain("--emit-llvm");
|
||||
true
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(dead_code)];
|
||||
|
||||
use std::path::Path;
|
||||
use std::vec;
|
||||
|
||||
/// A crate is a unit of Rust code to be compiled into a binary or library
|
||||
#[deriving(Clone)]
|
||||
pub struct Crate {
|
||||
file: Path,
|
||||
flags: ~[~str],
|
||||
cfgs: ~[~str]
|
||||
}
|
||||
|
||||
impl Crate {
|
||||
|
||||
pub fn new(p: &Path) -> Crate {
|
||||
Crate {
|
||||
file: (*p).clone(),
|
||||
flags: ~[],
|
||||
cfgs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
fn flag(&self, flag: ~str) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(self.flags.clone(), [flag]),
|
||||
.. (*self).clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn flags(&self, flags: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
flags: vec::append(self.flags.clone(), flags),
|
||||
.. (*self).clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn cfg(&self, cfg: ~str) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(self.cfgs.clone(), [cfg]),
|
||||
.. (*self).clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn cfgs(&self, cfgs: ~[~str]) -> Crate {
|
||||
Crate {
|
||||
cfgs: vec::append(self.cfgs.clone(), cfgs),
|
||||
.. (*self).clone()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub static COPY_FAILED_CODE: int = 65;
|
||||
pub static BAD_FLAG_CODE: int = 67;
|
||||
pub static NONEXISTENT_PACKAGE_CODE: int = 68;
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Listing installed packages
|
||||
|
||||
use rustc::metadata::filesearch::rust_path;
|
||||
use std::os;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use syntax::crateid::CrateId;
|
||||
|
||||
pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool {
|
||||
let workspaces = rust_path();
|
||||
for p in workspaces.iter() {
|
||||
let binfiles = {
|
||||
let _guard = io::ignore_io_error();
|
||||
fs::readdir(&p.join("bin"))
|
||||
};
|
||||
for exec in binfiles.iter() {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
match exec.filestem_str() {
|
||||
None => (),
|
||||
Some(exec_path) => {
|
||||
let crate_id = from_str(exec_path).expect("valid crate id");
|
||||
if !f(&crate_id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let libfiles = {
|
||||
let _guard = io::ignore_io_error();
|
||||
fs::readdir(&p.join("lib"))
|
||||
};
|
||||
for lib in libfiles.iter() {
|
||||
debug!("Full name: {}", lib.display());
|
||||
match has_library(lib) {
|
||||
Some(basename) => {
|
||||
let parent = p.join("lib");
|
||||
debug!("parent = {}, child = {}",
|
||||
parent.display(), lib.display());
|
||||
let rel_p = lib.path_relative_from(&parent).unwrap();
|
||||
debug!("Rel: {}", rel_p.display());
|
||||
let rel_path = rel_p.join(basename);
|
||||
rel_path.display().with_str(|s| {
|
||||
debug!("Rel name: {}", s);
|
||||
let crate_id = from_str(s).expect("valid crate id");
|
||||
f(&crate_id);
|
||||
});
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
};
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn has_library(p: &Path) -> Option<~str> {
|
||||
let files = {
|
||||
let _guard = io::ignore_io_error();
|
||||
fs::readdir(p)
|
||||
};
|
||||
for path in files.iter() {
|
||||
if path.extension_str() == Some(os::consts::DLL_EXTENSION) {
|
||||
let stuff : &str = path.filestem_str().expect("has_library: weird path");
|
||||
let mut stuff2 = stuff.split_str("-");
|
||||
let stuff3: ~[&str] = stuff2.collect();
|
||||
// argh
|
||||
let chars_to_drop = os::consts::DLL_PREFIX.len();
|
||||
return Some(stuff3[0].slice(chars_to_drop, stuff3[0].len()).to_owned());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn package_is_installed(p: &CrateId) -> bool {
|
||||
let mut is_installed = false;
|
||||
list_installed_packages(|installed| {
|
||||
if installed == p {
|
||||
is_installed = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
is_installed
|
||||
}
|
|
@ -1,816 +0,0 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// rustpkg - a package manager and build system for Rust
|
||||
|
||||
#[crate_id = "rustpkg#0.10-pre"];
|
||||
#[license = "MIT/ASL2"];
|
||||
#[crate_type = "dylib"];
|
||||
|
||||
#[feature(globs, managed_boxes)];
|
||||
|
||||
extern mod extra;
|
||||
extern mod rustc;
|
||||
extern mod syntax;
|
||||
|
||||
use std::{os, run, str, task};
|
||||
use std::io::process;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
pub use std::path::Path;
|
||||
|
||||
use extra::workcache;
|
||||
use rustc::driver::{driver, session};
|
||||
use rustc::metadata::creader::Loader;
|
||||
use rustc::metadata::filesearch;
|
||||
use rustc::metadata::filesearch::rust_path;
|
||||
use rustc::util::sha2;
|
||||
use syntax::{ast, diagnostic};
|
||||
use syntax::crateid::CrateId;
|
||||
use messages::{error, warn, note};
|
||||
use parse_args::{ParseResult, parse_args};
|
||||
use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
|
||||
use path_util::in_rust_path;
|
||||
use path_util::{built_executable_in_workspace, built_library_in_workspace, default_workspace};
|
||||
use path_util::{target_executable_in_workspace, target_library_in_workspace, dir_has_crate_file};
|
||||
use source_control::{CheckedOutSources, is_git_dir, make_read_only};
|
||||
use workspace::{each_pkg_parent_workspace, pkg_parent_workspaces, cwd_to_workspace};
|
||||
use workspace::determine_destination;
|
||||
use context::{BuildContext, Trans, Nothing, Pretty, Analysis,
|
||||
LLVMAssemble, LLVMCompileBitcode};
|
||||
use context::{Command, BuildCmd, CleanCmd, DoCmd, HelpCmd, InfoCmd, InstallCmd, ListCmd,
|
||||
PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd};
|
||||
use package_source::PkgSrc;
|
||||
use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
|
||||
use target::{Main, Tests, MaybeCustom, Inferred, JustOne};
|
||||
use workcache_support::digest_only_date;
|
||||
use exit_codes::{COPY_FAILED_CODE};
|
||||
|
||||
pub mod api;
|
||||
mod conditions;
|
||||
pub mod context;
|
||||
mod crate;
|
||||
pub mod exit_codes;
|
||||
mod installed_packages;
|
||||
mod messages;
|
||||
pub mod package_source;
|
||||
mod parse_args;
|
||||
mod path_util;
|
||||
mod source_control;
|
||||
mod target;
|
||||
#[cfg(not(windows), test)] // FIXME test failure on windows: #10471
|
||||
mod tests;
|
||||
mod util;
|
||||
pub mod version;
|
||||
pub mod workcache_support;
|
||||
mod workspace;
|
||||
|
||||
pub mod usage;
|
||||
|
||||
/// A PkgScript represents user-supplied custom logic for
|
||||
/// special build hooks. This only exists for packages with
|
||||
/// an explicit package script.
|
||||
struct PkgScript<'a> {
|
||||
/// Uniquely identifies this package
|
||||
id: &'a CrateId,
|
||||
/// File path for the package script
|
||||
input: Path,
|
||||
/// The session to use *only* for compiling the custom
|
||||
/// build script
|
||||
sess: session::Session,
|
||||
/// The config for compiling the custom build script
|
||||
cfg: ast::CrateConfig,
|
||||
/// The crate and ast_map for the custom build script
|
||||
crate_and_map: Option<(ast::Crate, syntax::ast_map::Map)>,
|
||||
/// Directory in which to store build output
|
||||
build_dir: Path
|
||||
}
|
||||
|
||||
impl<'a> PkgScript<'a> {
|
||||
/// Given the path name for a package script
|
||||
/// and a package ID, parse the package script into
|
||||
/// a PkgScript that we can then execute
|
||||
fn parse<'a>(sysroot: Path,
|
||||
script: Path,
|
||||
workspace: &Path,
|
||||
id: &'a CrateId) -> PkgScript<'a> {
|
||||
// Get the executable name that was invoked
|
||||
let binary = os::args()[0];
|
||||
// Build the rustc session data structures to pass
|
||||
// to the compiler
|
||||
debug!("pkgscript parse: {}", sysroot.display());
|
||||
let options = @session::Options {
|
||||
binary: binary,
|
||||
maybe_sysroot: Some(@sysroot),
|
||||
outputs: ~[session::OutputExecutable],
|
||||
.. (*session::basic_options()).clone()
|
||||
};
|
||||
let input = driver::FileInput(script.clone());
|
||||
let sess = driver::build_session(options,
|
||||
Some(script.clone()),
|
||||
@diagnostic::DefaultEmitter);
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
let loader = &mut Loader::new(sess);
|
||||
let crate_and_map = driver::phase_2_configure_and_expand(sess,
|
||||
cfg.clone(),
|
||||
loader,
|
||||
crate);
|
||||
let work_dir = build_pkg_id_in_workspace(id, workspace);
|
||||
|
||||
debug!("Returning package script with id {}", id.to_str());
|
||||
|
||||
PkgScript {
|
||||
id: id,
|
||||
input: script,
|
||||
sess: sess,
|
||||
cfg: cfg,
|
||||
crate_and_map: Some(crate_and_map),
|
||||
build_dir: work_dir
|
||||
}
|
||||
}
|
||||
|
||||
fn build_custom(&mut self, exec: &mut workcache::Exec) -> ~str {
|
||||
let sess = self.sess;
|
||||
|
||||
debug!("Working directory = {}", self.build_dir.display());
|
||||
// Collect together any user-defined commands in the package script
|
||||
let (crate, ast_map) = self.crate_and_map.take_unwrap();
|
||||
let crate = util::ready_crate(sess, crate);
|
||||
debug!("Building output filenames with script name {}",
|
||||
driver::source_name(&driver::FileInput(self.input.clone())));
|
||||
let exe = self.build_dir.join("pkg" + util::exe_suffix());
|
||||
util::compile_crate_from_input(&self.input,
|
||||
exec,
|
||||
Nothing,
|
||||
&self.build_dir,
|
||||
sess,
|
||||
crate,
|
||||
ast_map,
|
||||
Main);
|
||||
// Discover the output
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
// Discover the output
|
||||
exec.discover_output("binary", exe.as_str().unwrap().to_owned(), digest_only_date(&exe));
|
||||
exe.as_str().unwrap().to_owned()
|
||||
}
|
||||
|
||||
/// Run the contents of this package script, where <what>
|
||||
/// is the command to pass to it (e.g., "build", "clean", "install")
|
||||
/// Returns a pair of an exit code and list of configs (obtained by
|
||||
/// calling the package script's configs() function if it exists, or
|
||||
/// None if `exe` could not be started.
|
||||
fn run_custom(exe: &Path, sysroot: &Path) -> Option<(~[~str], process::ProcessExit)> {
|
||||
debug!("Running program: {} {} {}", exe.as_str().unwrap().to_owned(),
|
||||
sysroot.display(), "install");
|
||||
// FIXME #7401 should support commands besides `install`
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let opt_status = run::process_status(exe.as_str().unwrap(),
|
||||
[sysroot.as_str().unwrap().to_owned(), ~"install"]);
|
||||
match opt_status {
|
||||
Some(status) => {
|
||||
if !status.success() {
|
||||
debug!("run_custom: first pkg command failed with {:?}", status);
|
||||
Some((~[], status))
|
||||
}
|
||||
else {
|
||||
debug!("Running program (configs): {} {} {}",
|
||||
exe.display(), sysroot.display(), "configs");
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let opt_output = run::process_output(exe.as_str().unwrap(),
|
||||
[sysroot.as_str().unwrap().to_owned(),
|
||||
~"configs"]);
|
||||
match opt_output {
|
||||
Some(output) => {
|
||||
debug!("run_custom: second pkg command did {:?}", output.status);
|
||||
// Run the configs() function to get the configs
|
||||
let cfgs = str::from_utf8(output.output).unwrap().words()
|
||||
.map(|w| w.to_owned()).collect();
|
||||
Some((cfgs, output.status))
|
||||
},
|
||||
None => {
|
||||
debug!("run_custom: second pkg command failed to start");
|
||||
Some((~[], status))
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
debug!("run_custom: first pkg command failed to start");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait CtxMethods {
|
||||
fn run(&self, cmd: Command, args: ~[~str]);
|
||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str);
|
||||
/// Returns a pair of the selected package ID, and the destination workspace
|
||||
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(CrateId, Path)>;
|
||||
/// Returns the destination workspace
|
||||
fn build(&self, pkg_src: &mut PkgSrc, what: &WhatToBuild);
|
||||
fn clean(&self, workspace: &Path, id: &CrateId);
|
||||
fn info(&self);
|
||||
/// Returns a pair. First component is a list of installed paths,
|
||||
/// second is a list of declared and discovered inputs
|
||||
fn install(&self, src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]);
|
||||
/// Returns a list of installed files
|
||||
fn install_no_build(&self,
|
||||
build_workspace: &Path,
|
||||
build_inputs: &[Path],
|
||||
target_workspace: &Path,
|
||||
id: &CrateId) -> ~[~str];
|
||||
fn prefer(&self, _id: &str, _vers: Option<~str>);
|
||||
fn test(&self, id: &CrateId, workspace: &Path);
|
||||
fn uninstall(&self, _id: &str, _vers: Option<~str>);
|
||||
fn unprefer(&self, _id: &str, _vers: Option<~str>);
|
||||
fn init(&self);
|
||||
}
|
||||
|
||||
impl CtxMethods for BuildContext {
|
||||
fn build_args(&self, args: ~[~str], what: &WhatToBuild) -> Option<(CrateId, Path)> {
|
||||
let cwd = os::getcwd();
|
||||
|
||||
if args.len() < 1 {
|
||||
match cwd_to_workspace() {
|
||||
None if dir_has_crate_file(&cwd) => {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let crateid = from_str(cwd.filename_str().unwrap()).expect("valid crate id");
|
||||
let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, crateid);
|
||||
self.build(&mut pkg_src, what);
|
||||
match pkg_src {
|
||||
PkgSrc { destination_workspace: ws,
|
||||
id: id, .. } => {
|
||||
Some((id, ws))
|
||||
}
|
||||
}
|
||||
}
|
||||
None => { usage::build(); None }
|
||||
Some((ws, crateid)) => {
|
||||
let mut pkg_src = PkgSrc::new(ws.clone(), ws, false, crateid);
|
||||
self.build(&mut pkg_src, what);
|
||||
match pkg_src {
|
||||
PkgSrc { destination_workspace: ws,
|
||||
id: id, .. } => {
|
||||
Some((id, ws))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The package id is presumed to be the first command-line
|
||||
// argument
|
||||
let crateid = from_str(args[0]).expect("valid crate id");
|
||||
let mut dest_ws = default_workspace();
|
||||
each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
|
||||
debug!("found pkg {} in workspace {}, trying to build",
|
||||
crateid.to_str(), workspace.display());
|
||||
dest_ws = determine_destination(os::getcwd(),
|
||||
self.context.use_rust_path_hack,
|
||||
workspace);
|
||||
let mut pkg_src = PkgSrc::new(workspace.clone(), dest_ws.clone(),
|
||||
false, crateid.clone());
|
||||
self.build(&mut pkg_src, what);
|
||||
true
|
||||
});
|
||||
// n.b. If this builds multiple packages, it only returns the workspace for
|
||||
// the last one. The whole building-multiple-packages-with-the-same-ID is weird
|
||||
// anyway and there are no tests for it, so maybe take it out
|
||||
Some((crateid, dest_ws))
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&self, cmd: Command, args: ~[~str]) {
|
||||
let cwd = os::getcwd();
|
||||
match cmd {
|
||||
BuildCmd => {
|
||||
self.build_args(args, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
CleanCmd => {
|
||||
if args.len() < 1 {
|
||||
match cwd_to_workspace() {
|
||||
None => { usage::clean(); return }
|
||||
// tjc: Maybe clean should clean all the packages in the
|
||||
// current workspace, though?
|
||||
Some((ws, crateid)) => self.clean(&ws, &crateid)
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
// The package id is presumed to be the first command-line
|
||||
// argument
|
||||
let crateid = from_str(args[0]).expect("valid crate id");
|
||||
self.clean(&cwd, &crateid); // tjc: should use workspace, not cwd
|
||||
}
|
||||
}
|
||||
DoCmd => {
|
||||
if args.len() < 2 {
|
||||
return usage::do_cmd();
|
||||
}
|
||||
|
||||
self.do_cmd(args[0].clone(), args[1].clone());
|
||||
}
|
||||
HelpCmd => {
|
||||
if args.len() != 1 {
|
||||
return usage::general();
|
||||
}
|
||||
match FromStr::from_str(args[0]) {
|
||||
Some(help_cmd) => usage::usage_for_command(help_cmd),
|
||||
None => {
|
||||
usage::general();
|
||||
error(format!("{} is not a recognized command", args[0]))
|
||||
}
|
||||
}
|
||||
}
|
||||
InfoCmd => {
|
||||
self.info();
|
||||
}
|
||||
InstallCmd => {
|
||||
if args.len() < 1 {
|
||||
match cwd_to_workspace() {
|
||||
None if dir_has_crate_file(&cwd) => {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
|
||||
let inferred_crateid =
|
||||
from_str(cwd.filename_str().unwrap()).expect("valid crate id");
|
||||
self.install(PkgSrc::new(cwd, default_workspace(),
|
||||
true, inferred_crateid),
|
||||
&WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
None => { usage::install(); return; }
|
||||
Some((ws, crateid)) => {
|
||||
let pkg_src = PkgSrc::new(ws.clone(), ws.clone(), false, crateid);
|
||||
self.install(pkg_src, &WhatToBuild::new(MaybeCustom,
|
||||
Everything));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The package id is presumed to be the first command-line
|
||||
// argument
|
||||
let crateid = from_str(args[0]).expect("valid crate id");
|
||||
let workspaces = pkg_parent_workspaces(&self.context, &crateid);
|
||||
debug!("package ID = {}, found it in {:?} workspaces",
|
||||
crateid.to_str(), workspaces.len());
|
||||
if workspaces.is_empty() {
|
||||
let d = default_workspace();
|
||||
let src = PkgSrc::new(d.clone(), d, false, crateid.clone());
|
||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
}
|
||||
else {
|
||||
for workspace in workspaces.iter() {
|
||||
let dest = determine_destination(os::getcwd(),
|
||||
self.context.use_rust_path_hack,
|
||||
workspace);
|
||||
let src = PkgSrc::new(workspace.clone(),
|
||||
dest,
|
||||
self.context.use_rust_path_hack,
|
||||
crateid.clone());
|
||||
self.install(src, &WhatToBuild::new(MaybeCustom, Everything));
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
ListCmd => {
|
||||
println!("Installed packages:");
|
||||
installed_packages::list_installed_packages(|pkg_id| {
|
||||
println!("{}", pkg_id.path);
|
||||
true
|
||||
});
|
||||
}
|
||||
PreferCmd => {
|
||||
if args.len() < 1 {
|
||||
return usage::prefer();
|
||||
}
|
||||
|
||||
self.prefer(args[0], None);
|
||||
}
|
||||
TestCmd => {
|
||||
// Build the test executable
|
||||
let maybe_id_and_workspace = self.build_args(args,
|
||||
&WhatToBuild::new(MaybeCustom, Tests));
|
||||
match maybe_id_and_workspace {
|
||||
Some((pkg_id, workspace)) => {
|
||||
// Assuming it's built, run the tests
|
||||
self.test(&pkg_id, &workspace);
|
||||
}
|
||||
None => {
|
||||
error("Testing failed because building the specified package failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
InitCmd => {
|
||||
if args.len() != 0 {
|
||||
return usage::init();
|
||||
} else {
|
||||
self.init();
|
||||
}
|
||||
}
|
||||
UninstallCmd => {
|
||||
if args.len() < 1 {
|
||||
return usage::uninstall();
|
||||
}
|
||||
|
||||
let crateid = from_str(args[0]).expect("valid crate id");
|
||||
if !installed_packages::package_is_installed(&crateid) {
|
||||
warn(format!("Package {} doesn't seem to be installed! \
|
||||
Doing nothing.", args[0]));
|
||||
return;
|
||||
}
|
||||
else {
|
||||
let rp = rust_path();
|
||||
assert!(!rp.is_empty());
|
||||
each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
|
||||
path_util::uninstall_package_from(workspace, &crateid);
|
||||
note(format!("Uninstalled package {} (was installed in {})",
|
||||
crateid.to_str(), workspace.display()));
|
||||
true
|
||||
});
|
||||
}
|
||||
}
|
||||
UnpreferCmd => {
|
||||
if args.len() < 1 {
|
||||
return usage::unprefer();
|
||||
}
|
||||
|
||||
self.unprefer(args[0], None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn do_cmd(&self, _cmd: &str, _pkgname: &str) {
|
||||
// stub
|
||||
fail!("`do` not yet implemented");
|
||||
}
|
||||
|
||||
fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) {
|
||||
use conditions::git_checkout_failed::cond;
|
||||
|
||||
let workspace = pkg_src.source_workspace.clone();
|
||||
let crateid = pkg_src.id.clone();
|
||||
|
||||
let path = crateid.path.as_slice();
|
||||
debug!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
|
||||
crateid = {} pkgsrc start_dir = {}", workspace.display(),
|
||||
in_rust_path(&workspace), is_git_dir(&workspace.join(path)),
|
||||
crateid.to_str(), pkg_src.start_dir.display());
|
||||
debug!("build: what to build = {:?}", what_to_build);
|
||||
|
||||
// If workspace isn't in the RUST_PATH, and it's a git repo,
|
||||
// then clone it into the first entry in RUST_PATH, and repeat
|
||||
if !in_rust_path(&workspace) && is_git_dir(&workspace.join(path)) {
|
||||
let mut out_dir = default_workspace().join("src");
|
||||
out_dir.push(path);
|
||||
let git_result = source_control::safe_git_clone(&workspace.join(path),
|
||||
&crateid.version,
|
||||
&out_dir);
|
||||
match git_result {
|
||||
CheckedOutSources => make_read_only(&out_dir),
|
||||
_ => cond.raise((path.to_owned(), out_dir.clone()))
|
||||
};
|
||||
let default_ws = default_workspace();
|
||||
debug!("Calling build recursively with {:?} and {:?}", default_ws.display(),
|
||||
crateid.to_str());
|
||||
return self.build(&mut PkgSrc::new(default_ws.clone(),
|
||||
default_ws,
|
||||
false,
|
||||
crateid.clone()), what_to_build);
|
||||
}
|
||||
|
||||
// Is there custom build logic? If so, use it
|
||||
let mut custom = false;
|
||||
debug!("Package source directory = {}", pkg_src.to_str());
|
||||
let opt = pkg_src.package_script_option();
|
||||
debug!("Calling pkg_script_option on {:?}", opt);
|
||||
let cfgs = match (pkg_src.package_script_option(), what_to_build.build_type) {
|
||||
(Some(package_script_path), MaybeCustom) => {
|
||||
let sysroot = self.sysroot_to_use();
|
||||
// Build the package script if needed
|
||||
let script_build = format!("build_package_script({})",
|
||||
package_script_path.display());
|
||||
let pkg_exe = self.workcache_context.with_prep(script_build, |prep| {
|
||||
let subsysroot = sysroot.clone();
|
||||
let psp = package_script_path.clone();
|
||||
let ws = workspace.clone();
|
||||
let pid = crateid.clone();
|
||||
prep.exec(proc(exec) {
|
||||
let mut pscript = PkgScript::parse(subsysroot.clone(),
|
||||
psp.clone(),
|
||||
&ws,
|
||||
&pid);
|
||||
pscript.build_custom(exec)
|
||||
})
|
||||
});
|
||||
// We always *run* the package script
|
||||
match PkgScript::run_custom(&Path::new(pkg_exe), &sysroot) {
|
||||
Some((cfgs, hook_result)) => {
|
||||
debug!("Command return code = {:?}", hook_result);
|
||||
if !hook_result.success() {
|
||||
fail!("Error running custom build command")
|
||||
}
|
||||
custom = true;
|
||||
// otherwise, the package script succeeded
|
||||
cfgs
|
||||
},
|
||||
None => {
|
||||
fail!("Error starting custom build command")
|
||||
}
|
||||
}
|
||||
}
|
||||
(Some(_), Inferred) => {
|
||||
debug!("There is a package script, but we're ignoring it");
|
||||
~[]
|
||||
}
|
||||
(None, _) => {
|
||||
debug!("No package script, continuing");
|
||||
~[]
|
||||
}
|
||||
} + self.context.cfgs;
|
||||
|
||||
// If there was a package script, it should have finished
|
||||
// the build already. Otherwise...
|
||||
if !custom {
|
||||
match what_to_build.sources {
|
||||
// Find crates inside the workspace
|
||||
Everything => pkg_src.find_crates(),
|
||||
// Find only tests
|
||||
Tests => pkg_src.find_crates_with_filter(|s| { is_test(&Path::new(s)) }),
|
||||
// Don't infer any crates -- just build the one that was requested
|
||||
JustOne(ref p) => {
|
||||
// We expect that p is relative to the package source's start directory,
|
||||
// so check that assumption
|
||||
debug!("JustOne: p = {}", p.display());
|
||||
assert!(pkg_src.start_dir.join(p).exists());
|
||||
if is_lib(p) {
|
||||
PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
|
||||
} else if is_main(p) {
|
||||
PkgSrc::push_crate(&mut pkg_src.mains, 0, p);
|
||||
} else if is_test(p) {
|
||||
PkgSrc::push_crate(&mut pkg_src.tests, 0, p);
|
||||
} else if is_bench(p) {
|
||||
PkgSrc::push_crate(&mut pkg_src.benchs, 0, p);
|
||||
} else {
|
||||
warn(format!("Not building any crates for dependency {}", p.display()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Build it!
|
||||
pkg_src.build(self, cfgs, []);
|
||||
}
|
||||
}
|
||||
|
||||
fn clean(&self, workspace: &Path, id: &CrateId) {
|
||||
// Could also support a custom build hook in the pkg
|
||||
// script for cleaning files rustpkg doesn't know about.
|
||||
// Do something reasonable for now
|
||||
|
||||
let dir = build_pkg_id_in_workspace(id, workspace);
|
||||
note(format!("Cleaning package {} (removing directory {})",
|
||||
id.to_str(), dir.display()));
|
||||
if dir.exists() {
|
||||
fs::rmdir_recursive(&dir);
|
||||
note(format!("Removed directory {}", dir.display()));
|
||||
}
|
||||
|
||||
note(format!("Cleaned package {}", id.to_str()));
|
||||
}
|
||||
|
||||
fn info(&self) {
|
||||
// stub
|
||||
fail!("info not yet implemented");
|
||||
}
|
||||
|
||||
fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str, ~str)]) {
|
||||
|
||||
let id = pkg_src.id.clone();
|
||||
|
||||
let mut installed_files = ~[];
|
||||
let mut inputs = ~[];
|
||||
let mut build_inputs = ~[];
|
||||
|
||||
debug!("Installing package source: {}", pkg_src.to_str());
|
||||
|
||||
// workcache only knows about *crates*. Building a package
|
||||
// just means inferring all the crates in it, then building each one.
|
||||
self.build(&mut pkg_src, what);
|
||||
|
||||
debug!("Done building package source {}", pkg_src.to_str());
|
||||
|
||||
let to_do = ~[pkg_src.libs.clone(), pkg_src.mains.clone(),
|
||||
pkg_src.tests.clone(), pkg_src.benchs.clone()];
|
||||
debug!("In declare inputs for {}", id.to_str());
|
||||
for cs in to_do.iter() {
|
||||
for c in cs.iter() {
|
||||
let path = pkg_src.start_dir.join(&c.file);
|
||||
debug!("Recording input: {}", path.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
inputs.push((~"file", path.as_str().unwrap().to_owned()));
|
||||
build_inputs.push(path);
|
||||
}
|
||||
}
|
||||
|
||||
let result = self.install_no_build(pkg_src.build_workspace(),
|
||||
build_inputs,
|
||||
&pkg_src.destination_workspace,
|
||||
&id).map(|s| Path::new(s.as_slice()));
|
||||
installed_files = installed_files + result;
|
||||
note(format!("Installed package {} to {}",
|
||||
id.to_str(),
|
||||
pkg_src.destination_workspace.display()));
|
||||
(installed_files, inputs)
|
||||
}
|
||||
|
||||
// again, working around lack of Encodable for Path
|
||||
fn install_no_build(&self,
|
||||
build_workspace: &Path,
|
||||
build_inputs: &[Path],
|
||||
target_workspace: &Path,
|
||||
id: &CrateId) -> ~[~str] {
|
||||
|
||||
debug!("install_no_build: assuming {} comes from {} with target {}",
|
||||
id.to_str(), build_workspace.display(), target_workspace.display());
|
||||
|
||||
// Now copy stuff into the install dirs
|
||||
let maybe_executable = built_executable_in_workspace(id, build_workspace);
|
||||
let maybe_library = built_library_in_workspace(id, build_workspace);
|
||||
let target_exec = target_executable_in_workspace(id, target_workspace);
|
||||
let target_lib = maybe_library.as_ref()
|
||||
.map(|_| target_library_in_workspace(id, target_workspace));
|
||||
|
||||
debug!("target_exec = {} target_lib = {:?} \
|
||||
maybe_executable = {:?} maybe_library = {:?}",
|
||||
target_exec.display(), target_lib,
|
||||
maybe_executable, maybe_library);
|
||||
|
||||
let install_tag = format!("install({}-{})", id.path, id.version_or_default());
|
||||
self.workcache_context.with_prep(install_tag, |prep| {
|
||||
for ee in maybe_executable.iter() {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prep.declare_input("binary",
|
||||
ee.as_str().unwrap(),
|
||||
workcache_support::digest_only_date(ee));
|
||||
}
|
||||
for ll in maybe_library.iter() {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prep.declare_input("binary",
|
||||
ll.as_str().unwrap(),
|
||||
workcache_support::digest_only_date(ll));
|
||||
}
|
||||
let subex = maybe_executable.clone();
|
||||
let sublib = maybe_library.clone();
|
||||
let sub_target_ex = target_exec.clone();
|
||||
let sub_target_lib = target_lib.clone();
|
||||
let sub_build_inputs = build_inputs.to_owned();
|
||||
prep.exec(proc(exe_thing) {
|
||||
let mut outputs = ~[];
|
||||
// Declare all the *inputs* to the declared input too, as inputs
|
||||
for executable in subex.iter() {
|
||||
exe_thing.discover_input("binary",
|
||||
executable.as_str().unwrap().to_owned(),
|
||||
workcache_support::digest_only_date(executable));
|
||||
}
|
||||
for library in sublib.iter() {
|
||||
exe_thing.discover_input("binary",
|
||||
library.as_str().unwrap().to_owned(),
|
||||
workcache_support::digest_only_date(library));
|
||||
}
|
||||
|
||||
for transitive_dependency in sub_build_inputs.iter() {
|
||||
exe_thing.discover_input(
|
||||
"file",
|
||||
transitive_dependency.as_str().unwrap().to_owned(),
|
||||
workcache_support::digest_file_with_date(transitive_dependency));
|
||||
}
|
||||
|
||||
|
||||
for exec in subex.iter() {
|
||||
debug!("Copying: {} -> {}", exec.display(), sub_target_ex.display());
|
||||
fs::mkdir_recursive(&sub_target_ex.dir_path(), io::UserRWX);
|
||||
fs::copy(exec, &sub_target_ex);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
exe_thing.discover_output("binary",
|
||||
sub_target_ex.as_str().unwrap(),
|
||||
workcache_support::digest_only_date(&sub_target_ex));
|
||||
outputs.push(sub_target_ex.as_str().unwrap().to_owned());
|
||||
}
|
||||
for lib in sublib.iter() {
|
||||
let mut target_lib = sub_target_lib
|
||||
.clone().expect(format!("I built {} but apparently \
|
||||
didn't install it!", lib.display()));
|
||||
target_lib.set_filename(lib.filename().expect("weird target lib"));
|
||||
fs::mkdir_recursive(&target_lib.dir_path(), io::UserRWX);
|
||||
fs::copy(lib, &target_lib);
|
||||
debug!("3. discovering output {}", target_lib.display());
|
||||
exe_thing.discover_output("binary",
|
||||
target_lib.as_str().unwrap(),
|
||||
workcache_support::digest_only_date(&target_lib));
|
||||
outputs.push(target_lib.as_str().unwrap().to_owned());
|
||||
}
|
||||
outputs
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn prefer(&self, _id: &str, _vers: Option<~str>) {
|
||||
fail!("prefer not yet implemented");
|
||||
}
|
||||
|
||||
fn test(&self, crateid: &CrateId, workspace: &Path) {
|
||||
match built_test_in_workspace(crateid, workspace) {
|
||||
Some(test_exec) => {
|
||||
debug!("test: test_exec = {}", test_exec.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let opt_status = run::process_status(test_exec.as_str().unwrap(), [~"--test"]);
|
||||
match opt_status {
|
||||
Some(status) => {
|
||||
if !status.success() {
|
||||
fail!("Some tests failed");
|
||||
}
|
||||
},
|
||||
None => fail!("Could not exec `{}`", test_exec.display())
|
||||
}
|
||||
}
|
||||
None => {
|
||||
error(format!("Internal error: test executable for package ID {} in workspace {} \
|
||||
wasn't built! Please report this as a bug.",
|
||||
crateid.to_str(), workspace.display()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(&self) {
|
||||
fs::mkdir_recursive(&Path::new("src"), io::UserRWX);
|
||||
fs::mkdir_recursive(&Path::new("bin"), io::UserRWX);
|
||||
fs::mkdir_recursive(&Path::new("lib"), io::UserRWX);
|
||||
fs::mkdir_recursive(&Path::new("build"), io::UserRWX);
|
||||
}
|
||||
|
||||
fn uninstall(&self, _id: &str, _vers: Option<~str>) {
|
||||
fail!("uninstall not yet implemented");
|
||||
}
|
||||
|
||||
fn unprefer(&self, _id: &str, _vers: Option<~str>) {
|
||||
fail!("unprefer not yet implemented");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
println!("WARNING: The Rust package manager is experimental and may be unstable");
|
||||
os::set_exit_status(main_args(os::args()));
|
||||
}
|
||||
|
||||
pub fn main_args(args: &[~str]) -> int {
|
||||
|
||||
let (command, args, context, supplied_sysroot) = match parse_args(args) {
|
||||
Ok(ParseResult {
|
||||
command: cmd,
|
||||
args: args,
|
||||
context: ctx,
|
||||
sysroot: sroot}) => (cmd, args, ctx, sroot),
|
||||
Err(error_code) => {
|
||||
debug!("Parsing failed. Returning error code {}", error_code);
|
||||
return error_code
|
||||
}
|
||||
};
|
||||
debug!("Finished parsing commandline args {:?}", args);
|
||||
debug!(" Using command: {:?}", command);
|
||||
debug!(" Using args {:?}", args);
|
||||
debug!(" Using cflags: {:?}", context.rustc_flags);
|
||||
debug!(" Using rust_path_hack {:b}", context.use_rust_path_hack);
|
||||
debug!(" Using cfgs: {:?}", context.cfgs);
|
||||
debug!(" Using supplied_sysroot: {:?}", supplied_sysroot);
|
||||
|
||||
let sysroot = match supplied_sysroot {
|
||||
Some(s) => Path::new(s),
|
||||
_ => filesearch::get_or_default_sysroot()
|
||||
};
|
||||
|
||||
debug!("Using sysroot: {}", sysroot.display());
|
||||
let ws = default_workspace();
|
||||
debug!("Will store workcache in {}", ws.display());
|
||||
|
||||
// Wrap the rest in task::try in case of a condition failure in a task
|
||||
let result = task::try(proc() {
|
||||
BuildContext {
|
||||
context: context,
|
||||
sysroot: sysroot.clone(), // Currently, only tests override this
|
||||
workcache_context: api::default_context(sysroot.clone(),
|
||||
default_workspace()).workcache_context
|
||||
}.run(command, args.clone())
|
||||
});
|
||||
// FIXME #9262: This is using the same error code for all errors,
|
||||
// and at least one test case succeeds if rustpkg returns COPY_FAILED_CODE,
|
||||
// when actually, it might set the exit code for that even if a different
|
||||
// unhandled condition got raised.
|
||||
if result.is_err() { return COPY_FAILED_CODE; }
|
||||
return 0;
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use extra::term;
|
||||
use std::io;
|
||||
|
||||
pub fn note(msg: &str) {
|
||||
pretty_message(msg, "note: ", term::color::GREEN);
|
||||
}
|
||||
|
||||
pub fn warn(msg: &str) {
|
||||
pretty_message(msg, "warning: ", term::color::YELLOW);
|
||||
}
|
||||
|
||||
pub fn error(msg: &str) {
|
||||
pretty_message(msg, "error: ", term::color::RED);
|
||||
}
|
||||
|
||||
fn pretty_message<'a>(msg: &'a str,
|
||||
prefix: &'a str,
|
||||
color: term::color::Color) {
|
||||
let mut term = term::Terminal::new(io::stdout());
|
||||
let mut stdout = io::stdout();
|
||||
match term {
|
||||
Ok(ref mut t) => {
|
||||
t.fg(color);
|
||||
t.write(prefix.as_bytes());
|
||||
t.reset();
|
||||
},
|
||||
_ => {
|
||||
stdout.write(prefix.as_bytes());
|
||||
}
|
||||
}
|
||||
stdout.write(msg.as_bytes());
|
||||
stdout.write(['\n' as u8]);
|
||||
}
|
|
@ -1,554 +0,0 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod extra;
|
||||
|
||||
use target::*;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use std::os;
|
||||
use context::*;
|
||||
use crate::Crate;
|
||||
use messages::*;
|
||||
use source_control::{safe_git_clone, git_clone_url, DirToUse, CheckedOutSources};
|
||||
use source_control::make_read_only;
|
||||
use path_util::{find_dir_using_rust_path_hack, make_dir_rwx_recursive, default_workspace};
|
||||
use path_util::{target_build_dir, versionize, dir_has_crate_file};
|
||||
use util::{compile_crate, DepMap};
|
||||
use workcache_support;
|
||||
use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
|
||||
use extra::workcache;
|
||||
use extra::treemap::TreeMap;
|
||||
use syntax::crateid::CrateId;
|
||||
use rustc::driver::session;
|
||||
|
||||
// An enumeration of the unpacked source of a package workspace.
|
||||
// This contains a list of files found in the source workspace.
|
||||
#[deriving(Clone)]
|
||||
pub struct PkgSrc {
|
||||
/// Root of where the package source code lives
|
||||
source_workspace: Path,
|
||||
/// If build_in_destination is true, temporary results should
|
||||
/// go in the build/ subdirectory of the destination workspace.
|
||||
/// (Otherwise, they go in the build/ subdirectory of the
|
||||
/// source workspace.) This happens if the "RUST_PATH hack" is
|
||||
/// in effect, or if sources were fetched from a remote
|
||||
/// repository.
|
||||
build_in_destination: bool,
|
||||
/// Where to install the results. May or may not be the same
|
||||
/// as source_workspace
|
||||
destination_workspace: Path,
|
||||
// Directory to start looking in for packages -- normally
|
||||
// this is workspace/src/id but it may be just workspace
|
||||
start_dir: Path,
|
||||
id: CrateId,
|
||||
libs: ~[Crate],
|
||||
mains: ~[Crate],
|
||||
tests: ~[Crate],
|
||||
benchs: ~[Crate],
|
||||
}
|
||||
|
||||
pub enum BuildSort { InPlace, Discovered }
|
||||
|
||||
impl ToStr for PkgSrc {
|
||||
fn to_str(&self) -> ~str {
|
||||
format!("Package ID {} in start dir {} [workspaces = {} -> {}]",
|
||||
self.id.to_str(),
|
||||
self.start_dir.display(),
|
||||
self.source_workspace.display(),
|
||||
self.destination_workspace.display())
|
||||
}
|
||||
}
|
||||
condition! {
|
||||
build_err: (~str) -> ~str;
|
||||
}
|
||||
|
||||
fn prefixes(p: &Path) -> Prefixes {
|
||||
Prefixes {
|
||||
components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
|
||||
remaining: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
struct Prefixes {
|
||||
components: ~[~str],
|
||||
remaining: ~[~str]
|
||||
}
|
||||
|
||||
impl Iterator<(Path, Path)> for Prefixes {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<(Path, Path)> {
|
||||
if self.components.len() <= 1 {
|
||||
None
|
||||
}
|
||||
else {
|
||||
let last = self.components.pop().unwrap();
|
||||
self.remaining.unshift(last);
|
||||
// converting to str and then back is a little unfortunate
|
||||
Some((Path::new(self.components.connect("/")),
|
||||
Path::new(self.remaining.connect("/"))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PkgSrc {
|
||||
pub fn new(mut source_workspace: Path,
|
||||
destination_workspace: Path,
|
||||
use_rust_path_hack: bool,
|
||||
id: CrateId) -> PkgSrc {
|
||||
use conditions::nonexistent_package::cond;
|
||||
|
||||
debug!("Checking package source for package ID {}, \
|
||||
workspace = {} -> {}, use_rust_path_hack = {:?}",
|
||||
id.to_str(),
|
||||
source_workspace.display(),
|
||||
destination_workspace.display(),
|
||||
use_rust_path_hack);
|
||||
|
||||
let mut destination_workspace = destination_workspace.clone();
|
||||
|
||||
let mut to_try = ~[];
|
||||
let mut output_names = ~[];
|
||||
let build_dir = target_build_dir(&source_workspace);
|
||||
|
||||
if use_rust_path_hack {
|
||||
to_try.push(source_workspace.clone());
|
||||
} else {
|
||||
// We search for sources under both src/ and build/ , because build/ is where
|
||||
// automatically-checked-out sources go.
|
||||
let path = Path::new(id.path.as_slice());
|
||||
let mut result = source_workspace.join("src");
|
||||
result.push(&path.dir_path());
|
||||
result.push(id.short_name_with_version());
|
||||
to_try.push(result);
|
||||
let mut result = source_workspace.join("src");
|
||||
result.push(&path);
|
||||
to_try.push(result);
|
||||
|
||||
let mut result = build_dir.join("src");
|
||||
result.push(&path.dir_path());
|
||||
result.push(id.short_name_with_version());
|
||||
to_try.push(result.clone());
|
||||
output_names.push(result);
|
||||
let mut other_result = build_dir.join("src");
|
||||
other_result.push(&path);
|
||||
to_try.push(other_result.clone());
|
||||
output_names.push(other_result);
|
||||
|
||||
}
|
||||
|
||||
debug!("Checking dirs: {:?}", to_try.map(|p| p.display().to_str()).connect(":"));
|
||||
|
||||
let path = to_try.iter().find(|&d| d.is_dir()
|
||||
&& dir_has_crate_file(d));
|
||||
|
||||
// See the comments on the definition of PkgSrc
|
||||
let mut build_in_destination = use_rust_path_hack;
|
||||
debug!("1. build_in_destination = {:?}", build_in_destination);
|
||||
|
||||
let dir: Path = match path {
|
||||
Some(d) => (*d).clone(),
|
||||
None => {
|
||||
// See if any of the prefixes of this package ID form a valid package ID
|
||||
// That is, is this a package ID that points into the middle of a workspace?
|
||||
for (prefix, suffix) in prefixes(&Path::new(id.path.as_slice())) {
|
||||
let crate_id: Option<CrateId> = from_str(prefix.as_str().unwrap());
|
||||
let crate_id = crate_id.expect("valid crate id");
|
||||
let path = build_dir.join(crate_id.path.as_slice());
|
||||
debug!("in loop: checking if {} is a directory", path.display());
|
||||
if path.is_dir() {
|
||||
let ps = PkgSrc::new(source_workspace,
|
||||
destination_workspace,
|
||||
use_rust_path_hack,
|
||||
crate_id);
|
||||
match ps {
|
||||
PkgSrc {
|
||||
source_workspace: source,
|
||||
destination_workspace: destination,
|
||||
start_dir: start,
|
||||
id: id, .. } => {
|
||||
let result = PkgSrc {
|
||||
source_workspace: source.clone(),
|
||||
build_in_destination: build_in_destination,
|
||||
destination_workspace: destination,
|
||||
start_dir: start.join(&suffix),
|
||||
id: id,
|
||||
libs: ~[],
|
||||
mains: ~[],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
};
|
||||
debug!("pkgsrc: Returning {}", result.to_str());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Ok, no prefixes work, so try fetching from git
|
||||
let mut ok_d = None;
|
||||
for w in output_names.iter() {
|
||||
debug!("Calling fetch_git on {}", w.display());
|
||||
let target_dir_opt = PkgSrc::fetch_git(w, &id);
|
||||
for p in target_dir_opt.iter() {
|
||||
ok_d = Some(p.clone());
|
||||
build_in_destination = true;
|
||||
debug!("2. build_in_destination = {:?}", build_in_destination);
|
||||
break;
|
||||
}
|
||||
match ok_d {
|
||||
Some(ref d) => {
|
||||
let path = Path::new(id.path.as_slice());
|
||||
if d.is_ancestor_of(&path)
|
||||
|| d.is_ancestor_of(&versionize(id.path, &id.version)) {
|
||||
// Strip off the package ID
|
||||
source_workspace = d.clone();
|
||||
for _ in path.components() {
|
||||
source_workspace.pop();
|
||||
}
|
||||
// Strip off the src/ part
|
||||
source_workspace.pop();
|
||||
// Strip off the build/<target-triple> part to get the workspace
|
||||
destination_workspace = source_workspace.clone();
|
||||
destination_workspace.pop();
|
||||
destination_workspace.pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
match ok_d {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
// See if the sources are in $CWD
|
||||
let cwd = os::getcwd();
|
||||
if dir_has_crate_file(&cwd) {
|
||||
return PkgSrc {
|
||||
// In this case, source_workspace isn't really a workspace.
|
||||
// This data structure needs yet more refactoring.
|
||||
source_workspace: cwd.clone(),
|
||||
destination_workspace: default_workspace(),
|
||||
build_in_destination: true,
|
||||
start_dir: cwd,
|
||||
id: id,
|
||||
libs: ~[],
|
||||
mains: ~[],
|
||||
benchs: ~[],
|
||||
tests: ~[]
|
||||
}
|
||||
} else if use_rust_path_hack {
|
||||
match find_dir_using_rust_path_hack(&id) {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
cond.raise((id.clone(),
|
||||
~"supplied path for package dir does not \
|
||||
exist, and couldn't interpret it as a URL fragment"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cond.raise((id.clone(),
|
||||
~"supplied path for package dir does not \
|
||||
exist, and couldn't interpret it as a URL fragment"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
debug!("3. build_in_destination = {:?}", build_in_destination);
|
||||
debug!("source: {} dest: {}", source_workspace.display(), destination_workspace.display());
|
||||
|
||||
debug!("For package id {}, returning {}", id.to_str(), dir.display());
|
||||
|
||||
if !dir.is_dir() {
|
||||
cond.raise((id.clone(), ~"supplied path for package dir is a \
|
||||
non-directory"));
|
||||
}
|
||||
|
||||
PkgSrc {
|
||||
source_workspace: source_workspace.clone(),
|
||||
build_in_destination: build_in_destination,
|
||||
destination_workspace: destination_workspace,
|
||||
start_dir: dir,
|
||||
id: id,
|
||||
libs: ~[],
|
||||
mains: ~[],
|
||||
tests: ~[],
|
||||
benchs: ~[]
|
||||
}
|
||||
}
|
||||
|
||||
/// Try interpreting self's package id as a git repository, and try
|
||||
/// fetching it and caching it in a local directory. Return the cached directory
|
||||
/// if this was successful, None otherwise. Similarly, if the package id
|
||||
/// refers to a git repo on the local version, also check it out.
|
||||
/// (right now we only support git)
|
||||
pub fn fetch_git(local: &Path, crateid: &CrateId) -> Option<Path> {
|
||||
use conditions::git_checkout_failed::cond;
|
||||
|
||||
let cwd = os::getcwd();
|
||||
let path = Path::new(crateid.path.as_slice());
|
||||
debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}",
|
||||
crateid.to_str(), crateid.path,
|
||||
cwd.display(),
|
||||
path.exists());
|
||||
|
||||
match safe_git_clone(&path, &crateid.version, local) {
|
||||
CheckedOutSources => {
|
||||
make_read_only(local);
|
||||
Some(local.clone())
|
||||
}
|
||||
DirToUse(clone_target) => {
|
||||
if path.components().nth(1).is_none() {
|
||||
// If a non-URL, don't bother trying to fetch
|
||||
return None;
|
||||
}
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let url = format!("https://{}", path.as_str().unwrap());
|
||||
debug!("Fetching package: git clone {} {} [version={}]",
|
||||
url, clone_target.display(), crateid.version_or_default());
|
||||
|
||||
let mut failed = false;
|
||||
|
||||
cond.trap(|_| {
|
||||
failed = true;
|
||||
}).inside(|| git_clone_url(url, &clone_target, &crateid.version));
|
||||
|
||||
if failed {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Move clone_target to local.
|
||||
// First, create all ancestor directories.
|
||||
let moved = make_dir_rwx_recursive(&local.dir_path())
|
||||
&& io::result(|| fs::rename(&clone_target, local)).is_ok();
|
||||
if moved { Some(local.clone()) }
|
||||
else { None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a file named "pkg.rs" in the start directory exists,
|
||||
// return the path for it. Otherwise, None
|
||||
pub fn package_script_option(&self) -> Option<Path> {
|
||||
let maybe_path = self.start_dir.join("pkg.rs");
|
||||
debug!("package_script_option: checking whether {} exists", maybe_path.display());
|
||||
if maybe_path.exists() {
|
||||
Some(maybe_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) {
|
||||
let mut it = p.components().peekable();
|
||||
if prefix > 0 {
|
||||
it.nth(prefix-1); // skip elements
|
||||
}
|
||||
assert!(it.peek().is_some());
|
||||
let mut sub = Path::new(".");
|
||||
for c in it {
|
||||
sub.push(c);
|
||||
}
|
||||
debug!("Will compile crate {}", sub.display());
|
||||
cs.push(Crate::new(&sub));
|
||||
}
|
||||
|
||||
/// Infers crates to build. Called only in the case where there
|
||||
/// is no custom build logic
|
||||
pub fn find_crates(&mut self) {
|
||||
self.find_crates_with_filter(|_| true);
|
||||
}
|
||||
|
||||
pub fn find_crates_with_filter(&mut self, filter: |&str| -> bool) {
|
||||
use conditions::missing_pkg_files::cond;
|
||||
|
||||
let prefix = self.start_dir.components().len();
|
||||
debug!("Matching against {}", self.id.name);
|
||||
for pth in fs::walk_dir(&self.start_dir) {
|
||||
let maybe_known_crate_set = match pth.filename_str() {
|
||||
Some(filename) if filter(filename) => match filename {
|
||||
"lib.rs" => Some(&mut self.libs),
|
||||
"main.rs" => Some(&mut self.mains),
|
||||
"test.rs" => Some(&mut self.tests),
|
||||
"bench.rs" => Some(&mut self.benchs),
|
||||
_ => None
|
||||
},
|
||||
_ => None
|
||||
};
|
||||
|
||||
match maybe_known_crate_set {
|
||||
Some(crate_set) => PkgSrc::push_crate(crate_set, prefix, &pth),
|
||||
None => ()
|
||||
}
|
||||
}
|
||||
|
||||
let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
|
||||
if crate_sets.iter().all(|crate_set| crate_set.is_empty()) {
|
||||
|
||||
note("Couldn't infer any crates to build.\n\
|
||||
Try naming a crate `main.rs`, `lib.rs`, \
|
||||
`test.rs`, or `bench.rs`.");
|
||||
cond.raise(self.id.clone());
|
||||
}
|
||||
|
||||
debug!("In {}, found {} libs, {} mains, {} tests, {} benchs",
|
||||
self.start_dir.display(),
|
||||
self.libs.len(),
|
||||
self.mains.len(),
|
||||
self.tests.len(),
|
||||
self.benchs.len())
|
||||
}
|
||||
|
||||
fn build_crates(&self,
|
||||
ctx: &BuildContext,
|
||||
deps: &mut DepMap,
|
||||
crates: &[Crate],
|
||||
cfgs: &[~str],
|
||||
what: OutputType,
|
||||
inputs_to_discover: &[(~str, Path)]) {
|
||||
for crate in crates.iter() {
|
||||
let path = self.start_dir.join(&crate.file);
|
||||
debug!("build_crates: compiling {}", path.display());
|
||||
let cfgs = crate.cfgs + cfgs;
|
||||
|
||||
ctx.workcache_context.with_prep(crate_tag(&path), |prep| {
|
||||
debug!("Building crate {}, declaring it as an input", path.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prep.declare_input("file", path.as_str().unwrap(),
|
||||
workcache_support::digest_file_with_date(&path));
|
||||
let subpath = path.clone();
|
||||
let subcfgs = cfgs.clone();
|
||||
let subcx = ctx.clone();
|
||||
let id = self.id.clone();
|
||||
let sub_dir = self.build_workspace().clone();
|
||||
let sub_flags = crate.flags.clone();
|
||||
let sub_deps = deps.clone();
|
||||
let inputs = inputs_to_discover.map(|&(ref k, ref p)|
|
||||
(k.clone(), p.as_str().unwrap().to_owned()));
|
||||
prep.exec(proc(exec) {
|
||||
for &(ref kind, ref p) in inputs.iter() {
|
||||
let pth = Path::new(p.clone());
|
||||
exec.discover_input(*kind, *p, if *kind == ~"file" {
|
||||
digest_file_with_date(&pth)
|
||||
} else if *kind == ~"binary" {
|
||||
digest_only_date(&Path::new(p.clone()))
|
||||
} else {
|
||||
fail!("Bad kind in build_crates")
|
||||
});
|
||||
}
|
||||
debug!("Compiling crate {}; its output will be in {}",
|
||||
subpath.display(), sub_dir.display());
|
||||
let opt: session::OptLevel = subcx.context.rustc_flags.optimization_level;
|
||||
let result = compile_crate(&subcx,
|
||||
exec,
|
||||
&id,
|
||||
&subpath,
|
||||
&sub_dir,
|
||||
&mut (sub_deps.clone()),
|
||||
sub_flags,
|
||||
subcfgs,
|
||||
opt,
|
||||
what);
|
||||
// FIXME: result is an Option<Path>. The following code did not take that
|
||||
// into account. I'm not sure if the workcache really likes seeing the
|
||||
// output as "Some(\"path\")". But I don't know what to do about it.
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let result = result.as_ref().map(|p|p.as_str().unwrap());
|
||||
debug!("Result of compiling {} was {}", subpath.display(), result.to_str());
|
||||
result.to_str()
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare all the crate files in the package source as inputs
|
||||
/// (to the package)
|
||||
pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
|
||||
let to_do = ~[self.libs.clone(), self.mains.clone(),
|
||||
self.tests.clone(), self.benchs.clone()];
|
||||
debug!("In declare inputs, self = {}", self.to_str());
|
||||
for cs in to_do.iter() {
|
||||
for c in cs.iter() {
|
||||
let path = self.start_dir.join(&c.file);
|
||||
debug!("Declaring input: {}", path.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prep.declare_input("file", path.as_str().unwrap(),
|
||||
workcache_support::digest_file_with_date(&path.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build(&self,
|
||||
build_context: &BuildContext,
|
||||
// DepMap is a map from str (crate name) to (kind, name) --
|
||||
// it tracks discovered dependencies per-crate
|
||||
cfgs: ~[~str],
|
||||
inputs_to_discover: &[(~str, Path)]) -> DepMap {
|
||||
let mut deps = TreeMap::new();
|
||||
let libs = self.libs.clone();
|
||||
let mains = self.mains.clone();
|
||||
let tests = self.tests.clone();
|
||||
let benchs = self.benchs.clone();
|
||||
debug!("Building libs in {}, destination = {}",
|
||||
self.source_workspace.display(),
|
||||
self.build_workspace().display());
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
libs,
|
||||
cfgs,
|
||||
Lib,
|
||||
inputs_to_discover);
|
||||
debug!("Building mains");
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
mains,
|
||||
cfgs,
|
||||
Main,
|
||||
inputs_to_discover);
|
||||
debug!("Building tests");
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
tests,
|
||||
cfgs,
|
||||
Test,
|
||||
inputs_to_discover);
|
||||
debug!("Building benches");
|
||||
self.build_crates(build_context,
|
||||
&mut deps,
|
||||
benchs,
|
||||
cfgs,
|
||||
Bench,
|
||||
inputs_to_discover);
|
||||
deps
|
||||
}
|
||||
|
||||
/// Return the workspace to put temporary files in. See the comment on `PkgSrc`
|
||||
pub fn build_workspace<'a>(&'a self) -> &'a Path {
|
||||
if self.build_in_destination {
|
||||
&self.destination_workspace
|
||||
}
|
||||
else {
|
||||
&self.source_workspace
|
||||
}
|
||||
}
|
||||
|
||||
/// Debugging
|
||||
pub fn dump_crates(&self) {
|
||||
let crate_sets = [&self.libs, &self.mains, &self.tests, &self.benchs];
|
||||
for crate_set in crate_sets.iter() {
|
||||
for c in crate_set.iter() {
|
||||
debug!("Built crate: {}", c.file.display())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,196 +0,0 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use context::{Context, RustcFlags, Trans, Link, Nothing, Pretty, Analysis, Assemble,
|
||||
LLVMAssemble, LLVMCompileBitcode};
|
||||
use context::{Command, flags_forbidden_for_cmd};
|
||||
use rustc::version;
|
||||
use exit_codes::{BAD_FLAG_CODE};
|
||||
use rustc::driver::{session};
|
||||
|
||||
use usage;
|
||||
|
||||
use extra::{getopts};
|
||||
use std::{result};
|
||||
use std::hashmap::HashSet;
|
||||
|
||||
/// Result of parsing command line arguments
|
||||
pub struct ParseResult {
|
||||
// Command
|
||||
command: Command,
|
||||
// Args
|
||||
args: ~[~str],
|
||||
// Parsed command line flags
|
||||
context: Context,
|
||||
// Path to system root
|
||||
sysroot: Option<~str>
|
||||
}
|
||||
|
||||
/// Parses command line arguments of rustpkg.
|
||||
/// Returns a triplet (command, remaining_args, context)
|
||||
pub fn parse_args(args: &[~str]) -> Result<ParseResult, int> {
|
||||
let opts = ~[ getopts::optflag("h"), getopts::optflag("help"),
|
||||
getopts::optflag("no-link"),
|
||||
getopts::optflag("no-trans"),
|
||||
// n.b. Ignores different --pretty options for now
|
||||
getopts::optflag("pretty"),
|
||||
getopts::optflag("parse-only"),
|
||||
getopts::optflag("S"), getopts::optflag("assembly"),
|
||||
getopts::optmulti("c"), getopts::optmulti("cfg"),
|
||||
getopts::optflag("v"), getopts::optflag("version"),
|
||||
getopts::optflag("r"), getopts::optflag("rust-path-hack"),
|
||||
getopts::optopt("sysroot"),
|
||||
getopts::optflag("emit-llvm"),
|
||||
getopts::optopt("linker"),
|
||||
getopts::optopt("link-args"),
|
||||
getopts::optopt("opt-level"),
|
||||
getopts::optflag("O"),
|
||||
getopts::optflag("save-temps"),
|
||||
getopts::optopt("target"),
|
||||
getopts::optopt("target-cpu"),
|
||||
getopts::optmulti("Z") ];
|
||||
let matches = &match getopts::getopts(args, opts) {
|
||||
result::Ok(m) => m,
|
||||
result::Err(f) => {
|
||||
error!("{}", f.to_err_msg());
|
||||
return Err(1);
|
||||
}
|
||||
};
|
||||
let no_link = matches.opt_present("no-link");
|
||||
let no_trans = matches.opt_present("no-trans");
|
||||
let supplied_sysroot = matches.opt_str("sysroot");
|
||||
let generate_asm = matches.opt_present("S") ||
|
||||
matches.opt_present("assembly");
|
||||
let parse_only = matches.opt_present("parse-only");
|
||||
let pretty = matches.opt_present("pretty");
|
||||
let emit_llvm = matches.opt_present("emit-llvm");
|
||||
|
||||
if matches.opt_present("h") ||
|
||||
matches.opt_present("help") {
|
||||
usage::general();
|
||||
return Err(0);
|
||||
}
|
||||
|
||||
if matches.opt_present("v") ||
|
||||
matches.opt_present("version") {
|
||||
version(args[0]);
|
||||
return Err(0);
|
||||
}
|
||||
|
||||
let use_rust_path_hack = matches.opt_present("r") ||
|
||||
matches.opt_present("rust-path-hack");
|
||||
|
||||
let linker = matches.opt_str("linker");
|
||||
let link_args = matches.opt_str("link-args");
|
||||
let cfgs = matches.opt_strs("cfg") + matches.opt_strs("c");
|
||||
let mut user_supplied_opt_level = true;
|
||||
let opt_level = match matches.opt_str("opt-level") {
|
||||
Some(~"0") => session::No,
|
||||
Some(~"1") => session::Less,
|
||||
Some(~"2") => session::Default,
|
||||
Some(~"3") => session::Aggressive,
|
||||
_ if matches.opt_present("O") => session::Default,
|
||||
_ => {
|
||||
user_supplied_opt_level = false;
|
||||
session::No
|
||||
}
|
||||
};
|
||||
|
||||
let save_temps = matches.opt_present("save-temps");
|
||||
let target = matches.opt_str("target");
|
||||
let target_cpu = matches.opt_str("target-cpu");
|
||||
let experimental_features = {
|
||||
let strs = matches.opt_strs("Z");
|
||||
if matches.opt_present("Z") {
|
||||
Some(strs)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let mut args = matches.free.clone();
|
||||
args.shift();
|
||||
|
||||
if args.len() < 1 {
|
||||
usage::general();
|
||||
return Err(1);
|
||||
}
|
||||
|
||||
let rustc_flags = RustcFlags {
|
||||
linker: linker,
|
||||
link_args: link_args,
|
||||
optimization_level: opt_level,
|
||||
compile_upto: if no_trans {
|
||||
Trans
|
||||
} else if no_link {
|
||||
Link
|
||||
} else if pretty {
|
||||
Pretty
|
||||
} else if parse_only {
|
||||
Analysis
|
||||
} else if emit_llvm && generate_asm {
|
||||
LLVMAssemble
|
||||
} else if generate_asm {
|
||||
Assemble
|
||||
} else if emit_llvm {
|
||||
LLVMCompileBitcode
|
||||
} else {
|
||||
Nothing
|
||||
},
|
||||
save_temps: save_temps,
|
||||
target: target,
|
||||
target_cpu: target_cpu,
|
||||
additional_library_paths:
|
||||
HashSet::new(), // No way to set this from the rustpkg command line
|
||||
experimental_features: experimental_features
|
||||
};
|
||||
|
||||
let cmd_opt = args.iter().filter_map( |s| from_str(s.clone())).next();
|
||||
let command = match cmd_opt {
|
||||
None => {
|
||||
debug!("No legal command. Returning 0");
|
||||
usage::general();
|
||||
return Err(0);
|
||||
}
|
||||
Some(cmd) => {
|
||||
let bad_option = flags_forbidden_for_cmd(&rustc_flags,
|
||||
cfgs,
|
||||
cmd,
|
||||
user_supplied_opt_level);
|
||||
if bad_option {
|
||||
usage::usage_for_command(cmd);
|
||||
debug!("Bad option, returning BAD_FLAG_CODE");
|
||||
return Err(BAD_FLAG_CODE);
|
||||
} else {
|
||||
cmd
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Pop off all flags, plus the command
|
||||
let mut remaining_args: ~[~str] = args.iter().skip_while(|&s| {
|
||||
let maybe_command: Option<Command> = from_str(*s);
|
||||
maybe_command.is_none()
|
||||
}).map(|s| s.clone()).collect();
|
||||
remaining_args.shift();
|
||||
|
||||
let context = Context{
|
||||
rustc_flags: rustc_flags,
|
||||
cfgs: cfgs,
|
||||
use_rust_path_hack: use_rust_path_hack,
|
||||
};
|
||||
Ok(ParseResult {
|
||||
command: command,
|
||||
args: remaining_args,
|
||||
context: context,
|
||||
sysroot: supplied_sysroot
|
||||
})
|
||||
}
|
|
@ -1,426 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// rustpkg utilities having to do with paths and directories
|
||||
|
||||
#[allow(dead_code)];
|
||||
|
||||
pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
|
||||
pub use version::{Version, split_version_general};
|
||||
pub use rustc::metadata::filesearch::rust_path;
|
||||
|
||||
use std::libc;
|
||||
use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
|
||||
use std::os;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use syntax::crateid::CrateId;
|
||||
use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
|
||||
use rustc::driver::driver::host_triple;
|
||||
use messages::*;
|
||||
|
||||
pub fn default_workspace() -> Path {
|
||||
let p = rust_path();
|
||||
if p.is_empty() {
|
||||
fail!("Empty RUST_PATH");
|
||||
}
|
||||
let result = p[0];
|
||||
if !result.is_dir() {
|
||||
fs::mkdir_recursive(&result, io::UserRWX);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn in_rust_path(p: &Path) -> bool {
|
||||
rust_path().contains(p)
|
||||
}
|
||||
|
||||
pub static U_RWX: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32;
|
||||
|
||||
/// Creates a directory that is readable, writeable,
|
||||
/// and executable by the user. Returns true iff creation
|
||||
/// succeeded.
|
||||
pub fn make_dir_rwx(p: &Path) -> bool {
|
||||
io::result(|| fs::mkdir(p, io::UserRWX)).is_ok()
|
||||
}
|
||||
|
||||
pub fn make_dir_rwx_recursive(p: &Path) -> bool {
|
||||
io::result(|| fs::mkdir_recursive(p, io::UserRWX)).is_ok()
|
||||
}
|
||||
|
||||
// n.b. The next three functions ignore the package version right
|
||||
// now. Should fix that.
|
||||
|
||||
/// True if there's a directory in <workspace> with
|
||||
/// crateid's short name
|
||||
pub fn workspace_contains_crate_id(crateid: &CrateId, workspace: &Path) -> bool {
|
||||
workspace_contains_crate_id_(crateid, workspace, |p| p.join("src")).is_some()
|
||||
}
|
||||
|
||||
pub fn workspace_contains_crate_id_(crateid: &CrateId, workspace: &Path,
|
||||
// Returns the directory it was actually found in
|
||||
workspace_to_src_dir: |&Path| -> Path) -> Option<Path> {
|
||||
if !workspace.is_dir() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let src_dir = workspace_to_src_dir(workspace);
|
||||
if !src_dir.is_dir() { return None }
|
||||
|
||||
let mut found = None;
|
||||
for p in fs::walk_dir(&src_dir) {
|
||||
if p.is_dir() {
|
||||
if p == src_dir.join(crateid.path.as_slice()) || {
|
||||
let pf = p.filename_str();
|
||||
pf.iter().any(|&g| {
|
||||
match split_version_general(g, '-') {
|
||||
None => false,
|
||||
Some((ref might_match, ref vers)) => {
|
||||
*might_match == crateid.name
|
||||
&& (crateid.version == *vers || crateid.version == None)
|
||||
}
|
||||
}
|
||||
})
|
||||
} {
|
||||
found = Some(p.clone());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if found.is_some() {
|
||||
debug!("Found {} in {}", crateid.to_str(), workspace.display());
|
||||
} else {
|
||||
debug!("Didn't find {} in {}", crateid.to_str(), workspace.display());
|
||||
}
|
||||
found
|
||||
}
|
||||
|
||||
/// Return the target-specific build subdirectory, pushed onto `base`;
|
||||
/// doesn't check that it exists or create it
|
||||
pub fn target_build_dir(workspace: &Path) -> Path {
|
||||
let mut dir = workspace.join("build");
|
||||
dir.push(host_triple());
|
||||
dir
|
||||
}
|
||||
|
||||
/// Return the target-specific lib subdirectory, pushed onto `base`;
|
||||
/// doesn't check that it exists or create it
|
||||
fn target_lib_dir(workspace: &Path) -> Path {
|
||||
let mut dir = workspace.join(libdir());
|
||||
dir.push(host_triple());
|
||||
dir
|
||||
}
|
||||
|
||||
/// Return the bin subdirectory, pushed onto `base`;
|
||||
/// doesn't check that it exists or create it
|
||||
/// note: this isn't target-specific
|
||||
fn target_bin_dir(workspace: &Path) -> Path {
|
||||
workspace.join("bin")
|
||||
}
|
||||
|
||||
/// Figure out what the executable name for <crateid> in <workspace>'s build
|
||||
/// directory is, and if the file exists, return it.
|
||||
pub fn built_executable_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
||||
let mut result = target_build_dir(workspace);
|
||||
result = mk_output_path(Main, Build, crateid, result);
|
||||
debug!("built_executable_in_workspace: checking whether {} exists",
|
||||
result.display());
|
||||
if result.exists() {
|
||||
Some(result)
|
||||
}
|
||||
else {
|
||||
debug!("built_executable_in_workspace: {} does not exist", result.display());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Figure out what the test name for <crateid> in <workspace>'s build
|
||||
/// directory is, and if the file exists, return it.
|
||||
pub fn built_test_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
||||
output_in_workspace(crateid, workspace, Test)
|
||||
}
|
||||
|
||||
/// Figure out what the test name for <crateid> in <workspace>'s build
|
||||
/// directory is, and if the file exists, return it.
|
||||
pub fn built_bench_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
||||
output_in_workspace(crateid, workspace, Bench)
|
||||
}
|
||||
|
||||
fn output_in_workspace(crateid: &CrateId, workspace: &Path, what: OutputType) -> Option<Path> {
|
||||
let mut result = target_build_dir(workspace);
|
||||
// should use a target-specific subdirectory
|
||||
result = mk_output_path(what, Build, crateid, result);
|
||||
debug!("output_in_workspace: checking whether {} exists",
|
||||
result.display());
|
||||
if result.exists() {
|
||||
Some(result)
|
||||
}
|
||||
else {
|
||||
error!("output_in_workspace: {} does not exist", result.display());
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Figure out what the library name for <crateid> in <workspace>'s build
|
||||
/// directory is, and if the file exists, return it.
|
||||
pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
|
||||
library_in_workspace(crateid, Build, workspace)
|
||||
}
|
||||
|
||||
/// Does the actual searching stuff
|
||||
pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> {
|
||||
// This could break once we're handling multiple versions better -- I should add a test for it
|
||||
let path = Path::new(crate_id.path.as_slice());
|
||||
match path.filename_str() {
|
||||
None => None,
|
||||
Some(_short_name) => library_in_workspace(crate_id, Install, workspace)
|
||||
}
|
||||
}
|
||||
|
||||
/// `workspace` is used to figure out the directory to search.
|
||||
/// `name` is taken as the link name of the library.
|
||||
pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> {
|
||||
debug!("library_in_workspace: checking whether a library named {} exists",
|
||||
crate_id.name);
|
||||
|
||||
let dir_to_search = match where {
|
||||
Build => target_build_dir(workspace).join(crate_id.path.as_slice()),
|
||||
Install => target_lib_dir(workspace)
|
||||
};
|
||||
|
||||
library_in(crate_id, &dir_to_search)
|
||||
}
|
||||
|
||||
pub fn system_library(sysroot: &Path, crate_id: &CrateId) -> Option<Path> {
|
||||
library_in(crate_id, &sysroot.join(relative_target_lib_path(host_triple())))
|
||||
}
|
||||
|
||||
fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
|
||||
let version_str = match crate_id.version {
|
||||
Some(ref v) => format!("-{}", *v),
|
||||
None => ~"",
|
||||
};
|
||||
let patterns = ~[
|
||||
(format!("lib{}", crate_id.name), format!("{}.rlib", version_str)),
|
||||
(format!("{}{}", os::consts::DLL_PREFIX, crate_id.name),
|
||||
format!("{}{}", version_str, os::consts::DLL_SUFFIX)),
|
||||
];
|
||||
|
||||
for (prefix, suffix) in patterns.move_iter() {
|
||||
let files = match io::result(|| fs::readdir(dir_to_search)) {
|
||||
Ok(dir) => dir, Err(..) => continue,
|
||||
};
|
||||
for file in files.move_iter() {
|
||||
let filename = match file.filename_str() {
|
||||
Some(s) => s, None => continue,
|
||||
};
|
||||
if filename.starts_with(prefix) && filename.ends_with(suffix) {
|
||||
return Some(file.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("warning: library_in_workspace didn't find a library in {} for {}",
|
||||
dir_to_search.display(), crate_id.to_str());
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Returns the executable that would be installed for <crateid>
|
||||
/// in <workspace>
|
||||
/// As a side effect, creates the bin-dir if it doesn't exist
|
||||
pub fn target_executable_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
||||
target_file_in_workspace(crateid, workspace, Main, Install)
|
||||
}
|
||||
|
||||
|
||||
/// Returns the executable that would be installed for <crateid>
|
||||
/// in <workspace>
|
||||
/// As a side effect, creates the lib-dir if it doesn't exist
|
||||
pub fn target_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
||||
use conditions::bad_path::cond;
|
||||
if !workspace.is_dir() {
|
||||
cond.raise(((*workspace).clone(),
|
||||
format!("Workspace supplied to target_library_in_workspace \
|
||||
is not a directory! {}", workspace.display())));
|
||||
}
|
||||
target_file_in_workspace(crateid, workspace, Lib, Install)
|
||||
}
|
||||
|
||||
/// Returns the test executable that would be installed for <crateid>
|
||||
/// in <workspace>
|
||||
/// note that we *don't* install test executables, so this is just for unit testing
|
||||
pub fn target_test_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
||||
target_file_in_workspace(crateid, workspace, Test, Install)
|
||||
}
|
||||
|
||||
/// Returns the bench executable that would be installed for <crateid>
|
||||
/// in <workspace>
|
||||
/// note that we *don't* install bench executables, so this is just for unit testing
|
||||
pub fn target_bench_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
||||
target_file_in_workspace(crateid, workspace, Bench, Install)
|
||||
}
|
||||
|
||||
|
||||
/// Returns the path that crateid `crateid` would have if placed `where`
|
||||
/// in `workspace`
|
||||
fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
|
||||
what: OutputType, where: Target) -> Path {
|
||||
use conditions::bad_path::cond;
|
||||
|
||||
let subdir = match what {
|
||||
Lib => "lib", Main | Test | Bench => "bin"
|
||||
};
|
||||
// Artifacts in the build directory live in a package-ID-specific subdirectory,
|
||||
// but installed ones don't.
|
||||
let result = match (where, what) {
|
||||
(Build, _) => target_build_dir(workspace).join(crateid.path.as_slice()),
|
||||
(Install, Lib) => target_lib_dir(workspace),
|
||||
(Install, _) => target_bin_dir(workspace)
|
||||
};
|
||||
if io::result(|| fs::mkdir_recursive(&result, io::UserRWX)).is_err() {
|
||||
cond.raise((result.clone(), format!("target_file_in_workspace couldn't \
|
||||
create the {} dir (crateid={}, workspace={}, what={:?}, where={:?}",
|
||||
subdir, crateid.to_str(), workspace.display(), what, where)));
|
||||
}
|
||||
mk_output_path(what, where, crateid, result)
|
||||
}
|
||||
|
||||
/// Return the directory for <crateid>'s build artifacts in <workspace>.
|
||||
/// Creates it if it doesn't exist.
|
||||
pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
|
||||
let mut result = target_build_dir(workspace);
|
||||
result.push(crateid.path.as_slice());
|
||||
debug!("Creating build dir {} for package id {}", result.display(),
|
||||
crateid.to_str());
|
||||
fs::mkdir_recursive(&result, io::UserRWX);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Return the output file for a given directory name,
|
||||
/// given whether we're building a library and whether we're building tests
|
||||
pub fn mk_output_path(what: OutputType, where: Target,
|
||||
crate_id: &CrateId, workspace: Path) -> Path {
|
||||
let short_name_with_version = crate_id.short_name_with_version();
|
||||
// Not local_path.dir_path()! For package foo/bar/blat/, we want
|
||||
// the executable blat-0.5 to live under blat/
|
||||
let dir = match where {
|
||||
// If we're installing, it just goes under <workspace>...
|
||||
Install => workspace,
|
||||
// and if we're just building, it goes in a package-specific subdir
|
||||
Build => workspace.join(crate_id.path.as_slice())
|
||||
};
|
||||
debug!("[{:?}:{:?}] mk_output_path: name = {}, path = {}", what, where,
|
||||
if what == Lib { short_name_with_version.clone() } else { crate_id.name.clone() },
|
||||
dir.display());
|
||||
let mut output_path = match what {
|
||||
// this code is duplicated from elsewhere; fix this
|
||||
Lib => dir.join(os::dll_filename(short_name_with_version)),
|
||||
// executable names *aren't* versioned
|
||||
_ => dir.join(format!("{}{}{}", crate_id.name,
|
||||
match what {
|
||||
Test => "test",
|
||||
Bench => "bench",
|
||||
_ => ""
|
||||
},
|
||||
os::consts::EXE_SUFFIX))
|
||||
};
|
||||
if !output_path.is_absolute() {
|
||||
output_path = os::getcwd().join(&output_path);
|
||||
}
|
||||
debug!("mk_output_path: returning {}", output_path.display());
|
||||
output_path
|
||||
}
|
||||
|
||||
/// Removes files for the package `crateid`, assuming it's installed in workspace `workspace`
|
||||
pub fn uninstall_package_from(workspace: &Path, crateid: &CrateId) {
|
||||
let mut did_something = false;
|
||||
let installed_bin = target_executable_in_workspace(crateid, workspace);
|
||||
if installed_bin.exists() {
|
||||
fs::unlink(&installed_bin);
|
||||
did_something = true;
|
||||
}
|
||||
let installed_lib = target_library_in_workspace(crateid, workspace);
|
||||
if installed_lib.exists() {
|
||||
fs::unlink(&installed_lib);
|
||||
did_something = true;
|
||||
}
|
||||
if !did_something {
|
||||
warn(format!("Warning: there don't seem to be any files for {} installed in {}",
|
||||
crateid.to_str(), workspace.display()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn dir_has_crate_file(dir: &Path) -> bool {
|
||||
dir_has_file(dir, "lib.rs") || dir_has_file(dir, "main.rs")
|
||||
|| dir_has_file(dir, "test.rs") || dir_has_file(dir, "bench.rs")
|
||||
}
|
||||
|
||||
fn dir_has_file(dir: &Path, file: &str) -> bool {
|
||||
assert!(dir.is_absolute());
|
||||
dir.join(file).exists()
|
||||
}
|
||||
|
||||
pub fn find_dir_using_rust_path_hack(p: &CrateId) -> Option<Path> {
|
||||
let rp = rust_path();
|
||||
let path = Path::new(p.path.as_slice());
|
||||
for dir in rp.iter() {
|
||||
// Require that the parent directory match the package ID
|
||||
// Note that this only matches if the package ID being searched for
|
||||
// has a name that's a single component
|
||||
if dir.ends_with_path(&path) || dir.ends_with_path(&versionize(p.path, &p.version)) {
|
||||
debug!("In find_dir_using_rust_path_hack: checking dir {}", dir.display());
|
||||
if dir_has_crate_file(dir) {
|
||||
debug!("Did find id {} in dir {}", p.to_str(), dir.display());
|
||||
return Some(dir.clone());
|
||||
}
|
||||
}
|
||||
debug!("Didn't find id {} in dir {}", p.to_str(), dir.display())
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// True if the user set RUST_PATH to something non-empty --
|
||||
/// as opposed to the default paths that rustpkg adds automatically
|
||||
pub fn user_set_rust_path() -> bool {
|
||||
match os::getenv("RUST_PATH") {
|
||||
None | Some(~"") => false,
|
||||
Some(_) => true
|
||||
}
|
||||
}
|
||||
|
||||
/// Append the version string onto the end of the path's filename
|
||||
pub fn versionize(p: &str, v: &Version) -> Path {
|
||||
let p = Path::new(p);
|
||||
let q = p.filename().expect("path is a directory");
|
||||
let mut q = q.to_owned();
|
||||
q.push('-' as u8);
|
||||
let vs = match v { &Some(ref s) => s.to_owned(), &None => ~"0.0" };
|
||||
q.push_all(vs.as_bytes());
|
||||
p.with_filename(q)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "win32")]
|
||||
pub fn chmod_read_only(p: &Path) -> bool {
|
||||
unsafe {
|
||||
p.with_c_str(|src_buf| libc::chmod(src_buf, S_IRUSR as libc::c_int) == 0 as libc::c_int)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "win32"))]
|
||||
pub fn chmod_read_only(p: &Path) -> bool {
|
||||
unsafe {
|
||||
p.with_c_str(|src_buf| libc::chmod(src_buf, S_IRUSR as libc::mode_t) == 0 as libc::c_int)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn platform_library_name(s: &str) -> ~str {
|
||||
format!("{}{}{}", os::consts::DLL_PREFIX, s, os::consts::DLL_SUFFIX)
|
||||
}
|
|
@ -1,633 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* An implementation of the SHA-1 cryptographic hash.
|
||||
*
|
||||
* First create a `sha1` object using the `sha1` constructor, then
|
||||
* feed it input using the `input` or `input_str` methods, which may be
|
||||
* called any number of times.
|
||||
*
|
||||
* After the entire input has been fed to the hash read the result using
|
||||
* the `result` or `result_str` methods.
|
||||
*
|
||||
* The `sha1` object may be reused to create multiple hashes by calling
|
||||
* the `reset` method.
|
||||
*
|
||||
* This implementation has not been reviewed for cryptographic uses.
|
||||
* As such, all cryptographic uses of this implementation are strongly
|
||||
* discouraged.
|
||||
*/
|
||||
|
||||
use std::num::Zero;
|
||||
use std::vec;
|
||||
use std::vec::bytes::{MutableByteVector, copy_memory};
|
||||
use extra::hex::ToHex;
|
||||
|
||||
/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian
|
||||
/// format.
|
||||
fn write_u32_be(dst: &mut[u8], input: u32) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be32;
|
||||
assert!(dst.len() == 4);
|
||||
unsafe {
|
||||
let x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
||||
*x = to_be32(input as i32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
|
||||
fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
|
||||
use std::cast::transmute;
|
||||
use std::unstable::intrinsics::to_be32;
|
||||
assert!(dst.len() * 4 == input.len());
|
||||
unsafe {
|
||||
let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0));
|
||||
let mut y: *i32 = transmute(input.unsafe_ref(0));
|
||||
for _ in range(0, dst.len()) {
|
||||
*x = to_be32(*y);
|
||||
x = x.offset(1);
|
||||
y = y.offset(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait ToBits {
|
||||
/// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
|
||||
/// high-order value and the 2nd item is the low order value.
|
||||
fn to_bits(self) -> (Self, Self);
|
||||
}
|
||||
|
||||
impl ToBits for u64 {
|
||||
fn to_bits(self) -> (u64, u64) {
|
||||
return (self >> 61, self << 3);
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the specified number of bytes to the bit count. fail!() if this would cause numeric
|
||||
/// overflow.
|
||||
fn add_bytes_to_bits<T: Int + CheckedAdd + ToBits>(bits: T, bytes: T) -> T {
|
||||
let (new_high_bits, new_low_bits) = bytes.to_bits();
|
||||
|
||||
if new_high_bits > Zero::zero() {
|
||||
fail!("Numeric overflow occured.")
|
||||
}
|
||||
|
||||
match bits.checked_add(&new_low_bits) {
|
||||
Some(x) => return x,
|
||||
None => fail!("Numeric overflow occured.")
|
||||
}
|
||||
}
|
||||
|
||||
/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it
|
||||
/// must be processed. The input() method takes care of processing and then clearing the buffer
|
||||
/// automatically. However, other methods do not and require the caller to process the buffer. Any
|
||||
/// method that modifies the buffer directory or provides the caller with bytes that can be modifies
|
||||
/// results in those bytes being marked as used by the buffer.
|
||||
trait FixedBuffer {
|
||||
/// Input a vector of bytes. If the buffer becomes full, process it with the provided
|
||||
/// function and then clear the buffer.
|
||||
fn input(&mut self, input: &[u8], func: |&[u8]|);
|
||||
|
||||
/// Reset the buffer.
|
||||
fn reset(&mut self);
|
||||
|
||||
/// Zero the buffer up until the specified index. The buffer position currently must not be
|
||||
/// greater than that index.
|
||||
fn zero_until(&mut self, idx: uint);
|
||||
|
||||
/// Get a slice of the buffer of the specified size. There must be at least that many bytes
|
||||
/// remaining in the buffer.
|
||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8];
|
||||
|
||||
/// Get the current buffer. The buffer must already be full. This clears the buffer as well.
|
||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8];
|
||||
|
||||
/// Get the current position of the buffer.
|
||||
fn position(&self) -> uint;
|
||||
|
||||
/// Get the number of bytes remaining in the buffer until it is full.
|
||||
fn remaining(&self) -> uint;
|
||||
|
||||
/// Get the size of the buffer
|
||||
fn size(&self) -> uint;
|
||||
}
|
||||
|
||||
/// A fixed size buffer of 64 bytes useful for cryptographic operations.
|
||||
struct FixedBuffer64 {
|
||||
priv buffer: [u8, ..64],
|
||||
priv buffer_idx: uint,
|
||||
}
|
||||
|
||||
impl FixedBuffer64 {
|
||||
/// Create a new buffer
|
||||
fn new() -> FixedBuffer64 {
|
||||
return FixedBuffer64 {
|
||||
buffer: [0u8, ..64],
|
||||
buffer_idx: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedBuffer for FixedBuffer64 {
|
||||
fn input(&mut self, input: &[u8], func: |&[u8]|) {
|
||||
let mut i = 0;
|
||||
|
||||
let size = 64;
|
||||
|
||||
// If there is already data in the buffer, copy as much as we can into it and process
|
||||
// the data if the buffer becomes full.
|
||||
if self.buffer_idx != 0 {
|
||||
let buffer_remaining = size - self.buffer_idx;
|
||||
if input.len() >= buffer_remaining {
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(self.buffer_idx, size),
|
||||
input.slice_to(buffer_remaining));
|
||||
self.buffer_idx = 0;
|
||||
func(self.buffer);
|
||||
i += buffer_remaining;
|
||||
} else {
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + input.len()),
|
||||
input);
|
||||
self.buffer_idx += input.len();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// While we have at least a full buffer size chunks's worth of data, process that data
|
||||
// without copying it into the buffer
|
||||
while input.len() - i >= size {
|
||||
func(input.slice(i, i + size));
|
||||
i += size;
|
||||
}
|
||||
|
||||
// Copy any input data into the buffer. At this point in the method, the ammount of
|
||||
// data left in the input vector will be less than the buffer size and the buffer will
|
||||
// be empty.
|
||||
let input_remaining = input.len() - i;
|
||||
copy_memory(
|
||||
self.buffer.mut_slice(0, input_remaining),
|
||||
input.slice_from(i));
|
||||
self.buffer_idx += input_remaining;
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
self.buffer_idx = 0;
|
||||
}
|
||||
|
||||
fn zero_until(&mut self, idx: uint) {
|
||||
assert!(idx >= self.buffer_idx);
|
||||
self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0);
|
||||
self.buffer_idx = idx;
|
||||
}
|
||||
|
||||
fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] {
|
||||
self.buffer_idx += len;
|
||||
return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx);
|
||||
}
|
||||
|
||||
fn full_buffer<'s>(&'s mut self) -> &'s [u8] {
|
||||
assert!(self.buffer_idx == 64);
|
||||
self.buffer_idx = 0;
|
||||
return self.buffer.slice_to(64);
|
||||
}
|
||||
|
||||
fn position(&self) -> uint { self.buffer_idx }
|
||||
|
||||
fn remaining(&self) -> uint { 64 - self.buffer_idx }
|
||||
|
||||
fn size(&self) -> uint { 64 }
|
||||
}
|
||||
|
||||
/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer
|
||||
/// struct.
|
||||
trait StandardPadding {
|
||||
/// Add standard padding to the buffer. The buffer must not be full when this method is called
|
||||
/// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at
|
||||
/// least rem bytes available, the buffer will be zero padded, processed, cleared, and then
|
||||
/// filled with zeros again until only rem bytes are remaining.
|
||||
fn standard_padding(&mut self, rem: uint, func: |&[u8]|);
|
||||
}
|
||||
|
||||
impl <T: FixedBuffer> StandardPadding for T {
|
||||
fn standard_padding(&mut self, rem: uint, func: |&[u8]|) {
|
||||
let size = self.size();
|
||||
|
||||
self.next(1)[0] = 128;
|
||||
|
||||
if self.remaining() < rem {
|
||||
self.zero_until(size);
|
||||
func(self.full_buffer());
|
||||
}
|
||||
|
||||
self.zero_until(size - rem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2
|
||||
* family of digest functions.
|
||||
*/
|
||||
pub trait Digest {
|
||||
/**
|
||||
* Provide message data.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * input - A vector of message data
|
||||
*/
|
||||
fn input(&mut self, input: &[u8]);
|
||||
|
||||
/**
|
||||
* Retrieve the digest result. This method may be called multiple times.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * out - the vector to hold the result. Must be large enough to contain output_bits().
|
||||
*/
|
||||
fn result(&mut self, out: &mut [u8]);
|
||||
|
||||
/**
|
||||
* Reset the digest. This method must be called after result() and before supplying more
|
||||
* data.
|
||||
*/
|
||||
fn reset(&mut self);
|
||||
|
||||
/**
|
||||
* Get the output size in bits.
|
||||
*/
|
||||
fn output_bits(&self) -> uint;
|
||||
|
||||
/**
|
||||
* Convenience function that feeds a string into a digest.
|
||||
*
|
||||
* # Arguments
|
||||
*
|
||||
* * `input` The string to feed into the digest
|
||||
*/
|
||||
fn input_str(&mut self, input: &str) {
|
||||
self.input(input.as_bytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function that retrieves the result of a digest as a
|
||||
* newly allocated vec of bytes.
|
||||
*/
|
||||
fn result_bytes(&mut self) -> ~[u8] {
|
||||
let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8);
|
||||
self.result(buf);
|
||||
buf
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function that retrieves the result of a digest as a
|
||||
* ~str in hexadecimal format.
|
||||
*/
|
||||
fn result_str(&mut self) -> ~str {
|
||||
self.result_bytes().to_hex()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A SHA-1 implementation derived from Paul E. Jones's reference
|
||||
* implementation, which is written for clarity, not speed. At some
|
||||
* point this will want to be rewritten.
|
||||
*/
|
||||
|
||||
// Some unexported constants
|
||||
static DIGEST_BUF_LEN: uint = 5u;
|
||||
static WORK_BUF_LEN: uint = 80u;
|
||||
static K0: u32 = 0x5A827999u32;
|
||||
static K1: u32 = 0x6ED9EBA1u32;
|
||||
static K2: u32 = 0x8F1BBCDCu32;
|
||||
static K3: u32 = 0xCA62C1D6u32;
|
||||
|
||||
/// Structure representing the state of a Sha1 computation
|
||||
pub struct Sha1 {
|
||||
priv h: [u32, ..DIGEST_BUF_LEN],
|
||||
priv length_bits: u64,
|
||||
priv buffer: FixedBuffer64,
|
||||
priv computed: bool,
|
||||
}
|
||||
|
||||
fn add_input(st: &mut Sha1, msg: &[u8]) {
|
||||
assert!((!st.computed));
|
||||
// Assumes that msg.len() can be converted to u64 without overflow
|
||||
st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
|
||||
st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); });
|
||||
}
|
||||
|
||||
fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) {
|
||||
let mut t: int; // Loop counter
|
||||
|
||||
let mut w = [0u32, ..WORK_BUF_LEN];
|
||||
|
||||
// Initialize the first 16 words of the vector w
|
||||
read_u32v_be(w.mut_slice(0, 16), data);
|
||||
|
||||
// Initialize the rest of vector w
|
||||
t = 16;
|
||||
while t < 80 {
|
||||
let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
|
||||
w[t] = circular_shift(1, val);
|
||||
t += 1;
|
||||
}
|
||||
let mut a = h[0];
|
||||
let mut b = h[1];
|
||||
let mut c = h[2];
|
||||
let mut d = h[3];
|
||||
let mut e = h[4];
|
||||
let mut temp: u32;
|
||||
t = 0;
|
||||
while t < 20 {
|
||||
temp = circular_shift(5, a) + (b & c | !b & d) + e + w[t] + K0;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
while t < 40 {
|
||||
temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K1;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
while t < 60 {
|
||||
temp =
|
||||
circular_shift(5, a) + (b & c | b & d | c & d) + e + w[t] +
|
||||
K2;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
while t < 80 {
|
||||
temp = circular_shift(5, a) + (b ^ c ^ d) + e + w[t] + K3;
|
||||
e = d;
|
||||
d = c;
|
||||
c = circular_shift(30, b);
|
||||
b = a;
|
||||
a = temp;
|
||||
t += 1;
|
||||
}
|
||||
h[0] += a;
|
||||
h[1] += b;
|
||||
h[2] += c;
|
||||
h[3] += d;
|
||||
h[4] += e;
|
||||
}
|
||||
|
||||
fn circular_shift(bits: u32, word: u32) -> u32 {
|
||||
return word << bits | word >> 32u32 - bits;
|
||||
}
|
||||
|
||||
fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
|
||||
if !st.computed {
|
||||
st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) });
|
||||
write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
|
||||
write_u32_be(st.buffer.next(4), st.length_bits as u32);
|
||||
process_msg_block(st.buffer.full_buffer(), &mut st.h);
|
||||
|
||||
st.computed = true;
|
||||
}
|
||||
|
||||
write_u32_be(rs.mut_slice(0, 4), st.h[0]);
|
||||
write_u32_be(rs.mut_slice(4, 8), st.h[1]);
|
||||
write_u32_be(rs.mut_slice(8, 12), st.h[2]);
|
||||
write_u32_be(rs.mut_slice(12, 16), st.h[3]);
|
||||
write_u32_be(rs.mut_slice(16, 20), st.h[4]);
|
||||
}
|
||||
|
||||
impl Sha1 {
|
||||
/// Construct a `sha` object
|
||||
pub fn new() -> Sha1 {
|
||||
let mut st = Sha1 {
|
||||
h: [0u32, ..DIGEST_BUF_LEN],
|
||||
length_bits: 0u64,
|
||||
buffer: FixedBuffer64::new(),
|
||||
computed: false,
|
||||
};
|
||||
st.reset();
|
||||
return st;
|
||||
}
|
||||
}
|
||||
|
||||
impl Digest for Sha1 {
|
||||
fn reset(&mut self) {
|
||||
self.length_bits = 0;
|
||||
self.h[0] = 0x67452301u32;
|
||||
self.h[1] = 0xEFCDAB89u32;
|
||||
self.h[2] = 0x98BADCFEu32;
|
||||
self.h[3] = 0x10325476u32;
|
||||
self.h[4] = 0xC3D2E1F0u32;
|
||||
self.buffer.reset();
|
||||
self.computed = false;
|
||||
}
|
||||
fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
|
||||
fn result(&mut self, out: &mut [u8]) { return mk_result(self, out); }
|
||||
fn output_bits(&self) -> uint { 160 }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::num::Bounded;
|
||||
use std::rand::{IsaacRng, Rng};
|
||||
use std::vec;
|
||||
use extra::hex::FromHex;
|
||||
use super::{Digest, Sha1, add_bytes_to_bits};
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct Test {
|
||||
input: ~str,
|
||||
output: ~[u8],
|
||||
output_str: ~str,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
// Test messages from FIPS 180-1
|
||||
|
||||
let fips_180_1_tests = ~[
|
||||
Test {
|
||||
input: ~"abc",
|
||||
output: ~[
|
||||
0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
|
||||
0x47u8, 0x06u8, 0x81u8, 0x6Au8,
|
||||
0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
|
||||
0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
|
||||
0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
|
||||
],
|
||||
output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d"
|
||||
},
|
||||
Test {
|
||||
input:
|
||||
~"abcdbcdecdefdefgefghfghighij" +
|
||||
"hijkijkljklmklmnlmnomnopnopq",
|
||||
output: ~[
|
||||
0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
|
||||
0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
|
||||
0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
|
||||
0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
|
||||
0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
|
||||
],
|
||||
output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1"
|
||||
},
|
||||
];
|
||||
// Examples from wikipedia
|
||||
|
||||
let wikipedia_tests = ~[
|
||||
Test {
|
||||
input: ~"The quick brown fox jumps over the lazy dog",
|
||||
output: ~[
|
||||
0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
|
||||
0x7au8, 0x2du8, 0x28u8, 0xfcu8,
|
||||
0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
|
||||
0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
|
||||
0x1bu8, 0x93u8, 0xebu8, 0x12u8,
|
||||
],
|
||||
output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
|
||||
},
|
||||
Test {
|
||||
input: ~"The quick brown fox jumps over the lazy cog",
|
||||
output: ~[
|
||||
0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
|
||||
0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
|
||||
0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
|
||||
0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
|
||||
0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
|
||||
],
|
||||
output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
|
||||
},
|
||||
];
|
||||
let tests = fips_180_1_tests + wikipedia_tests;
|
||||
|
||||
// Test that it works when accepting the message all at once
|
||||
|
||||
let mut out = [0u8, ..20];
|
||||
|
||||
let mut sh = ~Sha1::new();
|
||||
for t in tests.iter() {
|
||||
(*sh).input_str(t.input);
|
||||
sh.result(out);
|
||||
assert!(t.output.as_slice() == out);
|
||||
|
||||
let out_str = (*sh).result_str();
|
||||
assert_eq!(out_str.len(), 40);
|
||||
assert!(out_str == t.output_str);
|
||||
|
||||
sh.reset();
|
||||
}
|
||||
|
||||
|
||||
// Test that it works when accepting the message in pieces
|
||||
for t in tests.iter() {
|
||||
let len = t.input.len();
|
||||
let mut left = len;
|
||||
while left > 0u {
|
||||
let take = (left + 1u) / 2u;
|
||||
(*sh).input_str(t.input.slice(len - left, take + len - left));
|
||||
left = left - take;
|
||||
}
|
||||
sh.result(out);
|
||||
assert!(t.output.as_slice() == out);
|
||||
|
||||
let out_str = (*sh).result_str();
|
||||
assert_eq!(out_str.len(), 40);
|
||||
assert!(out_str == t.output_str);
|
||||
|
||||
sh.reset();
|
||||
}
|
||||
}
|
||||
|
||||
/// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is
|
||||
/// correct.
|
||||
fn test_digest_1million_random<D: Digest>(digest: &mut D, blocksize: uint, expected: &str) {
|
||||
let total_size = 1000000;
|
||||
let buffer = vec::from_elem(blocksize * 2, 'a' as u8);
|
||||
let mut rng = IsaacRng::new_unseeded();
|
||||
let mut count = 0;
|
||||
|
||||
digest.reset();
|
||||
|
||||
while count < total_size {
|
||||
let next: uint = rng.gen_range(0, 2 * blocksize + 1);
|
||||
let remaining = total_size - count;
|
||||
let size = if next > remaining { remaining } else { next };
|
||||
digest.input(buffer.slice_to(size));
|
||||
count += size;
|
||||
}
|
||||
|
||||
let result_str = digest.result_str();
|
||||
let result_bytes = digest.result_bytes();
|
||||
|
||||
assert_eq!(expected, result_str.as_slice());
|
||||
assert_eq!(expected.from_hex().unwrap(), result_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_1million_random_sha1() {
|
||||
let mut sh = Sha1::new();
|
||||
test_digest_1million_random(
|
||||
&mut sh,
|
||||
64,
|
||||
"34aa973cd4c4daa4f61eeb2bdbad27316534016f");
|
||||
}
|
||||
|
||||
// A normal addition - no overflow occurs
|
||||
#[test]
|
||||
fn test_add_bytes_to_bits_ok() {
|
||||
assert!(add_bytes_to_bits::<u64>(100, 10) == 180);
|
||||
}
|
||||
|
||||
// A simple failure case - adding 1 to the max value
|
||||
#[test]
|
||||
#[should_fail]
|
||||
fn test_add_bytes_to_bits_overflow() {
|
||||
add_bytes_to_bits::<u64>(Bounded::max_value(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod bench {
|
||||
use extra::test::BenchHarness;
|
||||
use super::Sha1;
|
||||
|
||||
#[bench]
|
||||
pub fn sha1_10(bh: & mut BenchHarness) {
|
||||
let mut sh = Sha1::new();
|
||||
let bytes = [1u8, ..10];
|
||||
bh.iter(|| sh.input(bytes));
|
||||
bh.bytes = bytes.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn sha1_1k(bh: & mut BenchHarness) {
|
||||
let mut sh = Sha1::new();
|
||||
let bytes = [1u8, ..1024];
|
||||
bh.iter(|| sh.input(bytes));
|
||||
bh.bytes = bytes.len() as u64;
|
||||
}
|
||||
|
||||
#[bench]
|
||||
pub fn sha1_64k(bh: & mut BenchHarness) {
|
||||
let mut sh = Sha1::new();
|
||||
let bytes = [1u8, ..65536];
|
||||
bh.iter(|| sh.input(bytes));
|
||||
bh.bytes = bytes.len() as u64;
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Utils for working with version control repositories. Just git right now.
|
||||
|
||||
use std::{run, str};
|
||||
use std::run::{ProcessOutput, ProcessOptions, Process};
|
||||
use std::io::fs;
|
||||
use extra::tempfile::TempDir;
|
||||
use path_util::chmod_read_only;
|
||||
|
||||
/// Attempts to clone `source`, a local git repository, into `target`, a local
|
||||
/// directory that doesn't exist.
|
||||
/// Returns `DirToUse(p)` if the clone fails, where `p` is a newly created temporary
|
||||
/// directory (that the callee may use, for example, to check out remote sources into).
|
||||
/// Returns `CheckedOutSources` if the clone succeeded.
|
||||
pub fn safe_git_clone(source: &Path, v: &Option<~str>, target: &Path) -> CloneResult {
|
||||
if source.exists() {
|
||||
debug!("{} exists locally! Cloning it into {}",
|
||||
source.display(), target.display());
|
||||
// Ok to use target here; we know it will succeed
|
||||
assert!(source.is_dir());
|
||||
assert!(is_git_dir(source));
|
||||
|
||||
if !target.exists() {
|
||||
debug!("Running: git clone {} {}", source.display(), target.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let opt_outp = run::process_output("git", [~"clone",
|
||||
source.as_str().unwrap().to_owned(),
|
||||
target.as_str().unwrap().to_owned()]);
|
||||
let outp = opt_outp.expect("Failed to exec `git`");
|
||||
if !outp.status.success() {
|
||||
println!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
||||
println!("{}", str::from_utf8_owned(outp.error).unwrap());
|
||||
return DirToUse(target.clone());
|
||||
}
|
||||
else {
|
||||
match v {
|
||||
&Some(ref s) => {
|
||||
let git_dir = target.join(".git");
|
||||
debug!("`Running: git --work-tree={} --git-dir={} checkout {}",
|
||||
*s, target.display(), git_dir.display());
|
||||
// FIXME (#9639: This needs to handle non-utf8 paths
|
||||
let outp = run::process_output("git",
|
||||
[format!("--work-tree={}", target.as_str().unwrap().to_owned()),
|
||||
format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
|
||||
~"checkout", format!("{}", *s)]).expect("Failed to exec `git`");
|
||||
if !outp.status.success() {
|
||||
println!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
||||
println!("{}", str::from_utf8_owned(outp.error).unwrap());
|
||||
return DirToUse(target.clone());
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check that no version was specified. There's no reason to not handle the
|
||||
// case where a version was requested, but I haven't implemented it.
|
||||
assert!(*v == None);
|
||||
let git_dir = target.join(".git");
|
||||
debug!("Running: git --work-tree={} --git-dir={} pull --no-edit {}",
|
||||
target.display(), git_dir.display(), source.display());
|
||||
// FIXME (#9639: This needs to handle non-utf8 paths
|
||||
let args = [format!("--work-tree={}", target.as_str().unwrap().to_owned()),
|
||||
format!("--git-dir={}", git_dir.as_str().unwrap().to_owned()),
|
||||
~"pull", ~"--no-edit", source.as_str().unwrap().to_owned()];
|
||||
let opt_outp = run::process_output("git", args);
|
||||
let outp = opt_outp.expect("Failed to exec `git`");
|
||||
assert!(outp.status.success());
|
||||
}
|
||||
CheckedOutSources
|
||||
} else {
|
||||
use conditions::failed_to_create_temp_dir::cond;
|
||||
|
||||
let scratch_dir = TempDir::new("rustpkg");
|
||||
let clone_target = match scratch_dir {
|
||||
Some(d) => d.unwrap().join("rustpkg_temp"),
|
||||
None => cond.raise(~"Failed to create temporary directory for fetching git sources")
|
||||
};
|
||||
|
||||
DirToUse(clone_target)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum CloneResult {
|
||||
DirToUse(Path), // Created this empty directory to use as the temp dir for git
|
||||
CheckedOutSources // Successfully checked sources out into the given target dir
|
||||
}
|
||||
|
||||
pub fn make_read_only(target: &Path) {
|
||||
// Now, make all the files in the target dir read-only
|
||||
for p in fs::walk_dir(target) {
|
||||
if !p.is_dir() {
|
||||
assert!(chmod_read_only(&p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Source can be either a URL or a local file path.
|
||||
pub fn git_clone_url(source: &str, target: &Path, v: &Option<~str>) {
|
||||
use conditions::git_checkout_failed::cond;
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let opt_outp = run::process_output("git", [~"clone", source.to_owned(),
|
||||
target.as_str().unwrap().to_owned()]);
|
||||
let outp = opt_outp.expect("Failed to exec `git`");
|
||||
if !outp.status.success() {
|
||||
debug!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
||||
debug!("{}", str::from_utf8_owned(outp.error).unwrap());
|
||||
cond.raise((source.to_owned(), target.clone()))
|
||||
}
|
||||
else {
|
||||
match v {
|
||||
&Some(ref s) => {
|
||||
let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()],
|
||||
target);
|
||||
let outp = opt_outp.expect("Failed to exec `git`");
|
||||
if !outp.status.success() {
|
||||
debug!("{}", str::from_utf8_owned(outp.output.clone()).unwrap());
|
||||
debug!("{}", str::from_utf8_owned(outp.error).unwrap());
|
||||
cond.raise((source.to_owned(), target.clone()))
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_output_in_cwd(prog: &str, args: &[~str], cwd: &Path) -> Option<ProcessOutput> {
|
||||
let mut opt_prog = Process::new(prog, args, ProcessOptions{ dir: Some(cwd)
|
||||
,..ProcessOptions::new()});
|
||||
match opt_prog {
|
||||
Some(ref mut prog) => Some(prog.finish_with_output()),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_git_dir(p: &Path) -> bool {
|
||||
p.join(".git").is_dir()
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
|
||||
// Data types that express build artifacts
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum OutputType { Main, Lib, Bench, Test }
|
||||
|
||||
#[deriving(Eq)]
|
||||
pub enum Target {
|
||||
/// In-place build
|
||||
Build,
|
||||
/// Install to bin/ or lib/ dir
|
||||
Install
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub struct WhatToBuild {
|
||||
build_type: BuildType, // Whether or not to ignore the pkg.rs file
|
||||
sources: SourceType, // Which crates to build
|
||||
inputs_to_discover: ~[(~str, Path)] // Inputs to these crates to be discovered
|
||||
// (For now all of these inputs will be taken as discovered inputs
|
||||
// for all of the crates)
|
||||
// (Paired with their kinds)
|
||||
}
|
||||
|
||||
impl WhatToBuild {
|
||||
pub fn new(build_type: BuildType, sources: SourceType) -> WhatToBuild {
|
||||
WhatToBuild { build_type: build_type,
|
||||
sources: sources,
|
||||
inputs_to_discover: ~[] }
|
||||
}
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum BuildType {
|
||||
Inferred, // Ignore the pkg.rs file even if one exists
|
||||
MaybeCustom // Use the pkg.rs file if it exists
|
||||
}
|
||||
|
||||
#[deriving(Eq, Clone)]
|
||||
pub enum SourceType {
|
||||
/// Build just one lib.rs file in `path`, which is relative to the active workspace's src/ dir
|
||||
JustOne(Path),
|
||||
/// Build any test.rs files that can be recursively found in the active workspace
|
||||
Tests,
|
||||
/// Build everything
|
||||
Everything
|
||||
}
|
||||
|
||||
pub fn is_lib(p: &Path) -> bool {
|
||||
file_is(p, "lib")
|
||||
}
|
||||
|
||||
pub fn is_main(p: &Path) -> bool {
|
||||
file_is(p, "main")
|
||||
}
|
||||
|
||||
pub fn is_test(p: &Path) -> bool {
|
||||
file_is(p, "test")
|
||||
}
|
||||
|
||||
pub fn is_bench(p: &Path) -> bool {
|
||||
file_is(p, "bench")
|
||||
}
|
||||
|
||||
fn file_is(p: &Path, stem: &str) -> bool {
|
||||
match p.filestem() {
|
||||
Some(s) if s == stem.as_bytes() => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn lib_name_of(p: &Path) -> Path {
|
||||
p.join("lib.rs")
|
||||
}
|
||||
|
||||
pub static lib_crate_filename: &'static str = "lib.rs";
|
File diff suppressed because it is too large
Load diff
|
@ -1,20 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg build hello-world`:
|
||||
* testsuite/hello-world/build/ exists
|
||||
* testsuite/hello-world/build/ contains an executable named hello-world
|
||||
* testsuite/hello-world/build/ does not contain a library
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
println!("Hello world!");
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
Commands that should succeed:
|
||||
|
||||
1. rustpkg install github.com/mozilla-servo/rust-http-client
|
||||
|
||||
2. Create a git repo containing a package "foo", add a tag called "1.0" -- `rustpkg install foo` should install a library called "libfoo-....-1.0..."
|
||||
|
||||
3. rustpkg install foo, if ./.rust/foo exists and is a valid package directory
|
||||
|
||||
4. RUST_PATH=/home/rust rustpkg install foo installs an executable in /home/rust/foo if ./foo exists and is a valid package directory
|
||||
|
||||
5. RUST_PATH=/home/rust:/home/more_rust rustpkg install foo succeeds if /home/more_rust/foo exists and is a valid package directory
|
||||
|
||||
6. rustpkg install foo; rustpkg install bar; rustpkg install quux; rustpkg list should show foo, bar, and quux
|
||||
6a. then, rustpkg remove foo; rustpkg list should show bar and quux, but not foo
|
||||
|
||||
7. Execute `rustpkg build foo`. Check the datestamp on build/foo. Execute the same command again. Make sure the datestamp hasn't changed.
|
||||
|
||||
8. Execute `rustpkg build foo` where foo has a dependency on bar, which hasn't been built before. Check the datestamps on build/foo and build/bar and make sure bar's datestamp is earlier than foo's.
|
||||
|
||||
9. Execute `rustpkg build foo` where foo has a dependency on bar, which hasn't been built before. Then, change one of the source files in bar. Execute `rustpkg build foo` again. Make sure, based on datestamps, that foo was really rebuilt.
|
||||
|
||||
10. Repeat test 9 in the case where the contents of the source file in bar change but its datestamp doesn't change.
|
||||
|
||||
11. If the current directory contains package directories for foo-0.1 and foo.0.2, `rustpkg install foo#0.1` installs foo#0.1 and doesn't install foo#0.2.
|
||||
|
||||
12. `rustpkg do fancy-pkg frob` succeeds if `fancy-pkg` has a package script that defines a custom build hook named `frob`.
|
||||
|
||||
13. `rustpkg info foo` prints out something about foo, if foo is installed.
|
||||
|
||||
14. (Not sure what prefer and unprefer do)
|
||||
|
||||
15. `rustpkg test foo` runs tests and prints their output, if foo contains #[test]s.
|
||||
|
||||
16. If foo is installed, `rustpkg uninstall foo; rustpkg list` doesn't include foo in the list
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn assert_true() {
|
||||
assert!(true);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod std;
|
||||
|
||||
pub mod foo;
|
||||
pub mod bar;
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod rustpkg;
|
||||
extern mod rustc;
|
||||
|
||||
use std::{os, task};
|
||||
use rustpkg::api;
|
||||
use rustpkg::version::None;
|
||||
use rustpkg::workcache_support::digest_file_with_date;
|
||||
use rustpkg::exit_codes::COPY_FAILED_CODE;
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
|
||||
// by convention, first arg is sysroot
|
||||
if args.len() < 2 {
|
||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
||||
argument");
|
||||
}
|
||||
|
||||
let path_for_db = api::default_workspace();
|
||||
debug!("path_for_db = {}", path_for_db.display());
|
||||
|
||||
let sysroot_arg = args[1].clone();
|
||||
let sysroot = Path::new(sysroot_arg);
|
||||
if !sysroot.exists() {
|
||||
fail!("Package script requires a sysroot that exists; {} doesn't", sysroot.display());
|
||||
}
|
||||
|
||||
if args[2] != ~"install" {
|
||||
println!("Warning: I don't know how to {}", args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
let mut context = api::default_context(sysroot, path_for_db);
|
||||
let my_workspace = api::my_workspace(&context.context, "cdep");
|
||||
let foo_c_name = my_workspace.join_many(["src", "cdep-0.0", "foo.c"]);
|
||||
|
||||
let out_lib_path = context.workcache_context.with_prep("foo.c", |prep| {
|
||||
let sub_cx = context.context.clone();
|
||||
debug!("foo_c_name = {}", foo_c_name.display());
|
||||
prep.declare_input("file",
|
||||
foo_c_name.as_str().unwrap().to_owned(),
|
||||
digest_file_with_date(&foo_c_name));
|
||||
let out_path = prep.exec(|exec| {
|
||||
let out_path = api::build_library_in_workspace(exec,
|
||||
&mut sub_cx.clone(),
|
||||
"cdep",
|
||||
"gcc",
|
||||
[~"-c"],
|
||||
[~"foo.c"],
|
||||
"foo");
|
||||
let out_p = Path::new(out_path.unwrap());
|
||||
out_p.as_str().unwrap().to_owned()
|
||||
});
|
||||
out_path
|
||||
});
|
||||
let out_lib_path = Path::new(out_lib_path);
|
||||
debug!("out_lib_path = {}", out_lib_path.display());
|
||||
context.add_library_path(out_lib_path.dir_path());
|
||||
|
||||
let context_clone = context.clone();
|
||||
let task_res = task::try(proc() {
|
||||
let mut cc = context_clone.clone();
|
||||
api::install_pkg(&mut cc,
|
||||
os::getcwd(),
|
||||
~"cdep",
|
||||
None,
|
||||
~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
|
||||
});
|
||||
|
||||
if task_res.is_err() {
|
||||
os::set_exit_status(COPY_FAILED_CODE);
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg install deeply/nested/path/foo`:
|
||||
with RUST_PATH undefined in the environment:
|
||||
* ./deeply/nested/path/foo exists and is an executable
|
||||
*/
|
||||
|
||||
fn main() {}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg install external crate`
|
||||
with RUST_PATH undefined in the environment
|
||||
and with `rustpkg install deeply/nested/path/foo` already
|
||||
executed:
|
||||
* ../bin/external_crate exists and is an executable
|
||||
|
||||
tjc: Also want a test like this where foo is an external URL,
|
||||
which requires the `extern mod` changes
|
||||
*/
|
||||
|
||||
extern mod foo;
|
||||
|
||||
fn main() {}
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn assert_true() {
|
||||
assert!(true);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg build fancy-lib`:
|
||||
* testsuite/fancy-lib/build/ exists
|
||||
* testsuite/fancy-lib/build/ contains a file called generated.rs
|
||||
* testsuite/fancy-lib/build/ contains a library named libfancy_lib
|
||||
* testsuite/fancy-lib/build/ does not contain an executable
|
||||
*
|
||||
*/
|
||||
|
||||
extern mod std;
|
||||
|
||||
pub mod foo;
|
||||
pub mod bar;
|
||||
#[path = "../../build/fancy-lib/generated.rs"] pub mod generated;
|
|
@ -1,52 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern mod rustpkg;
|
||||
extern mod rustc;
|
||||
|
||||
use std::os;
|
||||
use std::io::File;
|
||||
use rustpkg::api;
|
||||
use rustpkg::version::None;
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
|
||||
// by convention, first arg is sysroot
|
||||
if args.len() < 2 {
|
||||
debug!("Failing, arg len");
|
||||
fail!("Package script requires a directory where rustc libraries live as the first \
|
||||
argument");
|
||||
}
|
||||
|
||||
let sysroot_arg = args[1].clone();
|
||||
let sysroot = Path::new(sysroot_arg);
|
||||
if !sysroot.exists() {
|
||||
debug!("Failing, sysroot");
|
||||
fail!("Package script requires a sysroot that exists;{} doesn't", sysroot.display());
|
||||
}
|
||||
|
||||
if args[2] != ~"install" {
|
||||
debug!("Failing, weird command");
|
||||
println!("Warning: I don't know how to {}", args[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("Checking self_exe_path");
|
||||
let out_path = os::self_exe_path().expect("Couldn't get self_exe path");
|
||||
|
||||
debug!("Writing file");
|
||||
let mut file = File::create(&out_path.join("generated.rs"));
|
||||
file.write("pub fn wheeeee() { let xs = [1, 2, 3]; \
|
||||
for _ in xs.iter() { assert!(true); } }".as_bytes());
|
||||
|
||||
let context = api::default_context(sysroot, api::default_workspace());
|
||||
api::install_pkg(&context, os::getcwd(), ~"fancy-lib", None, ~[]);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn f() {}
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg build hello-world`:
|
||||
* testsuite/pass/hello-world/build/ exists
|
||||
* testsuite/pass/hello-world/build/ contains an executable named hello-world
|
||||
* testsuite/pass/hello-world/build/ does not contain a library
|
||||
|
||||
It should also check that after `rustpkg clean hello-world`:
|
||||
* testsuite/pass/hello-world/build is empty
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
println!("Hello world!");
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[bench]
|
||||
pub fn g() {
|
||||
let mut x = 0;
|
||||
while x < 1000 {
|
||||
x += 1;
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn f() -> int { 42 }
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg install install-paths`
|
||||
with RUST_PATH undefined in the environment:
|
||||
* ./.rust/install_paths exists and is an executable
|
||||
* ./.rust/libinstall_paths exists and is a library
|
||||
* ./.rust/install_pathstest does not exist
|
||||
* ./.rust/install_pathsbench does not exist
|
||||
* install-paths/build/install_pathstest exists and is an executable
|
||||
* install-paths/build/install_pathsbench exists and is an executable
|
||||
*/
|
||||
|
||||
use lib::f;
|
||||
|
||||
mod lib;
|
||||
|
||||
fn main() {
|
||||
f();
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[test]
|
||||
fn test_two_plus_two() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn assert_true() {
|
||||
assert!(true);
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
pub fn do_nothing() {
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*
|
||||
The test runner should check that, after `rustpkg build simple-lib`:
|
||||
* testsuite/simple-lib/build/ exists
|
||||
* testsuite/simple-lib/build/ contains a library named libsimple_lib
|
||||
* testsuite/simple-lib/build/ does not contain an executable
|
||||
*/
|
||||
|
||||
extern mod std;
|
||||
|
||||
pub mod foo;
|
||||
pub mod bar;
|
|
@ -1,181 +0,0 @@
|
|||
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use context::Command;
|
||||
|
||||
pub fn general() {
|
||||
println!("Usage: rustpkg [options] <cmd> [args..]
|
||||
|
||||
Where <cmd> is one of:
|
||||
build, clean, do, info, install, list, prefer, test, uninstall, unprefer
|
||||
|
||||
For more help on a given command, you can run:
|
||||
rustpkg help <cmd>
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help Display this message
|
||||
--sysroot PATH Override the system root
|
||||
<cmd> -h, <cmd> --help Display help for <cmd>");
|
||||
}
|
||||
|
||||
pub fn build() {
|
||||
println!("rustpkg build [options..] [package-ID]
|
||||
|
||||
Build the given package ID if specified. With no package ID argument,
|
||||
build the package in the current directory. In that case, the current
|
||||
directory must be a direct child of an `src` directory in a workspace.
|
||||
|
||||
Options:
|
||||
-c, --cfg Pass a cfg flag to the package script
|
||||
--no-link Compile and assemble, but don't link (like -c in rustc)
|
||||
--no-trans Parse and translate, but don't generate any code
|
||||
--pretty Pretty-print the code, but don't generate output
|
||||
--parse-only Parse the code, but don't typecheck or generate code
|
||||
-S Generate assembly code, but don't assemble or link it
|
||||
-S --emit-llvm Generate LLVM assembly code
|
||||
--emit-llvm Generate LLVM bitcode
|
||||
--linker PATH Use a linker other than the system linker
|
||||
--link-args [ARG..] Extra arguments to pass to the linker
|
||||
--opt-level=n Set the optimization level (0 <= n <= 3)
|
||||
-O Equivalent to --opt-level=2
|
||||
--save-temps Don't delete temporary files
|
||||
--target TRIPLE Set the target triple
|
||||
--target-cpu CPU Set the target CPU
|
||||
-Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
|
||||
}
|
||||
|
||||
pub fn clean() {
|
||||
println!("rustpkg clean
|
||||
|
||||
Remove all build files in the work cache for the package in the current
|
||||
directory.");
|
||||
}
|
||||
|
||||
pub fn do_cmd() {
|
||||
println!(r"rustpkg do <cmd>
|
||||
|
||||
Runs a command in the package script. You can listen to a command
|
||||
by tagging a function with the attribute `\#[pkg_do(cmd)]`.");
|
||||
}
|
||||
|
||||
pub fn info() {
|
||||
println!("rustpkg [options..] info
|
||||
|
||||
Probe the package script in the current directory for information.
|
||||
|
||||
Options:
|
||||
-j, --json Output the result as JSON");
|
||||
}
|
||||
|
||||
pub fn list() {
|
||||
println!("rustpkg list
|
||||
|
||||
List all installed packages.");
|
||||
}
|
||||
|
||||
pub fn install() {
|
||||
println!(r"rustpkg install [options..] [package-ID]
|
||||
|
||||
Install the given package ID if specified. With no package ID
|
||||
argument, install the package in the current directory.
|
||||
In that case, the current directory must be a direct child of a
|
||||
`src` directory in a workspace.
|
||||
|
||||
Examples:
|
||||
rustpkg install
|
||||
rustpkg install github.com/mozilla/servo
|
||||
rustpkg install github.com/mozilla/servo\#0.1.2
|
||||
|
||||
Options:
|
||||
-c, --cfg Pass a cfg flag to the package script
|
||||
--emit-llvm Generate LLVM bitcode
|
||||
--linker PATH Use a linker other than the system linker
|
||||
--link-args [ARG..] Extra arguments to pass to the linker
|
||||
--opt-level=n Set the optimization level (0 <= n <= 3)
|
||||
-O Equivalent to --opt-level=2
|
||||
--save-temps Don't delete temporary files
|
||||
--target TRIPLE Set the target triple
|
||||
--target-cpu CPU Set the target CPU
|
||||
-Z FLAG Enable an experimental rustc feature (see `rustc --help`)");
|
||||
}
|
||||
|
||||
pub fn uninstall() {
|
||||
println!("rustpkg uninstall <id|name>[@version]
|
||||
|
||||
Remove a package by id or name and optionally version. If the package(s)
|
||||
is/are depended on by another package then they cannot be removed.");
|
||||
}
|
||||
|
||||
pub fn prefer() {
|
||||
println!("rustpkg [options..] prefer <id|name>[@version]
|
||||
|
||||
By default all binaries are given a unique name so that multiple versions can
|
||||
coexist. The prefer command will symlink the uniquely named binary to
|
||||
the binary directory under its bare name. If version is not supplied, the
|
||||
latest version of the package will be preferred.
|
||||
|
||||
Example:
|
||||
export PATH=$PATH:/home/user/.rustpkg/bin
|
||||
rustpkg prefer machine@1.2.4
|
||||
machine -v
|
||||
==> v1.2.4
|
||||
rustpkg prefer machine@0.4.6
|
||||
machine -v
|
||||
==> v0.4.6");
|
||||
}
|
||||
|
||||
pub fn unprefer() {
|
||||
println!("rustpkg [options..] unprefer <id|name>[@version]
|
||||
|
||||
Remove all symlinks from the store to the binary directory for a package
|
||||
name and optionally version. If version is not supplied, the latest version
|
||||
of the package will be unpreferred. See `rustpkg prefer -h` for more
|
||||
information.");
|
||||
}
|
||||
|
||||
pub fn test() {
|
||||
println!("rustpkg [options..] test
|
||||
|
||||
Build all test crates in the current directory with the test flag.
|
||||
Then, run all the resulting test executables, redirecting the output
|
||||
and exit code.
|
||||
|
||||
Options:
|
||||
-c, --cfg Pass a cfg flag to the package script");
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
println!("rustpkg init
|
||||
|
||||
This will turn the current working directory into a workspace. The first
|
||||
command you run when starting off a new project.
|
||||
");
|
||||
}
|
||||
|
||||
pub fn usage_for_command(command: Command){
|
||||
match command {
|
||||
BuildCmd => build(),
|
||||
CleanCmd => clean(),
|
||||
DoCmd => do_cmd(),
|
||||
HelpCmd => general(),
|
||||
InfoCmd => info(),
|
||||
InstallCmd => install(),
|
||||
ListCmd => list(),
|
||||
PreferCmd => prefer(),
|
||||
TestCmd => test(),
|
||||
InitCmd => init(),
|
||||
UninstallCmd => uninstall(),
|
||||
UnpreferCmd => unprefer(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,699 +0,0 @@
|
|||
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[allow(dead_code)];
|
||||
|
||||
pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
|
||||
pub use target::{Target, Build, Install};
|
||||
pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::libc;
|
||||
use std::os;
|
||||
use std::io;
|
||||
use std::io::fs;
|
||||
use extra::workcache;
|
||||
use rustc::metadata::creader::Loader;
|
||||
use extra::treemap::TreeMap;
|
||||
use extra::getopts::groups::getopts;
|
||||
use syntax;
|
||||
use syntax::codemap::{DUMMY_SP, Spanned};
|
||||
use syntax::ext::base;
|
||||
use syntax::ext::base::{ExtCtxt, MacroCrate};
|
||||
use syntax::{ast, attr, codemap, diagnostic, fold, visit};
|
||||
use syntax::attr::AttrMetaMethods;
|
||||
use syntax::fold::Folder;
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::parse::token;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::util::small_vector::SmallVector;
|
||||
use syntax::crateid::CrateId;
|
||||
use rustc::back::link::OutputTypeExe;
|
||||
use rustc::back::link;
|
||||
use rustc::driver::{driver, session};
|
||||
use CtxMethods;
|
||||
use context::{in_target, StopBefore, Link, Assemble, BuildContext};
|
||||
use package_source::PkgSrc;
|
||||
use workspace::pkg_parent_workspaces;
|
||||
use path_util::{system_library, target_build_dir};
|
||||
use path_util::{default_workspace, built_library_in_workspace};
|
||||
use workcache_support::{digest_file_with_date, digest_only_date};
|
||||
use messages::error;
|
||||
|
||||
|
||||
pub type ExitCode = int; // For now
|
||||
|
||||
pub struct Pkg {
|
||||
id: CrateId,
|
||||
bins: ~[~str],
|
||||
libs: ~[~str],
|
||||
}
|
||||
|
||||
impl ToStr for Pkg {
|
||||
fn to_str(&self) -> ~str {
|
||||
self.id.to_str()
|
||||
}
|
||||
}
|
||||
|
||||
struct ListenerFn {
|
||||
cmds: ~[~str],
|
||||
span: codemap::Span,
|
||||
path: ~[ast::Ident]
|
||||
}
|
||||
|
||||
struct ReadyCtx<'a> {
|
||||
sess: session::Session,
|
||||
ext_cx: ExtCtxt<'a>,
|
||||
path: ~[ast::Ident],
|
||||
fns: ~[ListenerFn]
|
||||
}
|
||||
|
||||
fn fold_mod(m: &ast::Mod, fold: &mut CrateSetup) -> ast::Mod {
|
||||
fn strip_main(item: @ast::Item) -> @ast::Item {
|
||||
@ast::Item {
|
||||
attrs: item.attrs.iter().filter_map(|attr| {
|
||||
if !attr.name().equiv(&("main")) {
|
||||
Some(*attr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect(),
|
||||
.. (*item).clone()
|
||||
}
|
||||
}
|
||||
|
||||
fold::noop_fold_mod(&ast::Mod {
|
||||
items: m.items.map(|item| strip_main(*item)),
|
||||
.. (*m).clone()
|
||||
}, fold)
|
||||
}
|
||||
|
||||
fn fold_item(item: @ast::Item, fold: &mut CrateSetup)
|
||||
-> SmallVector<@ast::Item> {
|
||||
fold.ctx.path.push(item.ident);
|
||||
|
||||
let mut cmds = ~[];
|
||||
let mut had_pkg_do = false;
|
||||
|
||||
for attr in item.attrs.iter() {
|
||||
if attr.name().equiv(&("pkg_do")) {
|
||||
had_pkg_do = true;
|
||||
match attr.node.value.node {
|
||||
ast::MetaList(_, ref mis) => {
|
||||
for mi in mis.iter() {
|
||||
match mi.node {
|
||||
ast::MetaWord(ref cmd) => {
|
||||
cmds.push(cmd.get().to_owned())
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => cmds.push(~"build")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if had_pkg_do {
|
||||
fold.ctx.fns.push(ListenerFn {
|
||||
cmds: cmds,
|
||||
span: item.span,
|
||||
path: /*bad*/fold.ctx.path.clone()
|
||||
});
|
||||
}
|
||||
|
||||
let res = fold::noop_fold_item(item, fold);
|
||||
|
||||
fold.ctx.path.pop();
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
struct CrateSetup<'a> {
|
||||
ctx: &'a mut ReadyCtx<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Folder for CrateSetup<'a> {
|
||||
fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
|
||||
fold_item(item, self)
|
||||
}
|
||||
fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
|
||||
fold_mod(module, self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate/filter main function, add the list of commands, etc.
|
||||
pub fn ready_crate(sess: session::Session,
|
||||
crate: ast::Crate) -> ast::Crate {
|
||||
let loader = &mut Loader::new(sess);
|
||||
let mut ctx = ReadyCtx {
|
||||
sess: sess,
|
||||
ext_cx: ExtCtxt::new(sess.parse_sess, sess.opts.cfg.clone(), loader),
|
||||
path: ~[],
|
||||
fns: ~[]
|
||||
};
|
||||
let mut fold = CrateSetup {
|
||||
ctx: &mut ctx,
|
||||
};
|
||||
fold.fold_crate(crate)
|
||||
}
|
||||
|
||||
pub fn compile_input(context: &BuildContext,
|
||||
exec: &mut workcache::Exec,
|
||||
crate_id: &CrateId,
|
||||
in_file: &Path,
|
||||
workspace: &Path,
|
||||
deps: &mut DepMap,
|
||||
flags: &[~str],
|
||||
cfgs: &[~str],
|
||||
opt: session::OptLevel,
|
||||
what: OutputType) -> Option<Path> {
|
||||
assert!(in_file.components().nth(1).is_some());
|
||||
let input = driver::FileInput(in_file.clone());
|
||||
debug!("compile_input: {} / {:?}", in_file.display(), what);
|
||||
// tjc: by default, use the package ID name as the link name
|
||||
// not sure if we should support anything else
|
||||
|
||||
let mut out_dir = target_build_dir(workspace);
|
||||
out_dir.push(crate_id.path.as_slice());
|
||||
// Make the output directory if it doesn't exist already
|
||||
fs::mkdir_recursive(&out_dir, io::UserRWX);
|
||||
|
||||
let binary = os::args()[0];
|
||||
|
||||
debug!("flags: {}", flags.connect(" "));
|
||||
debug!("cfgs: {}", cfgs.connect(" "));
|
||||
let csysroot = context.sysroot();
|
||||
debug!("compile_input's sysroot = {}", csysroot.display());
|
||||
|
||||
let matches = getopts(debug_flags()
|
||||
+ match what {
|
||||
Lib => ~[~"--lib"],
|
||||
// --test compiles both #[test] and #[bench] fns
|
||||
Test | Bench => ~[~"--test"],
|
||||
Main => ~[]
|
||||
}
|
||||
+ flags
|
||||
+ context.flag_strs()
|
||||
+ cfgs.flat_map(|c| { ~[~"--cfg", (*c).clone()] }),
|
||||
driver::optgroups()).unwrap();
|
||||
debug!("rustc flags: {:?}", matches);
|
||||
|
||||
// Hack so that rustpkg can run either out of a rustc target dir,
|
||||
// or the host dir
|
||||
let sysroot_to_use = @if !in_target(&context.sysroot()) {
|
||||
context.sysroot()
|
||||
}
|
||||
else {
|
||||
let mut p = context.sysroot().clone();
|
||||
p.pop();
|
||||
p.pop();
|
||||
p.pop();
|
||||
p
|
||||
};
|
||||
let csysroot = context.sysroot();
|
||||
debug!("compile_input's sysroot = {}", csysroot.display());
|
||||
debug!("sysroot_to_use = {}", sysroot_to_use.display());
|
||||
|
||||
let output_type = match context.compile_upto() {
|
||||
Assemble => link::OutputTypeAssembly,
|
||||
Link => link::OutputTypeObject,
|
||||
Pretty | Trans | Analysis => link::OutputTypeNone,
|
||||
LLVMAssemble => link::OutputTypeLlvmAssembly,
|
||||
LLVMCompileBitcode => link::OutputTypeBitcode,
|
||||
Nothing => link::OutputTypeExe
|
||||
};
|
||||
|
||||
debug!("Output type = {:?}", output_type);
|
||||
|
||||
let options = @session::Options {
|
||||
optimize: opt,
|
||||
test: what == Test || what == Bench,
|
||||
maybe_sysroot: Some(sysroot_to_use),
|
||||
addl_lib_search_paths:
|
||||
@RefCell::new(context.additional_library_paths()),
|
||||
output_type: output_type,
|
||||
.. (*driver::build_session_options(binary,
|
||||
&matches,
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter)).clone()
|
||||
};
|
||||
|
||||
debug!("Created options...");
|
||||
|
||||
let addl_lib_search_paths = @RefCell::new(options.addl_lib_search_paths);
|
||||
// Make sure all the library directories actually exist, since the linker will complain
|
||||
// otherwise
|
||||
{
|
||||
let mut addl_lib_search_paths = addl_lib_search_paths.borrow_mut();
|
||||
let addl_lib_search_paths = addl_lib_search_paths.get();
|
||||
let mut addl_lib_search_paths = addl_lib_search_paths.borrow_mut();
|
||||
for p in addl_lib_search_paths.get().iter() {
|
||||
if p.exists() {
|
||||
assert!(p.is_dir())
|
||||
}
|
||||
else {
|
||||
fs::mkdir_recursive(p, io::UserRWX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug!("About to build session...");
|
||||
|
||||
let sess = driver::build_session(options,
|
||||
Some(in_file.clone()),
|
||||
@diagnostic::DefaultEmitter as
|
||||
@diagnostic::Emitter);
|
||||
|
||||
debug!("About to build config...");
|
||||
|
||||
// Infer dependencies that rustpkg needs to build, by scanning for
|
||||
// `extern mod` directives.
|
||||
let cfg = driver::build_configuration(sess);
|
||||
let crate = driver::phase_1_parse_input(sess, cfg.clone(), &input);
|
||||
|
||||
let (mut crate, ast_map) = {
|
||||
let installer = CrateInstaller {
|
||||
context: context,
|
||||
parent: crate_id,
|
||||
parent_crate: in_file,
|
||||
sess: sess,
|
||||
exec: exec,
|
||||
deps: deps,
|
||||
save: |p| {
|
||||
debug!("a dependency: {}", p.display());
|
||||
let mut addl_lib_search_paths =
|
||||
addl_lib_search_paths.borrow_mut();
|
||||
let addl_lib_search_paths =
|
||||
addl_lib_search_paths.get();
|
||||
let mut addl_lib_search_paths =
|
||||
addl_lib_search_paths.borrow_mut();
|
||||
// Pass the directory containing a dependency
|
||||
// as an additional lib search path
|
||||
addl_lib_search_paths.get().insert(p);
|
||||
},
|
||||
};
|
||||
let mut loader = CrateLoader {
|
||||
installer: installer,
|
||||
loader: Loader::new(sess),
|
||||
};
|
||||
let (crate, ast_map) = driver::phase_2_configure_and_expand(sess,
|
||||
cfg.clone(),
|
||||
&mut loader,
|
||||
crate);
|
||||
let CrateLoader { mut installer, .. } = loader;
|
||||
debug!("About to call find_and_install_dependencies...");
|
||||
find_and_install_dependencies(&mut installer, &crate);
|
||||
(crate, ast_map)
|
||||
};
|
||||
|
||||
// Inject the crate_id attribute so we get the right package name and version
|
||||
if !attr::contains_name(crate.attrs, "crate_id") {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let crateid_attr =
|
||||
attr::mk_name_value_item_str(
|
||||
InternedString::new("crate_id"),
|
||||
token::intern_and_get_ident(crate_id.to_str()));
|
||||
|
||||
debug!("crateid attr: {:?}", crateid_attr);
|
||||
crate.attrs.push(attr::mk_attr(crateid_attr));
|
||||
}
|
||||
|
||||
debug!("calling compile_crate_from_input, workspace = {},
|
||||
building_library = {:?}", out_dir.display(), sess.building_library);
|
||||
let result = compile_crate_from_input(in_file,
|
||||
exec,
|
||||
context.compile_upto(),
|
||||
&out_dir,
|
||||
sess,
|
||||
crate,
|
||||
ast_map,
|
||||
what);
|
||||
// Discover the output
|
||||
let discovered_output = if what == Lib {
|
||||
built_library_in_workspace(crate_id, workspace) // Huh???
|
||||
}
|
||||
else {
|
||||
result
|
||||
};
|
||||
for p in discovered_output.iter() {
|
||||
debug!("About to discover output {}", p.display());
|
||||
if p.exists() {
|
||||
debug!("4. discovering output {}", p.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
exec.discover_output("binary", p.as_str().unwrap(), digest_only_date(p));
|
||||
}
|
||||
// Nothing to do if it doesn't exist -- that could happen if we had the
|
||||
// -S or -emit-llvm flags, etc.
|
||||
}
|
||||
discovered_output
|
||||
}
|
||||
|
||||
// Should use workcache to avoid recompiling when not necessary
|
||||
// Should also rename this to something better
|
||||
// If crate_opt is present, then finish compilation. If it's None, then
|
||||
// call compile_upto and return the crate
|
||||
// also, too many arguments
|
||||
// Returns list of discovered dependencies
|
||||
pub fn compile_crate_from_input(input: &Path,
|
||||
exec: &mut workcache::Exec,
|
||||
stop_before: StopBefore,
|
||||
// should be of the form <workspace>/build/<pkg id's path>
|
||||
out_dir: &Path,
|
||||
sess: session::Session,
|
||||
// Returns None if one of the flags that suppresses compilation output was
|
||||
// given
|
||||
crate: ast::Crate,
|
||||
ast_map: syntax::ast_map::Map,
|
||||
what: OutputType) -> Option<Path> {
|
||||
debug!("Calling build_output_filenames with {}, building library? {:?}",
|
||||
out_dir.display(), sess.building_library);
|
||||
|
||||
// bad copy
|
||||
debug!("out_dir = {}", out_dir.display());
|
||||
let file_input = driver::FileInput(input.clone());
|
||||
let mut outputs = driver::build_output_filenames(&file_input,
|
||||
&Some(out_dir.clone()), &None,
|
||||
crate.attrs, sess);
|
||||
match what {
|
||||
Lib | Main => {}
|
||||
Test => {
|
||||
let mut ofile = outputs.out_filename.filename_str().unwrap().to_owned();
|
||||
ofile.push_str("test");
|
||||
outputs.out_filename.set_filename(ofile);
|
||||
}
|
||||
Bench => {
|
||||
let mut ofile = outputs.out_filename.filename_str().unwrap().to_owned();
|
||||
ofile.push_str("bench");
|
||||
outputs.out_filename.set_filename(ofile);
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Outputs are out_filename: {} and obj_filename: {} and output type = {:?}",
|
||||
outputs.out_filename.display(),
|
||||
outputs.obj_filename.display(),
|
||||
sess.opts.output_type);
|
||||
debug!("additional libraries:");
|
||||
{
|
||||
let addl_lib_search_paths = sess.opts.addl_lib_search_paths.borrow();
|
||||
for lib in addl_lib_search_paths.get().iter() {
|
||||
debug!("an additional library: {}", lib.display());
|
||||
}
|
||||
}
|
||||
let analysis = driver::phase_3_run_analysis_passes(sess, &crate, ast_map);
|
||||
if driver::stop_after_phase_3(sess) { return None; }
|
||||
let translation = driver::phase_4_translate_to_llvm(sess, crate,
|
||||
&analysis,
|
||||
outputs);
|
||||
driver::phase_5_run_llvm_passes(sess, &translation, outputs);
|
||||
// The second check shouldn't be necessary, but rustc seems to ignore
|
||||
// -c
|
||||
if driver::stop_after_phase_5(sess)
|
||||
|| stop_before == Link || stop_before == Assemble { return Some(outputs.out_filename); }
|
||||
driver::phase_6_link_output(sess, &translation, outputs);
|
||||
|
||||
// Register dependency on the source file
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
exec.discover_input("file", input.as_str().unwrap(), digest_file_with_date(input));
|
||||
|
||||
debug!("Built {}, date = {:?}", outputs.out_filename.display(),
|
||||
datestamp(&outputs.out_filename));
|
||||
Some(outputs.out_filename)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn exe_suffix() -> ~str { ~".exe" }
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(target_os = "android")]
|
||||
#[cfg(target_os = "freebsd")]
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn exe_suffix() -> ~str { ~"" }
|
||||
|
||||
// Called by build_crates
|
||||
pub fn compile_crate(ctxt: &BuildContext,
|
||||
exec: &mut workcache::Exec,
|
||||
crate_id: &CrateId,
|
||||
crate: &Path,
|
||||
workspace: &Path,
|
||||
deps: &mut DepMap,
|
||||
flags: &[~str],
|
||||
cfgs: &[~str],
|
||||
opt: session::OptLevel,
|
||||
what: OutputType) -> Option<Path> {
|
||||
debug!("compile_crate: crate={}, workspace={}", crate.display(), workspace.display());
|
||||
debug!("compile_crate: name = {}, flags =...", crate_id.to_str());
|
||||
for fl in flags.iter() {
|
||||
debug!("+++ {}", *fl);
|
||||
}
|
||||
compile_input(ctxt, exec, crate_id, crate, workspace, deps, flags, cfgs, opt, what)
|
||||
}
|
||||
|
||||
struct CrateInstaller<'a> {
|
||||
context: &'a BuildContext,
|
||||
parent: &'a CrateId,
|
||||
parent_crate: &'a Path,
|
||||
sess: session::Session,
|
||||
exec: &'a mut workcache::Exec,
|
||||
save: 'a |Path|,
|
||||
deps: &'a mut DepMap
|
||||
}
|
||||
|
||||
impl<'a> CrateInstaller<'a> {
|
||||
fn install_crate(&mut self, vi: &ast::ViewItem) {
|
||||
use conditions::nonexistent_package::cond;
|
||||
|
||||
match vi.node {
|
||||
// ignore metadata, I guess
|
||||
ast::ViewItemExternMod(ref lib_ident, ref path_opt, _) => {
|
||||
let lib_name = match *path_opt {
|
||||
Some((ref p, _)) => (*p).clone(),
|
||||
None => token::get_ident(lib_ident.name),
|
||||
};
|
||||
debug!("Finding and installing... {}", lib_name);
|
||||
let crate_id: CrateId =
|
||||
from_str(lib_name.get()).expect("valid crate id");
|
||||
// Check standard Rust library path first
|
||||
let whatever = system_library(&self.context.sysroot_to_use(), &crate_id);
|
||||
debug!("system library returned {:?}", whatever);
|
||||
match whatever {
|
||||
Some(ref installed_path) => {
|
||||
debug!("It exists: {}", installed_path.display());
|
||||
// Say that [path for c] has a discovered dependency on
|
||||
// installed_path
|
||||
// For binary files, we only hash the datestamp, not the contents.
|
||||
// I'm not sure what the right thing is.
|
||||
// Now we know that this crate has a discovered dependency on
|
||||
// installed_path
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
add_dep(self.deps, self.parent_crate.as_str().unwrap().to_owned(),
|
||||
(~"binary", installed_path.as_str().unwrap().to_owned()));
|
||||
self.exec.discover_input("binary",
|
||||
installed_path.as_str().unwrap(),
|
||||
digest_only_date(installed_path));
|
||||
}
|
||||
None => {
|
||||
// FIXME #8711: need to parse version out of path_opt
|
||||
debug!("Trying to install library {}, rebuilding it", crate_id.to_str());
|
||||
// Try to install it
|
||||
// Find all the workspaces in the RUST_PATH that contain this package.
|
||||
let workspaces = pkg_parent_workspaces(&self.context.context,
|
||||
&crate_id);
|
||||
// Three cases:
|
||||
// (a) `workspaces` is empty. That means there's no local source
|
||||
// for this package. In that case, we pass the default workspace
|
||||
// into `PkgSrc::new`, so that if it exists as a remote repository,
|
||||
// its sources will be fetched into it. We also put the output in the
|
||||
// same workspace.
|
||||
// (b) We're using the Rust path hack. In that case, the output goes
|
||||
// in the destination workspace.
|
||||
// (c) `workspaces` is non-empty -- we found a local source for this
|
||||
// package and will build in that workspace.
|
||||
let (source_workspace, dest_workspace) = if workspaces.is_empty() {
|
||||
(default_workspace(), default_workspace())
|
||||
} else {
|
||||
if self.context.context.use_rust_path_hack {
|
||||
(workspaces[0], default_workspace())
|
||||
} else {
|
||||
(workspaces[0].clone(), workspaces[0])
|
||||
}
|
||||
};
|
||||
// In this case, the source and destination workspaces are the same:
|
||||
// Either it's a remote package, so the local sources don't exist
|
||||
// and the `PkgSrc` constructor will detect that;
|
||||
// or else it's already in a workspace and we'll build into that
|
||||
// workspace
|
||||
let pkg_src = cond.trap(|_| {
|
||||
// Nonexistent package? Then print a better error
|
||||
error(format!("Package {} depends on {}, but I don't know \
|
||||
how to find it",
|
||||
self.parent.path,
|
||||
crate_id.path));
|
||||
fail!()
|
||||
}).inside(|| {
|
||||
PkgSrc::new(source_workspace.clone(),
|
||||
dest_workspace.clone(),
|
||||
// Use the rust_path_hack to search for dependencies iff
|
||||
// we were already using it
|
||||
self.context.context.use_rust_path_hack,
|
||||
crate_id.clone())
|
||||
});
|
||||
let (outputs_disc, inputs_disc) =
|
||||
self.context.install(
|
||||
pkg_src,
|
||||
&WhatToBuild::new(Inferred,
|
||||
JustOne(Path::new(lib_crate_filename))));
|
||||
debug!("Installed {}, returned {:?} dependencies and \
|
||||
{:?} transitive dependencies",
|
||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||
debug!("discovered outputs = {:?} discovered_inputs = {:?}",
|
||||
outputs_disc, inputs_disc);
|
||||
// It must have installed *something*...
|
||||
assert!(!outputs_disc.is_empty());
|
||||
for dep in outputs_disc.iter() {
|
||||
debug!("Discovering a binary input: {}", dep.display());
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
self.exec.discover_input("binary",
|
||||
dep.as_str().unwrap(),
|
||||
digest_only_date(dep));
|
||||
add_dep(self.deps,
|
||||
self.parent_crate.as_str().unwrap().to_owned(),
|
||||
(~"binary", dep.as_str().unwrap().to_owned()));
|
||||
|
||||
// Also, add an additional search path
|
||||
let dep_dir = dep.dir_path();
|
||||
debug!("Installed {} into {}", dep.display(), dep_dir.display());
|
||||
(self.save)(dep_dir);
|
||||
}
|
||||
debug!("Installed {}, returned {} dependencies and \
|
||||
{} transitive dependencies",
|
||||
lib_name, outputs_disc.len(), inputs_disc.len());
|
||||
// It must have installed *something*...
|
||||
assert!(!outputs_disc.is_empty());
|
||||
let mut target_workspace = outputs_disc[0].clone();
|
||||
target_workspace.pop();
|
||||
for &(ref what, ref dep) in inputs_disc.iter() {
|
||||
if *what == ~"file" {
|
||||
add_dep(self.deps,
|
||||
self.parent_crate.as_str().unwrap().to_owned(),
|
||||
(~"file", dep.clone()));
|
||||
self.exec.discover_input(*what,
|
||||
*dep,
|
||||
digest_file_with_date(
|
||||
&Path::new(dep.as_slice())));
|
||||
} else if *what == ~"binary" {
|
||||
add_dep(self.deps,
|
||||
self.parent_crate.as_str().unwrap().to_owned(),
|
||||
(~"binary", dep.clone()));
|
||||
self.exec.discover_input(*what,
|
||||
*dep,
|
||||
digest_only_date(
|
||||
&Path::new(dep.as_slice())));
|
||||
} else {
|
||||
fail!("Bad kind: {}", *what);
|
||||
}
|
||||
// Also, add an additional search path
|
||||
debug!("Installed {} into {}",
|
||||
lib_name, target_workspace.as_str().unwrap().to_owned());
|
||||
(self.save)(target_workspace.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ignore `use`s
|
||||
_ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visitor<()> for CrateInstaller<'a> {
|
||||
fn visit_view_item(&mut self, vi: &ast::ViewItem, env: ()) {
|
||||
self.install_crate(vi);
|
||||
visit::walk_view_item(self, vi, env)
|
||||
}
|
||||
}
|
||||
|
||||
struct CrateLoader<'a> {
|
||||
installer: CrateInstaller<'a>,
|
||||
loader: Loader,
|
||||
}
|
||||
|
||||
impl<'a> base::CrateLoader for CrateLoader<'a> {
|
||||
fn load_crate(&mut self, crate: &ast::ViewItem) -> MacroCrate {
|
||||
self.installer.install_crate(crate);
|
||||
self.loader.load_crate(crate)
|
||||
}
|
||||
|
||||
fn get_exported_macros(&mut self, cnum: ast::CrateNum) -> ~[~str] {
|
||||
self.loader.get_exported_macros(cnum)
|
||||
}
|
||||
|
||||
fn get_registrar_symbol(&mut self, cnum: ast::CrateNum) -> Option<~str> {
|
||||
self.loader.get_registrar_symbol(cnum)
|
||||
}
|
||||
}
|
||||
|
||||
/// Collect all `extern mod` directives in `c`, then
|
||||
/// try to install their targets, failing if any target
|
||||
/// can't be found.
|
||||
pub fn find_and_install_dependencies(installer: &mut CrateInstaller,
|
||||
c: &ast::Crate) {
|
||||
debug!("In find_and_install_dependencies...");
|
||||
visit::walk_crate(installer, c, ())
|
||||
}
|
||||
|
||||
pub fn mk_string_lit(s: InternedString) -> ast::Lit {
|
||||
Spanned {
|
||||
node: ast::LitStr(s, ast::CookedStr),
|
||||
span: DUMMY_SP
|
||||
}
|
||||
}
|
||||
|
||||
pub fn option_to_vec<T>(x: Option<T>) -> ~[T] {
|
||||
match x {
|
||||
Some(y) => ~[y],
|
||||
None => ~[]
|
||||
}
|
||||
}
|
||||
|
||||
// tjc: cheesy
|
||||
fn debug_flags() -> ~[~str] { ~[] }
|
||||
// static DEBUG_FLAGS: ~[~str] = ~[~"-Z", ~"time-passes"];
|
||||
|
||||
|
||||
/// Returns the last-modified date as an Option
|
||||
pub fn datestamp(p: &Path) -> Option<libc::time_t> {
|
||||
debug!("Scrutinizing datestamp for {} - does it exist? {:?}", p.display(),
|
||||
p.exists());
|
||||
match io::result(|| p.stat()) {
|
||||
Ok(s) => {
|
||||
let out = s.modified;
|
||||
debug!("Date = {:?}", out);
|
||||
Some(out as libc::time_t)
|
||||
}
|
||||
Err(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub type DepMap = TreeMap<~str, ~[(~str, ~str)]>;
|
||||
|
||||
/// Records a dependency from `parent` to the kind and value described by `info`,
|
||||
/// in `deps`
|
||||
fn add_dep(deps: &mut DepMap, parent: ~str, info: (~str, ~str)) {
|
||||
let mut done = false;
|
||||
let info_clone = info.clone();
|
||||
match deps.find_mut(&parent) {
|
||||
None => { }
|
||||
Some(v) => { done = true; (*v).push(info) }
|
||||
};
|
||||
if !done {
|
||||
deps.insert(parent, ~[info_clone]);
|
||||
}
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// A version is either an exact revision,
|
||||
/// or a semantic version
|
||||
|
||||
extern mod std;
|
||||
|
||||
use std::char;
|
||||
|
||||
pub type Version = Option<~str>;
|
||||
|
||||
// Being lazy since we don't have a regexp library now
|
||||
#[deriving(Eq)]
|
||||
enum ParseState {
|
||||
Start,
|
||||
SawDigit,
|
||||
SawDot
|
||||
}
|
||||
|
||||
pub fn try_parsing_version(s: &str) -> Option<~str> {
|
||||
let s = s.trim();
|
||||
debug!("Attempting to parse: {}", s);
|
||||
let mut parse_state = Start;
|
||||
for c in s.chars() {
|
||||
if char::is_digit(c) {
|
||||
parse_state = SawDigit;
|
||||
}
|
||||
else if c == '.' && parse_state == SawDigit {
|
||||
parse_state = SawDot;
|
||||
}
|
||||
else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
match parse_state {
|
||||
SawDigit => Some(s.to_owned()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// If s is of the form foo#bar, where bar is a valid version
|
||||
/// number, return the prefix before the # and the version.
|
||||
/// Otherwise, return None.
|
||||
pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> {
|
||||
// Check for extra '#' characters separately
|
||||
if s.split('#').len() > 2 {
|
||||
return None;
|
||||
}
|
||||
split_version_general(s, '#')
|
||||
}
|
||||
|
||||
pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Version)> {
|
||||
match s.rfind(sep) {
|
||||
Some(i) => {
|
||||
let path = s.slice(0, i);
|
||||
// n.b. for now, assuming an exact revision is intended, not a SemVer
|
||||
Some((path, Some(s.slice(i + 1, s.len()).to_owned())))
|
||||
}
|
||||
None => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_version() {
|
||||
assert!(try_parsing_version("1.2") == Some(~"1.2"));
|
||||
assert!(try_parsing_version("1.0.17") == Some(~"1.0.17"));
|
||||
assert!(try_parsing_version("you're_a_kitty") == None);
|
||||
assert!(try_parsing_version("42..1") == None);
|
||||
assert!(try_parsing_version("17") == Some(~"17"));
|
||||
assert!(try_parsing_version(".1.2.3") == None);
|
||||
assert!(try_parsing_version("2.3.") == None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_split_version() {
|
||||
let s = "a/b/c#0.1";
|
||||
debug!("== {:?} ==", split_version(s));
|
||||
assert!(split_version(s) == Some((s.slice(0, 5), Some(~"0.1"))));
|
||||
assert!(split_version("a/b/c") == None);
|
||||
let s = "a#1.2";
|
||||
assert!(split_version(s) == Some((s.slice(0, 1), Some(~"1.2"))));
|
||||
assert!(split_version("a#a#3.4") == None);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::io;
|
||||
use std::io::File;
|
||||
use extra::workcache;
|
||||
use sha2::{Digest, Sha256};
|
||||
|
||||
/// Hashes the file contents along with the last-modified time
|
||||
pub fn digest_file_with_date(path: &Path) -> ~str {
|
||||
use conditions::bad_path::cond;
|
||||
|
||||
match io::result(|| File::open(path).read_to_end()) {
|
||||
Ok(bytes) => {
|
||||
let mut sha = Sha256::new();
|
||||
sha.input(bytes);
|
||||
let st = path.stat();
|
||||
sha.input_str(st.modified.to_str());
|
||||
sha.result_str()
|
||||
}
|
||||
Err(e) => {
|
||||
cond.raise((path.clone(), format!("Couldn't read file: {}", e.desc)));
|
||||
~""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Hashes only the last-modified time
|
||||
pub fn digest_only_date(path: &Path) -> ~str {
|
||||
let mut sha = Sha256::new();
|
||||
let st = path.stat();
|
||||
sha.input_str(st.modified.to_str());
|
||||
sha.result_str()
|
||||
}
|
||||
|
||||
/// Adds multiple discovered outputs
|
||||
pub fn discover_outputs(e: &mut workcache::Exec, outputs: ~[Path]) {
|
||||
debug!("Discovering {:?} outputs", outputs.len());
|
||||
for p in outputs.iter() {
|
||||
debug!("Discovering output! {}", p.display());
|
||||
// For now, assume that all discovered outputs are binaries
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
e.discover_output("binary", p.as_str().unwrap(), digest_only_date(p));
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the function name for building a crate
|
||||
pub fn crate_tag(p: &Path) -> ~str {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
p.as_str().unwrap().to_owned() // implicitly, it's "build(p)"...
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// rustpkg utilities having to do with workspaces
|
||||
|
||||
use std::os;
|
||||
use context::Context;
|
||||
use path_util::{workspace_contains_crate_id, find_dir_using_rust_path_hack, default_workspace};
|
||||
use path_util::rust_path;
|
||||
use util::option_to_vec;
|
||||
use syntax::crateid::CrateId;
|
||||
|
||||
pub fn each_pkg_parent_workspace(cx: &Context,
|
||||
crateid: &CrateId,
|
||||
action: |&Path| -> bool)
|
||||
-> bool {
|
||||
// Using the RUST_PATH, find workspaces that contain
|
||||
// this package ID
|
||||
let workspaces = pkg_parent_workspaces(cx, crateid);
|
||||
if workspaces.is_empty() {
|
||||
// tjc: make this a condition
|
||||
fail!("Package {} not found in any of \
|
||||
the following workspaces: {}",
|
||||
crateid.path,
|
||||
rust_path().map(|p| p.display().to_str()).to_str());
|
||||
}
|
||||
for ws in workspaces.iter() {
|
||||
if action(ws) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Given a package ID, return a vector of all of the workspaces in
|
||||
/// the RUST_PATH that contain it
|
||||
pub fn pkg_parent_workspaces(cx: &Context, crateid: &CrateId) -> ~[Path] {
|
||||
let rs: ~[Path] = rust_path().move_iter()
|
||||
.filter(|ws| workspace_contains_crate_id(crateid, ws))
|
||||
.collect();
|
||||
if cx.use_rust_path_hack {
|
||||
rs + option_to_vec(find_dir_using_rust_path_hack(crateid))
|
||||
}
|
||||
else {
|
||||
rs
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a workspace and package-ID name based on the current directory.
|
||||
/// This gets used when rustpkg gets invoked without a package-ID argument.
|
||||
pub fn cwd_to_workspace() -> Option<(Path, CrateId)> {
|
||||
let cwd = os::getcwd();
|
||||
for path in rust_path().move_iter() {
|
||||
let srcpath = path.join("src");
|
||||
if srcpath.is_ancestor_of(&cwd) {
|
||||
let rel = cwd.path_relative_from(&srcpath);
|
||||
let rel_s = rel.as_ref().and_then(|p|p.as_str());
|
||||
if rel_s.is_some() {
|
||||
let crate_id = from_str(rel_s.unwrap()).expect("valid crate id");
|
||||
return Some((path, crate_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// If `workspace` is the same as `cwd`, and use_rust_path_hack is false,
|
||||
/// return `workspace`; otherwise, return the first workspace in the RUST_PATH.
|
||||
pub fn determine_destination(cwd: Path, use_rust_path_hack: bool, workspace: &Path) -> Path {
|
||||
if workspace == &cwd && !use_rust_path_hack {
|
||||
workspace.clone()
|
||||
}
|
||||
else {
|
||||
default_workspace()
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue