• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nightconcept / almandine / 14716629923

28 Apr 2025 07:54PM UTC coverage: 95.996%. First build
14716629923

push

github

web-flow
feat: Initial features (#1)

863 of 899 new or added lines in 16 files covered. (96.0%)

863 of 899 relevant lines covered (96.0%)

1.99 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.43
/src/modules/install.lua
1
--[[
2
  Install Command Module
3

4
  Provides functionality to install all dependencies listed in project.lua or a specific dependency.
5
]]
6
--
7

8
---
9
-- Installs dependencies from the manifest or lockfile.
10
-- If dep_name is provided, only installs that dependency.
11
-- @param dep_name string|nil Dependency name to install (or all if nil).
12
-- @param load_manifest function Function to load the manifest.
13
-- @param ensure_lib_dir function Function to ensure lib dir exists.
14
-- @param downloader table utils.downloader module.
15
-- @param utils table Utils module (must provide .downloader).
16
-- @param lockfile_deps table|nil Lockfile dependency table (optional)
17
local function install_dependencies(dep_name, load_manifest, ensure_lib_dir, downloader, utils, lockfile_deps)
18
  ensure_lib_dir()
4✔
19
  if lockfile_deps then
4✔
20
    local deps = lockfile_deps
1✔
21
    for name, source in pairs(deps) do
3✔
22
      if (not dep_name) or (dep_name == name) then
2✔
23
        local out_path
24
        local url
25
        if type(source) == "table" and source.url and source.path then
2✔
26
          url = source.url
1✔
27
          out_path = source.path
1✔
28
        else
29
          url = source
1✔
30
          local filesystem_utils = require("utils.filesystem")
1✔
31
          out_path = filesystem_utils.join_path("src", "lib", name .. ".lua")
1✔
32
        end
33
        local ok3, err3 = (utils or { downloader = downloader }).downloader.download(url, out_path)
2✔
34
        if ok3 then
2✔
35
          print(string.format("Downloaded %s to %s", name, out_path))
2✔
36
        else
NEW
37
          print(string.format("Failed to download %s: %s", name, err3))
×
38
        end
39
      end
40
    end
41
  else
42
    local manifest, err = load_manifest()
3✔
43
    if not manifest then
3✔
44
      print(err)
1✔
45
      return
1✔
46
    end
47
    local deps = manifest.dependencies or {}
2✔
48
    for name, source in pairs(deps) do
6✔
49
      if (not dep_name) or (dep_name == name) then
4✔
50
        local out_path
51
        local url
52
        if type(source) == "table" and source.url and source.path then
3✔
53
          url = source.url
1✔
54
          out_path = source.path
1✔
55
        else
56
          url = source
2✔
57
          local filesystem_utils = require("utils.filesystem")
2✔
58
          out_path = filesystem_utils.join_path("src", "lib", name .. ".lua")
2✔
59
        end
60
        local ok3, err3 = (utils or { downloader = downloader }).downloader.download(url, out_path)
3✔
61
        if ok3 then
3✔
62
          print(string.format("Downloaded %s to %s", name, out_path))
3✔
63
        else
NEW
64
          print(string.format("Failed to download %s: %s", name, err3))
×
65
        end
66
      end
67
    end
68
  end
69
end
70

71
--[[
72
  Lockfile Management Module (migrated from src/lib/lockfile.lua)
73
  Provides functions to generate, serialize, and write the Almandine lockfile (`almd-lock.lua`).
74
  The lockfile captures exact dependency versions and hashes for reproducible builds.
75
]]
76
--
77

78
local lockfile = {}
1✔
79

80
local io = io
1✔
81
local table = table
1✔
82
local tostring = tostring
1✔
83

84
--- Lockfile schema version (increment if schema changes)
85
local API_VERSION = "1"
1✔
86

87
---
88
-- Generates a lockfile table from resolved dependencies.
89
-- @param resolved_deps table Table of resolved dependencies. Each key is a package name, value is a table with fields:
90
--                          - version (string, optional)
91
--                          - hash (string, required)
92
--                          - source (string, optional)
93
-- @return table Lockfile table matching the schema
94
function lockfile.generate_lockfile_table(resolved_deps)
1✔
95
  assert(type(resolved_deps) == "table", "resolved_deps must be a table")
4✔
96
  local pkgs = {}
3✔
97
  for name, dep in pairs(resolved_deps) do
5✔
98
    assert(type(dep) == "table", "Dependency entry must be a table")
4✔
99
    assert(dep.hash, "Dependency '" .. name .. "' must have a hash")
3✔
100
    local entry = { hash = dep.hash }
2✔
101
    if dep.version then
2✔
102
      entry.version = dep.version
1✔
103
    end
104
    if dep.source then
2✔
105
      entry.source = dep.source
1✔
106
    end
107
    pkgs[name] = entry
2✔
108
  end
109
  return {
1✔
110
    api_version = API_VERSION,
1✔
111
    package = pkgs,
1✔
112
  }
1✔
113
end
114

115
---
116
-- Serializes a lockfile table to a string (Lua syntax).
117
-- @param lockfile_table table Lockfile table
118
-- @return string Lua code as string
119
function lockfile.serialize_lockfile(lockfile_table)
1✔
120
  assert(type(lockfile_table) == "table", "lockfile_table must be a table")
4✔
121
  local function serialize(tbl, indent)
122
    indent = indent or 0
9✔
123
    local pad = string.rep("  ", indent)
9✔
124
    local lines = { "{" }
9✔
125
    for k, v in pairs(tbl) do
21✔
126
      local key = (type(k) == "string" and string.format("%s = ", k)) or ("[" .. tostring(k) .. "] = ")
12✔
127
      if type(v) == "table" then
12✔
128
        table.insert(lines, pad .. "  " .. key .. serialize(v, indent + 1) .. ",")
6✔
129
      elseif type(v) == "string" then
6✔
130
        table.insert(lines, pad .. "  " .. key .. string.format('"%s"', v) .. ",")
6✔
131
      else
NEW
132
        table.insert(lines, pad .. "  " .. key .. tostring(v) .. ",")
×
133
      end
134
    end
135
    table.insert(lines, pad .. "}")
9✔
136
    return table.concat(lines, "\n")
9✔
137
  end
138
  return "return " .. serialize(lockfile_table, 0) .. "\n"
3✔
139
end
140

141
---
142
-- Writes the lockfile to disk as `almd-lock.lua`.
143
-- @param lockfile_table table Lockfile table
144
-- @param path string (optional) Path to write to (default: "almd-lock.lua" in project root)
145
-- @return boolean, string True and path if successful, false and error message otherwise
146
function lockfile.write_lockfile(lockfile_table, path)
1✔
147
  path = path or "almd-lock.lua"
2✔
148
  local content = lockfile.serialize_lockfile(lockfile_table)
2✔
149
  local file, err = io.open(path, "w")
2✔
150
  if not file then
2✔
151
    return false, err
1✔
152
  end
153
  file:write(content)
1✔
154
  file:close()
1✔
155
  return true, path
1✔
156
end
157

158
---
159
-- Prints usage/help information for the `install` command.
160
-- Usage: almd install [<dep_name>]
161
-- Installs all dependencies listed in project.lua, or only <dep_name> if specified.
162
local function help_info()
163
  print([[\nUsage: almd install [<dep_name>]
2✔
164

165
Installs all dependencies listed in project.lua, or only <dep_name> if specified.
166
Example:
167
  almd install
168
  almd install lunajson
169
]])
1✔
170
end
171

172
return {
1✔
173
  install_dependencies = install_dependencies,
1✔
174
  lockfile = lockfile,
1✔
175
  help_info = help_info,
1✔
176
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc