Remove rustpkg.

I'm sorry :'(

Closes #11859
This commit is contained in:
Corey Richardson 2014-02-02 02:56:55 -05:00
parent 3e39e3e80d
commit 25fe2cadb1
59 changed files with 14 additions and 8480 deletions

View file

@ -370,7 +370,6 @@ SREQ$(1)_T_$(2)_H_$(3) = \
# libraries # libraries
CSREQ$(1)_T_$(2)_H_$(3) = \ CSREQ$(1)_T_$(2)_H_$(3) = \
$$(TSREQ$(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)) \ $$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
$$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \ $$(foreach dep,$$(CRATES),$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$$(dep)) \
$$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep)) $$(foreach dep,$$(HOST_CRATES),$$(HLIB$(1)_H_$(3))/stamp.$$(dep))

View file

@ -52,8 +52,8 @@ documentation.
> options are also supported, pass `--help` for more information on them. > options are also supported, pass `--help` for more information on them.
When complete, `make install` will place several programs into When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool, and `rustpkg`, the Rust package manager and build API-documentation tool.
system. system.
3. Read the [tutorial]. 3. Read the [tutorial].
4. Enjoy! 4. Enjoy!

View file

@ -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.

View file

@ -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 "## マネージドボックス"

View file

@ -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 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 ##### Use declarations

View file

@ -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.

View file

@ -117,8 +117,8 @@ can be adjusted by passing a `--prefix` argument to
for more information on them. for more information on them.
When complete, `make install` will place several programs into When complete, `make install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler; `rustdoc`, the `/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool; and `rustpkg`, the Rust package manager. API-documentation tool.
[tarball]: http://static.rust-lang.org/dist/rust-0.9.tar.gz [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 [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 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). 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 ## Crate metadata and settings
For every crate you can define a number of metadata items, such as link name, version or author. 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() {} # 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 ## A minimal example
Now for something that you can actually compile yourself. 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 [extra library]: extra/index.html
Right now `extra` contains those definitions directly, but in the future it will likely just 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? # What next?
@ -3267,7 +3254,6 @@ guides on individual topics.
* [The foreign function interface][ffi] * [The foreign function interface][ffi]
* [Containers and iterators][container] * [Containers and iterators][container]
* [Error-handling and Conditions][conditions] * [Error-handling and Conditions][conditions]
* [Packaging up Rust code][rustpkg]
* [Documenting Rust code][rustdoc] * [Documenting Rust code][rustdoc]
* [Testing Rust code][testing] * [Testing Rust code][testing]
* [The Rust Runtime][runtime] * [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 [ffi]: guide-ffi.html
[container]: guide-container.html [container]: guide-container.html
[conditions]: guide-conditions.html [conditions]: guide-conditions.html
[rustpkg]: guide-rustpkg.html
[testing]: guide-testing.html [testing]: guide-testing.html
[runtime]: guide-runtime.html [runtime]: guide-runtime.html
[rustdoc]: rustdoc.html [rustdoc]: rustdoc.html

View file

@ -130,7 +130,7 @@ To build an executable with debug info (experimental):
.SH "SEE ALSO" .SH "SEE ALSO"
rustdoc, rustpkg rustdoc
.SH "BUGS" .SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues. See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.

View file

@ -84,7 +84,7 @@ The generated HTML can be viewed with any standard web browser.
.SH "SEE ALSO" .SH "SEE ALSO"
rustc, rustpkg rustc
.SH "BUGS" .SH "BUGS"
See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues. See <\fBhttps://github.com/mozilla/rust/issues\fR> for issues.

View file

@ -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.

View file

@ -50,9 +50,9 @@
################################################################################ ################################################################################
TARGET_CRATES := std extra green rustuv native flate arena glob 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) CRATES := $(TARGET_CRATES) $(HOST_CRATES)
TOOLS := compiletest rustpkg rustdoc rustc TOOLS := compiletest rustdoc rustc
DEPS_std := native:rustrt DEPS_std := native:rustrt
DEPS_extra := std DEPS_extra := std
@ -62,17 +62,14 @@ DEPS_native := std
DEPS_syntax := std extra DEPS_syntax := std extra
DEPS_rustc := syntax native:rustllvm flate arena DEPS_rustc := syntax native:rustllvm flate arena
DEPS_rustdoc := rustc native:sundown DEPS_rustdoc := rustc native:sundown
DEPS_rustpkg := rustc
DEPS_flate := std native:miniz DEPS_flate := std native:miniz
DEPS_arena := std extra DEPS_arena := std extra
DEPS_glob := std DEPS_glob := std
TOOL_DEPS_compiletest := extra green rustuv TOOL_DEPS_compiletest := extra green rustuv
TOOL_DEPS_rustpkg := rustpkg green rustuv
TOOL_DEPS_rustdoc := rustdoc green rustuv TOOL_DEPS_rustdoc := rustdoc green rustuv
TOOL_DEPS_rustc := rustc green rustuv TOOL_DEPS_rustc := rustc green rustuv
TOOL_SOURCE_compiletest := $(S)src/compiletest/compiletest.rs 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_rustdoc := $(S)src/driver/driver.rs
TOOL_SOURCE_rustc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs

