1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
|
/******************************************************************************
__ ____ __
/ / ___ ____ _/ __/_____________ _/ /__
/ / / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \
/ /___/ __/ /_/ / __(__ ) /__/ /_/ / / __/
/_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/
(C)opyright 2025, Leafscale, LLC - https://www.leafscale.com
Project: Zygaena
Filename: main.reef
Authors: Chris Tusa <chris.tusa@leafscale.com>
License: <see LICENSE file included with this source code>
Description: Entry point for Coral package manager
******************************************************************************/
import sys.args
import sys.process
import sys.env
import io.dir
import core.str
import types
import exitcodes as ec
import commands.build as cmd_build
import commands.install as cmd_install
import commands.remove as cmd_remove
import commands.upgrade as cmd_upgrade
import commands.info as cmd_info
import commands.list as cmd_list
import commands.files as cmd_files
import commands.owner as cmd_owner
import commands.search as cmd_search
import commands.depends as cmd_depends
import commands.sync as cmd_sync
import commands.outdated as cmd_outdated
import commands.repo as cmd_repo
import commands.key as cmd_key
import commands.db as cmd_db
import commands.clean as cmd_clean
import commands.ports as cmd_ports
import commands.verify as cmd_verify
import util.color
import util.priv
fn version(): string
return "0.4.3"
end version
proc print_usage()
println("coral " + version() + " - Package manager for Zygaena")
println("")
println("USAGE:")
println(" coral <command> [options] [packages...]")
println("")
println("COMMANDS:")
println(" Package Management:")
println(" install <pkg> Install packages")
println(" reinstall <pkg> Reinstall packages (same as install --force)")
println(" remove <pkg> Remove packages")
println(" upgrade Upgrade packages")
println("")
println(" Query Commands:")
println(" info <pkg> Show package info")
println(" list List installed packages")
println(" files <pkg> List package files")
println(" owner <file> Find file owner")
println(" search <term> Search packages")
println(" depends <pkg> Show dependencies")
println(" outdated Show available updates")
println(" verify <pkg> Verify package integrity")
println("")
println(" Build Commands:")
println(" build <port> Build package from port")
println(" sync Update ports tree")
println(" clean <target> Remove build artifacts (sources|packages|build|all)")
println("")
println(" System Commands:")
println(" db <cmd> Manage package database (init|rebuild|status)")
println(" ports <cmd> Port development tools (new|cache)")
println(" repo Manage repositories")
println(" key Manage signing keys")
println("")
println("OPTIONS:")
println(" -h, --help Show this help")
println(" --version Show version")
println(" -y, --yes Don't ask for confirmation")
println(" -f, --force Force operation")
println(" -v, --verbose Verbose output")
println(" -n, --dry-run Show what would be done")
println(" -q, --quiet Minimal output")
println(" --no-color Disable colored output")
println(" --root <path> Use alternative root directory")
println(" --prefix <path> Installation prefix (default: /usr)")
println(" --no-chroot-scripts Run maintainer scripts on the host, not chrooted")
println("")
println("EXIT CODES:")
println(" 0 Success")
println(" 1 General error")
println(" 2 Usage/syntax error")
println(" 10-19 Package errors")
println(" 20-29 Build errors")
println(" 30-39 Network errors")
println(" 50-59 Permission errors")
println(" 60-69 Dependency errors")
println(" 100+ Informational (scripting)")
end print_usage
// Find the index of the command argument, skipping global flags
fn find_command_index(): int
let argc = args.count()
mut i = 1
while i < argc
let arg = args.get(i)
// Skip flags that take a value
if arg == "--root" or arg == "--prefix"
i = i + 2 // Skip flag and its value
continue
end if
// Skip boolean flags
if arg == "-y" or arg == "--yes" or arg == "-f" or arg == "--force" or arg == "-v" or arg == "--verbose" or arg == "-n" or arg == "--dry-run" or arg == "-q" or arg == "--quiet" or arg == "--no-color" or arg == "--no-chroot-scripts"
i = i + 1
continue
end if
// Found the command
return i
end while
return -1
end find_command_index
// Parse global options from command line arguments
fn parse_global_options(): types.GlobalOptions
mut opts = types.new_global_options()
opts.yes = args.has_flag("y") or args.has_flag("yes")
opts.force = args.has_flag("f") or args.has_flag("force")
opts.verbose = args.has_flag("v") or args.has_flag("verbose")
opts.dry_run = args.has_flag("n") or args.has_flag("dry-run")
opts.quiet = args.has_flag("q") or args.has_flag("quiet")
// Check for --root option
if args.has_flag("root")
opts.root = args.get_flag_value("root")
end if
// Check for --prefix option
if args.has_flag("prefix")
opts.prefix = args.get_flag_value("prefix")
end if
// Check for --no-chroot-scripts option (valueless)
opts.no_chroot = args.has_flag("no-chroot-scripts")
return opts
end parse_global_options
// Check if a command is a query command (doesn't require root)
fn is_query_command(cmd: string): bool
// Query commands that don't modify the system
if cmd == "info"
return true
elif cmd == "list"
return true
elif cmd == "files"
return true
elif cmd == "owner"
return true
elif cmd == "search"
return true
elif cmd == "depends"
return true
elif cmd == "outdated"
return true
elif cmd == "verify"
return true
elif cmd == "build"
// Building packages doesn't require root - only writes to build directories
return true
elif cmd == "--help" or cmd == "-h"
return true
elif cmd == "--version" or cmd == "version"
return true
end if
return false
end is_query_command
fn main(): int
let argc = args.count()
if argc < 2
print_usage()
return ec.EXIT_USAGE()
end if
// Check for --help and --version before finding command
// (these can appear anywhere)
if args.has_flag("help") or args.has_flag("h")
print_usage()
return ec.EXIT_SUCCESS()
end if
if args.has_flag("version")
println("coral " + version())
return ec.EXIT_SUCCESS()
end if
// Find the actual command, skipping global flags
let cmd_index = find_command_index()
if cmd_index < 0
print_usage()
return ec.EXIT_USAGE()
end if
let cmd = args.get(cmd_index)
// Parse global options and set command index
mut opts = parse_global_options()
opts.cmd_index = cmd_index
// Check for root privileges if required
if not is_query_command(cmd)
if not priv.is_root()
color.print_error("This command requires root privileges")
println("Run 'coral " + cmd + "' as root or with sudo")
return ec.EXIT_ROOT_REQUIRED()
end if
end if
// Dispatch to command handlers
// Commands return exit codes
if cmd == "build"
return cmd_build.execute(opts)
elif cmd == "install"
return cmd_install.execute(opts)
elif cmd == "reinstall"
// Reinstall is install with force flag enabled
mut reinstall_opts = opts
reinstall_opts.force = true
return cmd_install.execute(reinstall_opts)
elif cmd == "remove"
return cmd_remove.execute(opts)
elif cmd == "upgrade"
return cmd_upgrade.execute(opts)
elif cmd == "info"
return cmd_info.execute(opts)
elif cmd == "list"
return cmd_list.execute(opts)
elif cmd == "files"
return cmd_files.execute(opts)
elif cmd == "owner"
return cmd_owner.execute(opts)
elif cmd == "search"
return cmd_search.execute()
elif cmd == "depends"
return cmd_depends.execute()
elif cmd == "sync"
return cmd_sync.execute()
elif cmd == "outdated"
return cmd_outdated.execute()
elif cmd == "repo"
return cmd_repo.execute()
elif cmd == "key"
return cmd_key.execute()
elif cmd == "db"
return cmd_db.execute(opts)
elif cmd == "clean"
return cmd_clean.execute()
elif cmd == "ports"
return cmd_ports.execute(opts)
elif cmd == "verify"
return cmd_verify.execute(opts)
elif cmd == "version"
println(version())
return ec.EXIT_SUCCESS()
else
color.print_error("unknown command '" + cmd + "'")
println("Run 'coral --help' for usage.")
return ec.EXIT_USAGE()
end if
end main
|