update.lua

251 lines · 7.4 KB

Open raw

Bulk updater for CC-Tweaked scripts

Usage: run: update

Copy & run

wget https://perlytiara.github.io/turtles.tips/raw/programs/BigGamingGamers/update.lua
1-- Bulk updater for CC-Tweaked scripts
2-- Overwrites local scripts with the latest from GitHub
3-- Usage: run: update
4
5local BASE = 'https://raw.githubusercontent.com/perlytiara/CC-Tweaked-TurtsAndComputers/refs/heads/main/'
6
7local manifest = {
8 ["programs/perlytiara/BigBaemingGamers"] = {
9 -- client
10 "client/client-bomb.lua",
11 "client/client-dig.lua",
12 "client/client-quarry.lua",
13 "client/client.lua",
14 -- farm
15 "farm/cactus-farm.lua",
16 "farm/harvest_0.lua",
17 "farm/harvest_1.lua",
18 -- phone
19 "phone/phone-app-mine.lua",
20 "phone/phone-bombing.lua",
21 -- server
22 "server/server-phone.lua",
23 -- tasks
24 "tasks/quarry-miner.lua",
25 "tasks/simple-quarry.lua",
26 -- tnt
27 "tnt/tnt-deployer.lua",
28 "tnt/tnt-igniter.lua",
29 -- update helpers
30 "update/update_bamboo.lua",
31 "update/update_dispense.lua",
32 "update/update_lift.lua",
33 "update/update_pos.lua",
34 -- utils
35 "utils/block-placer.lua",
36 "utils/detectids.lua",
37 "utils/item-counter.lua",
38 "utils/lava-refueler.lua",
39 "utils/ore-keeper.lua",
40 "utils/ractor.lua",
41 "utils/refuel-test.lua",
42 "utils/upward-quarry-test.lua",
43 },
44}
45
46local function ensureDir(path)
47 if not fs.exists(path) then
48 fs.makeDir(path)
49 end
50end
51
52local function ensureParentDir(localPath)
53 local parent = string.match(localPath, "(.+)/[^/]+$")
54 if parent then ensureDir(parent) end
55end
56
57local function fetch(remotePath)
58 local url = BASE .. remotePath .. '?breaker=' .. tostring(math.random(0, 999999))
59 local res, err = http.get(url)
60 if not res then
61 print('ERROR: http.get failed for ' .. remotePath .. ' - ' .. tostring(err))
62 return false, nil
63 end
64 local code = res.readAll()
65 res.close()
66 return true, code
67end
68
69local function writeFile(path, contents)
70 local handle = fs.open(path, 'w')
71 handle.write(contents)
72 handle.close()
73end
74
75local function readFile(path)
76 if not fs.exists(path) then return '' end
77 local h = fs.open(path, 'r')
78 local c = h.readAll()
79 h.close()
80 return c or ''
81end
82
83local function bytesDiff(a, b)
84 return string.len(b) - string.len(a)
85end
86
87local function progressBar(current, total, label)
88 local width = 28
89 local filled = math.floor((current / total) * width)
90 local bar = string.rep('#', filled) .. string.rep('-', width - filled)
91 print(string.format('[%s] %d/%d %s', bar, current, total, label or ''))
92end
93
94local function removeStale(localDir, keepSet)
95 if not fs.exists(localDir) then return end
96 local function walk(dir, relPrefix)
97 local items = fs.list(dir)
98 for i = 1, #items, 1 do
99 local name = items[i]
100 local full = dir .. '/' .. name
101 local relPath = (relPrefix ~= '' and (relPrefix .. '/' .. name)) or name
102 if fs.isDir(full) then
103 walk(full, relPath)
104 if #fs.list(full) == 0 then fs.delete(full) end
105 else
106 if relPath ~= 'load.lua' and relPath ~= 'update.lua' and not keepSet[relPath] then
107 fs.delete(full)
108 print('Removed stale: ' .. full)
109 end
110 end
111 end
112 end
113 walk(localDir, '')
114end
115
116local function updateDir(dir, files)
117 local updated, same = 0, 0
118 local localDir = '/' .. dir
119 ensureDir(localDir)
120
121 local keep = {}
122 for i = 1, #files, 1 do keep[files[i]] = true end
123
124 local total = #files
125 for i = 1, #files, 1 do
126 local fname = files[i]
127 local remotePath = dir .. '/' .. fname
128 local localPath = localDir .. '/' .. fname
129 local ok, code = fetch(remotePath)
130 if ok and code then
131 local old = readFile(localPath)
132 if old == code then
133 same = same + 1
134 else
135 ensureParentDir(localPath)
136 writeFile(localPath, code)
137 local diff = bytesDiff(old, code)
138 local change = (diff >= 0 and (tostring(math.abs(diff)) .. ' bytes added')) or (tostring(math.abs(diff)) .. ' bytes removed')
139 print('Updated: ' .. localPath .. ' (' .. change .. ')')
140 updated = updated + 1
141 end
142 end
143 progressBar(i, total, fname)
144 if sleep then sleep(0) end
145 end
146
147 removeStale(localDir, keep)
148 print(string.format('Done. Updated %d, unchanged %d.', updated, same))
149end
150
151local function promptSelect(options)
152 for i = 1, #options, 1 do
153 print(string.format('%d) %s', i, options[i]))
154 end
155 io.write('Select number: ')
156 local choice = read()
157 local idx = tonumber(choice)
158 if idx and idx >= 1 and idx <= #options then
159 return idx
160 end
161 return nil
162end
163
164local function showMenu()
165 print('== Update Menu ==')
166 print('1) Auto update all (clean stale)')
167 print('2) Update a single file')
168 print('3) Remove a local file')
169 print('4) Exit')
170 io.write('Choose: ')
171 local ch = read()
172 return tonumber(ch)
173end
174
175local function updateAll()
176 for dir, files in pairs(manifest) do
177 updateDir(dir, files)
178 end
179end
180
181local function updateSingle()
182 local dir, files
183 for d, f in pairs(manifest) do dir, files = d, f break end
184 print('Select file to update:')
185 local idx = promptSelect(files)
186 if not idx then print('Invalid selection') return end
187 updateDir(dir, { files[idx] })
188end
189
190local function removeOne()
191 local dir, files
192 for d, f in pairs(manifest) do dir, files = d, f break end
193 print('Select file to remove locally:')
194 local idx = promptSelect(files)
195 if not idx then print('Invalid selection') return end
196 local localDir = '/' .. dir
197 local localPath = localDir .. '/' .. files[idx]
198 if fs.exists(localPath) then
199 fs.delete(localPath)
200 print('Removed: ' .. localPath)
201 else
202 print('Not found: ' .. localPath)
203 end
204end
205
206if not http then
207 print('ERROR: http API not available. Enable in mod config.')
208else
209 if #arg >= 1 then
210 local cmd = tostring(arg[1])
211 if cmd == 'all' then
212 updateAll()
213 elseif cmd == 'rm' and arg[2] then
214 local target = tostring(arg[2])
215 local dir, files
216 for d, f in pairs(manifest) do dir, files = d, f break end
217 local found = false
218 for i = 1, #files, 1 do if files[i] == target then found = true break end end
219 if found then
220 local localDir = '/' .. dir
221 local localPath = localDir .. '/' .. target
222 if fs.exists(localPath) then fs.delete(localPath) print('Removed: ' .. localPath) else print('Not found: ' .. localPath) end
223 else
224 print('Unknown file: ' .. target)
225 end
226 else
227 local target = cmd
228 local dir, files
229 for d, f in pairs(manifest) do dir, files = d, f break end
230 local found = false
231 for i = 1, #files, 1 do if files[i] == target then found = true break end end
232 if found then updateDir(dir, { target }) else print('Unknown file: ' .. target) end
233 end
234 else
235 while true do
236 local ch = showMenu()
237 if ch == 1 then
238 updateAll()
239 elseif ch == 2 then
240 updateSingle()
241 elseif ch == 3 then
242 removeOne()
243 else
244 break
245 end
246 end
247 end
248end
249
250
251