Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
nanoscopic committed May 15, 2024
0 parents commit 9346929
Show file tree
Hide file tree
Showing 18 changed files with 1,788 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*~
lib
pkgs
bottle
bin
curlprog
tarball_incremental
scan
minibrew.tar.xz
22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
all: minibrew.tar.xz

SOURCES := dl.pl extract.pl genlib.pl genbin.pl rebase.pl deploy.pl $(wildcard *.json) curlprog tarball_incremental scan mod/Ujsonin.pm
EMPTY_FOLDERS := bin pkgs lib bottle

minibrew.tar.xz: $(SOURCES)
tar --no-recursion -cJf minibrew.tar.xz $(SOURCES) $(EMPTY_FOLDERS)

scan: scan.c
clang -arch x86_64 -arch arm64 -o scan scan.c
codesign --sign - scan

tarball_incremental: tarball_incremental.c
clang -arch x86_64 -arch arm64 -o tarball_incremental tarball_incremental.c -I/usr/local/opt/libarchive/include -ldl
codesign --sign - tarball_incremental

curlprog: curlprog.m
clang -arch x86_64 -arch arm64 -fobjc-arc -o curlprog curlprog.m -ldl -framework Foundation
codesign --sign - curlprog

clean:
rm scan curlprog tarball_incremental minibrew.tar.xz
Empty file added bin/.gitkeep
Empty file.
Empty file added bottle/.gitkeep
Empty file.
178 changes: 178 additions & 0 deletions curlprog.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <curl/curl.h>
#import <sys/sysctl.h>
#include <unistd.h>
#import <Foundation/Foundation.h>

// Define a structure to hold function pointers for the libcurl functions we need
struct curl_functions {
CURL* (*easy_init )(void);
CURLcode (*easy_setopt )(CURL *curl, CURLoption option, ...);
CURLcode (*easy_perform )(CURL *curl);
void (*easy_cleanup )(CURL *curl);
const char* (*easy_strerror )(CURLcode);
struct curl_slist* (*slist_append )(struct curl_slist *, const char *);
void (*slist_free_all)(struct curl_slist *);
const char* (*version )(void);
};

// Callback function for writing received data to a file
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp) {
FILE *writehere = (FILE *)userp;
return fwrite(buffer, size, nmemb, writehere);
}

// Progress callback function
int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
static double last_dl = 0;
if (dlnow - last_dl > 20480) { // 20KB
printf("%.0f\n", dlnow-last_dl);
last_dl = dlnow;
}
return 0;
}

// Header callback function to print each header line
size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) {
fwrite(buffer, size, nitems, (FILE *)userdata);
return nitems * size;
}

