feat: Better configuration and description
This commit is contained in:
		
				
					committed by
					
						
						Nikolai Rodionov
					
				
			
			
				
	
			
			
			
						parent
						
							6459152833
						
					
				
				
					commit
					07e156dd3f
				
			
							
								
								
									
										46
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -1,46 +0,0 @@
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
type: kubernetes
 | 
			
		||||
name: Containeraztion latest
 | 
			
		||||
steps:
 | 
			
		||||
- name: Docker build
 | 
			
		||||
  resources:
 | 
			
		||||
    limits:
 | 
			
		||||
      cpu: 100
 | 
			
		||||
      memory: 2048MiB
 | 
			
		||||
  when:
 | 
			
		||||
   branch:
 | 
			
		||||
     - main
 | 
			
		||||
  privileged: true
 | 
			
		||||
  settings:
 | 
			
		||||
    registry: git.badhouseplants.net
 | 
			
		||||
    username: allanger
 | 
			
		||||
    password: 
 | 
			
		||||
      from_secret: GITEA_TOKEN
 | 
			
		||||
    repo: git.badhouseplants.net/badhouseplants/clever-install
 | 
			
		||||
    tags: latest
 | 
			
		||||
    platforms: 
 | 
			
		||||
      - linux/arm64
 | 
			
		||||
      - linux/amd64
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
- name: Docker build
 | 
			
		||||
  image: thegeeklab/drone-docker-buildx
 | 
			
		||||
  trigger:
 | 
			
		||||
    event:
 | 
			
		||||
      - tag
 | 
			
		||||
  resources:
 | 
			
		||||
    limits:
 | 
			
		||||
      cpu: 100
 | 
			
		||||
      memory: 2048MiB
 | 
			
		||||
  privileged: true
 | 
			
		||||
  settings:
 | 
			
		||||
    registry: git.badhouseplants.net
 | 
			
		||||
    username: allanger
 | 
			
		||||
    password: 
 | 
			
		||||
      from_secret: GITEA_TOKEN
 | 
			
		||||
    repo: git.badhouseplants.net/badhouseplants/clever-install
 | 
			
		||||
    tags: latest
 | 
			
		||||
    platforms: 
 | 
			
		||||
      - linux/arm64
 | 
			
		||||
      - linux/amd64
 | 
			
		||||
							
								
								
									
										2
									
								
								.github/workflows/build-version.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/build-version.yaml
									
									
									
									
										vendored
									
									
								
							@@ -50,7 +50,7 @@ jobs:
 | 
			
		||||
        uses: actions/download-artifact@v3
 | 
			
		||||
 | 
			
		||||
      - name: Set version variable
 | 
			
		||||
        run: echo "CLIN_VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV
 | 
			
		||||
        run: echo "VERSION=${GITHUB_REF##*/}" >> $GITHUB_ENV
 | 
			
		||||
 | 
			
		||||
      - name: Rename release to avoid name conflict
 | 
			
		||||
        run: ./scripts/rename_releases.sh
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
name: "Stable container"
 | 
			
		||||
name: "Latest container"
 | 
			
		||||
 | 
			
		||||
on:
 | 
			
		||||
  push:
 | 
			
		||||
