List of commits:
Subject Hash Author Date (UTC)
Rename project to 'Ambassade'. 4f9c0e27ca25042a97acebc9f3282e4f941706fe Jan Allersma 2019-01-10 15:01:39
Git integration. 0ebc5b3769e50c3463bdc39af0160c7db0d3f00b Jan Allersma 2019-01-03 17:34:18
Implement `hide` command. ab693b8fd91c93dfd7ee7b82cbae75b2a6043b0f Jan Allersma 2018-12-29 15:13:25
Resolve missing/erroneous build/run commands. e81d57882036a6475718b0653169c609d23b1c30 Jan Allersma 2018-12-25 13:06:00
Show working directory in status. ab188603dda062de4b2ea76c5bc1d2d41d98b8c2 Jan Allersma 2018-12-25 10:36:35
Add shell fallthrough. 02078135791fb3889152c11defaa2df21d0ae597 Jan Allersma 2018-12-22 19:47:36
Show dependencies when using `delete` command. cfa9779714d5e6d46ab5b4eeb84a915a15f23f54 Jan Allersma 2018-12-20 15:46:05
Resolve dep-tree by building project recursively. f53e38d790ec67d99ec8204af97273a53b73a9dc Jan Allersma 2018-12-19 14:54:07
Improve `dep-tree` command. 90bfa0340b7b874d65c08dc05c3d711abda1c469 Jan Allersma 2018-12-17 20:10:14
Implement experimental `dep-tree` command. 45d9dfdbfc99c59174e7c587621276b78ab7a4e9 Jan Allersma 2018-12-14 16:11:53
Implement `add` command. bbb2544bd06f29866465d651c32ca4d6e017f5e9 Jan Allersma 2018-12-11 15:43:10
Implement `exe` command. 1eaa36242201cf7ade5f23a14340e630c267db07 Jan Allersma 2018-12-11 13:23:32
Implement `run` and `build` commands. 14e9e25b6a06f587c1a50829e72c829ae59a87c2 Jan Allersma 2018-12-10 20:57:08
Implement non-recursive dependency check. 5ffd40604755d1c2dde9353c74f06a006deea33c Jan Allersma 2018-12-07 20:50:42
Restructure project. c2d98caf7897e87284fb2891e1d4b92d14cf37e1 Jan Allersma 2018-12-06 16:20:46
Initial commit. 4c152d55edc20ac55fd749a2b32b204134a664e3 Jan Allersma 2018-12-05 17:03:08
Commit 4f9c0e27ca25042a97acebc9f3282e4f941706fe - Rename project to 'Ambassade'.
Author: Jan Allersma
Author date (UTC): 2019-01-10 15:01
Committer name: Jan Allersma
Committer date (UTC): 2019-01-10 15:46
Parent(s): 0ebc5b3769e50c3463bdc39af0160c7db0d3f00b
Signing key:
Tree: 0f5b35eb06933d8d4e0070cf071699ed3b16a4c6
File Lines added Lines deleted
.gitignore 1 1
Cargo.lock 1 1
Cargo.toml 1 1
README.md 1 1
doc/use_cases.md 76 0
src/backend/build.rs 3 3
src/backend/config.rs 4 4
src/backend/dep.rs 9 9
src/backend/fetch.rs 2 2
src/backend/filesystem.rs 1 1
src/backend/project.rs 5 5
File .gitignore changed (mode: 100644) (index 8741fe0..cec1169)
1 1 /target /target
2 2 **/*.rs.bk **/*.rs.bk
3 *beheer.json
3 *ambassade.json
File Cargo.lock changed (mode: 100644) (index 0aa7ce0..072f7aa)
... ... dependencies = [
43 43 ] ]
44 44
45 45 [[package]] [[package]]
46 name = "beheer"
46 name = "ambassade"
47 47 version = "0.1.0" version = "0.1.0"
48 48 dependencies = [ dependencies = [
49 49 "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "git2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
File Cargo.toml changed (mode: 100644) (index 47d2e5c..ef6b9ac)
1 1 [package] [package]
2 name = "beheer"
2 name = "ambassade"
3 3 version = "0.1.0" version = "0.1.0"
4 4 authors = ["Jan Allersma <jan@allersma.be>"] authors = ["Jan Allersma <jan@allersma.be>"]
5 5
File README.md changed (mode: 100644) (index c04e7ca..e1dd235)
1 # Beheer
1 # Ambassade
2 2
3 3 ## Notes ## Notes
4 4
File doc/use_cases.md added (mode: 100644) (index 0000000..bf16fcd)
1 # Migrate your software.
2
3 Saying goodbye to a reliable old framework can be scary.
4 You need to make sure that every piece of software has been migrated and
5 working correctly when it gets in production.
6 With Ambassade it is easy to set up dependencies and pieces of your code in a
7 hybrid way, making your migrations smoother.
8 Once you have migrated a part of your code, Ambassade checks for remaining
9 dependencies in your configuration before you remove your old code.
10
11 # Control over heterogenous packages.
12
13 In some cases, you want to make use of libraries/packages that take some effort
14 to be compatible with your project. Take the OPC-UA protocol for example. The
15 protocol has limited implementations because of a 400+ pages counting
16 specification. There are some useful C libraries available that support the
17 OPC-UA protocol. If you want to combine the library with Node.js, you have some
18 solutions, for example:
19
20 * Create an NPM package that interfaces with the C implementation using Node's
21 Native API.
22
23 * Seperate your project in a server-side part, using [Oat++](https://oatpp.io)
24 to create an executable for the server, containing the back-end code. The
25 client-side part will consist of front-end code.
26
27 * Compile the library to WebAssembly and "glue" the compiled binary to your
28 Node.js code.
29
30 Without having a central package manager that organizes all the different parts
31 of the code in different languages, keeping control over your software will be
32 difficult. There are some package managers and git features (like submodules
33 and mergetrees) that can help you with managing your packages. However, most
34 of them will not provide a satisfying solution. Ambassade is dedicated to manage
35 heterogenous packages, and does not even require special configuration files in
36 the dependencies themselves.
37
38 # Make your software more modular.
39
40 Because Ambassade takes care of dependencies, it gives you as developer more
41 freedom to make your projects more modular. You could split your project in
42 more repositories. The advantage of modulating your project is that you can
43 re-use code more easily. If a deprecated feature should not be implemented
44 in your project anymore, you can rebuild your project without having to delete
45 files. Maybe that code could be useful later for future projects.
46
47 If you already have certain features implemented in project A, you can import
48 that feature in project B with one command, so you only have to focus on
49 calling the feature from your project.
50
51 # Keep the structure of non-trivial projects simple.
52
53 Once a successful project grows, and grows, it's structure will be less obvious.
54 The developers that developed the project from the start, know exactly the
55 relationships between dependencies. New developers that join the development
56 team will have a harder time figuring the project's structure out. An
57 easy-to-read configuration file and a flat dependency structure would be a
58 solution.
59
60 ## What is a 'flat dependency structure'?
61
62 NPM version 2 uses a nested dependency structure. This basically means that a
63 dependency resides in a dependency, which resides in another dependency and so
64 on.
65
66 A flat dependency structure has all dependencies at the same level. Ambassade
67 puts all dependencies in one directory, the `dep` directory. This makes finding
68 dependencies easier and keeps directory paths relatively small.
69
70 # Backup all of your code with one command.
71
72 Having to checkout and backup all of your code manually, could take a lot of
73 time and joy. Automating checkouts and backups of your code takes a lot of time
74 as well and isn't that enjoyable. Initializing a Ambassade project with all your
75 code as dependencies saves a lot of time. This way you can use Ambassade as a
76 system to backup all important files.
File src/backend/build.rs changed (mode: 100644) (index 2db696b..be084c6)
... ... fn build_module(config: serde_json::Value) -> Result<String, String> {
60 60 let build_cmd = &config["build"]["linux"]; let build_cmd = &config["build"]["linux"];
61 61
62 62 if !build_cmd.is_string() { if !build_cmd.is_string() {
63 return Err(String::from("beheer.json: 'build->linux' should be a string."));
63 return Err(String::from("ambassade.json: 'build->linux' should be a string."));
64 64 } }
65 65
66 66 super::fetch::build(env::current_dir().unwrap(), String::from(build_cmd.as_str().unwrap())) super::fetch::build(env::current_dir().unwrap(), String::from(build_cmd.as_str().unwrap()))
 
... ... fn build_module(config: serde_json::Value) -> Result<String, String> {
73 73 let build_cmd = &config["build"]["os-x"]; let build_cmd = &config["build"]["os-x"];
74 74
75 75 if !build_cmd.is_string() { if !build_cmd.is_string() {
76 return Err(String::from("beheer.json: 'build->os-x' should be a string."));
76 return Err(String::from("ambassade.json: 'build->os-x' should be a string."));
77 77 } }
78 78
79 79 super::fetch::fetch(env::get_current_dir().unwrap(), String::from(build_cmd.as_str().unwrap())) super::fetch::fetch(env::get_current_dir().unwrap(), String::from(build_cmd.as_str().unwrap()))
 
... ... fn build_module(config: serde_json::Value) -> Result<String, String> {
86 86 let build_cmd = &config["build"]["windows"]; let build_cmd = &config["build"]["windows"];
87 87
88 88 if !build_cmd.is_string() { if !build_cmd.is_string() {
89 return Err(String::from("beheer.json: 'build->windows' should be a string."));
89 return Err(String::from("ambassade.json: 'build->windows' should be a string."));
90 90 } }
91 91
92 92 super::fetch::fetch(env::get_current_dir().unwrap(), String::from(build_cmd.as_str().unwrap())) super::fetch::fetch(env::get_current_dir().unwrap(), String::from(build_cmd.as_str().unwrap()))
File src/backend/config.rs changed (mode: 100644) (index 4ece9c9..98b1644)
... ... use std::path::PathBuf;
7 7 use std::result::Result; use std::result::Result;
8 8
9 9 pub fn create(mut path: PathBuf) -> Result<(), Error> { pub fn create(mut path: PathBuf) -> Result<(), Error> {
10 path.push("beheer.json");
10 path.push("ambassade.json");
11 11 init(&path) init(&path)
12 12 } }
13 13
 
... ... fn init(path: &PathBuf) -> Result<(), Error> {
26 26 }); });
27 27
28 28 match File::open(path.to_str().unwrap()) { match File::open(path.to_str().unwrap()) {
29 Ok(_) => return Err(Error::new(ErrorKind::AlreadyExists, "Already found a 'beheer.json' file.")),
29 Ok(_) => return Err(Error::new(ErrorKind::AlreadyExists, "Already found a 'ambassade.json' file.")),
30 30 Err(_) => { Err(_) => {
31 31 match File::create(path) { match File::create(path) {
32 32 Ok(mut file) => { Ok(mut file) => {
 
... ... fn init(path: &PathBuf) -> Result<(), Error> {
41 41 } }
42 42
43 43 pub fn update(mut path: PathBuf, value: serde_json::Value) -> Result<(), String> { pub fn update(mut path: PathBuf, value: serde_json::Value) -> Result<(), String> {
44 path.push("beheer.json");
44 path.push("ambassade.json");
45 45
46 46 match File::create(path) { match File::create(path) {
47 47 Ok(mut file) => { Ok(mut file) => {
 
... ... pub fn update(mut path: PathBuf, value: serde_json::Value) -> Result<(), String>
57 57 fn read(path: &mut PathBuf) -> Result<String, Error> { fn read(path: &mut PathBuf) -> Result<String, Error> {
58 58 let mut config = String::new(); let mut config = String::new();
59 59
60 path.push("beheer.json");
60 path.push("ambassade.json");
61 61 check(&path); check(&path);
62 62
63 63 match File::open(path.to_str().unwrap()) { match File::open(path.to_str().unwrap()) {
File src/backend/dep.rs changed (mode: 100644) (index 6f7d34b..530863b)
... ... pub fn json(config: String) -> Result<serde_json::Value, String> {
21 21 return Err(error); return Err(error);
22 22 }, },
23 23 serde_json::error::Category::Syntax => { serde_json::error::Category::Syntax => {
24 error.push_str("Syntax error in 'beheer.json'");
24 error.push_str("Syntax error in 'ambassade.json'");
25 25 return Err(error); return Err(error);
26 26 }, },
27 27 serde_json::error::Category::Data => { serde_json::error::Category::Data => {
28 error.push_str("Semantic error in 'beheer.json'");
28 error.push_str("Semantic error in 'ambassade.json'");
29 29 return Err(error); return Err(error);
30 30 }, },
31 31 serde_json::error::Category::Eof => { serde_json::error::Category::Eof => {
32 error.push_str("Unexpected end-of-file in 'beheer.json'");
32 error.push_str("Unexpected end-of-file in 'ambassade.json'");
33 33 return Err(error); return Err(error);
34 34 } }
35 35 } }
 
... ... pub fn dep(config: serde_json::Value, os: &OS) -> Result<Vec<(String, String)>,
73 73 Some(object) => { Some(object) => {
74 74 for dep in object.iter() { for dep in object.iter() {
75 75 if !dep.1.is_string() { if !dep.1.is_string() {
76 return Err(String::from("beheer.json: all deps should be strings!"))
76 return Err(String::from("ambassade.json: all deps should be strings!"))
77 77 } }
78 78 output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap()))); output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap())));
79 79 } }
80 80 }, },
81 None => return Err(String::from("beheer.json: 'deps->linux' should be an object."))
81 None => return Err(String::from("ambassade.json: 'deps->linux' should be an object."))
82 82 } }
83 83 } }
84 84 }, },
 
... ... pub fn dep(config: serde_json::Value, os: &OS) -> Result<Vec<(String, String)>,
89 89 Some(object) => { Some(object) => {
90 90 for dep in object.iter() { for dep in object.iter() {
91 91 if !dep.1.is_string() { if !dep.1.is_string() {
92 return Err(String::from("beheer.json: all deps should be strings!"))
92 return Err(String::from("ambassade.json: all deps should be strings!"))
93 93 } }
94 94 output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap()))); output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap())));
95 95 } }
96 96 }, },
97 None => return Err(String::from("beheer.json: 'deps->os-x' should be an object."))
97 None => return Err(String::from("ambassade.json: 'deps->os-x' should be an object."))
98 98 } }
99 99 } }
100 100 }, },
 
