Compare commits

...

22 Commits
v0.1.0 ... main

Author SHA1 Message Date
48fe4ba396
Version 0.2.2 2024-02-27 15:20:45 +01:00
535d13222d
Update dependencies 2024-02-27 14:39:26 +01:00
Nikolai Rodionov
a008e20cc7
fix: Fix the Dockerfile, so it can build again
I think I've just forgotten to add `-y` to apt-get. So the image could
not be built because it was waiting for a user's input

Issue: https://git.badhouseplants.net/allanger/dumb-downloader/issues/9
2023-06-24 10:01:46 +02:00
Nikolai Rodionov
0f80b14869
chore: Update the builder container version 2023-06-19 21:58:27 +02:00
Nikolai Rodionov
c594257c4f
Run cargo update to keep dependencies updated 2023-06-10 00:06:38 +02:00
Nikolai Rodionov
bd6c0a0bc6
chore: Update dependencies 2023-05-07 11:15:47 +02:00
Nikolai Rodionov
04c79984c0 fix: Use nightly so Github actions won't exit with 137 2023-03-24 15:59:58 +01:00
Nikolai Rodionov
534834680b fix: Update Cargo.lock 2023-03-24 15:50:32 +01:00
Nikolai Rodionov
a6737c1871 Version 0.2.0 2023-03-24 15:42:15 +01:00
Nikolai Rodionov
07e156dd3f feat: Better configuration and description 2023-03-24 15:39:47 +01:00
Nikolai Rodionov
6459152833 Migrate the Dockerfile to Ubuntu 2023-02-12 20:13:42 +01:00
Nikolai Rodionov
86f00a4c9c Add a rusttls feature 2023-02-12 14:06:31 +01:00
Nikolai Rodionov
5471d3126b Version 0.1.1 2023-02-12 10:07:03 +01:00
Nikolai Rodionov
bf362afb98
Add docker build (#1) 2023-02-12 09:51:14 +01:00
Nikolai Rodionov
18fd9d827b Update some stuff, now everything must work 2023-01-18 13:28:57 +01:00
Nikolai Rodionov
ce0a54a08b Try using repo info from the github object again 2023-01-18 12:36:12 +01:00
Nikolai Rodionov
c278056a2c Try using repo info from the github object 2023-01-18 12:34:05 +01:00
Nikolai Rodionov
f18bf4d5d7 Use another env for an image tag 2023-01-18 12:31:07 +01:00
Nikolai Rodionov
543ca1b21b Fix worklow syntax 2023-01-18 12:29:50 +01:00
Nikolai Rodionov
fdfc64924e Debug workflows 2023-01-18 12:28:46 +01:00
Nikolai Rodionov
cf2678c299 Add a license and update github workflow 2023-01-18 12:24:07 +01:00
Nikolai Rodionov
0162b080f1 FIX: Update containers build jobs 2023-01-17 22:46:26 +01:00
14 changed files with 1076 additions and 496 deletions

View File

@ -21,7 +21,7 @@ jobs:
target: aarch64-apple-darwin
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:
@ -34,23 +34,23 @@ jobs:
args: --release --all-features --target=${{ matrix.target }}
- name: Archive build artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: build-${{matrix.target}}
path: ${{ github.workspace }}/target/${{ matrix.target }}/release/clin
path: ${{ github.workspace }}/target/${{ matrix.target }}/release/dudo
release:
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Download artifact
uses: actions/download-artifact@v2
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

View File

@ -1,19 +1,19 @@
---
name: "Stable container"
name: "Latest container"
on:
push:
branches:
- main
paths:
- "src/**"
jobs:
containerization:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set action link variable
run: echo "LINK=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_ENV
@ -28,14 +28,14 @@ jobs:
uses: docker/setup-buildx-action@master
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
@ -43,8 +43,7 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/allanger/${{ env.GITHUB_REPOSITORY }}:stable
ghcr.io/allanger/${{ env.GITHUB_REPOSITORY }}:latest
ghcr.io/${{ github.repository }}:latest
labels: |
action_id=${{ github.action }}
action_link=${{ env.LINK }}

View File

@ -9,9 +9,11 @@ on:
jobs:
containerization:
runs-on: ubuntu-latest
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set version variable
run: echo "TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV
@ -29,14 +31,14 @@ jobs:
uses: docker/setup-buildx-action@master
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.CR_PAT }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build
uses: docker/build-push-action@v2
uses: docker/build-push-action@v3
with:
builder: ${{ steps.buildx.outputs.name }}
context: .
@ -44,7 +46,8 @@ jobs:
platforms: linux/amd64,linux/arm64
push: true
tags: |
ghcr.io/allanger/${{ env.GITHUB_REPOSITORY }}:${{ env.TAG }}
ghcr.io/${{ github.repository }}:${{ env.TAG }}
ghcr.io/${{ github.repository }}:stable
labels: |
action_id=${{ github.action }}
action_link=${{ env.LINK }}

