diff --git a/README.md b/README.md index d0289ed..82fa320 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,17 @@ A simple package manager for the Motoko programming language. ## How it works `vessel` is inspired by the [spago](https://github.com/purescript/spago) package -manager for PureScript. Any git repository with a `src/` directory is a valid +manager for PureScript. + +Any git repository with a `src/` directory is a valid package to `vessel`, which is a flexible and lightweight approach to package management, that is easily extended with more guarantees and features as our community grows. The two concepts you need to understand to work with `vessel` are _package sets_ and the _manifest_ file. +If your git repository uses a source directory other than `src/`, you can still use `vessel` +by specifying that source `path` explicitly. + ### Package sets `vessel` uses the idea of a _package set_ to manage where it pulls dependencies @@ -82,6 +87,7 @@ your `additions` in the `package-set.dhall` file: let additions = [ { name = "mypackage" , repo = "file:///home/path/to/mypackage" + , path = None Text , version = "v1.0.0" , dependencies = ["base"] } @@ -90,6 +96,40 @@ let additions = [ Now you can depend on this package by adding `mypackage` to your `vessel.dhall` file. + +### What about *custom source paths* in a repo? + +Suppose that `https://github.com/theUsername/theRepo` uses a path other than `src/` for its Motoko source code. + +Assuming that the source path is `foo/bar`, we can specify that path using `path = Some "foo/bar"` for the package entry. + +### What about *multiple packages* in one `repo`? + +The `path` field also permits multiple packages within one repository. + +Suppose that `https://github.com/theUsername/theRepo` has two subdirectories, `apple` and `banana`, each with the source code for a `vessel` package. + +We can specify these packages in our package set as follows: + +```dhall +{ + "name": "apple", + "repo": "https://github.com/theUsername/theRepo.git", + "path": Some "apple/src", + "version": "v1.1.1", + "dependencies": ["base", "banana"] +}, +{ + "name": "banana", + "repo": "https://github.com/theUsername/theRepo.git", + "path": Some "banana/src", + "version": "v2.2.2", + "dependencies": ["base"] +} +``` + +Notice that the field `path` appears in each entry, to direct `vessel` within the single, shared `repo`. + ### How do I integrate `vessel` into my custom build? Running `vessel sources` will return flags in a format you can pass directly to diff --git a/src/lib.rs b/src/lib.rs index d09e17c..63ac26c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,7 +260,8 @@ pub fn download_compiler(version: &str) -> Result { Ok(dest) } -/// Downloads a package either as a tar-ball from Github or clones it as a repo +/// Downloads a package either as a tar-ball from Github or clones it as a repo. +/// Returns its installation location. pub fn download_package(package: &Package) -> Result { let package_dir = Path::new(".vessel").join(package.name.clone()); if !package_dir.exists() { @@ -294,7 +295,15 @@ pub fn download_package(package: &Package) -> Result { package.name, package.version ) } - Ok(repo_dir.join("src")) + // include the package path within the repo, if it exists. + match package.path { + None => Ok(repo_dir.join("src")), + Some(ref p) => { + let q = Path::new(p); + assert!(q.is_relative()); // otherwise .join will misbehave + Ok(repo_dir.join(q)) + } + } } /// Downloads and unpacks a tar-ball from Github into the `dest` path @@ -370,7 +379,6 @@ fn clone_package(tmp: &Path, dest: &Path, repo: &str, version: &str) -> Result<( std::str::from_utf8(&checkout_result.stderr).unwrap() )); } - fs::rename(repo_dir, dest)?; Ok(()) } @@ -505,20 +513,31 @@ pub type Tag = String; pub type Name = String; +pub type PackagePath = String; + #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, serde_dhall::StaticType)] pub struct Package { pub name: Name, pub repo: Url, + pub path: Option, pub version: Tag, pub dependencies: Vec, } impl Package { pub fn install_path(&self) -> PathBuf { - Path::new(".vessel") + let path = Path::new(".vessel") .join(self.name.clone()) - .join(self.version.clone()) - .join("src") + .join(self.version.clone()); + // include the package path within the repo, if it exists. + match self.path { + None => path.join("src"), + Some(ref p) => { + let q = Path::new(p); + assert!(q.is_relative()); // otherwise .join will misbehave + path.join(q) + } + } } /// Returns all Motoko sources found inside this package's installation directory @@ -609,6 +628,7 @@ mod test { Package { name: name.to_string(), repo: "".to_string(), + path: None, version: "".to_string(), dependencies: deps.into_iter().map(|x| x.to_string()).collect(), }