Skip to content

Commit

Permalink
feat: modular functions (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
nyoungstudios authored Sep 24, 2022
2 parents f740d3b + 762d19d commit 3e7f9b1
Show file tree
Hide file tree
Showing 88 changed files with 529 additions and 427 deletions.
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ If you have a bug fix, performance improvement, feature addition, documentation

### Coding

#### Dart

It does not really matter what editor you use; however, if you want to contribute to the Dart codebase and do not want to set up Dart on your local machine, you can use a containerized development environment with all of the requirements built-in. Here are two options:

1. Gitpod. This repo has a Gitpod config already setup, so all you have to do is visit: https://gitpod.io/#https://github.com/nyoungstudios/alfa. Or replace my GitHub url with your fork.
2. VS Code's dev container. In order to use this, clone your fork to your local machine and follow this [setup guide](https://code.visualstudio.com/docs/remote/containers) before opening the folder in VS Code. In short, you will need to install Docker and the [VS Code Remote Containers extension](https://aka.ms/vscode-remote/download/containers). Finally, when opening the repo in VS Code, it will prompt you to open it in the dev container. Then, it will build the Docker image with all the dependencies needed.

To build the Dart executable, just run `make` from the repository's root directory. Then, run the `./rename.sh` script to rename the executable to the filename the `install.sh` script expects.

#### Entries (Bash script functions)

If you like to contribute a new entry with a function to install something, you can run this script `./tools/create_function.sh entry_name` from the repo's root directory to create the boilerplate code. For the guidelines and best practices for writing your function, please see the example [here](functions/_example/).

### Style

This respository uses EditorConfig to define the number of spaces for indentation as well as removing excess white characters. A lot of editors come bundled with native support, but if not you can always install an EditorConfig extension. For more information, visit their [website](https://editorconfig.org). Additionally, if you are using VS Code and are contributing to the Dart codebase, this repo includes a `settings.json` file with the recommended Dart style guidelines.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Config files are defined as `toml` files. This has the benefits of JSON, but fri

The schema for the config file can be found [here](docs/ConfigSchema.md).

All the installation scripts are bash scripts, and they are defined in the [functions.sh](functions.sh) file. This script includes the functions to install popular tools such as brew, Oh My Zsh (and plugins), Anaconda, NVM, Docker, and much more! The documentation for all of the things you can install (along with its input arguments) can be found [here](docs/entries/). If there is not a function to install your favorite tool(s), it is easy to extend the bash script with a new function (and open a PR with your contribution).
All the different things that you can install are defined in the [functions](functions/) folder. Take a look at the `README.md` for each of the function entries to see how to add them to your configuration file and what options to pass to it. The built-in functions includes the ability to install popular tools such as brew, Oh My Zsh (and plugins), Anaconda, NVM, Docker, and much more! If there is not an entry to install your favorite tool(s), it is easy to add a new entry - just run `./tools/create_function.sh entry_name` from the repository's root directory to get started.

### Install list file

Expand Down
54 changes: 35 additions & 19 deletions bin/alfa.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,14 @@ void main(List<String> args) async {
Map<String, List<String>> tagToInstallKey = {};

for (MapEntry e in config.entries) {
for (String tag in e.value['tags']) {
tagToInstallKey.putIfAbsent(tag, () => []).add(e.key);
var tags = e.value['tags'];
if (tags != null) {
for (String tag in e.value['tags']) {
tagToInstallKey.putIfAbsent(tag, () => []).add(e.key);
}
}
}

// gets map of names to install functions
var dictionaryFile = await TomlDocument.load('dictionary.toml');
var dictionary = dictionaryFile.toMap();

// stores an ordered set of the names of the things to install
var namesToInstall = Set<String>();

Expand All @@ -108,8 +107,8 @@ void main(List<String> args) async {
if (tagToInstallKey.containsKey(line)) {
namesToInstall.addAll(tagToInstallKey[line]);
// in the case where the tag and config name has the same name
if (dictionary.containsKey(line.split('+')[0]) &&
config.containsKey(line)) {
if (config.containsKey(line) &&
await File("functions/${line.split('+')[0]}/install.sh").exists()) {
namesToInstall.add(line);
}
} else {
Expand All @@ -118,32 +117,48 @@ void main(List<String> args) async {
}
}

// for storing map of names to install functions
Map<String, Map> dictionary = {};
List<String> filteredNamesToInstall = [];

// filters invalid names to install
for (String name in namesToInstall) {
var baseName = name.split('+')[0];

if (!dictionary.containsKey(baseName)) {
String installScriptPath = "functions/${baseName}/install.sh";
String configTomlPath = "functions/${baseName}/config.toml";
File installScript = File(installScriptPath);
File configToml = File(configTomlPath);

if (!config.containsKey(name)) {
print(
"dictionary.toml does not have a reference for \"${baseName}\" to install.");
"${argResults['config']} does not have a reference for \"${name}\" to install.");
print("Installer exiting");
exit(1);
} else if (!config.containsKey(name)) {
} else if (!await installScript.exists()) {
print(
"${argResults['config']} does not have a reference for \"${name}\" to install.");
"Trying to install \"${baseName}\", but install script \"${installScriptPath}\" does not exist.");
print("Installer exiting");
exit(1);
} else if (!await configToml.exists()) {
print(
"Trying to install \"${baseName}\", but config \"${configTomlPath}\" does not exist.");
print("Installer exiting");
exit(1);
} else if (config[name].containsKey("os") &&
!config[name]['os'].contains(osName)) {
print(
"Skipping install of \"${name}\" since the operating system, ${osName}, is not in ${config[name]['os']}.");
} else if (!dictionary[baseName].containsKey("install_function") &&
!dictionary[baseName].containsKey(osName)) {
print(
"Skipping install of \"${name}\" since there is no install function for \"${baseName}\" on operating system, ${osName}.");
} else {
filteredNamesToInstall.add(name);
var tempConfig = await TomlDocument.load(configTomlPath);
dictionary[baseName] = tempConfig.toMap();
if (!dictionary[baseName].containsKey("install_function") &&
!dictionary[baseName].containsKey(osName)) {
print(
"Skipping install of \"${name}\" since there is no install function for \"${baseName}\" on operating system, ${osName}.");
} else {
filteredNamesToInstall.add(name);
}
}
}

Expand Down Expand Up @@ -173,7 +188,7 @@ void main(List<String> args) async {

var functionName = functionMap["install_function"];

String command = 'source functions.sh; ${functionName}';
String command = 'source functions/${baseName}/install.sh; ${functionName}';

// checks if there are any options to pass when installing this
if (config[name].containsKey("options") &&
Expand All @@ -190,7 +205,8 @@ void main(List<String> args) async {
arguments = ['-u', user];
}

arguments.addAll(['--preserve-env=ALFA_USER,ALFA_ARCH', '--', '/bin/bash']);
arguments
.addAll(['--preserve-env=ALFA_USER,ALFA_ARCH', '--', '/bin/bash']);
}

arguments.addAll(['-euc', command]);
Expand Down
90 changes: 0 additions & 90 deletions dictionary.toml

This file was deleted.

2 changes: 1 addition & 1 deletion docs/ConfigSchema.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ options = []

### Name

The `name` field refers to the `name` field in the `dictionary.toml` file. Looking at the `dictionary.toml` file, you can find the associated bash function that is called in the `functions.sh` file. The name field is also what you would put in the install list file (passed with the `-f` argument in the `install.sh` script). Alternatively, you can always write a more friendly name in the `tags` array. See the next section for more detail on that.
The `name` field refers any of the folder names in the [functions](../functions/) directory. Read the `README.md` file within each of the folders and/or take a look at the `install.sh` file to see what any given entry does upon being called. The name field in your config is also what you would put in the install list file (passed with the `-f` argument in the `install.sh` script). Alternatively, you can always write a more friendly name in the `tags` array. See the next section for more detail on that.

If you like to call a function more than once, but with different options; then, you can append a plus sign after the name followed by a string to help you remember what that entry does (sort of like email address aliases). This is so we do not have duplicate keys within the dictionary in the toml file. For example, if we wanted to call the `apt_get_packages` function twice, we could do something like this.

Expand Down
7 changes: 7 additions & 0 deletions docs/InstallListSchema.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ name
// name2
custom
```

And in this case, only these items would be installed:
```txt
name
item1
item2
```
Loading

0 comments on commit 3e7f9b1

Please sign in to comment.