int main( int argc, char **argv ) {
void *libcurl;
struct curl_functions curl;
CURL *handle;
CURLcode res;

if( argc < 3 ) {
printf("Usage: %s [url] [save location]\n\n", argv[0] );
return 1;
}

// Load the libcurl shared library
libcurl = dlopen("/usr/lib/libcurl.dylib", RTLD_LAZY);
if (!libcurl) {
fprintf(stderr, "Error loading libcurl: %s\n", dlerror());
return 1;
}

// Load function symbols
curl.easy_init = dlsym(libcurl, "curl_easy_init");
curl.easy_setopt = dlsym(libcurl, "curl_easy_setopt");
curl.easy_perform = dlsym(libcurl, "curl_easy_perform");
curl.easy_cleanup = dlsym(libcurl, "curl_easy_cleanup");
curl.easy_strerror = dlsym(libcurl, "curl_easy_strerror");
curl.slist_append = dlsym(libcurl, "curl_slist_append");
curl.slist_free_all = dlsym(libcurl, "curl_slist_free_all");
curl.version = dlsym(libcurl, "curl_version");

if (!curl.easy_init || !curl.easy_setopt || !curl.easy_perform || !curl.easy_cleanup ||
!curl.easy_strerror || !curl.slist_append || !curl.slist_free_all || !curl.version) {
fprintf(stderr, "Error loading functions: %s\n", dlerror());
dlclose(libcurl);
return 1;
}

char *curlVersion = strdup( curl.version() );
for( int i=0;i<strlen( curlVersion ); i++ ) {
if( curlVersion[i] == ' ' ) {
curlVersion[i] = 0x00;
break;
}
}
//printf("Curl version: %s\n", version );
//libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0

char *version = NULL;
@autoreleasepool {
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
NSOperatingSystemVersion osVersion = [processInfo operatingSystemVersion];
NSString *versionString = [NSString stringWithFormat:@"Mac OS X %ld.%ld.%ld",
osVersion.majorVersion,
osVersion.minorVersion,
osVersion.patchVersion];
version = strdup( [versionString UTF8String] );
}

const char hwMachine[] = "hw.machine";
size_t size;
sysctlbyname(hwMachine, NULL, &size, NULL, 0);
char *value = malloc(size);
sysctlbyname(hwMachine, value, &size, NULL, 0);

//printf("Arch:%s\n", value );

const char archIntel[] = "Intel";
const char archArm[] = "Arm";
char *arch = NULL;
if( !strncmp( value, "x86_64", 6 ) ) {
arch = strdup( archIntel );
free( value );
value = NULL;
}
else if( !strncmp( value, "arm64", 5 ) ) {
arch = strdup( archArm );
free( value );
value = NULL;
}
else {
arch = value;
value = NULL;
}

// Initialize a libcurl easy session
handle = curl.easy_init();
if (handle) {
//FILE *fp = fopen("openssl.tar.gz", "wb");
FILE *fp = fopen( argv[2], "wb");

if (!fp) {
perror("File opening failed");
return EXIT_FAILURE;
}

// Set URL
//curl.easy_setopt(handle, CURLOPT_URL, "https://ghcr.io/v2/homebrew/core/openssl/3/blobs/sha256:28be258776e175a8c29a19be5312b885574a98324d7b03c7ec12f2d7eadcbce1");
curl.easy_setopt(handle, CURLOPT_URL, argv[1] );

// Set progress function and enable it
curl.easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
curl.easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
curl.easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, progress_callback);
// Set headers
struct curl_slist *headers = NULL;
char ua[300];
snprintf( ua, 300, "User-Agent: Minibrew/0.0.1 (Macintosh; %s %s) %s", arch, version, curlVersion );

headers = curl.slist_append(headers, ua);
headers = curl.slist_append(headers, "Accept-Language: en");
headers = curl.slist_append(headers, "Authorization: Bearer QQ==");
curl.easy_setopt(handle, CURLOPT_HTTPHEADER, headers);
// Set write function
curl.easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
curl.easy_setopt(handle, CURLOPT_WRITEDATA, fp);

//curl.easy_setopt(handle, CURLOPT_HEADERFUNCTION, header_callback);
//curl.easy_setopt(handle, CURLOPT_HEADERDATA, stdout);

// Perform the request
res = curl.easy_perform(handle);
if (res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl.easy_strerror(res));
}

// Cleanup
curl.easy_cleanup(handle);
curl.slist_free_all(headers);
fclose(fp);
}

dlclose(libcurl);

if( arch ) free( arch );
if( version ) free( version );
if( curlVersion ) free( curlVersion );
return 0;
}
9 changes: 9 additions & 0 deletions deploy.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/perl -w
use strict;

system("./dl.pl");
system("./extract.pl");
system("./genlib.pl");
system("./genbin.pl");
system("./rebase.pl");
print "DONE\n";
156 changes: 156 additions & 0 deletions dl.pl
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/perl -w
# Copyright (c) 2024 Dry Ark LLC
use strict;
use lib 'mod';
use Ujsonin;
use Data::Dumper;

my $arch = `uname -m`;
$arch =~ s/\n//;

my $macosVersion = `sw_vers -productVersion`;
my $major = $macosVersion;
$major =~ s/\..+//;

my $plat = "";#"ventura";
if( $arch eq 'arm64' ) {
$plat = "arm64_";
}


if( $major == 12 ) { $plat .= "monterey"; }
elsif( $major == 13 ) { $plat .= "ventura"; }
elsif( $major == 14 ) { $plat .= "sonoma"; }
else {
print "MacOS older than monterey(12) or newer than sonoma(14)\n";
exit;
}

my $doneSize = 0;
my $totSize = 0;
my $dlTot = 0;

