├── .devcontainer └── devcontainer.json ├── .fluentci ├── .devcontainer │ └── devcontainer.json ├── .github │ └── workflows │ │ ├── ci.yml │ │ ├── example.yml │ │ └── zenith.yml ├── .vscode │ └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ci.ts ├── dagger.json ├── deno.json ├── deno.lock ├── deps.ts ├── fixtures │ ├── .gitlab-ci.yml │ ├── azure-pipelines.yml │ ├── buildspec.yml │ ├── config.yml │ └── workflow.yml ├── gen │ └── nexus.ts ├── import_map.json ├── mod.ts ├── schema.graphql └── src │ ├── aws │ ├── README.md │ ├── config.ts │ ├── config_test.ts │ └── init.ts │ ├── azure │ ├── README.md │ ├── config.ts │ ├── config_test.ts │ └── init.ts │ ├── circleci │ ├── README.md │ ├── config.ts │ ├── config_test.ts │ └── init.ts │ ├── dagger │ ├── index.ts │ ├── jobs.ts │ ├── list_jobs.ts │ ├── pipeline.ts │ ├── queries.ts │ ├── runner.ts │ └── schema.ts │ ├── github │ ├── README.md │ ├── config.ts │ ├── config_test.ts │ └── init.ts │ └── gitlab │ ├── README.md │ ├── config.ts │ ├── config_test.ts │ └── init.ts ├── .github ├── FUNDING.yml └── workflows │ ├── flakehub-publish-tagged.yml │ ├── release-for-mac.yml.disable │ ├── release.yml │ └── tests.yml.disable ├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── crates ├── cli │ ├── Cargo.toml │ └── src │ │ ├── cmd │ │ ├── add.rs │ │ ├── diff.rs │ │ ├── history.rs │ │ ├── init.rs │ │ ├── install.rs │ │ ├── mod.rs │ │ └── search.rs │ │ ├── macros.rs │ │ ├── main.rs │ │ └── types.rs ├── core │ ├── Cargo.toml │ └── src │ │ ├── config.rs │ │ ├── graph.rs │ │ └── lib.rs ├── entity │ ├── Cargo.toml │ └── src │ │ ├── file.rs │ │ ├── lib.rs │ │ └── modification.rs ├── installers │ ├── Cargo.toml │ └── src │ │ ├── apk.rs │ │ ├── apt.rs │ │ ├── brew.rs │ │ ├── curl.rs │ │ ├── dnf.rs │ │ ├── emerge.rs │ │ ├── fleek.rs │ │ ├── git.rs │ │ ├── home_manager.rs │ │ ├── lib.rs │ │ ├── nix.rs │ │ ├── pacman.rs │ │ ├── slackpkg.rs │ │ ├── yum.rs │ │ └── zypper.rs ├── macros │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── migration │ ├── Cargo.toml │ ├── README.md │ └── src │ │ ├── lib.rs │ │ ├── m20220101_000001_create_table.rs │ │ └── main.rs ├── nix │ ├── Cargo.toml │ ├── src │ │ ├── lib.rs │ │ └── search │ │ │ ├── client.rs │ │ │ ├── esclient.rs │ │ │ ├── matchers.rs │ │ │ ├── mod.rs │ │ │ ├── query.rs │ │ │ └── types.rs │ └── tests │ │ ├── home-with-vim-git.nix │ │ ├── home-with-vim.nix │ │ └── home.nix ├── repo │ ├── Cargo.toml │ └── src │ │ ├── file.rs │ │ ├── lib.rs │ │ └── modification.rs ├── ssh │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── tui │ ├── Cargo.toml │ └── src │ │ ├── history.rs │ │ └── lib.rs └── types │ ├── Cargo.toml │ └── src │ ├── apk.rs │ ├── apt.rs │ ├── brew.rs │ ├── configuration.rs │ ├── curl.rs │ ├── dnf.rs │ ├── emerge.rs │ ├── fleek.rs │ ├── git.rs │ ├── home_manager.rs │ ├── install.rs │ ├── inventory.rs │ ├── lib.rs │ ├── nix.rs │ ├── pacman.rs │ ├── slackpkg.rs │ ├── yum.rs │ └── zypper.rs ├── flake.lock ├── flake.nix ├── install.sh ├── preview.png └── tea.yaml /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/rust 3 | { 4 | "name": "Rust", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/rust:1-1-bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers/features/github-cli:1": {}, 9 | "ghcr.io/devcontainers/features/nix:1": {} 10 | }, 11 | 12 | // Use 'mounts' to make the cargo cache persistent in a Docker Volume. 13 | // "mounts": [ 14 | // { 15 | // "source": "devcontainer-cargo-cache-${devcontainerId}", 16 | // "target": "/usr/local/cargo", 17 | // "type": "volume" 18 | // } 19 | // ] 20 | 21 | // Features to add to the dev container. More info: https://containers.dev/features. 22 | // "features": {}, 23 | 24 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 25 | // "forwardPorts": [], 26 | 27 | // Use 'postCreateCommand' to run commands after the container is created. 28 | "postCreateCommand": "nix develop --experimental-features \"nix-command flakes\"" 29 | 30 | // Configure tool-specific properties. 31 | // "customizations": {}, 32 | 33 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 34 | // "remoteUser": "root" 35 | } 36 | -------------------------------------------------------------------------------- /.fluentci/.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the 2 | // README at: https://github.com/devcontainers/templates/tree/main/src/debian 3 | { 4 | "name": "Debian", 5 | // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile 6 | "image": "mcr.microsoft.com/devcontainers/base:bullseye", 7 | "features": { 8 | "ghcr.io/devcontainers/features/github-cli:1": {}, 9 | "ghcr.io/devcontainers/features/nix:1": {} 10 | }, 11 | 12 | // Features to add to the dev container. More info: https://containers.dev/features. 13 | // "features": {}, 14 | 15 | // Use 'forwardPorts' to make a list of ports inside the container available locally. 16 | // "forwardPorts": [], 17 | 18 | // Use 'postCreateCommand' to run commands after the container is created. 19 | "postCreateCommand": "nix develop --experimental-features \"nix-command flakes\"" 20 | // Configure tool-specific properties. 21 | // "customizations": {}, 22 | 23 | // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. 24 | // "remoteUser": "root" 25 | } 26 | -------------------------------------------------------------------------------- /.fluentci/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by Fluent Github Actions 2 | 3 | name: Codecov 4 | on: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | tests: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: denoland/setup-deno@v1 14 | with: 15 | deno-version: v1.37 16 | - name: Setup Fluent CI CLI 17 | run: deno install -A -r https://cli.fluentci.io -n fluentci 18 | - name: Setup Dagger 19 | run: | 20 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.8 sh 21 | sudo mv bin/dagger /usr/local/bin 22 | dagger version 23 | - name: Run Dagger Pipelines 24 | run: dagger run fluentci . fmt lint test 25 | - name: Upload to Codecov 26 | run: dagger run fluentci codecov_pipeline 27 | env: 28 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 29 | -------------------------------------------------------------------------------- /.fluentci/.github/workflows/example.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_github_actions 2 | 3 | name: Example 4 | on: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | tests: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: denoland/setup-deno@v1 14 | with: 15 | deno-version: v1.37 16 | - name: Setup Fluent CI CLI 17 | run: deno install -A -r https://cli.fluentci.io -n fluentci 18 | - name: Setup Dagger 19 | run: | 20 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.8 sh 21 | sudo mv bin/dagger /usr/local/bin 22 | dagger version 23 | - name: Run Dagger Pipelines 24 | run: dagger run deno run -A ../src/dagger/runner.ts 25 | working-directory: example 26 | -------------------------------------------------------------------------------- /.fluentci/.github/workflows/zenith.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_github_actions 2 | 3 | name: Zenith Example 4 | on: 5 | push: 6 | branches: 7 | - zenith 8 | 9 | jobs: 10 | tests: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Setup Dagger Zenith 15 | run: | 16 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.8 sh 17 | sudo mv bin/dagger /usr/local/bin 18 | dagger version 19 | - name: Run Dagger Pipelines 20 | run: | 21 | dagger query --doc test.gql 22 | dagger query --doc build.gql 23 | working-directory: example 24 | -------------------------------------------------------------------------------- /.fluentci/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true 3 | } 4 | -------------------------------------------------------------------------------- /.fluentci/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug 4 | report, new feature, correction, or additional documentation, we greatly value 5 | feedback and contributions from our community. 6 | 7 | Please read through this document before submitting any issues or pull requests 8 | to ensure we have all the necessary information to effectively respond to your 9 | bug report or contribution. 10 | 11 | ## Reporting Bugs/Feature Requests 12 | 13 | We welcome you to use the GitHub issue tracker to report bugs or suggest 14 | features. 15 | 16 | When filing an issue, please check existing open, or recently closed, issues to 17 | make sure somebody else hasn't already reported the issue. Please try to include 18 | as much information as you can. Details like these are incredibly useful: 19 | 20 | - A reproducible test case or series of steps 21 | - The version of our code being used 22 | - Any modifications you've made relevant to the bug 23 | - Anything unusual about your environment or deployment 24 | 25 | ## Contributing via Pull Requests 26 | 27 | Contributions via pull requests are much appreciated. Before sending us a pull 28 | request, please ensure that: 29 | 30 | 1. You are working against the latest source on the _master_ branch. 31 | 2. You check existing open, and recently merged, pull requests to make sure 32 | someone else hasn't addressed the problem already. 33 | 3. You open an issue to discuss any significant work - we would hate for your 34 | time to be wasted. 35 | 36 | To send us a pull request, please: 37 | 38 | 1. Fork the repository. 39 | 2. Modify the source; please focus on the specific change you are contributing. 40 | If you also reformat all the code, it will be hard for us to focus on your 41 | change. 42 | 3. Ensure local tests pass. 43 | 4. Commit to your fork using clear commit messages. 44 | 5. Send us a pull request, answering any default questions in the pull request 45 | interface. 46 | 6. Pay attention to any automated CI failures reported in the pull request, and 47 | stay involved in the conversation. 48 | 49 | GitHub provides additional document on 50 | [forking a repository](https://help.github.com/articles/fork-a-repo/) and 51 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 52 | 53 | ## Finding contributions to work on 54 | 55 | Looking at the existing issues is a great way to find something to contribute 56 | on. As our projects, by default, use the default GitHub issue labels 57 | (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 58 | 'help wanted' issues is a great place to start. 59 | 60 | ## Code of Conduct 61 | 62 | This project has adopted the 63 | [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, 64 | available at 65 | https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 66 | 67 | ## Licensing 68 | 69 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to 70 | confirm the licensing of your contribution. 71 | -------------------------------------------------------------------------------- /.fluentci/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2023 Tsiry Sandratraina 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /.fluentci/README.md: -------------------------------------------------------------------------------- 1 | # Rust Pipeline 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.37) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | A ready-to-use CI/CD Pipeline for your Rust projects. 9 | ## 🚀 Usage 10 | 11 | Run the following command in your Rust Project: 12 | 13 | ```bash 14 | fluentci run rust_pipeline 15 | ``` 16 | 17 | Or if you want to run specific jobs: 18 | 19 | ```bash 20 | fluentci run rust_pipeline test build 21 | ``` 22 | 23 | 24 | if you want to use it as a template: 25 | 26 | ```bash 27 | fluentci init -t rust 28 | ``` 29 | 30 | This will create a `.fluentci` folder in your project. 31 | 32 | Now you can run the pipeline with: 33 | 34 | ```bash 35 | fluentci run . 36 | ``` 37 | 38 | ## Jobs 39 | 40 | | Job | Description | 41 | | ----- | ------------------ | 42 | | build | build your project | 43 | | test | Run your tests | 44 | 45 | ## Programmatic usage 46 | 47 | You can also use this pipeline programmatically: 48 | 49 | ```ts 50 | import { build, test } from "https://pkg.fluentci.io/rust_pipeline@v0.6.1/mod.ts"; 51 | 52 | await test(); 53 | await build(); 54 | ``` 55 | -------------------------------------------------------------------------------- /.fluentci/ci.ts: -------------------------------------------------------------------------------- 1 | import { 2 | build, 3 | test, 4 | } from "https://pkg.fluentci.io/rust_pipeline@v0.6.1/mod.ts"; 5 | 6 | await test(); 7 | await build(); 8 | -------------------------------------------------------------------------------- /.fluentci/dagger.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "", 3 | "name": "rust", 4 | "sdkRuntime": "tsiry/dagger-sdk-deno" 5 | } -------------------------------------------------------------------------------- /.fluentci/deno.json: -------------------------------------------------------------------------------- 1 | { 2 | "importMap": "import_map.json", 3 | "tasks": { 4 | "esm:add": "deno run -A https://esm.sh/v128 add", 5 | "esm:update": "deno run -A https://esm.sh/v128 update", 6 | "esm:remove": "deno run -A https://esm.sh/v128 remove", 7 | "schema": "deno run -A src/dagger/schema.ts", 8 | "clean": "rm -rf gen schema.graphql" 9 | }, 10 | "fmt": { 11 | "exclude": [ 12 | "example/", 13 | ".fluentci/", 14 | "gen/" 15 | ] 16 | }, 17 | "lint": { 18 | "exclude": [ 19 | "example/", 20 | ".fluentci/", 21 | "gen/" 22 | ] 23 | }, 24 | "test": { 25 | "exclude": [ 26 | "example/", 27 | ".fluentci/", 28 | "gen/" 29 | ] 30 | } 31 | } -------------------------------------------------------------------------------- /.fluentci/deps.ts: -------------------------------------------------------------------------------- 1 | export { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import Client from "https://sdk.fluentci.io/v0.2.0/mod.ts"; 3 | export default Client; 4 | 5 | export { 6 | connect, 7 | uploadContext, 8 | CacheSharingMode, 9 | Container, 10 | } from "https://sdk.fluentci.io/v0.2.0/mod.ts"; 11 | export { brightGreen } from "https://deno.land/std@0.191.0/fmt/colors.ts"; 12 | export { withDevbox } from "https://nix.fluentci.io/v0.5.2/src/dagger/steps.ts"; 13 | export { stringifyTree } from "https://esm.sh/stringify-tree@1.1.1"; 14 | import gql from "https://esm.sh/graphql-tag@2.12.6"; 15 | export { gql }; 16 | 17 | export { 18 | arg, 19 | queryType, 20 | stringArg, 21 | intArg, 22 | nonNull, 23 | makeSchema, 24 | } from "npm:nexus"; 25 | export { 26 | dirname, 27 | join, 28 | resolve, 29 | } from "https://deno.land/std@0.203.0/path/mod.ts"; 30 | 31 | export * as FluentGitlabCI from "https://deno.land/x/fluent_gitlab_ci@v0.4.2/mod.ts"; 32 | export * as FluentGithubActions from "https://deno.land/x/fluent_github_actions@v0.2.1/mod.ts"; 33 | export * as FluentCircleCI from "https://deno.land/x/fluent_circleci@v0.2.5/mod.ts"; 34 | export * as FluentAzurePipelines from "https://deno.land/x/fluent_azure_pipelines@v0.2.0/mod.ts"; 35 | export * as FluentAWSCodePipeline from "https://deno.land/x/fluent_aws_codepipeline@v0.2.3/mod.ts"; 36 | -------------------------------------------------------------------------------- /.fluentci/fixtures/.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 2 | 3 | .docker: 4 | image: denoland/deno:alpine 5 | services: 6 | - docker:${DOCKER_VERSION}-dind 7 | variables: 8 | DOCKER_HOST: tcp://docker:2376 9 | DOCKER_TLS_VERIFY: "1" 10 | DOCKER_TLS_CERTDIR: /certs 11 | DOCKER_CERT_PATH: /certs/client 12 | DOCKER_DRIVER: overlay2 13 | DOCKER_VERSION: 20.10.16 14 | 15 | .dagger: 16 | extends: .docker 17 | before_script: 18 | - apk add docker-cli curl unzip 19 | - deno install -A -r https://cli.fluentci.io -n fluentci 20 | - curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 21 | - mv bin/dagger /usr/local/bin 22 | - dagger version 23 | 24 | tests: 25 | extends: .dagger 26 | script: 27 | - fluentci run rust_pipeline test build 28 | 29 | -------------------------------------------------------------------------------- /.fluentci/fixtures/azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_azure_pipelines 2 | 3 | trigger: 4 | - main 5 | pool: 6 | name: Default 7 | vmImage: ubuntu-latest 8 | steps: 9 | - script: | 10 | curl -fsSL https://deno.land/x/install/install.sh | sh 11 | export DENO_INSTALL="$HOME/.deno" 12 | export PATH="$DENO_INSTALL/bin:$PATH" 13 | displayName: Install Deno 14 | - script: deno install -A -r https://cli.fluentci.io -n fluentci 15 | displayName: Setup Fluent CI CLI 16 | - script: | 17 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 18 | sudo mv bin/dagger /usr/local/bin 19 | dagger version 20 | displayName: Setup Dagger 21 | - script: fluentci run rust_pipeline test build 22 | displayName: Run Dagger Pipelines 23 | -------------------------------------------------------------------------------- /.fluentci/fixtures/buildspec.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_aws_codepipeline 2 | 3 | version: 0.2 4 | phases: 5 | install: 6 | commands: 7 | - curl -fsSL https://deno.land/x/install/install.sh | sh 8 | - export DENO_INSTALL="$HOME/.deno" 9 | - export PATH="$DENO_INSTALL/bin:$PATH" 10 | - deno install -A -r https://cli.fluentci.io -n fluentci 11 | - curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 12 | - mv bin/dagger /usr/local/bin 13 | - dagger version 14 | build: 15 | commands: 16 | - fluentci run rust_pipeline test build 17 | post_build: 18 | commands: 19 | - echo Build completed on `date` 20 | -------------------------------------------------------------------------------- /.fluentci/fixtures/config.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_circleci 2 | 3 | version: 2.1 4 | jobs: 5 | tests: 6 | steps: 7 | - checkout 8 | - run: sudo apt-get update && sudo apt-get install -y curl unzip 9 | - run: | 10 | curl -fsSL https://deno.land/x/install/install.sh | sh 11 | export DENO_INSTALL="$HOME/.deno" 12 | export PATH="$DENO_INSTALL/bin:$PATH" 13 | - run: deno install -A -r https://cli.fluentci.io -n fluentci 14 | - run: | 15 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 16 | sudo mv bin/dagger /usr/local/bin 17 | dagger version 18 | - run: 19 | name: Run Dagger Pipelines 20 | command: fluentci run rust_pipeline test build 21 | machine: 22 | image: ubuntu-2004:2023.07.1 23 | workflows: 24 | dagger: 25 | jobs: 26 | - tests 27 | -------------------------------------------------------------------------------- /.fluentci/fixtures/workflow.yml: -------------------------------------------------------------------------------- 1 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_github_actions 2 | 3 | name: Test 4 | on: 5 | push: 6 | branches: 7 | - main 8 | jobs: 9 | test: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: denoland/setup-deno@v1 14 | with: 15 | deno-version: v1.37 16 | - name: Setup Fluent CI CLI 17 | run: deno install -A -r https://cli.fluentci.io -n fluentci 18 | - name: Setup Dagger 19 | run: | 20 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 21 | sudo mv bin/dagger /usr/local/bin 22 | dagger version 23 | - name: Run Tests and Build 24 | run: fluentci run rust_pipeline test build 25 | -------------------------------------------------------------------------------- /.fluentci/gen/nexus.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file was generated by Nexus Schema 3 | * Do not make changes to this file directly 4 | */ 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | declare global { 13 | interface NexusGen extends NexusGenTypes {} 14 | } 15 | 16 | export interface NexusGenInputs { 17 | } 18 | 19 | export interface NexusGenEnums { 20 | } 21 | 22 | export interface NexusGenScalars { 23 | String: string 24 | Int: number 25 | Float: number 26 | Boolean: boolean 27 | ID: string 28 | } 29 | 30 | export interface NexusGenObjects { 31 | Query: {}; 32 | } 33 | 34 | export interface NexusGenInterfaces { 35 | } 36 | 37 | export interface NexusGenUnions { 38 | } 39 | 40 | export type NexusGenRootTypes = NexusGenObjects 41 | 42 | export type NexusGenAllTypes = NexusGenRootTypes & NexusGenScalars 43 | 44 | export interface NexusGenFieldTypes { 45 | Query: { // field return type 46 | build: string | null; // String 47 | test: string | null; // String 48 | } 49 | } 50 | 51 | export interface NexusGenFieldTypeNames { 52 | Query: { // field return type name 53 | build: 'String' 54 | test: 'String' 55 | } 56 | } 57 | 58 | export interface NexusGenArgTypes { 59 | Query: { 60 | build: { // args 61 | src: string; // String! 62 | } 63 | test: { // args 64 | src: string; // String! 65 | } 66 | } 67 | } 68 | 69 | export interface NexusGenAbstractTypeMembers { 70 | } 71 | 72 | export interface NexusGenTypeInterfaces { 73 | } 74 | 75 | export type NexusGenObjectNames = keyof NexusGenObjects; 76 | 77 | export type NexusGenInputNames = never; 78 | 79 | export type NexusGenEnumNames = never; 80 | 81 | export type NexusGenInterfaceNames = never; 82 | 83 | export type NexusGenScalarNames = keyof NexusGenScalars; 84 | 85 | export type NexusGenUnionNames = never; 86 | 87 | export type NexusGenObjectsUsingAbstractStrategyIsTypeOf = never; 88 | 89 | export type NexusGenAbstractsUsingStrategyResolveType = never; 90 | 91 | export type NexusGenFeaturesConfig = { 92 | abstractTypeStrategies: { 93 | isTypeOf: false 94 | resolveType: true 95 | __typename: false 96 | } 97 | } 98 | 99 | export interface NexusGenTypes { 100 | context: any; 101 | inputTypes: NexusGenInputs; 102 | rootTypes: NexusGenRootTypes; 103 | inputTypeShapes: NexusGenInputs & NexusGenEnums & NexusGenScalars; 104 | argTypes: NexusGenArgTypes; 105 | fieldTypes: NexusGenFieldTypes; 106 | fieldTypeNames: NexusGenFieldTypeNames; 107 | allTypes: NexusGenAllTypes; 108 | typeInterfaces: NexusGenTypeInterfaces; 109 | objectNames: NexusGenObjectNames; 110 | inputNames: NexusGenInputNames; 111 | enumNames: NexusGenEnumNames; 112 | interfaceNames: NexusGenInterfaceNames; 113 | scalarNames: NexusGenScalarNames; 114 | unionNames: NexusGenUnionNames; 115 | allInputTypes: NexusGenTypes['inputNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['scalarNames']; 116 | allOutputTypes: NexusGenTypes['objectNames'] | NexusGenTypes['enumNames'] | NexusGenTypes['unionNames'] | NexusGenTypes['interfaceNames'] | NexusGenTypes['scalarNames']; 117 | allNamedTypes: NexusGenTypes['allInputTypes'] | NexusGenTypes['allOutputTypes'] 118 | abstractTypes: NexusGenTypes['interfaceNames'] | NexusGenTypes['unionNames']; 119 | abstractTypeMembers: NexusGenAbstractTypeMembers; 120 | objectsUsingAbstractStrategyIsTypeOf: NexusGenObjectsUsingAbstractStrategyIsTypeOf; 121 | abstractsUsingStrategyResolveType: NexusGenAbstractsUsingStrategyResolveType; 122 | features: NexusGenFeaturesConfig; 123 | } 124 | 125 | 126 | declare global { 127 | interface NexusGenPluginTypeConfig { 128 | } 129 | interface NexusGenPluginInputTypeConfig { 130 | } 131 | interface NexusGenPluginFieldConfig { 132 | } 133 | interface NexusGenPluginInputFieldConfig { 134 | } 135 | interface NexusGenPluginSchemaConfig { 136 | } 137 | interface NexusGenPluginArgConfig { 138 | } 139 | } -------------------------------------------------------------------------------- /.fluentci/import_map.json: -------------------------------------------------------------------------------- 1 | { 2 | "imports": { 3 | "@fluentci.io/dagger": "https://sdk.fluentci.io/v0.1.9/mod.ts", 4 | "@dagger.io/dagger": "https://esm.sh/v128/*@dagger.io/dagger@0.8.4", 5 | "graphql-tag": "https://esm.sh/v128/graphql-tag@2.12.6", 6 | "graphql-request": "https://esm.sh/v128/graphql-request@6.1.0", 7 | "fluent_gitlab_ci": "https://deno.land/x/fluent_gitlab_ci@v0.4.2/mod.ts", 8 | "fluent_github_actions": "https://deno.land/x/fluent_github_actions@v0.2.1/mod.ts", 9 | "fluent_circleci": "https://deno.land/x/fluent_circleci@v0.2.5/mod.ts", 10 | "fluent_azure_pipelines": "https://deno.land/x/fluent_azure_pipelines@v0.2.0/mod.ts", 11 | "fluent_aws_codepipeline": "https://deno.land/x/fluent_aws_codepipeline@v0.2.3/mod.ts", 12 | "crypto": "node:crypto", 13 | "fs": "node:fs", 14 | "os": "node:os", 15 | "path": "node:path", 16 | "process": "node:process", 17 | "readline": "node:readline", 18 | "url": "node:url" 19 | }, 20 | "scopes": { 21 | "https://esm.sh/v128/": { 22 | "@lifeomic/axios-fetch": "https://esm.sh/v128/@lifeomic/axios-fetch@3.0.1", 23 | "adm-zip": "https://esm.sh/v128/adm-zip@0.5.10", 24 | "env-paths": "https://esm.sh/v128/env-paths@3.0.0", 25 | "execa": "https://esm.sh/v128/execa@7.1.1", 26 | "graphql-request": "https://esm.sh/v128/graphql-request@6.1.0", 27 | "graphql-tag": "https://esm.sh/v128/graphql-tag@2.12.6", 28 | "graphql": "https://esm.sh/v128/graphql@16.7.1", 29 | "node-color-log": "https://esm.sh/v128/node-color-log@10.0.2", 30 | "node-fetch": "https://esm.sh/v128/node-fetch@3.3.1", 31 | "tar": "https://esm.sh/v128/tar@6.1.15" 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /.fluentci/mod.ts: -------------------------------------------------------------------------------- 1 | export * from "./src/dagger/index.ts"; 2 | export * as queries from "./src/dagger/queries.ts"; 3 | export { schema } from "./src/dagger/schema.ts"; 4 | -------------------------------------------------------------------------------- /.fluentci/schema.graphql: -------------------------------------------------------------------------------- 1 | ### This file was generated by Nexus Schema 2 | ### Do not make changes to this file directly 3 | 4 | 5 | type Query { 6 | build(src: String!): String 7 | test(src: String!): String 8 | } -------------------------------------------------------------------------------- /.fluentci/src/aws/README.md: -------------------------------------------------------------------------------- 1 | # AWS CodePipeline 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | The following command will generate a `buildspec.yml` file in your project: 9 | 10 | ```bash 11 | fluentci ac init -t rust_pipeline 12 | ``` 13 | 14 | Generated file: 15 | 16 | ```yaml 17 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_aws_codepipeline 18 | 19 | version: 0.2 20 | phases: 21 | install: 22 | commands: 23 | - curl -fsSL https://deno.land/x/install/install.sh | sh 24 | - export DENO_INSTALL="$HOME/.deno" 25 | - export PATH="$DENO_INSTALL/bin:$PATH" 26 | - deno install -A -r https://cli.fluentci.io -n fluentci 27 | - curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 28 | - mv bin/dagger /usr/local/bin 29 | - dagger version 30 | build: 31 | commands: 32 | - fluentci run rust_pipeline test build 33 | post_build: 34 | commands: 35 | - echo Build completed on `date` 36 | 37 | ``` 38 | 39 | Feel free to edit the template generator at `.fluentci/src/aws/config.ts` to your needs. 40 | -------------------------------------------------------------------------------- /.fluentci/src/aws/config.ts: -------------------------------------------------------------------------------- 1 | import { BuildSpec } from "fluent_aws_codepipeline"; 2 | 3 | export function generateYaml(): BuildSpec { 4 | const buildspec = new BuildSpec(); 5 | buildspec 6 | .phase("install", { 7 | commands: [ 8 | "curl -fsSL https://deno.land/x/install/install.sh | sh", 9 | 'export DENO_INSTALL="$HOME/.deno"', 10 | 'export PATH="$DENO_INSTALL/bin:$PATH"', 11 | "deno install -A -r https://cli.fluentci.io -n fluentci", 12 | "curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh", 13 | "mv bin/dagger /usr/local/bin", 14 | "dagger version", 15 | ], 16 | }) 17 | .phase("build", { 18 | commands: ["fluentci run rust_pipeline test build"], 19 | }) 20 | .phase("post_build", { 21 | commands: ["echo Build completed on `date`"], 22 | }); 23 | return buildspec; 24 | } 25 | -------------------------------------------------------------------------------- /.fluentci/src/aws/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateAWSCodePipelineTest() { 5 | const buildspec = generateYaml(); 6 | const actual = buildspec.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/buildspec.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/aws/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().save("buildspec.yml"); 4 | -------------------------------------------------------------------------------- /.fluentci/src/azure/README.md: -------------------------------------------------------------------------------- 1 | # Azure Pipelines 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | The following command will generate a `azure-pipelines.yml` file in your project: 9 | 10 | ```bash 11 | fluentci ap init -t rust_pipeline 12 | ``` 13 | 14 | Generated file: 15 | 16 | ```yaml 17 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_azure_pipelines 18 | 19 | trigger: 20 | - main 21 | pool: 22 | name: Default 23 | vmImage: ubuntu-latest 24 | steps: 25 | - script: | 26 | curl -fsSL https://deno.land/x/install/install.sh | sh 27 | export DENO_INSTALL="$HOME/.deno" 28 | export PATH="$DENO_INSTALL/bin:$PATH" 29 | displayName: Install Deno 30 | - script: deno install -A -r https://cli.fluentci.io -n fluentci 31 | displayName: Setup Fluent CI CLI 32 | - script: | 33 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 34 | sudo mv bin/dagger /usr/local/bin 35 | dagger version 36 | displayName: Setup Dagger 37 | - script: fluentci run rust_pipeline test build 38 | displayName: Run Dagger Pipelines 39 | 40 | ``` 41 | 42 | Feel free to edit the template generator at `.fluentci/src/azure/config.ts` to your needs. 43 | -------------------------------------------------------------------------------- /.fluentci/src/azure/config.ts: -------------------------------------------------------------------------------- 1 | import { AzurePipeline } from "fluent_azure_pipelines"; 2 | 3 | export function generateYaml(): AzurePipeline { 4 | const azurePipeline = new AzurePipeline(); 5 | 6 | const installDeno = `\ 7 | curl -fsSL https://deno.land/x/install/install.sh | sh 8 | export DENO_INSTALL="$HOME/.deno" 9 | export PATH="$DENO_INSTALL/bin:$PATH" 10 | `; 11 | 12 | const setupDagger = `\ 13 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 14 | sudo mv bin/dagger /usr/local/bin 15 | dagger version 16 | `; 17 | 18 | azurePipeline 19 | .trigger(["main"]) 20 | .pool({ 21 | name: "Default", 22 | vmImage: "ubuntu-latest", 23 | }) 24 | .step({ 25 | script: installDeno, 26 | displayName: "Install Deno", 27 | }) 28 | .step({ 29 | script: "deno install -A -r https://cli.fluentci.io -n fluentci", 30 | displayName: "Setup Fluent CI CLI", 31 | }) 32 | .step({ 33 | script: setupDagger, 34 | displayName: "Setup Dagger", 35 | }) 36 | .step({ 37 | script: "fluentci run rust_pipeline test build", 38 | displayName: "Run Dagger Pipelines", 39 | }); 40 | return azurePipeline; 41 | } 42 | -------------------------------------------------------------------------------- /.fluentci/src/azure/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateAzurePipelinesTest() { 5 | const azurepipelines = generateYaml(); 6 | const actual = azurepipelines.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/azure-pipelines.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/azure/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().save("azure-pipeline.yml"); 4 | -------------------------------------------------------------------------------- /.fluentci/src/circleci/README.md: -------------------------------------------------------------------------------- 1 | # Circle CI 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | 9 | The following command will generate a `.circleci/config.yml` file in your project: 10 | 11 | ```bash 12 | fluentci cci init -t rust_pipeline 13 | ``` 14 | 15 | Generated file: 16 | 17 | ```yaml 18 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_circleci 19 | 20 | version: 2.1 21 | jobs: 22 | tests: 23 | steps: 24 | - checkout 25 | - run: sudo apt-get update && sudo apt-get install -y curl unzip 26 | - run: | 27 | curl -fsSL https://deno.land/x/install/install.sh | sh 28 | export DENO_INSTALL="$HOME/.deno" 29 | export PATH="$DENO_INSTALL/bin:$PATH" 30 | - run: deno install -A -r https://cli.fluentci.io -n fluentci 31 | - run: | 32 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 33 | sudo mv bin/dagger /usr/local/bin 34 | dagger version 35 | - run: 36 | name: Upload Coverage 37 | command: fluentci run rust_pipeline test build 38 | machine: 39 | image: ubuntu-2004:2023.07.1 40 | workflows: 41 | dagger: 42 | jobs: 43 | - tests 44 | 45 | ``` 46 | 47 | Feel free to edit the template generator at `.fluentci/src/circleci/config.ts` to your needs. 48 | -------------------------------------------------------------------------------- /.fluentci/src/circleci/config.ts: -------------------------------------------------------------------------------- 1 | import { CircleCI, Job } from "fluent_circleci"; 2 | 3 | export function generateYaml(): CircleCI { 4 | const circleci = new CircleCI(); 5 | 6 | const tests = new Job().machine({ image: "ubuntu-2004:2023.07.1" }).steps([ 7 | "checkout", 8 | { 9 | run: "sudo apt-get update && sudo apt-get install -y curl unzip", 10 | }, 11 | { 12 | run: `\ 13 | curl -fsSL https://deno.land/x/install/install.sh | sh 14 | export DENO_INSTALL="$HOME/.deno" 15 | export PATH="$DENO_INSTALL/bin:$PATH"`, 16 | }, 17 | { 18 | run: "deno install -A -r https://cli.fluentci.io -n fluentci", 19 | }, 20 | { 21 | run: `\ 22 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 23 | sudo mv bin/dagger /usr/local/bin 24 | dagger version`, 25 | }, 26 | { 27 | run: { 28 | name: "Run Dagger Pipelines", 29 | command: "fluentci run rust_pipeline test build", 30 | }, 31 | }, 32 | ]); 33 | 34 | circleci.jobs({ tests }).workflow("dagger", ["tests"]); 35 | 36 | return circleci; 37 | } 38 | -------------------------------------------------------------------------------- /.fluentci/src/circleci/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateCircleCITest() { 5 | const circleci = generateYaml(); 6 | const actual = circleci.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/config.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/circleci/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().save(".circleci/config.yml"); 4 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/index.ts: -------------------------------------------------------------------------------- 1 | import pipeline from "./pipeline.ts"; 2 | import { build, test } from "./jobs.ts"; 3 | 4 | export { pipeline, build, test }; 5 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/jobs.ts: -------------------------------------------------------------------------------- 1 | import Client, { connect } from "../../deps.ts"; 2 | 3 | export enum Job { 4 | test = "test", 5 | build = "build", 6 | } 7 | 8 | export const exclude = ["target", ".git", ".devbox", ".fluentci"]; 9 | 10 | export const test = async (src = ".", options: string[] = []) => { 11 | await connect(async (client: Client) => { 12 | const context = client.host().directory(src); 13 | const ctr = client 14 | .pipeline(Job.test) 15 | .container() 16 | .from("rust:1.83-bullseye") 17 | .withDirectory("/app", context, { exclude }) 18 | .withWorkdir("/app") 19 | .withMountedCache("/app/target", client.cacheVolume("target")) 20 | .withMountedCache("/root/cargo/registry", client.cacheVolume("registry")) 21 | .withExec(["cargo", "test", ...options]); 22 | 23 | const result = await ctr.stdout(); 24 | 25 | console.log(result); 26 | }); 27 | return "done"; 28 | }; 29 | 30 | export const build = async (src = ".") => { 31 | await connect(async (client: Client) => { 32 | const context = client.host().directory(src); 33 | const ctr = client 34 | .pipeline(Job.build) 35 | .container() 36 | .from("rust:1.83-bullseye") 37 | .withExec(["apt-get", "update"]) 38 | .withExec([ 39 | "apt-get", 40 | "install", 41 | "-y", 42 | "build-essential", 43 | "gcc-aarch64-linux-gnu", 44 | ]) 45 | .withDirectory("/app", context, { exclude }) 46 | .withWorkdir("/app") 47 | .withMountedCache("/app/target", client.cacheVolume("target")) 48 | .withMountedCache("/root/cargo/registry", client.cacheVolume("registry")) 49 | .withMountedCache("/assets", client.cacheVolume("gh-release-assets")) 50 | .withEnvVariable( 51 | "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER", 52 | Deno.env.get("TARGET") === "aarch64-unknown-linux-gnu" 53 | ? "aarch64-linux-gnu-gcc" 54 | : "", 55 | ) 56 | .withEnvVariable("TAG", Deno.env.get("TAG") || "latest") 57 | .withEnvVariable( 58 | "TARGET", 59 | Deno.env.get("TARGET") || "x86_64-unknown-linux-gnu", 60 | ) 61 | .withExec(["sh", "-c", "rustup target add $TARGET"]) 62 | .withExec([ 63 | "sh", 64 | "-c", 65 | "cargo build -p crosup --release --target $TARGET", 66 | ]) 67 | .withExec(["sh", "-c", "cp target/${TARGET}/release/crosup ."]) 68 | .withExec([ 69 | "sh", 70 | "-c", 71 | "tar czvf /assets/crosup_${TAG}_${TARGET}.tar.gz crosup", 72 | ]) 73 | .withExec([ 74 | "sh", 75 | "-c", 76 | "shasum -a 256 /assets/crosup_${TAG}_${TARGET}.tar.gz > /assets/crosup_${TAG}_${TARGET}.tar.gz.sha256", 77 | ]); 78 | 79 | await ctr.stdout(); 80 | }); 81 | return "Done"; 82 | }; 83 | 84 | export type JobExec = (src?: string) => 85 | | Promise 86 | | (( 87 | src?: string, 88 | options?: { 89 | ignore: string[]; 90 | }, 91 | ) => Promise); 92 | 93 | export const runnableJobs: Record = { 94 | [Job.test]: test, 95 | [Job.build]: build, 96 | }; 97 | 98 | export const jobDescriptions: Record = { 99 | [Job.test]: "Run tests", 100 | [Job.build]: "Build the project", 101 | }; 102 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/list_jobs.ts: -------------------------------------------------------------------------------- 1 | import { brightGreen, stringifyTree } from "../../deps.ts"; 2 | import { runnableJobs, jobDescriptions, Job } from "./jobs.ts"; 3 | 4 | const tree = { 5 | name: brightGreen("rust_pipeline"), 6 | children: (Object.keys(runnableJobs) as Job[]).map((job) => ({ 7 | name: jobDescriptions[job] 8 | ? `${brightGreen(job)} - ${jobDescriptions[job]}` 9 | : brightGreen(job), 10 | children: [], 11 | })), 12 | }; 13 | 14 | console.log( 15 | stringifyTree( 16 | tree, 17 | (t) => t.name, 18 | (t) => t.children 19 | ) 20 | ); 21 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/pipeline.ts: -------------------------------------------------------------------------------- 1 | import { uploadContext } from "../../deps.ts"; 2 | import * as jobs from "./jobs.ts"; 3 | 4 | const { build, test, exclude } = jobs; 5 | 6 | export default async function pipeline(src = ".", args: string[] = []) { 7 | if (Deno.env.has("FLUENTCI_SESSION_ID")) { 8 | await uploadContext(src, exclude); 9 | } 10 | 11 | if (args.length > 0) { 12 | await runSpecificJobs(args); 13 | return; 14 | } 15 | 16 | await test(src); 17 | await build(src); 18 | } 19 | 20 | async function runSpecificJobs(args: string[]) { 21 | for (const name of args) { 22 | // deno-lint-ignore no-explicit-any 23 | const job = (jobs as any)[name]; 24 | if (!job) { 25 | throw new Error(`Job ${name} not found`); 26 | } 27 | await job(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/queries.ts: -------------------------------------------------------------------------------- 1 | import { gql } from "../../deps.ts"; 2 | 3 | export const test = gql` 4 | query test($src: String!) { 5 | test(src: $src) 6 | } 7 | `; 8 | 9 | export const build = gql` 10 | query build($src: String!) { 11 | build(src: $src) 12 | } 13 | `; 14 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/runner.ts: -------------------------------------------------------------------------------- 1 | import pipeline from "./pipeline.ts"; 2 | 3 | await pipeline(".", Deno.args); 4 | -------------------------------------------------------------------------------- /.fluentci/src/dagger/schema.ts: -------------------------------------------------------------------------------- 1 | import { 2 | queryType, 3 | makeSchema, 4 | dirname, 5 | join, 6 | resolve, 7 | stringArg, 8 | nonNull, 9 | } from "../../deps.ts"; 10 | 11 | import { test, build } from "./jobs.ts"; 12 | 13 | const Query = queryType({ 14 | definition(t) { 15 | t.string("test", { 16 | args: { 17 | src: nonNull(stringArg()), 18 | }, 19 | resolve: async (_root, args, _ctx) => await test(args.src), 20 | }); 21 | t.string("build", { 22 | args: { 23 | src: nonNull(stringArg()), 24 | }, 25 | resolve: async (_root, args, _ctx) => await build(args.src), 26 | }); 27 | }, 28 | }); 29 | 30 | export const schema = makeSchema({ 31 | types: [Query], 32 | outputs: { 33 | schema: resolve(join(dirname(".."), dirname(".."), "schema.graphql")), 34 | typegen: resolve(join(dirname(".."), dirname(".."), "gen", "nexus.ts")), 35 | }, 36 | }); 37 | -------------------------------------------------------------------------------- /.fluentci/src/github/README.md: -------------------------------------------------------------------------------- 1 | # Github Actions 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | The following command will generate a `.github/workflows/tests.yml` file in your project: 9 | 10 | ```bash 11 | fluentci gh init -t rust_pipeline 12 | ``` 13 | 14 | Or, if you already have a `.fluentci` folder (generated from `fluentci init -t rust`) in your project: 15 | 16 | ```bash 17 | fluentci gh init 18 | ``` 19 | 20 | Generated file: 21 | 22 | ```yaml 23 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_github_actions 24 | 25 | name: Test 26 | on: 27 | push: 28 | branches: 29 | - main 30 | jobs: 31 | test: 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v2 35 | - uses: denoland/setup-deno@v1 36 | with: 37 | deno-version: v1.37 38 | - name: Setup Fluent CI CLI 39 | run: deno install -A -r https://cli.fluentci.io -n fluentci 40 | - name: Setup Dagger 41 | run: | 42 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 43 | sudo mv bin/dagger /usr/local/bin 44 | dagger version 45 | - name: Run Tests and Build 46 | run: fluentci run rust_pipeline test build 47 | 48 | ``` 49 | 50 | Feel free to edit the template generator at `.fluentci/src/github/config.ts` to your needs. 51 | -------------------------------------------------------------------------------- /.fluentci/src/github/config.ts: -------------------------------------------------------------------------------- 1 | import { JobSpec, Workflow } from "fluent_github_actions"; 2 | 3 | export function generateYaml(): Workflow { 4 | const workflow = new Workflow("Test"); 5 | 6 | const push = { 7 | branches: ["main"], 8 | }; 9 | 10 | const setupDagger = `\ 11 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 12 | sudo mv bin/dagger /usr/local/bin 13 | dagger version`; 14 | 15 | const test: JobSpec = { 16 | "runs-on": "ubuntu-latest", 17 | steps: [ 18 | { 19 | uses: "actions/checkout@v2", 20 | }, 21 | { 22 | uses: "denoland/setup-deno@v1", 23 | with: { 24 | "deno-version": "v1.37", 25 | }, 26 | }, 27 | { 28 | name: "Setup Fluent CI CLI", 29 | run: "deno install -A -r https://cli.fluentci.io -n fluentci", 30 | }, 31 | { 32 | name: "Setup Dagger", 33 | run: setupDagger, 34 | }, 35 | { 36 | name: "Run Tests and Build", 37 | run: "fluentci run rust_pipeline test build", 38 | }, 39 | ], 40 | }; 41 | 42 | workflow.on({ push }).jobs({ test }); 43 | 44 | return workflow; 45 | } 46 | -------------------------------------------------------------------------------- /.fluentci/src/github/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateGithubActionsWorkflowTest() { 5 | const workflow = generateYaml(); 6 | const actual = workflow.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/workflow.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/github/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().save(".github/workflows/tests.yml"); 4 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/README.md: -------------------------------------------------------------------------------- 1 | # Gitlab CI 2 | 3 | [![fluentci pipeline](https://img.shields.io/badge/dynamic/json?label=pkg.fluentci.io&labelColor=%23000&color=%23460cf1&url=https%3A%2F%2Fapi.fluentci.io%2Fv1%2Fpipeline%2Frust_pipeline&query=%24.version)](https://pkg.fluentci.io/rust_pipeline) 4 | [![deno module](https://shield.deno.dev/x/rust_pipeline)](https://deno.land/x/rust_pipeline) 5 | ![deno compatibility](https://shield.deno.dev/deno/^1.34) 6 | [![](https://img.shields.io/codecov/c/gh/fluent-ci-templates/rust-pipeline)](https://codecov.io/gh/fluent-ci-templates/rust-pipeline) 7 | 8 | The following command will generate a `.gitlab-ci.yml` file in your project: 9 | 10 | ```bash 11 | fluentci gl init -t rust_pipeline 12 | ``` 13 | 14 | Generated file: 15 | 16 | ```yaml 17 | 18 | # Do not edit this file directly. It is generated by https://deno.land/x/fluent_gitlab_ci 19 | 20 | .docker: 21 | image: denoland/deno:alpine 22 | services: 23 | - docker:${DOCKER_VERSION}-dind 24 | variables: 25 | DOCKER_HOST: tcp://docker:2376 26 | DOCKER_TLS_VERIFY: "1" 27 | DOCKER_TLS_CERTDIR: /certs 28 | DOCKER_CERT_PATH: /certs/client 29 | DOCKER_DRIVER: overlay2 30 | DOCKER_VERSION: 20.10.16 31 | 32 | .dagger: 33 | extends: .docker 34 | before_script: 35 | - apk add docker-cli curl unzip 36 | - deno install -A -r https://cli.fluentci.io -n fluentci 37 | - curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 38 | - mv bin/dagger /usr/local/bin 39 | - dagger version 40 | 41 | tests: 42 | extends: .dagger 43 | script: 44 | - fluentci run rust_pipeline test build 45 | 46 | ``` 47 | 48 | Feel free to edit the template generator at `.fluentci/src/gitlab/config.ts` to your needs. 49 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/config.ts: -------------------------------------------------------------------------------- 1 | import { GitlabCI, Job } from "fluent_gitlab_ci"; 2 | 3 | export function generateYaml(): GitlabCI { 4 | const docker = new Job() 5 | .image("denoland/deno:alpine") 6 | .services(["docker:${DOCKER_VERSION}-dind"]) 7 | .variables({ 8 | DOCKER_HOST: "tcp://docker:2376", 9 | DOCKER_TLS_VERIFY: "1", 10 | DOCKER_TLS_CERTDIR: "/certs", 11 | DOCKER_CERT_PATH: "/certs/client", 12 | DOCKER_DRIVER: "overlay2", 13 | DOCKER_VERSION: "20.10.16", 14 | }); 15 | 16 | const dagger = new Job().extends(".docker").beforeScript( 17 | ` 18 | apk add docker-cli curl unzip 19 | deno install -A -r https://cli.fluentci.io -n fluentci 20 | curl -L https://dl.dagger.io/dagger/install.sh | DAGGER_VERSION=0.8.1 sh 21 | mv bin/dagger /usr/local/bin 22 | dagger version 23 | ` 24 | ); 25 | 26 | const tests = new Job() 27 | .extends(".dagger") 28 | .script("fluentci run rust_pipeline test build"); 29 | 30 | return new GitlabCI() 31 | .addJob(".docker", docker) 32 | .addJob(".dagger", dagger) 33 | .addJob("tests", tests); 34 | } 35 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/config_test.ts: -------------------------------------------------------------------------------- 1 | import { assertEquals } from "https://deno.land/std@0.191.0/testing/asserts.ts"; 2 | import { generateYaml } from "./config.ts"; 3 | 4 | Deno.test(function generateGitlabCITest() { 5 | const gitlabci = generateYaml(); 6 | const actual = gitlabci.toString(); 7 | const expected = Deno.readTextFileSync("./fixtures/.gitlab-ci.yml"); 8 | assertEquals(actual, expected); 9 | }); 10 | -------------------------------------------------------------------------------- /.fluentci/src/gitlab/init.ts: -------------------------------------------------------------------------------- 1 | import { generateYaml } from "./config.ts"; 2 | 3 | generateYaml().write(); 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: tsirysndr # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | open_collective: # Replace with a single Open Collective username 5 | ko_fi: # Replace with a single Ko-fi username 6 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 7 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 8 | liberapay: # Replace with a single Liberapay username 9 | issuehunt: # Replace with a single IssueHunt username 10 | otechie: # Replace with a single Otechie username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -------------------------------------------------------------------------------- /.github/workflows/flakehub-publish-tagged.yml: -------------------------------------------------------------------------------- 1 | name: "Publish tags to FlakeHub" 2 | on: 3 | push: 4 | tags: 5 | - "v?[0-9]+.[0-9]+.[0-9]+*" 6 | workflow_dispatch: 7 | inputs: 8 | tag: 9 | description: "The existing tag to publish to FlakeHub" 10 | type: "string" 11 | required: true 12 | jobs: 13 | flakehub-publish: 14 | runs-on: "ubuntu-latest" 15 | permissions: 16 | id-token: "write" 17 | contents: "read" 18 | steps: 19 | - uses: "actions/checkout@v3" 20 | with: 21 | ref: "${{ (inputs.tag != null) && format('refs/tags/{0}', inputs.tag) || '' }}" 22 | - uses: "DeterminateSystems/nix-installer-action@main" 23 | - uses: "DeterminateSystems/flakehub-push@main" 24 | with: 25 | visibility: "public" 26 | name: "tsirysndr/crosup" 27 | tag: "${{ inputs.tag }}" 28 | -------------------------------------------------------------------------------- /.github/workflows/release-for-mac.yml.disable: -------------------------------------------------------------------------------- 1 | on: 2 | release: 3 | types: [created] 4 | 5 | jobs: 6 | release: 7 | name: release ${{ matrix.target }} 8 | runs-on: macos-latest 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | include: 13 | - target: x86_64-apple-darwin 14 | archive: tar.gz tar.xz 15 | extensions: tar.gz tar.gz.sha256 16 | - target: aarch64-apple-darwin 17 | archive: tar.gz tar.xz 18 | extensions: tar.gz tar.gz.sha256 19 | 20 | steps: 21 | - name: Setup Fluent CI 22 | uses: fluentci-io/setup-fluentci@v5 23 | - name: Installing Rust toolchain 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | toolchain: stable 27 | target: ${{ matrix.target }} 28 | override: true 29 | - name: Checking out sources 30 | uses: actions/checkout@v1 31 | - name: Running cargo build 32 | uses: actions-rs/cargo@v1 33 | with: 34 | command: build 35 | toolchain: stable 36 | args: -p crosup --release --target ${{ matrix.target }} 37 | - name: Install aarch64-apple-darwin toolchain 38 | if: matrix.target == 'aarch64-apple-darwin' 39 | run: rustup target add aarch64-apple-darwin 40 | - name: Set env 41 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 42 | - name: Packaging final binary 43 | shell: bash 44 | run: | 45 | cd target/${{ matrix.target }}/release 46 | tar czvf ../../../crosup_${{ env.RELEASE_VERSION }}_${{ matrix.target }}.tar.gz crosup 47 | shasum -a 256 ../../../crosup_${{ env.RELEASE_VERSION }}_${{ matrix.target }}.tar.gz > ../../../crosup_${{ env.RELEASE_VERSION }}_${{ matrix.target }}.tar.gz.sha256 48 | cd ../../../ && rm -rf target 49 | - name: Upload release assets 50 | run: | 51 | rm -rf .fluentci/deno.lock 52 | for ext in tar.gz tar.gz.sha256; do 53 | export FILE=crosup_${{ env.RELEASE_VERSION }}_${{ matrix.target }}.$ext 54 | fluentci run github_pipeline release_upload 55 | done 56 | env: 57 | TAG: ${{ env.RELEASE_VERSION }} 58 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 59 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | on: 3 | release: 4 | types: [created] 5 | 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | target: 12 | - aarch64-unknown-linux-gnu 13 | - x86_64-unknown-linux-gnu 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Setup Fluent CI 17 | uses: fluentci-io/setup-fluentci@v5 18 | - name: Set env 19 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 20 | - name: Build 21 | run: | 22 | rm -rf .fluentci/deno.lock 23 | fluentci run . build 24 | env: 25 | TAG: ${{ env.RELEASE_VERSION }} 26 | TARGET: ${{ matrix.target }} 27 | - name: Upload release assets 28 | run: | 29 | for ext in tar.gz tar.gz.sha256; do 30 | export FILE=/assets/crosup_${{ env.RELEASE_VERSION }}_${{ matrix.target }}.$ext 31 | fluentci run github_pipeline release_upload 32 | done 33 | env: 34 | TAG: ${{ env.RELEASE_VERSION }} 35 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml.disable: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: 4 | push: 5 | branches: ["master"] 6 | pull_request: 7 | # The branches below must be a subset of the branches above 8 | branches: ["master"] 9 | workflow_dispatch: 10 | branches: ["*"] 11 | 12 | jobs: 13 | unit-tests: 14 | name: Run unit tests 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout code 18 | uses: actions/checkout@v2 19 | 20 | - uses: actions/cache@v3 21 | with: 22 | path: | 23 | ~/.cargo/bin/ 24 | ~/.cargo/registry/index/ 25 | ~/.cargo/registry/cache/ 26 | ~/.cargo/git/db/ 27 | target/ 28 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 29 | 30 | - name: Install Rust toolchain 31 | uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af #@v1 32 | with: 33 | profile: minimal 34 | toolchain: stable 35 | components: llvm-tools-preview 36 | override: true 37 | 38 | - name: Install cargo-llvm-cov 39 | run: | 40 | if type cargo-llvm-cov >/dev/null 2>&1; then echo "cargo-llvm-cov is already installed"; else cargo install cargo-llvm-cov ; fi 41 | 42 | - name: Run cargo-llvm-cov 43 | run: | 44 | cargo llvm-cov --all-features --lib --workspace --lcov --output-path lcov.info 45 | 46 | - name: Upload coverage to Codecov 47 | uses: codecov/codecov-action@v3 48 | with: 49 | files: lcov.info 50 | token: ${{ secrets.CODECOV_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | result* 3 | 4 | Crosfile* 5 | Inventory* -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "deno.enable": true 3 | } 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *master* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. 49 | 50 | 51 | ## Licensing 52 | 53 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 54 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | default-members = ["crates/cli"] 3 | members = ["crates/*"] 4 | resolver = "2" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Tsiry Sandratraina 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /crates/cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Tsiry Sandratraina "] 3 | categories = ["command-line-utilities"] 4 | description = "A simple CLI tool to quickly setup your development environment on Chomebook (ChromeOS) or any Linux Distribution." 5 | edition = "2021" 6 | keywords = ["chromebook", "chromeos", "homebrew", "docker", "nix"] 7 | license = "MIT" 8 | name = "crosup" 9 | readme = "../../README.md" 10 | repository = "https://github.com/tsirysndr/crosup" 11 | version = "0.5.2" 12 | 13 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 14 | 15 | [dependencies] 16 | anyhow = "1.0.71" 17 | clap = "3.2.20" 18 | crosup-core = { path = "../core", version = "0.2.1" } 19 | crosup-entity = { version = "0.1.0", path = "../entity" } 20 | crosup-installers = { path = "../installers", version = "0.2.0" } 21 | crosup-migration = { path = "../migration", version = "0.1.0" } 22 | crosup-nix = { path = "../nix", version = "0.1.1" } 23 | crosup-repo = { path = "../repo", version = "0.1.0" } 24 | crosup-ssh = { path = "../ssh", version = "0.1.0" } 25 | crosup-tui = { path = "../tui", version = "0.1.0" } 26 | crosup-types = { path = "../types", version = "0.2.1" } 27 | hcl-rs = "0.14.2" 28 | inquire = "0.6.2" 29 | owo-colors = "3.5.0" 30 | sea-orm = { version = "0.11.3", features = [ 31 | "runtime-tokio-rustls", 32 | "sqlx-sqlite", 33 | ] } 34 | serde = "1.0.164" 35 | sha256 = "1.1.4" 36 | similar = { version = "2.2.1", features = ["inline"] } 37 | spinners = "4.1.0" 38 | ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } 39 | tokio = { version = "1.28.2", features = ["full"] } 40 | toml = "0.7.4" 41 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/add.rs: -------------------------------------------------------------------------------- 1 | use std::fs; 2 | 3 | use anyhow::Error; 4 | use crosup_core::{config::verify_if_config_file_is_present, graph::build_installer_graph}; 5 | use crosup_types::configuration::Configuration; 6 | use owo_colors::OwoColorize; 7 | 8 | use crate::{cmd::print_diff, macros::install, types::InstallArgs}; 9 | 10 | pub async fn execute_add(tools: Vec, ask: bool) -> Result<(), Error> { 11 | let (mut current_config, filename, content, is_present) = verify_if_config_file_is_present()?; 12 | 13 | current_config.packages = match current_config.packages { 14 | Some(ref mut packages) => { 15 | tools.iter().for_each(|x| { 16 | if !packages.contains(x) { 17 | packages.push(x.clone()) 18 | } 19 | }); 20 | Some(packages.clone()) 21 | } 22 | None => Some(tools.clone()), 23 | }; 24 | let new_content = match filename.ends_with(".hcl") { 25 | true => hcl::to_string(¤t_config)?, 26 | false => toml::to_string(¤t_config)?, 27 | }; 28 | 29 | print_diff(&content, &new_content); 30 | 31 | if ask { 32 | ask_confirmation(ask, tools.clone()); 33 | } 34 | 35 | let args = InstallArgs { 36 | ..Default::default() 37 | }; 38 | 39 | install!(args, current_config, None); 40 | 41 | if is_present { 42 | fs::write(filename, new_content)?; 43 | } 44 | 45 | Ok(()) 46 | } 47 | 48 | fn ask_confirmation(ask: bool, tools: Vec) { 49 | if ask { 50 | println!("\n-> The following packages will be added to your configuration:"); 51 | 52 | for tool in tools.iter() { 53 | println!(" - {}", tool.bright_green()); 54 | } 55 | 56 | match tools.len() { 57 | 1 => println!("-> Are you sure you want to install this package? [y/N]"), 58 | _ => println!( 59 | "-> Are you sure you want to install these {} packages? [y/N]", 60 | tools.len().bold().cyan() 61 | ), 62 | }; 63 | let mut input = String::new(); 64 | std::io::stdin() 65 | .read_line(&mut input) 66 | .expect("Failed to read line"); 67 | match input.trim() { 68 | "y" | "Y" => {} 69 | _ => std::process::exit(0), 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/diff.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Error; 2 | use crosup_core::config::verify_if_config_file_is_present; 3 | use crosup_repo::{file::FileRepo, modification::ModificationRepo}; 4 | use migration::MigratorTrait; 5 | use owo_colors::OwoColorize; 6 | use sea_orm::DatabaseConnection; 7 | 8 | use crate::cmd::print_diff; 9 | 10 | use super::get_database_connection; 11 | 12 | pub async fn execute_diff() -> Result<(), Error> { 13 | let (_, filename, content, _) = verify_if_config_file_is_present()?; 14 | 15 | let db: DatabaseConnection = get_database_connection().await?; 16 | migration::Migrator::up(&db, None).await?; 17 | let current_dir = std::env::current_dir()?; 18 | let path = format!("{}/{}", current_dir.display(), filename); 19 | 20 | let result = FileRepo::new(&db).find_by_path(&path).await?; 21 | if let Some(file) = result { 22 | let result = ModificationRepo::new(&db) 23 | .find_last_by_file_id(file.id) 24 | .await?; 25 | if let Some(last_modif) = result { 26 | let hash = sha256::digest(content.clone()); 27 | if hash != last_modif.hash { 28 | println!(" 📝 {} has been modified", filename.bold().cyan()); 29 | print_diff(&last_modif.content, &content); 30 | return Ok(()); 31 | } 32 | println!("{} has not been modified", filename.bold().cyan()); 33 | } 34 | } 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/history.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use super::get_database_connection; 4 | use anyhow::Error; 5 | use crosup_core::config::verify_if_config_file_is_present; 6 | use crosup_repo::{file::FileRepo, modification::ModificationRepo}; 7 | use crosup_tui::{history::display_history, App}; 8 | use migration::MigratorTrait; 9 | use owo_colors::OwoColorize; 10 | use sea_orm::DatabaseConnection; 11 | 12 | pub async fn execute_history() -> Result<(), Error> { 13 | let (_, filename, _, _) = verify_if_config_file_is_present()?; 14 | 15 | let db: DatabaseConnection = get_database_connection().await?; 16 | 17 | migration::Migrator::up(&db, None).await?; 18 | 19 | let current_dir = std::env::current_dir()?; 20 | let path = format!("{}/{}", current_dir.display(), filename); 21 | 22 | let result = FileRepo::new(&db).find_by_path(&path).await?; 23 | 24 | if let Some(file) = result { 25 | let result = ModificationRepo::new(&db).find_by_file_id(file.id).await?; 26 | let mut content = HashMap::new(); 27 | let mut dates = HashMap::new(); 28 | let mut hashes = HashMap::new(); 29 | for (index, m) in result.iter().enumerate() { 30 | content.insert(index, m.content.clone()); 31 | dates.insert(index, m.timestamp); 32 | hashes.insert(index, m.hash.clone()); 33 | } 34 | 35 | let app = App { 36 | items: result 37 | .into_iter() 38 | .map(|m| format!("{} {} {}", m.timestamp.to_string(), filename, m.hash)) 39 | .collect(), 40 | content, 41 | selected_index: 0, 42 | title: filename, 43 | }; 44 | display_history(app)?; 45 | return Ok(()); 46 | } 47 | 48 | println!( 49 | "{} has not been modified, no history available", 50 | filename.bold().cyan() 51 | ); 52 | 53 | Ok(()) 54 | } 55 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/init.rs: -------------------------------------------------------------------------------- 1 | use std::io::Write; 2 | 3 | use anyhow::Error; 4 | use inquire::Confirm; 5 | use owo_colors::OwoColorize; 6 | 7 | use crosup_types::{ 8 | configuration::{ConfigFormat, Configuration}, 9 | inventory::Inventory, 10 | }; 11 | 12 | pub fn execute_init( 13 | cfg_format: ConfigFormat, 14 | inventory: bool, 15 | packages: Option>, 16 | ) -> Result<(), Error> { 17 | let ext = match cfg_format { 18 | ConfigFormat::HCL => "hcl", 19 | ConfigFormat::TOML => "toml", 20 | }; 21 | 22 | let filename = match inventory { 23 | true => format!("Inventory.{}", ext), 24 | false => format!("Crosfile.{}", ext), 25 | }; 26 | 27 | if std::path::Path::new(&filename).exists() { 28 | let answer = Confirm::new( 29 | format!( 30 | "A {} file already exists in this directory, do you want to overwrite it?", 31 | filename.bright_green() 32 | ) 33 | .as_str(), 34 | ) 35 | .with_default(false) 36 | .with_help_message("Press y to overwrite the file or n to exit") 37 | .prompt(); 38 | if answer.is_err() || !answer.unwrap() { 39 | println!("Exiting..."); 40 | return Ok(()); 41 | } 42 | } 43 | 44 | if inventory { 45 | let inventory = Inventory::default(); 46 | let serialized = match cfg_format { 47 | ConfigFormat::HCL => hcl::to_string(&inventory).unwrap(), 48 | ConfigFormat::TOML => toml::to_string_pretty(&inventory).unwrap(), 49 | }; 50 | 51 | let mut file = std::fs::File::create(&filename).unwrap(); 52 | file.write_all(serialized.as_bytes()).unwrap(); 53 | println!("Created {} ✨", filename.bright_green()); 54 | return Ok(()); 55 | } 56 | 57 | let config = match packages { 58 | Some(packages) => Configuration { 59 | packages: Some(packages), 60 | install: None, 61 | brew: None, 62 | apt: None, 63 | pacman: None, 64 | git: None, 65 | nix: None, 66 | curl: None, 67 | yum: None, 68 | dnf: None, 69 | zypper: None, 70 | apk: None, 71 | emerge: None, 72 | slackpkg: None, 73 | fleek: None, 74 | }, 75 | None => Configuration::default(), 76 | }; 77 | 78 | let serialized = match cfg_format { 79 | ConfigFormat::HCL => hcl::to_string(&config).unwrap(), 80 | ConfigFormat::TOML => toml::to_string_pretty(&config).unwrap(), 81 | }; 82 | 83 | let mut file = std::fs::File::create(&filename).unwrap(); 84 | file.write_all(serialized.as_bytes()).unwrap(); 85 | println!("Created {} ✨", filename.bright_green()); 86 | 87 | Ok(()) 88 | } 89 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/mod.rs: -------------------------------------------------------------------------------- 1 | use std::{fmt, fs}; 2 | 3 | use anyhow::Error; 4 | use owo_colors::{OwoColorize, Style}; 5 | use sea_orm::{Database, DatabaseConnection}; 6 | use similar::{ChangeTag, TextDiff}; 7 | 8 | pub mod add; 9 | pub mod diff; 10 | pub mod history; 11 | pub mod init; 12 | pub mod install; 13 | pub mod search; 14 | 15 | struct Line(Option); 16 | 17 | impl fmt::Display for Line { 18 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 19 | match self.0 { 20 | None => write!(f, " "), 21 | Some(idx) => write!(f, "{:>4}", idx + 1), 22 | } 23 | } 24 | } 25 | 26 | pub async fn get_database_connection() -> Result { 27 | let home = std::env::var("HOME").unwrap(); 28 | let crosup_dir = format!("{}/.config/crosup", home); 29 | 30 | fs::create_dir_all(&crosup_dir)?; 31 | 32 | let database_url = format!("sqlite:{}/modifications.sqlite3?mode=rwc", crosup_dir); 33 | 34 | let db: DatabaseConnection = Database::connect(&database_url).await?; 35 | Ok(db) 36 | } 37 | 38 | pub fn print_diff(previous: &str, current: &str) { 39 | let diff = TextDiff::from_lines(previous, current); 40 | 41 | for (idx, group) in diff.grouped_ops(3).iter().enumerate() { 42 | if idx > 0 { 43 | println!("{:-^1$}", "-", 80); 44 | } 45 | for op in group { 46 | for change in diff.iter_inline_changes(op) { 47 | let (sign, style) = match change.tag() { 48 | ChangeTag::Delete => ("-", Style::new().red().bold()), 49 | ChangeTag::Insert => ("+", Style::new().green().bold()), 50 | ChangeTag::Equal => (" ", Style::new()), 51 | }; 52 | print!("{}|{}", Line(change.new_index()), style.style(sign),); 53 | for (emphasized, value) in change.iter_strings_lossy() { 54 | if emphasized { 55 | print!("{}", style.style(value).underline()); 56 | continue; 57 | } 58 | print!("{}", style.style(value)); 59 | } 60 | if change.missing_newline() { 61 | println!(); 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /crates/cli/src/cmd/search.rs: -------------------------------------------------------------------------------- 1 | use crate::types::SearchArgs; 2 | use anyhow::{anyhow, Error}; 3 | use crosup_nix::search::{ 4 | client::NixPackagesClient, esclient::ElasticSearchClient, matchers::MatchName, query::Query, 5 | }; 6 | use owo_colors::OwoColorize; 7 | use spinners::{Spinner, Spinners}; 8 | 9 | pub async fn execute_search(args: SearchArgs) -> Result<(), Error> { 10 | let client = ElasticSearchClient::new() 11 | .map_err(|e| anyhow!("Failed to create ElasticSearch client: {}", e))?; 12 | let query = Query { 13 | channel: args.channel, 14 | name: Some(MatchName { name: args.package }), 15 | max_results: args.max_results, 16 | ..Default::default() 17 | }; 18 | 19 | let mut sp = Spinner::new(Spinners::Dots9, "Searching...".into()); 20 | let results = client.search(query).await?; 21 | sp.stop(); 22 | 23 | println!(""); 24 | 25 | for result in results { 26 | match result.package.description { 27 | Some(ref description) => { 28 | println!( 29 | "{} @ {} : {}", 30 | result.package.name.cyan().underline(), 31 | result.package.version.bright_green(), 32 | description 33 | ); 34 | } 35 | None => { 36 | println!( 37 | "{} @ {}", 38 | result.package.name.cyan().underline(), 39 | result.package.version.bright_green() 40 | ); 41 | } 42 | }; 43 | } 44 | Ok(()) 45 | } 46 | -------------------------------------------------------------------------------- /crates/cli/src/macros.rs: -------------------------------------------------------------------------------- 1 | macro_rules! install { 2 | ($args: ident, $config: ident, $session: expr) => { 3 | match $args.tools { 4 | Some(ref tools) => { 5 | for tool_name in tools { 6 | let tool_name = tool_name.replace("ble.sh", "blesh"); 7 | let mut default_config = Configuration::default(); 8 | let (default_graph, default_installers) = 9 | build_installer_graph(&mut default_config, $session.clone()); 10 | 11 | let mut visited = vec![false; default_graph.size()]; 12 | if let Some(tool) = default_installers 13 | .into_iter() 14 | .find(|installer| installer.name() == tool_name) 15 | { 16 | default_graph.install(tool, &mut visited)?; 17 | continue; 18 | } 19 | 20 | let (graph, installers) = build_installer_graph(&mut $config, $session.clone()); 21 | let tool = installers 22 | .into_iter() 23 | .find(|installer| installer.name() == tool_name) 24 | .unwrap(); 25 | let mut visited = vec![false; graph.size()]; 26 | graph.install(tool, &mut visited)?; 27 | } 28 | } 29 | None => { 30 | let (graph, _) = build_installer_graph(&mut $config, $session.clone()); 31 | graph.install_all()?; 32 | } 33 | } 34 | }; 35 | } 36 | 37 | pub(crate) use install; 38 | -------------------------------------------------------------------------------- /crates/cli/src/types.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Default)] 2 | pub struct InstallArgs { 3 | pub tools: Option>, 4 | pub ask: bool, 5 | pub remote_is_present: bool, 6 | pub remote: Option, 7 | pub port: Option, 8 | pub username: Option, 9 | pub inventory: Option, 10 | } 11 | 12 | #[derive(Clone, Default)] 13 | pub struct SearchArgs { 14 | pub package: String, 15 | pub channel: String, 16 | pub max_results: u32, 17 | } 18 | -------------------------------------------------------------------------------- /crates/core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Tsiry Sandratraina "] 3 | categories = ["command-line-utilities"] 4 | description = "A simple CLI tool to quickly setup your development environment on Chomebook (ChromeOS) or any Linux Distribution." 5 | edition = "2021" 6 | keywords = ["chromebook", "chromeos", "homebrew", "docker", "nix"] 7 | license = "MIT" 8 | name = "crosup-core" 9 | repository = "https://github.com/tsirysndr/crosup" 10 | version = "0.2.1" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | anyhow = "1.0.71" 16 | crosup-installers = { path = "../installers", version = "0.2.0" } 17 | crosup-macros = { path = "../macros", version = "0.2.0" } 18 | crosup-ssh = { path = "../ssh", version = "0.1.0" } 19 | crosup-types = { path = "../types", version = "0.2.1" } 20 | hcl-rs = "0.14.2" 21 | os-release = "0.1.0" 22 | owo-colors = "3.5.0" 23 | ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } 24 | toml = "0.7.4" 25 | -------------------------------------------------------------------------------- /crates/core/src/config.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Error; 2 | use owo_colors::OwoColorize; 3 | use std::path::Path; 4 | 5 | use crosup_types::{ 6 | configuration::Configuration, inventory::Inventory, CROSFILE_HCL, CROSFILE_TOML, INVENTORY_HCL, 7 | INVENTORY_TOML, 8 | }; 9 | 10 | pub fn verify_if_config_file_is_present() -> Result<(Configuration, String, String, bool), Error> { 11 | if !Path::new(CROSFILE_HCL).exists() && !Path::new(CROSFILE_TOML).exists() { 12 | let config = Configuration::default(); 13 | return Ok(( 14 | config.clone(), 15 | CROSFILE_HCL.into(), 16 | hcl::to_string(&config)?, 17 | false, 18 | )); 19 | } 20 | 21 | let current_dir = std::env::current_dir()?; 22 | 23 | if Path::new(CROSFILE_HCL).exists() { 24 | let config = std::fs::read_to_string(current_dir.join(CROSFILE_HCL))?; 25 | let content = config.clone(); 26 | let config = hcl::from_str(&config)?; 27 | return Ok((config, CROSFILE_HCL.into(), content, true)); 28 | } 29 | 30 | let config = std::fs::read_to_string(current_dir.join(CROSFILE_TOML))?; 31 | let content = config.clone(); 32 | let config = toml::from_str(&config)?; 33 | return Ok((config, CROSFILE_TOML.into(), content, true)); 34 | } 35 | 36 | pub fn verify_if_inventory_config_file_is_present() -> Result { 37 | if !Path::new(INVENTORY_HCL).exists() && !Path::new(INVENTORY_TOML).exists() { 38 | return Err(anyhow::anyhow!(format!( 39 | "Inventory file not found, please create one using {}", 40 | "crosup init --inventory".bright_green() 41 | ))); 42 | } 43 | 44 | let current_dir = std::env::current_dir()?; 45 | 46 | if Path::new(INVENTORY_HCL).exists() { 47 | let config = std::fs::read_to_string(current_dir.join(INVENTORY_HCL))?; 48 | let config = hcl::from_str(&config)?; 49 | return Ok(config); 50 | } 51 | 52 | let config = std::fs::read_to_string(current_dir.join(INVENTORY_TOML))?; 53 | let config = toml::from_str(&config)?; 54 | return Ok(config); 55 | } 56 | -------------------------------------------------------------------------------- /crates/core/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod config; 2 | pub mod graph; 3 | -------------------------------------------------------------------------------- /crates/entity/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Tsiry Sandratraina "] 3 | categories = ["command-line-utilities"] 4 | description = "A simple CLI tool to quickly setup your development environment on Chomebook (ChromeOS) or any Linux Distribution." 5 | edition = "2021" 6 | keywords = ["chromebook", "chromeos", "homebrew", "docker", "nix"] 7 | license = "MIT" 8 | name = "crosup-entity" 9 | repository = "https://github.com/tsirysndr/crosup" 10 | version = "0.1.0" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | chrono = "0.4.26" 16 | sea-orm = {version = "0.11.3", features = ["runtime-tokio-rustls", "sqlx-sqlite"]} 17 | serde = "1.0.164" 18 | -------------------------------------------------------------------------------- /crates/entity/src/file.rs: -------------------------------------------------------------------------------- 1 | use sea_orm::entity::prelude::*; 2 | use sea_orm::DeriveEntityModel; 3 | 4 | #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] 5 | #[sea_orm(table_name = "file")] 6 | pub struct Model { 7 | #[sea_orm(primary_key)] 8 | pub id: i32, 9 | pub name: String, 10 | pub path: String, 11 | #[sea_orm(column_type = "Timestamp")] 12 | pub created_at: chrono::NaiveDateTime, 13 | } 14 | 15 | #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] 16 | pub enum Relation { 17 | #[sea_orm(has_many = "super::modification::Entity")] 18 | Modification, 19 | } 20 | 21 | // `Related` trait has to be implemented by hand 22 | impl Related for Entity { 23 | fn to() -> RelationDef { 24 | Relation::Modification.def() 25 | } 26 | } 27 | 28 | impl ActiveModelBehavior for ActiveModel {} 29 | -------------------------------------------------------------------------------- /crates/entity/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod file; 2 | pub mod modification; 3 | -------------------------------------------------------------------------------- /crates/entity/src/modification.rs: -------------------------------------------------------------------------------- 1 | use sea_orm::entity::prelude::*; 2 | use sea_orm::DeriveEntityModel; 3 | 4 | #[derive(Clone, Debug, PartialEq, DeriveEntityModel)] 5 | #[sea_orm(table_name = "modification")] 6 | pub struct Model { 7 | #[sea_orm(primary_key)] 8 | pub id: i32, 9 | #[sea_orm(column_type = "Timestamp")] 10 | pub timestamp: chrono::NaiveDateTime, 11 | pub hash: String, 12 | pub file_id: i32, 13 | pub previous_id: Option, 14 | #[sea_orm(column_type = "Text")] 15 | pub content: String, 16 | } 17 | 18 | #[derive(Copy, Clone, Debug, EnumIter)] 19 | pub enum Relation { 20 | File, 21 | Modification, 22 | } 23 | 24 | impl RelationTrait for Relation { 25 | fn def(&self) -> RelationDef { 26 | match self { 27 | Self::File => Entity::belongs_to(super::file::Entity) 28 | .from(Column::FileId) 29 | .to(super::file::Column::Id) 30 | .into(), 31 | Self::Modification => Entity::has_one(super::modification::Entity) 32 | .from(Column::Id) 33 | .to(super::modification::Column::PreviousId) 34 | .into(), 35 | } 36 | } 37 | } 38 | 39 | impl Related for Entity { 40 | fn to() -> RelationDef { 41 | Relation::File.def() 42 | } 43 | } 44 | 45 | impl Related for Entity { 46 | fn to() -> RelationDef { 47 | Relation::Modification.def() 48 | } 49 | } 50 | 51 | impl ActiveModelBehavior for ActiveModel {} 52 | -------------------------------------------------------------------------------- /crates/installers/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Tsiry Sandratraina "] 3 | categories = ["command-line-utilities"] 4 | description = "A simple CLI tool to quickly setup your development environment on Chomebook (ChromeOS) or any Linux Distribution." 5 | edition = "2021" 6 | keywords = ["chromebook", "chromeos", "homebrew", "docker", "nix"] 7 | license = "MIT" 8 | name = "crosup-installers" 9 | repository = "https://github.com/tsirysndr/crosup" 10 | version = "0.2.1" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | anyhow = "1.0.71" 16 | crosup-macros = { path = "../macros", version = "0.2.0" } 17 | crosup-nix = { path = "../nix", version = "0.1.1" } 18 | crosup-ssh = { path = "../ssh", version = "0.1.0" } 19 | crosup-types = { path = "../types", version = "0.2.1" } 20 | indexmap = { version = "1.9.3", features = ["serde"] } 21 | owo-colors = "3.5.0" 22 | ssh2 = { version = "0.9.4", features = ["vendored-openssl"] } 23 | -------------------------------------------------------------------------------- /crates/installers/src/apk.rs: -------------------------------------------------------------------------------- 1 | use crosup_macros::{apk_add, check_version, exec_sh_with_output}; 2 | use crosup_types::apk::Package; 3 | 4 | use anyhow::Error; 5 | use owo_colors::OwoColorize; 6 | use ssh2::Session; 7 | use std::{any::Any, io::BufRead, process::Stdio}; 8 | 9 | use super::Installer; 10 | 11 | #[derive(Default, Clone)] 12 | pub struct ApkInstaller { 13 | pub name: String, 14 | pub version: String, 15 | pub dependencies: Vec, 16 | pub apk_dependencies: Vec, 17 | pub packages: Option>, 18 | pub postinstall: Option, 19 | pub version_check: Option, 20 | pub interactive: bool, 21 | pub provider: String, 22 | pub session: Option, 23 | } 24 | 25 | impl From for ApkInstaller { 26 | fn from(pkg: Package) -> Self { 27 | Self { 28 | name: pkg.name, 29 | packages: pkg.packages, 30 | apk_dependencies: pkg.depends_on.unwrap_or(vec![]), 31 | provider: "apk".into(), 32 | version_check: pkg.version_check, 33 | interactive: pkg.interactive.unwrap_or(false), 34 | ..Default::default() 35 | } 36 | } 37 | } 38 | 39 | impl ApkInstaller { 40 | pub fn install_dependencies(&self) -> Result<(), Error> { 41 | if self.apk_dependencies.is_empty() { 42 | return Ok(()); 43 | } 44 | 45 | println!( 46 | "-> Installing dependencies for {}", 47 | self.name.bright_green() 48 | ); 49 | let deps = self.apk_dependencies.join(" "); 50 | apk_add!(deps, "", self.session.clone()); 51 | Ok(()) 52 | } 53 | 54 | fn postinstall(&self) -> Result<(), Error> { 55 | if let Some(command) = self.postinstall.clone() { 56 | println!( 57 | "-> Running postinstall command:\n{}", 58 | command.bright_green() 59 | ); 60 | for cmd in command.split("\n") { 61 | exec_sh_with_output!(cmd, self.session.clone()); 62 | } 63 | } 64 | Ok(()) 65 | } 66 | } 67 | 68 | impl Installer for ApkInstaller { 69 | fn install(&self) -> Result<(), Error> { 70 | if self.is_installed().is_ok() { 71 | if self.is_installed().unwrap() { 72 | println!( 73 | "-> {} is already installed, skipping", 74 | self.name().bright_green() 75 | ); 76 | return Ok(()); 77 | } 78 | } 79 | 80 | self.install_dependencies()?; 81 | 82 | if let Some(packages) = self.packages.clone() { 83 | let options = match self.interactive { 84 | true => "--interactive", 85 | false => "", 86 | }; 87 | let packages = packages.join(" "); 88 | let command = format!("sudo apk add {} {}", options, packages); 89 | println!("-> Running {}", command.bright_green()); 90 | apk_add!(packages, options, self.session.clone()); 91 | } 92 | 93 | self.postinstall()?; 94 | Ok(()) 95 | } 96 | 97 | fn is_installed(&self) -> Result { 98 | println!( 99 | "-> Checking if {} is already installed", 100 | self.name.bright_green() 101 | ); 102 | if let Some(command) = self.version_check.clone() { 103 | check_version!(self, command, self.session.clone()); 104 | return Ok(false); 105 | } 106 | let command = self.name.clone(); 107 | check_version!(self, command, self.session.clone()); 108 | Ok(false) 109 | } 110 | 111 | fn name(&self) -> &str { 112 | &self.name 113 | } 114 | 115 | fn version(&self) -> &str { 116 | &self.version 117 | } 118 | 119 | fn dependencies(&self) -> Vec { 120 | self.dependencies.clone() 121 | } 122 | 123 | fn is_default(&self) -> bool { 124 | true 125 | } 126 | 127 | fn provider(&self) -> &str { 128 | &self.provider 129 | } 130 | 131 | fn as_any(&self) -> &dyn Any { 132 | self 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /crates/installers/src/brew.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Error; 2 | use owo_colors::OwoColorize; 3 | use ssh2::Session; 4 | use std::{any::Any, io::BufRead, process::Stdio}; 5 | 6 | use crosup_macros::{brew_install, check_version, exec_bash_with_output}; 7 | use crosup_types::brew::{BrewConfiguration, Package}; 8 | 9 | use super::Installer; 10 | 11 | #[derive(Default, Clone)] 12 | pub struct BrewInstaller { 13 | pub name: String, 14 | pub version: String, 15 | pub dependencies: Vec, 16 | pub brew_dependencies: Vec, 17 | pub pkgs: Vec, 18 | pub preinstall: Option, 19 | pub postinstall: Option, 20 | pub version_check: Option, 21 | pub provider: String, 22 | pub session: Option, 23 | pub cask: bool, 24 | } 25 | 26 | impl From for BrewInstaller { 27 | fn from(config: BrewConfiguration) -> Self { 28 | Self { 29 | name: "brew".to_string(), 30 | version: "latest".to_string(), 31 | dependencies: vec!["homebrew".into()], 32 | pkgs: config.pkgs.unwrap_or(vec![]), 33 | ..Default::default() 34 | } 35 | } 36 | } 37 | 38 | impl From for BrewInstaller { 39 | fn from(pkg: Package) -> Self { 40 | Self { 41 | name: pkg.name, 42 | version: "latest".to_string(), 43 | dependencies: vec!["homebrew".into()], 44 | preinstall: pkg.preinstall, 45 | postinstall: pkg.postinstall, 46 | provider: "brew".into(), 47 | version_check: pkg.version_check, 48 | cask: pkg.cask.unwrap_or(false), 49 | ..Default::default() 50 | } 51 | } 52 | } 53 | 54 | impl BrewInstaller { 55 | fn preinstall(&self) -> Result<(), Error> { 56 | if let Some(command) = self.preinstall.clone() { 57 | println!("-> Running preinstall command:\n{}", command.bright_green()); 58 | for cmd in command.split("\n") { 59 | exec_bash_with_output!(cmd, self.session.clone()); 60 | } 61 | } 62 | Ok(()) 63 | } 64 | 65 | fn postinstall(&self) -> Result<(), Error> { 66 | if let Some(command) = self.postinstall.clone() { 67 | println!( 68 | "-> Running postinstall command:\n{}", 69 | command.bright_green() 70 | ); 71 | for cmd in command.split("\n") { 72 | exec_bash_with_output!(cmd, self.session.clone()); 73 | } 74 | } 75 | Ok(()) 76 | } 77 | } 78 | 79 | impl Installer for BrewInstaller { 80 | fn install(&self) -> Result<(), Error> { 81 | if self.is_installed().is_ok() { 82 | println!( 83 | "-> {} is already installed, skipping", 84 | self.name().bright_green() 85 | ); 86 | return Ok(()); 87 | } 88 | println!("-> 🚚 Installing {}", self.name().bright_green()); 89 | self.preinstall()?; 90 | brew_install!(self, &self.name, self.cask, self.session.clone()); 91 | self.postinstall()?; 92 | Ok(()) 93 | } 94 | 95 | fn is_installed(&self) -> Result { 96 | println!( 97 | "-> Checking if {} is already installed", 98 | self.name.bright_green() 99 | ); 100 | if let Some(command) = self.version_check.clone() { 101 | check_version!(self, command, self.session.clone()); 102 | return Ok(false); 103 | } 104 | let command = self.name.clone(); 105 | check_version!(self, command, self.session.clone()); 106 | Ok(false) 107 | } 108 | 109 | fn name(&self) -> &str { 110 | &self.name 111 | } 112 | 113 | fn version(&self) -> &str { 114 | &self.version 115 | } 116 | 117 | fn dependencies(&self) -> Vec { 118 | self.dependencies.clone() 119 | } 120 | 121 | fn is_default(&self) -> bool { 122 | true 123 | } 124 | 125 | fn provider(&self) -> &str { 126 | &self.provider 127 | } 128 | 129 | fn as_any(&self) -> &dyn Any { 130 | self 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /crates/installers/src/curl.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Error; 2 | use indexmap::IndexMap; 3 | use owo_colors::OwoColorize; 4 | use ssh2::Session; 5 | use std::{any::Any, io::BufRead, process::Stdio}; 6 | 7 | use crosup_macros::{check_version, exec_bash_with_output}; 8 | use crosup_types::curl::Script; 9 | 10 | use super::Installer; 11 | 12 | #[derive(Default, Clone)] 13 | pub struct CurlInstaller { 14 | pub name: String, 15 | pub version: String, 16 | pub dependencies: Vec, 17 | pub url: String, 18 | pub enable_sudo: Option, 19 | pub version_check: Option, 20 | pub postinstall: Option, 21 | pub args: Option, 22 | pub env: Option>, 23 | pub shell: String, 24 | pub provider: String, 25 | pub session: Option, 26 | } 27 | 28 | impl From