1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#![deny(missing_docs)]

//! A tool for reasoning about breaking changes in Rust ecosystems
//!
//! Eco helps Rust programmers to keep an ecosystem updated.
//! An ecosystem is a collection of libraries that are relevant to a project.
//!
//! This library is organized into modules, where each module has its own
//! custom text format. By using text, it is easy to customize the
//! collecting and generating of data.
//!
//! ### Ecosystem
//!
//! The definition of an ecosystem used by Eco is:
//!
//! ```test
//! A list of libraries, each with a set of dependencies,
//! forming an directed acyclic graph for dependencies and directed cyclic
//! graph for dev-dependencies, with no holes.
//! ```
//!
//! ### Example
//!
//! Extract info is a bird view of an ecosystem of libraries.
//! This is used to build a dependency graph, which then is used to generate
//! recommended update actions to keep the ecosystem healthy.
//!
//! ```ignore
//! extern crate eco;
//!
//! fn main() {
//!     use std::io::Read;
//!     use std::fs::File;
//!
//!     // Load extract info from file.
//!     let mut extract_info_file = File::open("assets/extract/piston.txt").unwrap();
//!     let mut extract_info = String::new();
//!     extract_info_file.read_to_string(&mut extract_info).unwrap();
//!
//!     let dependency_info = eco::extract::extract_dependency_info_from(&extract_info).unwrap();
//!     let update_info = eco::update::generate_update_info_from(&dependency_info).unwrap();
//!     println!("{}", update_info);
//! }
//! ```
//!
//! ### Unsoundness of holes
//!
//! It is important to not leave any hole in the ecosystem.
//! A hole is when a dependency is not listed that uses a listed library.
//!
//! Example:
//!
//! ```text
//! A (listed) -> B (not listed) -> C (listed)
//! ```
//!
//! The dependencies of library B will not be analyzed because they are not
//! listed. This will lead to a potential error since breaking changes in
//! library C does not cause a breaking change in A.
//!
//! Notice it is OK to not list libraries that are lower level dependencies.
//!
//! As long as there are no holes, the update algorithm is sound.

extern crate piston_meta;
extern crate semver;

pub mod extract;
pub mod update;
pub mod dependencies;
pub mod todo;

#[cfg(test)]
mod tests {
    use piston_meta::*;

    #[test]
    fn extract_is_json() {
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/extract/test.txt");
    }

    #[test]
    fn extract() {
        let _data = load_syntax_data("assets/extract/syntax.txt", "assets/extract/test.txt");
        let _data = load_syntax_data("assets/extract/syntax.txt", "assets/extract/test2.txt");
        let _data = load_syntax_data("assets/extract/syntax.txt", "assets/extract/test3.txt");
    }

    #[test]
    fn dependencies_is_json() {
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/dependencies/test.txt");
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/dependencies/test2.txt");
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/dependencies/test3.txt");
    }

    #[test]
    fn dependencies() {
        let _data = load_syntax_data(
            "assets/dependencies/syntax.txt",
            "assets/dependencies/test.txt",
        );
        let _data = load_syntax_data(
            "assets/dependencies/syntax.txt",
            "assets/dependencies/test2.txt",
        );
        let _data = load_syntax_data(
            "assets/dependencies/syntax.txt",
            "assets/dependencies/test3.txt",
        );
        let _data = load_syntax_data(
            "assets/dependencies/syntax.txt",
            "assets/dependencies/test4.txt",
        );
    }

    #[test]
    fn cargo_toml() {
        let _data = load_syntax_data("assets/cargo-toml/syntax.txt", "assets/cargo-toml/test.txt");
        let _data = load_syntax_data(
            "assets/cargo-toml/syntax.txt",
            "assets/cargo-toml/test2.txt",
        );
        let _data = load_syntax_data(
            "assets/cargo-toml/syntax.txt",
            "assets/cargo-toml/test3.txt",
        );
        let _data = load_syntax_data(
            "assets/cargo-toml/syntax.txt",
            "assets/cargo-toml/test4.txt",
        );
    }

    #[test]
    fn update_is_json() {
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/update/test.txt");
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/update/test2.txt");
        let _ = load_syntax_data("assets/json/syntax.txt", "assets/update/test3.txt");
    }

    #[test]
    fn update() {
        let _data = load_syntax_data("assets/update/syntax.txt", "assets/update/test.txt");
        let _data = load_syntax_data("assets/update/syntax.txt", "assets/update/test2.txt");
        let _data = load_syntax_data("assets/update/syntax.txt", "assets/update/test3.txt");
    }

    #[test]
    fn parse_version() {
        let res = ::update::parse_version(">= 1.0, <= 1.3");
        assert!(res.is_ok());
    }
}