@@ -43,7 +43,6 @@ jobs:
 | 
			
		||||
          platforms: linux/amd64,linux/arm64
 | 
			
		||||
          push: true
 | 
			
		||||
          tags: |
 | 
			
		||||
            ghcr.io/${{ github.repository }}:stable
 | 
			
		||||
            ghcr.io/${{ github.repository }}:latest
 | 
			
		||||
          labels: |
 | 
			
		||||
            action_id=${{ github.action }}
 | 
			
		||||
							
								
								
									
										1
									
								
								.github/workflows/container-version.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.github/workflows/container-version.yaml
									
									
									
									
										vendored
									
									
								
							@@ -47,6 +47,7 @@ jobs:
 | 
			
		||||
          push: true
 | 
			
		||||
          tags: |
 | 
			
		||||
            ghcr.io/${{ github.repository }}:${{ env.TAG }}
 | 
			
		||||
            ghcr.io/${{ github.repository }}:stable
 | 
			
		||||
          labels: |
 | 
			
		||||
            action_id=${{ github.action }}
 | 
			
		||||
            action_link=${{ env.LINK }}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										99
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -155,6 +155,8 @@ dependencies = [
 | 
			
		||||
 "log",
 | 
			
		||||
 "reqwest",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_yaml",
 | 
			
		||||
 "tempfile",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -772,15 +774,6 @@ version = "0.6.28"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "remove_dir_all"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "reqwest"
 | 
			
		||||
version = "0.11.13"
 | 
			
		||||
@@ -805,6 +798,7 @@ dependencies = [
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
 "rustls",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "serde_urlencoded",
 | 
			
		||||
@@ -818,6 +812,21 @@ dependencies = [
 | 
			
		||||
 "winreg",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ring"
 | 
			
		||||
version = "0.16.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "spin",
 | 
			
		||||
 "untrusted",
 | 
			
		||||
 "web-sys",
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rustix"
 | 
			
		||||
version = "0.36.6"
 | 
			
		||||
@@ -832,6 +841,18 @@ dependencies = [
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rustls"
 | 
			
		||||
version = "0.20.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "log",
 | 
			
		||||
 "ring",
 | 
			
		||||
 "sct",
 | 
			
		||||
 "webpki",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ryu"
 | 
			
		||||
version = "1.0.12"
 | 
			
		||||
@@ -847,6 +868,16 @@ dependencies = [
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sct"
 | 
			
		||||
version = "0.7.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "ring",
 | 
			
		||||
 "untrusted",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "security-framework"
 | 
			
		||||
version = "2.7.0"
 | 
			
		||||
@@ -913,6 +944,19 @@ dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_yaml"
 | 
			
		||||
version = "0.9.19"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "indexmap",
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "ryu",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "unsafe-libyaml",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha2"
 | 
			
		||||
version = "0.10.6"
 | 
			
		||||
@@ -943,6 +987,12 @@ dependencies = [
 | 
			
		||||
 "winapi",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "spin"
 | 
			
		||||
version = "0.5.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "strsim"
 | 
			
		||||
version = "0.10.0"
 | 
			
		||||
@@ -962,16 +1012,15 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tempfile"
 | 
			
		||||
version = "3.3.0"
 | 
			
		||||
version = "3.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
 | 
			
		||||
checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "fastrand",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "redox_syscall",
 | 
			
		||||
 "remove_dir_all",
 | 
			
		||||
 "winapi",
 | 
			
		||||
 "rustix",
 | 
			
		||||
 "windows-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1124,6 +1173,18 @@ dependencies = [
 | 
			
		||||
 "tinyvec",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "unsafe-libyaml"
 | 
			
		||||
version = "0.2.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ad2024452afd3874bf539695e04af6732ba06517424dbf958fdb16a01f3bef6c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "untrusted"
 | 
			
		||||
version = "0.7.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "url"
 | 
			
		||||
version = "2.3.1"
 | 
			
		||||
@@ -1239,6 +1300,16 @@ dependencies = [
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "webpki"
 | 
			
		||||
version = "0.22.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "ring",
 | 
			
		||||
 "untrusted",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "winapi"
 | 
			
		||||
version = "0.3.9"
 | 
			
		||||
 
 | 
			
		||||
@@ -11,3 +11,8 @@ log = "0.4.17"
 | 
			
		||||
http = "0.2.8"
 | 
			
		||||
serde = { version = "1.0.126", features = ["derive"] }
 | 
			
		||||
reqwest = { version = "0.11", features = ["json", "blocking", "rustls"] }
 | 
			
		||||
serde_yaml = "0.9"
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
tempfile = "3.4.0"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								README.md
									
									
									
									
									
								
							@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
# What's it about?
 | 
			
		||||
It's just a tool to make downloading binaries for different platforms easier. 
 | 
			
		||||
 | 
			
		||||
## For example
 | 
			
		||||
If you want to build a docker image, but you want to make it available on different platforms. But your tool needs other tools as dependencies, e.g. `helm`.
 | 
			
		||||
To install helm on Alpine you need to use curl, wget, or something. You need to choose a version, an operating system, and an architecture. For me, it was obvious that you must be able to use `uname -m`...
 | 
			
		||||
@@ -32,15 +33,15 @@ Prebuilt binaries exist for **Linux x86_64** and **MacOS arm64** and **x86_64**
 | 
			
		||||
 | 
			
		||||
Don't forget to add the binary to $PATH
 | 
			
		||||
```
 | 
			
		||||
$ curl https://raw.githubusercontent.com/allanger/clever-install/main/scripts/download_dudo.sh | bash
 | 
			
		||||
$ dudo -h
 | 
			
		||||
$ curl https://raw.githubusercontent.com/allanger/dumb-downloader/main/scripts/download_dudo.sh | bash
 | 
			
		||||
$ dudo --help
 | 
			
		||||
```
 | 
			
		||||
### Docker
 | 
			
		||||
 | 
			
		||||
You can use the `latest` or a `tagged` docker image
 | 
			
		||||
```
 | 
			
		||||
$ docker pull ghcr.io/allanger/clever-install:latest
 | 
			
		||||
$ docker run ghcr.io/allanger/clever-install:latest dudo -h
 | 
			
		||||
$ docker pull ghcr.io/allanger/dumb-downloader:latest
 | 
			
		||||
$ docker run ghcr.io/allanger/dumb-downloader:latest dudo -h
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Build from source
 | 
			
		||||
@@ -48,7 +49,67 @@ $ docker run ghcr.io/allanger/clever-install:latest dudo -h
 | 
			
		||||
```
 | 
			
		||||
$ cargo build --release
 | 
			
		||||
``` 
 | 
			
		||||
2. Run `gum help`
 | 
			
		||||
2. Run `dudo --help`
 | 
			
		||||
 | 
			
		||||
# How to use?
 | 
			
		||||
To be done
 | 
			
		||||
## Custom configurations
 | 
			
		||||
 | 
			
		||||
In case the default config is not doing the trick for you, you can pass a custom configuration, for example, you need to download a package "package-linux-amd64_x86_64_intel_v1.0.3" and this kind of name for an architecture is not supported by the `dudo`, then you can create a config file like 
 | 
			
		||||
```yaml
 | 
			
		||||
# config-example.yaml
 | 
			
		||||
---
 | 
			
		||||
---
 | 
			
		||||
os:
 | 
			
		||||
  macos:
 | 
			
		||||
    - macos
 | 
			
		||||
    - darwin
 | 
			
		||||
    - mac
 | 
			
		||||
    - apple
 | 
			
		||||
  linux:
 | 
			
		||||
    - linux
 | 
			
		||||
  windows:
 | 
			
		||||
    - windows
 | 
			
		||||
  freebsd:
 | 
			
		||||
    - freebsd
 | 
			
		||||
arch:
 | 
			
		||||
  x86_64:
 | 
			
		||||
    - x86_64
 | 
			
		||||
    - amd64
 | 
			
		||||
    - amd
 | 
			
		||||
    - intel
 | 
			
		||||
    - amd64_x86_64_intel
 | 
			
		||||
  aarch64:
 | 
			
		||||
    - aarch64
 | 
			
		||||
    - arm64
 | 
			
		||||
    - m1
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
And execute `dudo -l "package-{{ os }}-{{ arch }}-{{ version}}" -p v1.0.3 -d /tmp/package` and dudo will download the package to the `/tmp/package` then, 
 | 
			
		||||
 | 
			
		||||
## Dockerfile
 | 
			
		||||
 | 
			
		||||
The initial intetion for developing this was to use it for writing multi-architecture Dockerfiles for my another projects. I needed to download `helm` and `helmfile` for `arm64` and `amd64`. And I couldn't come up with good simple script for settings environment variables that would point to the the correct url, because `uname -m` wasn't giving me results that I would need. I was thinkg about writing a script to create some kind of map for different architectures, but then I thought that is was already not the first time I was having that problem and I decided to come up with a tool. And here is example, how one could use it in a `Dockerfile`
 | 
			
		||||
 | 
			
		||||
```DOCKERFILE
 | 
			
		||||
ARG BASE_VERSION=latest
 | 
			
		||||
FROM ghcr.io/allanger/dumb-downloader as builder
 | 
			
		||||
RUN apt-get update -y && apt-get install tar -y
 | 
			
		||||
ARG HELM_VERSION=v3.10.3
 | 
			
		||||
ARG HELMFILE_VERSION=0.151.0
 | 
			
		||||
ENV RUST_LOG=info
 | 
			
		||||
RUN dudo -l "https://github.com/helmfile/helmfile/releases/download/v{{ version }}/helmfile_{{ version }}_{{ os }}_{{ arch }}.tar.gz" -i /tmp/helmfile.tar.gz -p $HELMFILE_VERSION
 | 
			
		||||
RUN dudo -l "https://get.helm.sh/helm-{{ version }}-{{ os }}-{{ arch }}.tar.gz" -i /tmp/helm.tar.gz -p $HELM_VERSION
 | 
			
		||||
RUN tar -xf /tmp/helm.tar.gz  -C /tmp && rm -f /tmp/helm.tar.gz 
 | 
			
		||||
RUN tar -xf /tmp/helmfile.tar.gz  -C /tmp && rm -f /tmp/helmfile.tar.gz 
 | 
			
		||||
RUN mkdir /out && for bin in `find /tmp | grep helm`; do cp $bin /out/; done
 | 
			
		||||
RUN chmod +x /out/helm
 | 
			
		||||
RUN chmod +x /out/helmfile
 | 
			
		||||
 | 
			
		||||
FROM ghcr.io/allanger/check-da-helm-base:${BASE_VERSION} 
 | 
			
		||||
COPY --from=builder /out/ /usr/bin
 | 
			
		||||
RUN apk update --no-cache && apk add --no-cache jq bash
 | 
			
		||||
ENTRYPOINT ["cdh"]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
In the builder it is downloading dependencies that are needed in my final docker image.
 | 
			
		||||
							
								
								
									
										23
									
								
								example/config.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								example/config.yaml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
---
 | 
			
		||||
os:
 | 
			
		||||
  macos:
 | 
			
		||||
    - macos
 | 
			
		||||
    - darwin
 | 
			
		||||
    - mac
 | 
			
		||||
    - apple
 | 
			
		||||
  linux:
 | 
			
		||||
    - linux
 | 
			
		||||
  windows:
 | 
			
		||||
    - windows
 | 
			
		||||
  freebsd:
 | 
			
		||||
    - freebsd
 | 
			
		||||
arch:
 | 
			
		||||
  x86_64:
 | 
			
		||||
    - x86_64
 | 
			
		||||
    - amd64
 | 
			
		||||
    - amd
 | 
			
		||||
    - intel
 | 
			
		||||
  aarch64:
 | 
			
		||||
    - aarch64
 | 
			
		||||
    - arm64
 | 
			
		||||
    - m1
 | 
			
		||||
@@ -1,10 +1,10 @@
 | 
			
		||||
#!/bin/bash
 | 
			
		||||
echo 'renaming dudo to dudo-$VERSION-$SYSTEM format'
 | 
			
		||||
mkdir -p release
 | 
			
		||||
echo "version - $CLIN_VERSION"
 | 
			
		||||
echo "version - $VERSION"
 | 
			
		||||
for BUILD in build*; do
 | 
			
		||||
  SYSTEM=$(echo $BUILD | sed -e 's/build-//g')
 | 
			
		||||
  echo "system - $SYSTEM"
 | 
			
		||||
  cp $BUILD/dudo release/dudo-$CLIN_VERSION-$SYSTEM
 | 
			
		||||
  cp $BUILD/dudo release/dudo-$VERSION-$SYSTEM
 | 
			
		||||
done
 | 
			
		||||
ls release
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										243
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										243
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -5,64 +5,251 @@ use log::{error, info};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
use std::{
 | 
			
		||||
    collections::HashMap,
 | 
			
		||||
    env::consts::{ARCH, OS},
 | 
			
		||||
    fs::File,
 | 
			
		||||
    io,
 | 
			
		||||
    fmt::Display,
 | 
			
		||||
    fs::{File, OpenOptions},
 | 
			
		||||
    io::{self},
 | 
			
		||||
    process::exit,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type Result<T> = std::result::Result<T, DudoError>;
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
enum DudoError {
 | 
			
		||||
    IoError(io::Error),
 | 
			
		||||
    SerdeYamlError(serde_yaml::Error),
 | 
			
		||||
}
 | 
			
		||||
impl From<io::Error> for DudoError {
 | 
			
		||||
    fn from(error: io::Error) -> Self {
 | 
			
		||||
        DudoError::IoError(error)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<serde_yaml::Error> for DudoError {
 | 
			
		||||
    fn from(error: serde_yaml::Error) -> Self {
 | 
			
		||||
        DudoError::SerdeYamlError(error)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Display for DudoError {
 | 
			
		||||
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            DudoError::SerdeYamlError(err) => write!(f, "{}", err),
 | 
			
		||||
            DudoError::IoError(err) => write!(f, "{}", err),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static CONFIG: &str = "
 | 
			
		||||
---
 | 
			
		||||
os:
 | 
			
		||||
  macos:
 | 
			
		||||
    - macos
 | 
			
		||||
    - darwin
 | 
			
		||||
    - mac
 | 
			
		||||
    - apple
 | 
			
		||||
  linux:
 | 
			
		||||
    - linux
 | 
			
		||||
  windows:
 | 
			
		||||
    - windows
 | 
			
		||||
  freebsd:
 | 
			
		||||
    - freebsd
 | 
			
		||||
arch:
 | 
			
		||||
  x86_64:
 | 
			
		||||
    - x86_64
 | 
			
		||||
    - amd64
 | 
			
		||||
    - amd
 | 
			
		||||
    - intel
 | 
			
		||||
  aarch64:
 | 
			
		||||
    - aarch64
 | 
			
		||||
    - arm64
 | 
			
		||||
    - m1
 | 
			
		||||
";
 | 
			
		||||
 | 
			
		||||
/// Maybe not that clever, but at least not dumb. Download binaries for defferent architectures easier
 | 
			
		||||
#[derive(Parser)]
 | 
			
		||||
#[clap(author = "allanger <allanger@zohomail.com>", version, about, long_about = None, arg_required_else_help(true))]
 | 
			
		||||
struct Args {
 | 
			
		||||
    /// A templated link for downloading
 | 
			
		||||
    #[clap(short, long, env = "CLIN_LINK")]
 | 
			
		||||
    #[clap(short, long, env = "DUDO_LINK_TEMPLATE")]
 | 
			
		||||
    link_template: String,
 | 
			
		||||
    /// Version that you want to download
 | 
			
		||||
    #[clap(short, long, env = "CLIN_VERSION")]
 | 
			
		||||
    #[clap(short, long, env = "DUDO_PACKAGE_VERSION")]
 | 
			
		||||
    package_version: String,
 | 
			
		||||
    /// Path to download
 | 
			
		||||
    #[clap(short, long, env = "CLIN_PATH")]
 | 
			
		||||
    install_path: String,
 | 
			
		||||
    #[clap(short, long, env = "DUDO_DOWNLOADPATH")]
 | 
			
		||||
    download_path: String,
 | 
			
		||||
    /// Path to dudo config file
 | 
			
		||||
    #[clap(short, long, default_value = "", env = "DUDO_CONFIG")]
 | 
			
		||||
    config: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize)]
 | 
			
		||||
struct Values {
 | 
			
		||||
struct SystemValues {
 | 
			
		||||
    version: String,
 | 
			
		||||
    os: String,
 | 
			
		||||
    arch: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize, Debug)]
 | 
			
		||||
struct Config {
 | 
			
		||||
    os: HashMap<String, Vec<String>>,
 | 
			
		||||
    arch: HashMap<String, Vec<String>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    // Initial steps
 | 
			
		||||
    env_logger::init();
 | 
			
		||||
    let args = Args::parse();
 | 
			
		||||
    let mut reg = Handlebars::new();
 | 
			
		||||
    reg.register_template_string("download_link", args.link_template)
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    let archs: Vec<String> = match ARCH {
 | 
			
		||||
        "x86_64" => vec!["x86_64".to_string(), "amd64".to_string()],
 | 
			
		||||
        "aarch64" => vec!["aarch64".to_string(), "arm64".to_string()],
 | 
			
		||||
        _ => {
 | 
			
		||||
            error!("Unknown architecture");
 | 
			
		||||
    // Register download url template
 | 
			
		||||
    let mut reg = Handlebars::new();
 | 
			
		||||
    match reg.register_template_string("download_link", args.link_template) {
 | 
			
		||||
        Ok(_) => info!("Your template is successfully registered"),
 | 
			
		||||
        Err(err) => error!("{}", err),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Set system aliases
 | 
			
		||||
    let config = match parse_config(args.config) {
 | 
			
		||||
        Ok(config) => config,
 | 
			
		||||
        Err(err) => {
 | 
			
		||||
            error!("{}", err);
 | 
			
		||||
            exit(1);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for arch in archs {
 | 
			
		||||
        let version = args.package_version.clone();
 | 
			
		||||
        let os = OS.to_string();
 | 
			
		||||
        let values = Values { arch, os, version };
 | 
			
		||||
    info!("Running on {} {}", OS, ARCH);
 | 
			
		||||
    let oss = config.os.get(&OS.clone().to_string()).unwrap();
 | 
			
		||||
    let archs = config.arch.get(&ARCH.clone().to_string()).unwrap();
 | 
			
		||||
 | 
			
		||||
        let link = reg.render("download_link", &values).unwrap();
 | 
			
		||||
        info!("Trying to download from {}", link.clone());
 | 
			
		||||
        let mut resp = reqwest::blocking::get(link).unwrap();
 | 
			
		||||
        if resp.status() == StatusCode::OK {
 | 
			
		||||
            info!("Response is 200, I'll try to download");
 | 
			
		||||
            let mut out = File::create(args.install_path).expect("failed to create file");
 | 
			
		||||
            io::copy(&mut resp, &mut out).expect("failed to copy content");
 | 
			
		||||
            break;
 | 
			
		||||
    for arch in archs {
 | 
			
		||||
        for os in oss {
 | 
			
		||||
            let version = args.package_version.clone();
 | 
			
		||||
            let values = SystemValues {
 | 
			
		||||
                arch: arch.clone(),
 | 
			
		||||
                os: os.clone(),
 | 
			
		||||
                version,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let link = reg.render("download_link", &values).unwrap();
 | 
			
		||||
            info!("Trying to download from {}", link.clone());
 | 
			
		||||
            let mut resp = reqwest::blocking::get(link).unwrap();
 | 
			
		||||
            if resp.status() == StatusCode::OK {
 | 
			
		||||
                info!("Response is 200, I'll try to download");
 | 
			
		||||
                let mut out =
 | 
			
		||||
                    File::create(args.download_path.clone()).expect("failed to create file");
 | 
			
		||||
                io::copy(&mut resp, &mut out).expect("failed to copy content");
 | 
			
		||||
                exit(0);
 | 
			
		||||
            }
 | 
			
		||||
            info!("Will try another name for arch, because response is not 200");
 | 
			
		||||
        }
 | 
			
		||||
        info!("Will try another name for arch, because response is not 200");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn parse_config(config_path: String) -> Result<Config> {
 | 
			
		||||
    let config_res: std::result::Result<Config, _>;
 | 
			
		||||
    if config_path.is_empty() {
 | 
			
		||||
        config_res = serde_yaml::from_str(CONFIG);
 | 
			
		||||
    } else {
 | 
			
		||||
        let f = OpenOptions::new().write(false).read(true).open(config_path);
 | 
			
		||||
        let f = match f {
 | 
			
		||||
            Ok(file) => file,
 | 
			
		||||
            Err(err) => {
 | 
			
		||||
                return Err(err.into());
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        config_res = serde_yaml::from_reader(f);
 | 
			
		||||
    }
 | 
			
		||||
    match config_res {
 | 
			
		||||
        Ok(config) => Ok(config),
 | 
			
		||||
        Err(err) => Err(err.into()),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::parse_config;
 | 
			
		||||
    use std::io::Write;
 | 
			
		||||
    use tempfile::NamedTempFile;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parse_config_default() {
 | 
			
		||||
        let config = parse_config("".to_owned()).unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("linux").unwrap().clone(),
 | 
			
		||||
            vec!["linux".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("windows").unwrap().clone(),
 | 
			
		||||
            vec!["windows".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("macos").unwrap().clone(),
 | 
			
		||||
            vec![
 | 
			
		||||
                "macos".to_string(),
 | 
			
		||||
                "darwin".to_string(),
 | 
			
		||||
                "mac".to_string(),
 | 
			
		||||
                "apple".to_string(),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.arch.get("x86_64").unwrap().clone(),
 | 
			
		||||
            vec![
 | 
			
		||||
                "x86_64".to_string(),
 | 
			
		||||
                "amd64".to_string(),
 | 
			
		||||
                "amd".to_string(),
 | 
			
		||||
                "intel".to_string(),
 | 
			
		||||
            ]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.arch.get("aarch64").unwrap().clone(),
 | 
			
		||||
            vec!["aarch64".to_string(), "arm64".to_string(), "m1".to_string(),]
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn parse_config_custom() {
 | 
			
		||||
        let config = "
 | 
			
		||||
---
 | 
			
		||||
os:
 | 
			
		||||
  macos:
 | 
			
		||||
    - macos
 | 
			
		||||
  linux:
 | 
			
		||||
    - linux
 | 
			
		||||
  windows:
 | 
			
		||||
    - windows
 | 
			
		||||
  freebsd:
 | 
			
		||||
    - freebsd
 | 
			
		||||
arch:
 | 
			
		||||
  x86_64:
 | 
			
		||||
    - x86_64
 | 
			
		||||
  aarch64:
 | 
			
		||||
    - aarch64
 | 
			
		||||
        ";
 | 
			
		||||
        let mut file = NamedTempFile::new().unwrap();
 | 
			
		||||
        writeln!(file, "{}", config).unwrap();
 | 
			
		||||
        let path = file.into_temp_path();
 | 
			
		||||
        // It's looking damn not right
 | 
			
		||||
        let config = parse_config(path.to_str().unwrap().clone().to_string()).unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("linux").unwrap().clone(),
 | 
			
		||||
            vec!["linux".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("windows").unwrap().clone(),
 | 
			
		||||
            vec!["windows".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.os.get("macos").unwrap().clone(),
 | 
			
		||||
            vec!["macos".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.arch.get("x86_64").unwrap().clone(),
 | 
			
		||||
            vec!["x86_64".to_string()]
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            config.arch.get("aarch64").unwrap().clone(),
 | 
			
		||||
            vec!["aarch64".to_string()]
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user