View File

@ -9,27 +9,11 @@ on:
- "src/**"
jobs:
cargo_udeps:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
- name: Install cargo-udeps
run: cargo install cargo-udeps --locked
- name: Check dependencies
run: cargo +nightly udeps
cargo_test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- uses: actions-rs/toolchain@v1
with:

25
.github/workflows/udeps_test.yaml vendored Normal file
View File

@ -0,0 +1,25 @@
---
name: "Tests"
on:
pull_request:
branches:
- main
jobs:
cargo_udeps:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: nightly
- name: Install cargo-udeps
run: cargo install cargo-udeps --locked
- name: Check dependencies
run: cargo +nightly udeps

1027
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,17 @@
[package]
name = "clin"
version = "0.1.0"
name = "dudo"
version = "0.2.2"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
clap = { version = "4.1.1", features = ["derive", "env"] }
handlebars = "4.3.1"
env_logger = "0.10.0"
handlebars = "5.1.0"
env_logger = "0.11.2"
log = "0.4.17"
http = "0.2.8"
serde = { version = "1.0.126", features = ["derive"] }
reqwest = { version = "0.11", features = ["json", "blocking"] }
reqwest = { version = "0.11", features = ["json", "blocking", "rustls"] }
serde_yaml = "0.9"
[dev-dependencies]
tempfile = "3.4.0"

View File

@ -1,12 +1,17 @@
FROM rust:1.66.1-alpine3.17 as builder
FROM rust:1.76.0-slim-bookworm as builder
WORKDIR /src
RUN apk update && apk add --no-cache libressl-dev musl-dev gcc
RUN apt-get update &&\
apt-get install -y libssl-dev gcc musl pkg-config
COPY ./ .
RUN cargo build --release
RUN rustup default nightly && rustup update
RUN cargo build --release --jobs 2 -Z sparse-registry
FROM alpine:3.17.1
COPY --from=builder /src/target/release/clin /bin/clin
RUN apk update && apk add openssl --no-cache
FROM debian:stable
COPY --from=builder /src/target/release/dudo /bin/dudo
RUN apt-get update &&\
apt-get install -y openssl ca-certificates &&\
apt-get clean -y
RUN chmod +x /bin/dudo
WORKDIR /workdir
ENTRYPOINT ["/bin/clin"]
ENTRYPOINT ["/bin/dudo"]

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) [year] [fullname]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

115
README.md
View File

@ -0,0 +1,115 @@
# Dumb Downloader (dudo)
# 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`...
```BASH
uname -m
aarch64
uname -m
x86_64
uname -m
arm64
```
While release naming is also not very consecutive
- release_example.amd-macos.zip
- another-release-for-amd64-macos.zip
- linux-aarch64-release.zip
# How to install?
## Install
### Download
Get executable from github releases
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/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/dumb-downloader:latest
$ docker run ghcr.io/allanger/dumb-downloader:latest dudo -h
```
### Build from source
1. Build binary
```
$ cargo build --release
```
2. Run `dudo --help`
# How to use?
## 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
View 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

View File

@ -36,15 +36,15 @@ esac
LATEST_VERSION="v$(curl -s https://raw.githubusercontent.com/allanger/clever-install/main/Cargo.toml | awk -F ' = ' '$1 ~ /version/ { gsub(/[\"]/, "", $2); printf("%s",$2); exit}')"
echo "Downloading $LATEST_VERSION"
RELEASE_NAME=clin-$LATEST_VERSION-$TARGET
RELEASE_NAME=dudo-$LATEST_VERSION-$TARGET
RELEASE_URL="https://github.com/allanger/clever-install/releases/download/$LATEST_VERSION/$RELEASE_NAME"
echo "Link for downloading: $RELEASE_URL"
curl -LJO $RELEASE_URL
mv $RELEASE_NAME clin
chmod +x clin
mv $RELEASE_NAME dudo
chmod +x dudo
echo 'Make sure that clin is in your $PATH'
echo 'Make sure that dudo is in your $PATH'
echo 'Try: '
echo ' $ export PATH=$PATH:$PWD'
echo ' $ clin -h'
echo ' $ dudo -h'

View File

@ -1,10 +1,10 @@
#!/bin/bash
echo 'renaming clin to clin-$VERSION-$SYSTEM format'
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/clin release/clin-$CLIN_VERSION-$SYSTEM
cp $BUILD/dudo release/dudo-$VERSION-$SYSTEM
done
ls release

View File

@ -1,68 +1,254 @@
use clap::Parser;
use handlebars::Handlebars;
use http::{StatusCode};
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,
};
/// Check you helm releaseas managed by Argo
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)]
#[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.to_string()).unwrap();
let archs = config.arch.get(&ARCH.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().is_success() {
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()]
)
}
}