Repositories

cargo-lichking

(mirrored on github)

Wim Looman <wim@nemo157.com>
0b68bd Initial commit
Wim Looman committed at 2016-03-07 17:26:36

Added .gitignore

@@ -0,0 +1,2 @@
target
Cargo.lock

Added Cargo.toml

@@ -0,0 +1,19 @@
[package]
name = "cargo-lichking"
version = "0.1.0"
authors = ["Wim Looman <[email protected]>"]
description = "Display info about licensing of dependencies"
readme = "README.md"
keywords = ["cargo", "licensing"]
license = "MIT/Apache-2.0"
[features]
default = []
[dependencies]
cargo = "0.8"
rustc-serialize = "0.3"
void = "1.0.1"
clippy = { version = "0.0.46", optional = true }

Added README.md

@@ -0,0 +1,22 @@
# cargo-lichking (automated LIcense CHecKING for rust)
`cargo lichking` is a [Cargo][] subcommand that checks licensing
information for dependencies
It will eventually have compatibility checking based off this [License
Slide][] by David A. Wheeler.
[Cargo]: https://github.com/rust-lang/cargo
[License Slide]: http://www.dwheeler.com/essays/floss-license-slide.html
## Developing
If building on OS X with a `homebrew` installed copy of OpenSSL you'll need to
specify where this is to enable building `libssh2-sys`. Use something like:
```sh
OPENSSL_ROOT_DIR=`brew --prefix openssl` \
OPENSSL_LIB_DIR=`brew --prefix openssl`/lib \
OPENSSL_INCLUDE_DIR=`brew --prefix openssl`/include \
cargo build
```

Added src/license.rs

@@ -0,0 +1,92 @@
use std::fmt;
use std::str::FromStr;
use std::path::PathBuf;
use void::Void;
#[derive(Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
#[allow(non_camel_case_types)]
pub enum License {
MIT,
X11,
BSD_3_Clause,
Apache_2_0,
LGPL_2_0,
LGPL_2_1Plus,
LGPL_3_0,
MPL_1_1,
GPL_2_0,
GPL_2_0Plus,
GPL_3_0,
GPL_3_0Plus,
AGPL_1_0,
Custom(String),
File(PathBuf),
Multiple(Vec<License>),
None,
}
impl Default for License {
fn default() -> License {
License::None
}
}
impl FromStr for License {
type Err = Void;
fn from_str(s: &str) -> Result<License, Void> {
match s {
"MIT" => Ok(License::MIT),
"X11" => Ok(License::X11),
"BSD-3-Clause" => Ok(License::BSD_3_Clause),
"Apache-2.0" => Ok(License::Apache_2_0),
"LGPL-2.0" => Ok(License::LGPL_2_0),
"LGPL-2.1+" => Ok(License::LGPL_2_1Plus),
"LGPL-3.0" => Ok(License::LGPL_3_0),
"MPL-1.1" => Ok(License::MPL_1_1),
"GPL-2.0" => Ok(License::GPL_2_0),
"GPL-2.0+" => Ok(License::GPL_2_0Plus),
"GPL-3.0" => Ok(License::GPL_3_0),
"GPL-3.0+" => Ok(License::GPL_3_0Plus),
"AGPL-1.0" => Ok(License::AGPL_1_0),
s if s.contains('/') => {
let mut licenses: Vec<License> = s.split('/').map(str::parse).map(Result::unwrap).collect();
licenses.sort();
Ok(License::Multiple(licenses))
},
s => Ok(License::Custom(s.to_owned())),
}
}
}
impl fmt::Display for License {
fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
match *self {
License::MIT => w.write_str("MIT"),
License::X11 => w.write_str("X11"),
License::BSD_3_Clause => w.write_str("BSD-3-Clause"),
License::Apache_2_0 => w.write_str("Apache-2.0"),
License::LGPL_2_0 => w.write_str("LGPL-2.0"),
License::LGPL_2_1Plus => w.write_str("LGPL-2.1+"),
License::LGPL_3_0 => w.write_str("LGPL-3.0"),
License::MPL_1_1 => w.write_str("MPL-1.1"),
License::GPL_2_0 => w.write_str("GPL-2.0"),
License::GPL_2_0Plus => w.write_str("GPL-2.0+"),
License::GPL_3_0 => w.write_str("GPL-3.0"),
License::GPL_3_0Plus => w.write_str("GPL-3.0+"),
License::AGPL_1_0 => w.write_str("AGPL-1.0"),
License::Custom(ref s) => write!(w, "Custom ({})", s),
License::File(ref f) => write!(w, "File ({})", f.to_string_lossy()),
License::Multiple(ref ls) => {
try!(w.write_str("Any of "));
try!(fmt::Display::fmt(&ls[0], w));
for l in ls.iter().skip(1) {
try!(w.write_str(", "));
try!(fmt::Display::fmt(l, w));
}
Ok(())
},
License::None => w.write_str("Unlicensed"),
}
}
}