... ... pub fn dep(config: serde_json::Value, os: &OS) -> Result<Vec<(String, String)>,
105 105 Some(object) => { Some(object) => {
106 106 for dep in object.iter() { for dep in object.iter() {
107 107 if !dep.1.is_string() { if !dep.1.is_string() {
108 return Err(String::from("beheer.json: all deps should be strings!"))
108 return Err(String::from("ambassade.json: all deps should be strings!"))
109 109 } }
110 110 output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap()))); output.push((dep.0.to_string(), String::from(dep.1.as_str().unwrap())));
111 111 } }
112 112 }, },
113 None => return Err(String::from("beheer.json: 'deps->windows' should be an object."))
113 None => return Err(String::from("ambassade.json: 'deps->windows' should be an object."))
114 114 } }
115 115 } }
116 116 } }
File src/backend/fetch.rs changed (mode: 100644) (index e98a1f3..2ddfbe7)
... ... fn fetch(dep: PathBuf, command: String) -> Result<String, String> {
44 44 }, },
45 45 Err(e) => { Err(e) => {
46 46 let mut config_file = dep.clone(); let mut config_file = dep.clone();
47 config_file.push("beheer.json");
47 config_file.push("ambassade.json");
48 48
49 49 let mut error = String::from("Fetching failed: command '"); let mut error = String::from("Fetching failed: command '");
50 50 error.push_str(command); error.push_str(command);
 
... ... fn fetch(dep: PathBuf, command: String) -> Result<String, String> {
54 54
55 55 match config_file.to_str() { match config_file.to_str() {
56 56 Some(path) => error.push_str(path), Some(path) => error.push_str(path),
57 None => error.push_str("beheer.json")
57 None => error.push_str("ambassade.json")
58 58 } }
59 59
60 60 error.push_str("' file."); error.push_str("' file.");
File src/backend/filesystem.rs changed (mode: 100644) (index 3a5e3b9..3467053)
... ... use std::io::{Result, Error, ErrorKind};
4 4 fn get_root(mut path: path::PathBuf) -> Option<path::PathBuf> { fn get_root(mut path: path::PathBuf) -> Option<path::PathBuf> {
5 5 loop { loop {
6 6 let mut config = path.clone(); let mut config = path.clone();
7 config.push("beheer.json");
7 config.push("ambassade.json");
8 8
9 9 if config.as_path().is_file() { if config.as_path().is_file() {
10 10 return Some(path); return Some(path);
File src/backend/project.rs changed (mode: 100644) (index 7540211..d4affa5)
... ... pub fn exe<I>(args: &mut I) -> Result<String, String> where I: Iterator<Item=Str
46 46 if cfg!(target_os = "linux") { if cfg!(target_os = "linux") {
47 47 match config["run"]["linux"].as_str() { match config["run"]["linux"].as_str() {
48 48 Some(string) => args = String::from(string), Some(string) => args = String::from(string),
49 None => return Err(String::from("beheer.json: 'run->linux' should be a string."))
49 None => return Err(String::from("ambassade.json: 'run->linux' should be a string."))
50 50 } }
51 51 } }
52 52 if cfg!(target_os = "macos") { if cfg!(target_os = "macos") {
53 53 match config["run"]["os-x"].as_str() { match config["run"]["os-x"].as_str() {
54 54 Some(string) => args = String::from(string), Some(string) => args = String::from(string),
55 None => return Err(String::from("beheer.json: 'run->os-x' should be a string."))
55 None => return Err(String::from("ambassade.json: 'run->os-x' should be a string."))
56 56 } }
57 57 } }
58 58 if cfg!(target_os = "windows") { if cfg!(target_os = "windows") {
59 59 match config["run"]["windows"].as_str() { match config["run"]["windows"].as_str() {
60 60 Some(string) => args = String::from(string), Some(string) => args = String::from(string),
61 None => return Err(String::from("beheer.json: 'run->windows' should be a string."))
61 None => return Err(String::from("ambassade.json: 'run->windows' should be a string."))
62 62 } }
63 63 } }
64 64 }, },
 
... ... pub fn ignore(args: &Vec<String>) -> Result<(), String> {
130 130 match super::filesystem::get_current_dep_root() { match super::filesystem::get_current_dep_root() {
131 131 Ok(mut dir) => { Ok(mut dir) => {
132 132 dir.push(&entry); dir.push(&entry);
133 super::git::ignore::add(&mut dir, &mut entry) // entry moet "beheer.json" worden.
133 super::git::ignore::add(&mut dir, &mut entry) // entry moet "ambassade.json" worden.
134 134 }, },
135 135 Err(e) => Err(e.to_string()) Err(e) => Err(e.to_string())
136 136 } }
 
... ... pub fn dep_tree<I>(args: &mut I) -> Result<deptree::Node, String> where I: Itera
154 154
155 155 pub fn help() { pub fn help() {
156 156 println!("Syntax:"); println!("Syntax:");
157 println!("$ beheer [FLAG] [COMMAND [ARGUMENTS]]");
157 println!("$ ambassade [FLAG] [COMMAND [ARGUMENTS]]");
158 158 println!(""); println!("");
159 159
160 160 println!("--help -h\t\t\t\tShow this message"); println!("--help -h\t\t\t\tShow this message");
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/kapstok/NHL-Beheer

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/kapstok/NHL-Beheer

Clone this repository using git:
git clone git://git.rocketgit.com/user/kapstok/NHL-Beheer

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main