View file

@ -28,7 +28,6 @@ PKG_FILES := \
$(addprefix $(S)src/, \ $(addprefix $(S)src/, \
README.txt \ README.txt \
driver \ driver \
librustpkg \
librustc \ librustc \
compiletest \ compiletest \
etc \ etc \

View file

@ -89,12 +89,6 @@ doc/rust.epub: rust.md
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \ $(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(EPUB_OPTS) --output=$@ $(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 DOCS += doc/rustdoc.html
doc/rustdoc.html: rustdoc.md $(HTML_DEPS) doc/rustdoc.html: rustdoc.md $(HTML_DEPS)
@$(call E, pandoc: $@) @$(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 $< | \ $(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
$(CFG_PANDOC) $(HTML_OPTS) --output=$@ $(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 DOCS += doc/guide-pointers.html
doc/guide-pointers.html: $(S)doc/guide-pointers.md $(HTML_DEPS) doc/guide-pointers.html: $(S)doc/guide-pointers.md $(HTML_DEPS)
@$(call E, pandoc: $@) @$(call E, pandoc: $@)

View file

@ -185,7 +185,6 @@ check-test: cleantestlibs cleantmptestlogs all check-stage2-rfail
check-lite: cleantestlibs cleantmptestlogs \ check-lite: cleantestlibs cleantmptestlogs \
check-stage2-std check-stage2-extra check-stage2-rpass \ check-stage2-std check-stage2-extra check-stage2-rpass \
check-stage2-rustuv check-stage2-native check-stage2-green \ check-stage2-rustuv check-stage2-native check-stage2-green \
check-stage2-rustpkg \
check-stage2-rfail check-stage2-cfail check-stage2-rmake check-stage2-rfail check-stage2-cfail check-stage2-rmake
$(Q)$(CFG_PYTHON) $(S)src/etc/check-summary.py tmp/*.log $(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))) \ $(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.) # Rules for the compiletest tests (rpass, rfail, etc.)
###################################################################### ######################################################################

View file

@ -30,7 +30,6 @@ Source layout:
| `test/auxiliary` | - Dependencies of tests | | `test/auxiliary` | - Dependencies of tests |
| ------------------- | --------------------------------------------------------- | | ------------------- | --------------------------------------------------------- |
| `librustdoc/` | The Rust API documentation tool | | `librustdoc/` | The Rust API documentation tool |
| `librustpkg/` | The package manager and build system |
| `libuv/` | The libuv submodule | | `libuv/` | The libuv submodule |
| ------------------- | --------------------------------------------------------- | | ------------------- | --------------------------------------------------------- |
| `llvm/` | The LLVM submodule | | `llvm/` | The LLVM submodule |

View file

@ -8,9 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
#[cfg(rustpkg)]
extern mod this = "rustpkg";
#[cfg(rustdoc)] #[cfg(rustdoc)]
extern mod this = "rustdoc"; extern mod this = "rustdoc";

View file

@ -150,8 +150,9 @@ pub struct Options {
lint_opts: ~[(lint::Lint, lint::level)], lint_opts: ~[(lint::Lint, lint::level)],
save_temps: bool, save_temps: bool,
output_type: back::link::OutputType, output_type: back::link::OutputType,
// This is mutable for rustpkg, which updates search paths based on the // This was mutable for rustpkg, which updates search paths based on the
// parsed code. // parsed code. It remains mutable in case its replacements wants to use
// this.
addl_lib_search_paths: @RefCell<HashSet<Path>>, addl_lib_search_paths: @RefCell<HashSet<Path>>,
ar: Option<~str>, ar: Option<~str>,
linker: Option<~str>, linker: Option<~str>,

View file

@ -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

View file

@ -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: ~[] }
}

View file

@ -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;
}

View file

@ -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
}
}

View file

@ -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()
}
}
}

View file

@ -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;

View file

@ -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
}

View file

@ -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;
}

View file

@ -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]);
}

View file

@ -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())
}
}
}
}

View file

@ -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
})
}

View file

@ -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)
}

View file

@ -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;
}
}

View file

@ -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()
}

View file

@ -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

View file

@ -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!");
}

View file

@ -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

View file

@ -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);
}

View file

@ -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() {
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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);
}

View file

@ -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() {
}

View file

@ -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;

View file

@ -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, ~[]);
}

View file

@ -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() {}

View file

@ -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!");
}

View file

@ -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;
}
}

View file

@ -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 }

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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() {
}

View file

@ -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;

View file

@ -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(),
};
}

View file

@ -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]);
}
}

View file

@ -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);
}

View file

@ -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)"...
}

View file

@ -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()
}
}