Added src/licensed.rs

@@ -0,0 +1,20 @@
use cargo::core::Package;
use license::License;
pub trait Licensed {
fn license(&self) -> License;
}
impl Licensed for Package {
fn license(&self) -> License {
let metadata = self.manifest().metadata();
metadata.license
.as_ref()
.and_then(|license| license.parse::<License>().ok())
.or_else(|| metadata.license_file
.as_ref()
.and_then(|file| self.root().join(file).canonicalize().ok())
.map(License::File))
.unwrap_or_default()
}
}

Added src/main.rs

@@ -0,0 +1,86 @@
extern crate void;
extern crate cargo;
extern crate rustc_serialize;
mod license;
mod licensed;
use std::collections::HashMap;
use cargo::core::registry::PackageRegistry;
use cargo::core::{ Source, Package };
use cargo::ops;
use cargo::sources::path::PathSource;
use cargo::util::{ important_paths, CargoResult };
use cargo::{ Config, CliResult };
use licensed::Licensed;
const USAGE: &'static str = "
Display info about licensing of dependencies
Usage: cargo-lichking [options]
cargo-lichking --help
Options:
-h, --help Print this message
-V, --version Print version info and exit
-v, --verbose Use verbose output
-q, --quiet Use quiet output
";
#[derive(RustcDecodable)]
struct Flags {
flag_version: bool,
flag_verbose: bool,
flag_quiet: bool,
}
fn main() {
cargo::execute_main_without_stdin(real_main, false, USAGE);
}
fn real_main(flags: Flags, config: &Config) -> CliResult<Option<()>> {
let Flags {
flag_version,
flag_verbose,
flag_quiet,
} = flags;
if flag_version {
println!("cargo-lichking {}", env!("CARGO_PKG_VERSION"));
return Ok(None);
}
try!(config.shell().set_verbosity(flag_verbose, flag_quiet));
let mut source = try!(source(config));
let package = try!(source.root_package());
let mut registry = try!(registry(config, &package));
let resolve = try!(ops::resolve_pkg(&mut registry, &package));
let packages = try!(ops::get_resolved_packages(&resolve, &mut registry));
let mut license_to_packages = HashMap::new();
for package in packages {
let list = license_to_packages.entry(package.license()).or_insert(Vec::new());
list.push(package);
}
for (license, packages) in license_to_packages {
println!("{}: {}", license, packages.iter().map(|package| package.name()).collect::<Vec<&str>>().join(", "));
}
Ok(None)
}
fn source(config: &Config) -> CargoResult<PathSource> {
let root = try!(important_paths::find_root_manifest_for_wd(None, config.cwd()));
let mut source = try!(PathSource::for_path(root.parent().unwrap(), config));
try!(source.update());
Ok(source)
}
fn registry<'a>(config: &'a Config, package: &Package) -> CargoResult<PackageRegistry<'a>> {
let mut registry = PackageRegistry::new(config);
try!(registry.add_sources(&[package.package_id().source_id().clone()]));
Ok(registry)
}