Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hemlang/hpm",
"version": "1.0.5",
"version": "1.0.6",
"description": "Hemlock Package Manager - A package manager for the Hemlock programming language",
"author": "Hemlock Team",
"license": "MIT",
Expand Down
9 changes: 5 additions & 4 deletions src/cache.hml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// hpm - Global cache management

import { exists, read_file, write_file, make_dir, list_dir, remove_file, remove_dir, is_dir } from "@stdlib/fs";
import { exists, read_file, write_file, make_dir, list_dir, remove_file, remove_dir, is_dir, file_stat } from "@stdlib/fs";
import * as env from "@stdlib/env";
import { parse, stringify, pretty } from "@stdlib/json";
import { exec } from "@stdlib/process";
Expand Down Expand Up @@ -248,9 +248,10 @@ export fn get_cache_size(): i64 {
while (i < packages.length) {
let pkg = packages[i];
try {
let content = read_file(pkg.path);
if (content != null) {
total = total + content.length;
// Use file_stat to get file size without reading entire file into memory
let stat = file_stat(pkg.path);
if (stat != null && stat.size >= 0) {
total = total + stat.size;
}
} catch (e) {
// Ignore errors
Expand Down
16 changes: 12 additions & 4 deletions src/github.hml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,20 @@ import { get, get_binary, is_success } from "@stdlib/http";
import { parse } from "@stdlib/json";
import * as env from "@stdlib/env";
import { exists, read_file, write_file } from "@stdlib/fs";
import { sleep } from "@stdlib/time";
import { sleep, now } from "@stdlib/time";
import { getpid } from "@stdlib/process";

// Retry configuration
let MAX_RETRIES = 4;
let INITIAL_BACKOFF_MS = 1000; // 1 second

// Generate a unique suffix for temp files using PID and timestamp
fn unique_suffix(): string {
let pid = getpid();
let ts = now();
return "" + pid + "_" + ts;
}

// Get GitHub token from environment or config
export fn get_token() {
// First check environment variable
Expand Down Expand Up @@ -48,7 +56,7 @@ fn github_request(url: string) {
}

headers.push("Accept: application/vnd.github.v3+json");
headers.push("User-Agent: hpm/1.0.0");
headers.push("User-Agent: hpm/1.0.6");

let retries = 0;
let backoff_ms = INITIAL_BACKOFF_MS;
Expand Down Expand Up @@ -222,7 +230,7 @@ export fn get_tarball_url(owner: string, repo: string, version: string): string
// Returns the path to the downloaded file
export fn download_tarball(owner: string, repo: string, version: string): string {
let url = get_tarball_url(owner, repo, version);
let tmpfile = "/tmp/hpm_tarball_" + owner + "_" + repo + "_" + version + ".tar.gz";
let tmpfile = "/tmp/hpm_tarball_" + owner + "_" + repo + "_" + version + "_" + unique_suffix() + ".tar.gz";

// Build headers with auth if available
let headers = [];
Expand Down Expand Up @@ -270,7 +278,7 @@ export fn repo_exists(owner: string, repo: string): bool {
}

headers.push("Accept: application/vnd.github.v3+json");
headers.push("User-Agent: hpm/1.0.0");
headers.push("User-Agent: hpm/1.0.6");

let retries = 0;
let backoff_ms = INITIAL_BACKOFF_MS;
Expand Down
27 changes: 22 additions & 5 deletions src/installer.hml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import { exists, read_file, write_file, make_dir, remove_dir, list_dir, is_dir } from "@stdlib/fs";
import { sha256 } from "@stdlib/hash";
import { fork, waitpid, exec } from "@stdlib/process";
import { fork, waitpid, exec, getpid } from "@stdlib/process";
import { exit } from "@stdlib/env";
import { now } from "@stdlib/time";

import * as github from "./github.hml";
import * as cache from "./cache.hml";
Expand All @@ -12,6 +13,13 @@ import * as manifest from "./manifest.hml";
// Maximum number of parallel downloads
let MAX_PARALLEL_DOWNLOADS = 4;

// Generate a unique suffix for temp directories using PID and timestamp
fn unique_suffix(): string {
let pid = getpid();
let ts = now();
return "" + pid + "_" + ts;
}

// Install a resolved package to hem_modules
// Set offline=true to install only from cache (no network requests)
export fn install_package(pkg_name: string, resolution, project_dir: string, verbose: bool, offline: bool) {
Expand Down Expand Up @@ -73,8 +81,8 @@ export fn install_package(pkg_name: string, resolution, project_dir: string, ver
}
make_dir(install_dir);

// Create temp extraction dir
let extract_dir = "/tmp/hpm_extract_" + owner + "_" + repo + "_" + version;
// Create temp extraction dir with unique suffix to avoid race conditions
let extract_dir = "/tmp/hpm_extract_" + owner + "_" + repo + "_" + version + "_" + unique_suffix();
if (exists(extract_dir)) {
remove_dir_recursive(extract_dir);
}
Expand Down Expand Up @@ -102,8 +110,17 @@ export fn install_package(pkg_name: string, resolution, project_dir: string, ver
// Clean up temp extraction dir
remove_dir_recursive(extract_dir);

// Calculate integrity from file
let integrity = "sha256-unknown"; // TODO: calculate sha256 of tarball file
// Calculate integrity from tarball file
let integrity = "sha256-unknown";
try {
let tarball_content = read_file(tarball_path);
if (tarball_content != null) {
let hash = sha256(tarball_content);
integrity = "sha256-" + hash;
}
} catch (e) {
// Keep unknown integrity if calculation fails
}

return integrity;
}
Expand Down
27 changes: 6 additions & 21 deletions src/main.hml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as installer from "./installer.hml";
import * as cache from "./cache.hml";

// Version info
let HPM_VERSION = "1.0.5";
let HPM_VERSION = "1.0.6";

// Exit codes
let EXIT_SUCCESS = 0;
Expand Down Expand Up @@ -90,7 +90,7 @@ fn get_positional_args(): array {
let i = 2; // Skip script name and command
while (i < args.length) {
let arg = args[i];
if (arg[0] != '-') {
if (arg.length > 0 && arg[0] != '-') {
result.push(arg);
}
i = i + 1;
Expand Down Expand Up @@ -203,7 +203,7 @@ fn cmd_install() {
let sorted = semver.sort(versions);
let latest = sorted[sorted.length - 1];
// Remove 'v' prefix
if (latest[0] == 'v') {
if (latest.length > 0 && latest[0] == 'v') {
latest = latest.substr(1, latest.length - 1);
}
version_constraint = "^" + latest;
Expand Down Expand Up @@ -475,7 +475,7 @@ fn cmd_list() {
let arg = args[i];
if (arg.starts_with("--depth=")) {
let val = arg.substr(8, arg.length - 8);
depth = parse_int(val);
depth = semver.parse_int(val);
}
i = i + 1;
}
Expand Down Expand Up @@ -563,21 +563,6 @@ fn print_tree(children: array, prefix: string, max_depth: i32, current_depth: i3
}
}

fn parse_int(s: string): i32 {
let result = 0;
let i = 0;
while (i < s.length) {
let ch = s[i];
if (ch >= '0' && ch <= '9') {
let digit: i32 = ch;
digit = digit - 48;
result = result * 10 + digit;
}
i = i + 1;
}
return result;
}

// hpm outdated
fn cmd_outdated() {
let project_dir = get_project_dir();
Expand Down Expand Up @@ -622,14 +607,14 @@ fn cmd_outdated() {
if (versions.length > 0) {
let sorted = semver.sort(versions);
let latest = sorted[sorted.length - 1];
if (latest[0] == 'v') {
if (latest.length > 0 && latest[0] == 'v') {
latest = latest.substr(1, latest.length - 1);
}

// Find wanted (highest satisfying constraint)
let parsed_constraint = semver.parse_constraint(constraint);
let wanted = semver.max_satisfying(versions, parsed_constraint);
if (wanted != null && wanted[0] == 'v') {
if (wanted != null && wanted.length > 0 && wanted[0] == 'v') {
wanted = wanted.substr(1, wanted.length - 1);
}
if (wanted == null) {
Expand Down
10 changes: 5 additions & 5 deletions src/semver.hml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export fn stringify(ver): string {
}

// Helper: Parse string to integer
fn parse_int(s: string): i32 {
export fn parse_int(s: string): i32 {
let result = 0;
let i = 0;
let negative = false;
Expand Down Expand Up @@ -165,13 +165,13 @@ export fn parse_constraint(constraint_str: string) {
}

// Check for caret range (^)
if (s[0] == '^') {
if (s.length > 0 && s[0] == '^') {
let ver = parse(s.substr(1, s.length - 1));
return { type: "caret", version: ver };
}

// Check for tilde range (~)
if (s[0] == '~') {
if (s.length > 0 && s[0] == '~') {
let ver = parse(s.substr(1, s.length - 1));
return { type: "tilde", version: ver };
}
Expand All @@ -189,13 +189,13 @@ export fn parse_constraint(constraint_str: string) {
}

// Check for >
if (s[0] == '>') {
if (s.length > 0 && s[0] == '>') {
let ver = parse(s.substr(1, s.length - 1).trim());
return { type: "gt", version: ver };
}

// Check for <
if (s[0] == '<') {
if (s.length > 0 && s[0] == '<') {
let ver = parse(s.substr(1, s.length - 1).trim());
return { type: "lt", version: ver };
}
Expand Down