my $lastPercent = -1;

if( ! -e "/usr/bin/install_name_tool" ) {
if( ! -e "./install_name_tool.tar.xz" ) {
`curl --progress-bar --location https://github.com/dryark/cctools-port/releases/download/986/install_name_tool.tar.xz -o install_name_tool.tar.xz`;
}
if( ! -e "./install_name_tool" ) {
`tar -xf install_name_tool.tar.xz`;
}
}

download_plat( $plat );

sub download_plat {
my $plat = shift;
Ujsonin::init();
my $data = read_file("dlinfo.json");
my $data2 = read_file("dlsize.json");
my $root = Ujsonin::parse( $data, 0 );
my $root2 = Ujsonin::parse( $data2, 0 );
#print Dumper( $root );

my $curlVersion = get_curl_version();

my $pkgs = $root->{pkgs};
my $shas = $root2->{sha256};

#my $totSize = 0;
for my $pkg ( @$pkgs ) {
my $plats = $pkg->{platforms};
my $sha = $plats->{ $plat } || $plats->{all};
#print "$name - $sha\n";
my $size = $shas->{ $sha };
if( !$size ) {
print "Could not find size for $sha\n";
}
$totSize += $size;
}
print "Total size of packages to download: $totSize\n";
print "Downloading raw brew packages...\n";
print_progress( 0 );

#exit;

for my $pkg ( @$pkgs ) {
my $name = $pkg->{name};
my $url = $pkg->{url};
my $plats = $pkg->{platforms};
my $sha = $plats->{ $plat } || $plats->{all};
my $size = $shas->{ $sha };
#print "$name - $sha\n";
$dlTot += $size;
ghcr_dl( "$url$sha", "bottle/$name.tar.gz", $curlVersion, $size );
#delete $plats->{_parent};
#print Dumper( $plats );
}
print "\n";
#print "\nDl tot: $dlTot\n";
}

sub get_curl_version {
my $curlInfo = `curl --version`;
my @curlLines = split("\n",$curlInfo);
my $curlVersion = "8.4.0";
if( $curlLines[0] =~ m/curl ([0-9\.]+)/ ) {
$curlVersion = $1;
}
return $curlVersion;
}

sub ghcr_dl {
my ( $url, $out, $curlVersion, $size ) = @_;
#my $ua = '--user-agent "Homebrew/4.2.20 (Macintosh; Intel Mac OS X 13.6.4) curl/'.$curlVersion.'"';
#my $lang = '--header Accept-Language:\\ en';
#my $auth = '--header "Authorization: Bearer QQ=="';
#my $fixed = "--disable --cookie /dev/null --globoff --show-error $ua $lang --fail --retry 3 $auth --remote-time";

if( ! -e "$out" ) {
#`curl $fixed --location $url -o $out`;
#print " curl $fixed --location $url -o $out\n";

#my $fileDone = 0;
#for( my $i=0;$i<5000;$i++ ) {
# $fileDone += 20000;
# last if( $fileDone >= $size );
# $doneSize += 20000;
# print_progress( int( ($doneSize/$totSize)*100 ) );
# select(undef, undef, undef, 0.001);
#}

my $cmd = "./curlprog \"$url\" \"$out\"";
open my $cmdfh, '-|', $cmd;
while( my $line = <$cmdfh> ) {
my $bytes = int( $line );
if( $bytes ) {
$doneSize += $bytes;
print_progress( int( ($doneSize/$totSize)*100 ) );
}
else {
print "Line: $line\n";
}
}
}
}

sub print_progress {
my ($percent) = @_;
return if( $percent == $lastPercent );
$percent *= 1.08;
$percent = 100 if( $percent > 100 );
my $num_blocks = int($percent / 2);
my $bar = '[' . '=' x $num_blocks . ' ' x (50 - $num_blocks) . ']';
printf("\r%s %3d%%", $bar, $percent);
STDOUT->flush(); # Flush the output buffer to update the display immediately
$lastPercent = $percent;
}

sub read_file {
my $fn = shift;
open my $fh, '<', $fn or return "";
my $data = do { local $/; <$fh> };
close( $fh );
return $data;
}
Loading

0 comments on commit 9346929

Please sign in to comment.