commit 6eec995d9873c8d6ce5869079e2953b68f3d04e0 Author: chersbobers Date: Mon May 11 17:00:07 2026 +1200 Initial commit diff --git a/.mol/repo b/.mol/repo new file mode 100644 index 0000000..d926704 --- /dev/null +++ b/.mol/repo @@ -0,0 +1 @@ +yawdl https://codeberg.org/chersbobers/yawdl.git \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..185c18a --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# mol +a simple [maybe suckless] package manager uses hg/git repos to build. + +install all you need is crystal +## linux/bsd/mac +chmod +x build.sh +./build.sh + +## windows +./build.ps1 + +## usage +mol grab [needs a molfile] +mol remove +mol update (updates package)` \ No newline at end of file diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000..4b598cb --- /dev/null +++ b/build.ps1 @@ -0,0 +1 @@ +crystal build src/mol.cr -o mol.exe --release \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..b2abf57 --- /dev/null +++ b/build.sh @@ -0,0 +1,2 @@ +#!/bin/sh +crystal build src/mol.cr -o mol --release \ No newline at end of file diff --git a/gc.dll b/gc.dll new file mode 100644 index 0000000..a8d9165 Binary files /dev/null and b/gc.dll differ diff --git a/iconv-2.dll b/iconv-2.dll new file mode 100644 index 0000000..68f773f Binary files /dev/null and b/iconv-2.dll differ diff --git a/libcrypto-3-x64.dll b/libcrypto-3-x64.dll new file mode 100644 index 0000000..1f96b49 Binary files /dev/null and b/libcrypto-3-x64.dll differ diff --git a/libssl-3-x64.dll b/libssl-3-x64.dll new file mode 100644 index 0000000..455bfba Binary files /dev/null and b/libssl-3-x64.dll differ diff --git a/mol.exe b/mol.exe new file mode 100644 index 0000000..20332d0 Binary files /dev/null and b/mol.exe differ diff --git a/mol.pdb b/mol.pdb new file mode 100644 index 0000000..a0a0025 Binary files /dev/null and b/mol.pdb differ diff --git a/pcre2-8.dll b/pcre2-8.dll new file mode 100644 index 0000000..f27728b Binary files /dev/null and b/pcre2-8.dll differ diff --git a/shard.lock b/shard.lock new file mode 100644 index 0000000..4f3e149 --- /dev/null +++ b/shard.lock @@ -0,0 +1,2 @@ +version: 2.0 +shards: {} diff --git a/shard.yml b/shard.yml new file mode 100644 index 0000000..e6dabd5 --- /dev/null +++ b/shard.yml @@ -0,0 +1,19 @@ +name: mol +version: 0.1.0 + +# authors: +# - name + +# description: | +# Short description of mol + +# dependencies: +# pg: +# github: will/crystal-pg +# version: "~> 0.5" + +# development_dependencies: +# webmock: +# github: manastech/webmock.cr + +# license: MIT diff --git a/src/mol.cr b/src/mol.cr new file mode 100644 index 0000000..e96a960 --- /dev/null +++ b/src/mol.cr @@ -0,0 +1,172 @@ +require "file_utils" +require "http/client" + +BIN = Path.home / ".local" / "bin" +SRC = ".mol/src" +DB = ".mol/repo" +REPO = ENV.fetch("MOL_REPO", "https://git.sr.ht/~chersbobers/mol-pkgrepo/blob/master/PACKAGES?raw=true") +OS = {% if flag?(:win32) %}"windows"{% elsif flag?(:linux) %}"linux"{% else %}"macos"{% end %} + +def run(cmd, args, dir = nil) + Process.run(cmd, args, chdir: dir, + output: Process::Redirect::Inherit, + error: Process::Redirect::Inherit).success? +end + +def lookup(t) : {String, String?} + return {t, nil} if t.includes?("://") + if File.exists?(DB) + File.each_line(DB) do |l| + l = l.strip; next if l.empty? || l.starts_with?('#') + p = l.split; next unless p[0] == t + return {p[1], p.find(&.starts_with?("B=")).try(&.[2..])} + end + end + abort "#{t} not found, run: mol sync" +end + +def installed?(name) + Dir.exists?(File.join(SRC, name)) || File.exists?((BIN / name).to_s) +end + +def link_bins(path) + Dir.mkdir_p(BIN) + [File.join(path,"bin"), File.join(path,"target","release"), path].each do |d| + next unless Dir.exists?(d) + Dir.each_child(d) do |f| + full = File.join(d, f) + next unless File.executable?(full) && !File.directory?(full) && !f.includes?('.') + dest = (BIN / f).to_s + FileUtils.cp(full, dest); File.chmod(dest, 0o755) + puts "-> #{dest}" + end + end +end + +def parse_molpkg(path) : {Array(String), Array(String)} + file = File.join(path, "mol.pkg") + deps = [] of String + build = [] of String + return deps, build unless File.exists?(file) + + in_build = false + in_os = false + in_install = false + + File.each_line(file) do |l| + l = l.strip + if l.includes?("(deps") + l.scan(/"([^"]+)"/).each { |m| deps << m[1] } + elsif l.includes?("(build") + in_build = true + elsif l.includes?("(install") + in_build = false; in_install = true + elsif in_build && l.includes?("(#{OS}") + in_os = true + elsif in_build && in_os && l.starts_with?("(run") + parts = l.scan(/"([^"]+)"/).map(&.[1]) + build << parts.join(" ") if parts.any? + elsif l == ")" && in_os + in_os = false + elsif l == ")" && in_build + in_build = false + elsif in_install && l.includes?("(bin") + name = l.scan(/"([^"]+)"/).first?.try(&.[1]) + if name + src = File.join(path, name) + src = File.join(path, "#{name}.exe") if OS == "windows" && !File.exists?(src) + if File.exists?(src) + dest = (BIN / File.basename(src)).to_s + FileUtils.cp(src, dest); File.chmod(dest, 0o755) + puts "-> #{dest}" + end + end + end + end + + {deps, build} +end + +def install(name, src = false) + return if installed?(name) + puts "installing #{name}" + url, bin = lookup(name) + + if !src && bin + r = HTTP::Client.get(bin) + abort "download failed" unless r.success? + dest = (BIN / File.basename(bin)).to_s + File.write(dest, r.body); File.chmod(dest, 0o755) + puts "-> #{dest}" + return + end + + n = url.split('/').last.gsub(/\.hg$|\.git$/, "") + path = File.join(SRC, n) + vcs = url.includes?("hg") ? "hg" : "git" + abort "clone failed" unless run(vcs, ["clone", url, path]) + + deps, build_cmds = parse_molpkg(path) + deps.each { |dep| install(dep) } + + if build_cmds.any? + build_cmds.each do |cmd| + parts = cmd.split + abort "build failed: #{cmd}" unless run(parts[0], parts[1..], path) + end + else + abort "no build steps for #{OS} in #{n}" + end + + link_bins(path) +end + +def remove_pkg(name) + path = File.join(SRC, name) + FileUtils.rm_rf(path) if Dir.exists?(path) + ["", ".exe"].each do |ext| + b = (BIN / "#{name}#{ext}").to_s + File.delete(b) if File.exists?(b) + end + puts "removed #{name}" +end + +def update_pkg(name) + path = File.join(SRC, name) + abort "#{name} not found, install first" unless Dir.exists?(path) + vcs = Dir.exists?(File.join(path, ".hg")) ? "hg" : "git" + args = vcs == "hg" ? ["pull", "-u"] : ["pull"] + abort "pull failed" unless run(vcs, args, path) + _, build_cmds = parse_molpkg(path) + build_cmds.each do |cmd| + parts = cmd.split + abort "build failed: #{cmd}" unless run(parts[0], parts[1..], path) + end + link_bins(path) + puts "updated #{name}" +end + +Dir.mkdir_p(SRC) +Dir.mkdir_p(File.dirname(DB)) + +case ARGV[0]? +when "install" + name = ARGV[1]? || abort("usage: mol install [--source]") + src = ARGV.includes?("--source") + install(name, src) +when "remove" + name = ARGV[1]? || abort("usage: mol remove ") + remove_pkg(name) +when "update" + name = ARGV[1]? || abort("usage: mol update ") + update_pkg(name) +when "sync" + r = HTTP::Client.get(REPO) + abort "sync failed" unless r.success? + File.write(DB, r.body); puts "synced" +when "-l" + abort "no repo, run: mol sync" unless File.exists?(DB) + File.each_line(DB) { |l| l=l.strip; puts l.split[0] unless l.empty? || l.starts_with?('#') } +else + puts "mol as in molecule\n install [--source] install a package\n remove remove a package\n update pull and rebuild\n sync fetch package list\n -l list packages" +end \ No newline at end of file diff --git a/zlib1.dll b/zlib1.dll new file mode 100644 index 0000000..06a332f Binary files /dev/null and b/zlib1.dll differ