|
root / src / core / groups.reef
groups.reef Reef 212 lines 5.6 KB
  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
/******************************************************************************
               __               ____                __
              / /   ___  ____ _/ __/_____________ _/ /__
             / /   / _ \/ __ `/ /_/ ___/ ___/ __ `/ / _ \
            / /___/  __/ /_/ / __(__  ) /__/ /_/ / /  __/
           /_____/\___/\__,_/_/ /____/\___/\__,_/_/\___/

   (C)opyright 2025, Leafscale, LLC -  https://www.leafscale.com

   Project: Zygaena
  Filename: groups.reef
   Authors: Chris Tusa <chris.tusa@leafscale.com>
   License: <see LICENSE file included with this source code>
Description: Package groups support for Coral (@groupname)

******************************************************************************/

module core.groups

import core.str
import io.file
import io.dir
import io.path
import encoding.toml
import types

export
    type GroupResult

    fn load_group(name: string): GroupResult
    fn list_groups(groups: [types.PackageGroup], max_count: int): int
    fn expand_group(name: string, packages: [string], max_count: int): int
    fn is_group(name: string): bool
end export

// Result for group loading
type GroupResult = struct
    success: bool
    group: types.PackageGroup
    error: string
end GroupResult

// Get the groups directory
fn get_groups_dir(): string
    return types.get_groups_dir()
end get_groups_dir

// Create empty group
fn new_group(): types.PackageGroup
    return types.new_package_group()
end new_group

// Create success result
fn success_result(g: types.PackageGroup): GroupResult
    return GroupResult{ success: true, group: g, error: "" }
end success_result

// Create error result
fn error_result(msg: string): GroupResult
    return GroupResult{ success: false, group: new_group(), error: msg }
end error_result

// Check if a package name is a group reference (starts with @)
fn is_group(name: string): bool
    if str.length(name) < 2
        return false
    end if
    return name[0] == '@'
end is_group

// Load a group definition from TOML file
fn load_group(name: string): GroupResult
    // Remove @ prefix if present
    mut group_name = name
    if name[0] == '@'
        group_name = str.substring(name, 1, str.length(name) - 1)
    end if

    let groups_dir = get_groups_dir()
    let group_file = path.join_path(groups_dir, group_name + ".toml")

    if not file.fileExists(group_file)
        return error_result("Group not found: " + group_name)
    end if

    let content = file.readFile(group_file)
    if str.length(content) == 0
        return error_result("Failed to read group file")
    end if

    // Parse TOML using key/value arrays
    let keys = toml.toml_alloc_keys()
    let vals = toml.toml_alloc_values()
    let entry_count = toml.toml_parse(content, keys, vals)

    if entry_count == 0
        return error_result("Invalid group file format")
    end if

    mut group = new_group()
    group.name = group_name

    // Get description
    if toml.toml_has_key(keys, vals, entry_count, "group.description")
        group.description = toml.toml_get(keys, vals, entry_count, "group.description")
    end if

    // Get members list (packages array)
    if toml.toml_has_key(keys, vals, entry_count, "group.packages")
        let members_str = toml.toml_get(keys, vals, entry_count, "group.packages")
        group.members_count = parse_toml_array(members_str, group.members, 256)
    end if

    return success_result(group)
end load_group

// List all available groups
fn list_groups(groups: [types.PackageGroup], max_count: int): int
    let groups_dir = get_groups_dir()

    if not dir.dir_exists(groups_dir)
        return 0
    end if

    mut entries: [string] = new [string](64)
    let entry_count = dir.list_dir(groups_dir, entries, 64)

    mut count = 0
    mut i = 0
    while i < entry_count and count < max_count
        let entry = entries[i]
        // Look for .toml files
        if str.ends_with(entry, ".toml")
            let name_len = str.length(entry) - 5
            let name = str.substring(entry, 0, name_len)

            let result = load_group(name)
            if result.success
                groups[count] = result.group
                count = count + 1
            end if
        end if
        i = i + 1
    end while

    return count
end list_groups

// Expand a group to its member packages
fn expand_group(name: string, packages: [string], max_count: int): int
    let result = load_group(name)

    if not result.success
        return 0
    end if

    let group = result.group
    mut count = 0

    while count < group.members_count and count < max_count
        packages[count] = group.members[count]
        count = count + 1
    end while

    return count
end expand_group

// Parse TOML array value into string array
// Format: ["item1", "item2", "item3"]
fn parse_toml_array(value: string, result: [string], max_items: int): int
    let len = str.length(value)
    if len < 2
        return 0
    end if

    // Check for array brackets
    if value[0] != '['
        return 0
    end if

    mut count = 0
    mut i = 1
    mut in_string = false
    mut item_start = 0

    while i < len and count < max_items
        let c = value[i]

        if c == '"' and not in_string
            in_string = true
            item_start = i + 1
        elif c == '"' and in_string
            // End of string item
            let item_len = i - item_start
            if item_len > 0
                result[count] = str.substring(value, item_start, item_len)
                count = count + 1
            end if
            in_string = false
        elif c == ']' and not in_string
            // End of array
            return count
        end if

        i = i + 1
    end while

    return count
end parse_toml_array

end module