diff --git a/.ci/.gitlab-ci.yml b/.ci/.gitlab-ci.yml index 39774d9..496455e 100644 --- a/.ci/.gitlab-ci.yml +++ b/.ci/.gitlab-ci.yml @@ -4,12 +4,12 @@ stages: flexapp_build_linux: stage: build - image: docker:27.4.1-dind + image: docker:latest variables: DOCKER_TLS_CERTDIR: "" DOCKER_HOST: tcp://docker:2375/ services: - - name: docker:27.4.1-dind + - name: docker:28.5.1-dind alias: docker rules: - if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^v/' @@ -30,12 +30,12 @@ flexapp_build_linux: flexapp_build_windows: stage: build - image: docker:27.4.1-dind + image: docker:latest variables: DOCKER_TLS_CERTDIR: "" DOCKER_HOST: tcp://docker:2375/ services: - - name: docker:27.4.1-dind + - name: docker:28.5.1-dind alias: docker rules: - if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG =~ /^v/' diff --git a/.ci/dagger.json b/.ci/dagger.json index 8f32fa1..abde828 100644 --- a/.ci/dagger.json +++ b/.ci/dagger.json @@ -1,6 +1,6 @@ { "name": "Ci", - "engineVersion": "v0.15.3", + "engineVersion": "v0.19.0", "sdk": "python", "source": "dagger" } diff --git a/.ci/dagger/src/ci/main.py b/.ci/dagger/src/ci/main.py index 701e441..dc3b81c 100644 --- a/.ci/dagger/src/ci/main.py +++ b/.ci/dagger/src/ci/main.py @@ -4,7 +4,7 @@ @object_type class Ci: - zig_version = "0.15.1" + zig_version = "0.15.2" zig_binary = f"zig-x86_64-linux-{zig_version}" @function diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d706b75..0dec3f8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM --platform=linux/amd64 ubuntu:24.04 +FROM ubuntu:24.04 RUN apt update RUN apt install curl unzip zsh git sudo \ build-essential wget libssl-dev software-properties-common \ @@ -10,8 +10,8 @@ RUN curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh RUN curl --proto '=https' --tlsv1.2 -sSf https://just.systems/install.sh | bash -s -- --to /usr/bin -ARG ZIG_VERSION_BINARY=zig-x86_64-linux-0.15.1 -ARG ZIG_VERSION=0.15.1 +ARG ZIG_VERSION_BINARY=zig-x86_64-linux-0.15.2 +ARG ZIG_VERSION=0.15.2 ARG ZLS_VERSION=0.15.0 # ARG ZIG_DOWNLOAD=https://ziglang.org/builds/$ZIG_VERSION.tar.xz ARG ZIG_DOWNLOAD=https://ziglang.org/download/$ZIG_VERSION/$ZIG_VERSION_BINARY.tar.xz diff --git a/.flox/env/manifest.toml b/.flox/env/manifest.toml index 139601b..70b80b6 100755 --- a/.flox/env/manifest.toml +++ b/.flox/env/manifest.toml @@ -15,7 +15,7 @@ zsh.pkg-path = "zsh" starship.pkg-path = "starship" docker.pkg-path = "docker" zig.pkg-path = "zig" -zig.version = "0.15.1" +zig.version = "0.15.2" zls.pkg-path = "zls" zls.version = "0.15.0" # hello.pkg-path = "hello" diff --git a/.forgejo/workflows/flexapp.yaml b/.forgejo/workflows/flexapp.yaml index 12a03a6..83b9420 100644 --- a/.forgejo/workflows/flexapp.yaml +++ b/.forgejo/workflows/flexapp.yaml @@ -18,7 +18,7 @@ on: jobs: testing: - runs-on: codeberg-tiny + runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Dagger Rust Tests @@ -46,7 +46,7 @@ jobs: once: needs: testing name: Create Forgejo release - runs-on: codeberg-tiny + runs-on: ubuntu-latest outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} steps: @@ -74,7 +74,7 @@ jobs: strategy: matrix: os: [linux, windows] - platform: [codeberg-tiny] + platform: [ubuntu-latest] runs-on: ${{ matrix.platform }} diff --git a/.gitea/workflows/flexapp.yaml b/.gitea/workflows/flexapp.yaml index 138f69e..b86cb39 100644 --- a/.gitea/workflows/flexapp.yaml +++ b/.gitea/workflows/flexapp.yaml @@ -1,4 +1,4 @@ -name: smdc_portal +name: flexapp on: push: @@ -18,20 +18,33 @@ on: jobs: testing: - strategy: - matrix: - optimize: [ReleaseSafe, ReleaseFast] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: mlugg/setup-zig@v2 - with: - version: master - cache-key: ${{ matrix.optimize }} - - run: zig test src/root.zig -O${{ matrix.optimize }} + - name: Dagger Rust Tests + run: | + apt update && apt install -y curl unzip wget docker.io + + # Try to connect to Docker + if docker info; then + echo "Docker is working!" + else + echo "Docker daemon not accessible, checking alternatives..." + + # Check if we can start dockerd + echo "Attempting to start Docker daemon..." + dockerd --host=unix:///var/run/docker.sock & + sleep 10 + docker info || echo "Still no Docker access" + fi + + curl -L https://dl.dagger.io/dagger/install.sh | BIN_DIR=$HOME/.local/bin sh; + export PATH="$HOME/.local/bin:$PATH"; + cd .ci; + dagger call tests --src=../; once: - name: Create GitHub release + name: Create Gitea release runs-on: 'ubuntu-latest' needs: testing outputs: @@ -46,7 +59,7 @@ jobs: tag_name: ${{ github.ref }} release_name: Release ${{ github.ref }} body: | - Automated Release by GitHub Action CI + Automated Release by Gitea Action CI draft: false prerelease: false diff --git a/.github/workflows/flexapp.yaml b/.github/workflows/flexapp.yaml index e55ccdb..854c7e3 100644 --- a/.github/workflows/flexapp.yaml +++ b/.github/workflows/flexapp.yaml @@ -7,11 +7,11 @@ on: tags: - "release-v[0-9]+.[0-9]+.[0-9]+" - "release-v[0-9]+.[0-9]+.[0-9]+-rc[0-9]+" - pull_request: - branches: - - main - paths: - - RELEASE_NOTES.md + # pull_request: + # branches: + # - main + # paths: + # - RELEASE_NOTES.md jobs: testing: @@ -23,7 +23,7 @@ jobs: - uses: actions/checkout@v4 - uses: mlugg/setup-zig@v2 with: - version: master + version: 0.15.2 cache-key: ${{ matrix.optimize }} - run: zig test src/root.zig -O${{ matrix.optimize }} diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 867dfc5..ca7cda0 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -16,6 +16,6 @@ jobs: - uses: actions/checkout@v4 - uses: mlugg/setup-zig@v2 with: - version: master + version: 0.15.2 cache-key: ${{ matrix.optimize }} - run: zig test src/root.zig -O${{ matrix.optimize }} \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4f3c89d..6ea6b98 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,12 +4,12 @@ stages: flexapp_testing: stage: .pre - image: docker:27.4.1-dind + image: docker:latest variables: DOCKER_TLS_CERTDIR: "" DOCKER_HOST: tcp://docker:2375/ services: - - name: docker:27.4.1-dind + - name: docker:28.5.1-dind alias: docker rules: - if: $CI_COMMIT_TAG =~ /^release-.*/ @@ -28,12 +28,12 @@ flexapp_testing: flexapp_build_linux: stage: build - image: docker:27.4.1-dind + image: docker:latest variables: DOCKER_TLS_CERTDIR: "" DOCKER_HOST: tcp://docker:2375/ services: - - name: docker:27.4.1-dind + - name: docker:28.5.1-dind alias: docker rules: - if: $CI_COMMIT_TAG =~ /^release-.*/ @@ -55,12 +55,12 @@ flexapp_build_linux: flexapp_build_windows: stage: build - image: docker:27.4.1-dind + image: docker:28.5.1-dind variables: DOCKER_TLS_CERTDIR: "" DOCKER_HOST: tcp://docker:2375/ services: - - name: docker:27.4.1-dind + - name: docker:28.5.1-dind alias: docker rules: - if: $CI_COMMIT_TAG =~ /^release-.*/ diff --git a/src/download.zig b/src/download.zig new file mode 100644 index 0000000..564ff30 --- /dev/null +++ b/src/download.zig @@ -0,0 +1,101 @@ +const std = @import("std"); +const helper = @import("helper.zig"); +pub fn download(allocator: std.mem.Allocator, url: []const u8) ![]const u8 { + std.debug.print("{s} {s}\n", .{ "Starting download for", url }); + + var client = std.http.Client{ + .allocator = allocator, + }; + defer client.deinit(); + + try client.ca_bundle.rescan(allocator); + // defer client.ca_bundle.deinit(allocator); + // std.debug.print("CA bundle size: {}\n", .{client.ca_bundle.bytes.items.len}); + + const uri = try std.Uri.parse(url); + var buf: [8192]u8 = undefined; + var req = client.request(.GET, uri, .{ + .redirect_behavior = .unhandled, + .keep_alive = false, + }) catch |err| { + std.debug.print("Error creating request: {}\n", .{err}); + return "unknown.txt"; + }; + defer req.deinit(); + + req.redirect_behavior = .unhandled; + try req.sendBodiless(); + var response = try req.receiveHead(&buf); + + if (response.head.status != .ok) { + if (response.head.status != .found) { + std.debug.print("Response Failed: {any}\n", .{response.head.status}); + return "unknown.txt"; + } + } + + var filename: []const u8 = "unknown.txt"; + var iter = response.head.iterateHeaders(); + while (iter.next()) |header| { + std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value }); + if (std.mem.containsAtLeast(u8, header.value, 1, "attachment; filename=")) { + var filename1 = std.mem.splitSequence(u8, header.value, "filename="); + // Consume first iterator + _ = filename1.first(); + filename = filename1.rest(); + // Check for more stuff in filename + var filename2 = std.mem.splitSequence(u8, filename, ";"); + filename = filename2.first(); + break; + } + } + + if (std.mem.eql(u8, filename, "unknown.txt")) { + var filename1 = std.mem.splitSequence(u8, url, "/"); + while (filename1.next()) |f| { + filename = f; + } + + filename = try helper.replaceAll(allocator, filename, "?*<|", "_____"); + } + const filename_final = try allocator.dupe(u8, filename); + + const file = try std.fs.cwd().createFile( + filename, + .{ .read = true }, + ); + allocator.free(filename); + defer file.close(); + + var buffer: [64]u8 = undefined; + const decompress_buffer: []u8 = switch (response.head.content_encoding) { + .identity => &.{}, + .zstd => try allocator.alloc(u8, std.compress.zstd.default_window_len), + .deflate, .gzip => try allocator.alloc(u8, std.compress.flate.max_window_len), + .compress => return error.UnsupportedCompressionMethod, + }; + defer allocator.free(decompress_buffer); + + var transfer_buffer: [64]u8 = undefined; + var decompress: std.http.Decompress = undefined; + const reader = response.readerDecompressing(&transfer_buffer, &decompress, decompress_buffer); + + var file_writer: std.fs.File.Writer = .init(file, &buffer); + _ = reader.streamRemaining(&file_writer.interface) catch |err| { + std.debug.print("Error during download/decompression: {}\n", .{err}); + return "unknown.txt"; + }; + // Flush remaining buffer just in case. + try file_writer.interface.flush(); + + return filename_final; +} + +test "download function" { + const testing_allocator = std.testing.allocator; + + const url = "https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi"; + const filename = try download(testing_allocator, url); + defer testing_allocator.free(filename); + std.debug.print("Downloaded file: {s}\n", .{filename}); +} diff --git a/src/helper.zig b/src/helper.zig index 5402f4c..54ca9bc 100644 --- a/src/helper.zig +++ b/src/helper.zig @@ -17,6 +17,20 @@ pub fn replace(allocator: std.mem.Allocator, haystack: []const u8, needle: []con } return result.toOwnedSlice(allocator); } +pub fn replaceAll(allocator: std.mem.Allocator, haystack: []const u8, needle: []const u8, replacement: []const u8) ![]u8 { + var result: std.ArrayList(u8) = .empty; + defer result.deinit(allocator); + outer: for (haystack) |c| { + for (needle, 0..) |ctr, i| { + if (c == ctr) { + try result.append(allocator, replacement[i]); + continue :outer; + } + } + try result.append(allocator, c); + } + return result.toOwnedSlice(allocator); +} pub fn test_file_path(path: []const u8) !bool { const file = std.fs.cwd().openFile(path, .{}) catch |err| { diff --git a/src/main.zig b/src/main.zig index 40cf47a..b24f896 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,6 +1,7 @@ const clap = @import("clap"); const std = @import("std"); const helper = @import("helper.zig"); +const download = @import("download.zig").download; const Version = struct { major: u16, @@ -196,72 +197,6 @@ pub fn execute(name: []const u8, package_version: []const u8, output: []const u8 } } -pub fn download(allocator: std.mem.Allocator, url: []const u8) ![]const u8 { - std.debug.print("{s} {s}\n", .{ "Starting download for", url }); - var client = std.http.Client{ .allocator = allocator }; - defer client.deinit(); - - const uri = try std.Uri.parse(url); - var buf: [8192]u8 = undefined; - var req = client.request(.GET, uri, .{}) catch { - return "unknown.txt"; - }; - defer req.deinit(); - - req.redirect_behavior = @enumFromInt(65000); - try req.sendBodiless(); - var response = try req.receiveHead(&buf); - - if (response.head.status != .ok) { - if (response.head.status != .found) { - std.debug.print("Response Failed: {any}\n", .{response.head.status}); - return "unknown.txt"; - } - } - - var filename: []const u8 = "unknown.txt"; - var iter = response.head.iterateHeaders(); - while (iter.next()) |header| { - // std.debug.print("Name:{s}, Value:{s}\n", .{ header.name, header.value }); - if (std.mem.containsAtLeast(u8, header.value, 1, "attachment; filename=")) { - var filename1 = std.mem.splitSequence(u8, header.value, "filename="); - // Consume first iterator - _ = filename1.first(); - filename = filename1.rest(); - // Check for more stuff in filename - var filename2 = std.mem.splitSequence(u8, filename, ";"); - filename = filename2.first(); - break; - } - } - - if (std.mem.eql(u8, filename, "unknown.txt")) { - var filename1 = std.mem.splitSequence(u8, url, "/"); - while (filename1.next()) |f| { - filename = f; - } - filename = try helper.replace(allocator, filename, "?", ""); - filename = try helper.replace(allocator, filename, "*", ""); - filename = try helper.replace(allocator, filename, "|", ""); - } - - const filename_final = try allocator.dupe(u8, filename); - - const file = try std.fs.cwd().createFile( - filename, - .{ .read = true }, - ); - defer file.close(); - - var buffer: [8192]u8 = undefined; - var file_writer: std.fs.File.Writer = .init(file, &buffer); - _ = try response.reader(&.{}).streamRemaining(&file_writer.interface); - // Flush remaining buffer just in case. - try file_writer.interface.flush(); - - return filename_final; -} - fn build_package(name: []const u8, package_version: []const u8, output: []const u8, installer: []const u8, extra: anytype) !void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); diff --git a/src/root.zig b/src/root.zig index 6f93d2a..8b15b96 100644 --- a/src/root.zig +++ b/src/root.zig @@ -3,6 +3,7 @@ const testing = std.testing; const main = @import("main.zig"); const helper = @import("helper.zig"); const builtin = @import("builtin"); +const download = @import("download.zig").download; export fn add(a: i32, b: i32) i32 { return a + b; @@ -16,7 +17,7 @@ test "checking failed download" { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const allocator = arena.allocator(); - try testing.expect(std.mem.eql(u8, try main.download(allocator, "https://durrrrr.io"), "unknown.txt")); + try testing.expect(std.mem.eql(u8, try download(allocator, "https://durrrrr.io"), "unknown.txt")); } test "checking replacer" { @@ -85,3 +86,16 @@ test "checking failed execute fpa not found" { try testing.expectError(main.ExecuteError.FpaPackagerNotFound, result); } } + +test "replace all function" { + const allocator = std.testing.allocator; + + const original = "file?name*with