You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							233 lines
						
					
					
						
							7.0 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							233 lines
						
					
					
						
							7.0 KiB
						
					
					
				| #!/usr/bin/env lua | |
| 
 | |
| function show_help() | |
| print(string.format([[This program will help you keep your satellites fresh and up to date. | |
| Usage: %s <sat|dir> <check> <save> | |
|  | |
| sat = Check only one satellite | |
| dir = Check a dir full of satellites | |
| check = What file (sat) or directory (dir) to check | |
| save = What file (sat) or directory (dir) to save known versions into]], arg[0])) | |
| end | |
| 
 | |
| -- Shamelessly stolen from http://stackoverflow.com/questions/15706270/sort-a-table-in-lua | |
| function spairs(t) | |
|     -- collect the keys | |
|     local keys = {} | |
|     for k in pairs(t) do keys[#keys+1] = k end | |
| 
 | |
|     table.sort(keys) | |
| 
 | |
|     -- return the iterator function | |
|     local i = 0 | |
|     return function() | |
|         i = i + 1 | |
|         if keys[i] then | |
|             return keys[i], t[keys[i]] | |
|         end | |
|     end | |
| end | |
| 
 | |
| function call(command) | |
|     --[[-- | |
|     --  Runs a command, returns all output except trailing newline on success. | |
|     --]]-- | |
| 
 | |
|     local pipe = io.popen(command) | |
|     if pipe then | |
|         local output = pipe:read("*all") | |
|         if pipe:close() then | |
|             if #output > 0 then | |
|                 return output:match("(.-)%s*$") | |
|             end | |
|         end | |
|     end | |
| end | |
| 
 | |
| function astrohelp(satellite, func) | |
|     -- satellite_dir is an example of me being lazy and wanting to keep output clean in other functions. | |
|     if satellite_dir then | |
|         return call("astrohelp '" .. satellite_dir .. "/" .. satellite .. "' " .. func) | |
|     else | |
|         return call("astrohelp '" .. satellite .. "' " .. func) | |
|     end | |
| end | |
| 
 | |
| function download(url) | |
|     return call("curl -Ls '" .. url .. "'") | |
| end | |
| 
 | |
| function escape_regex(string) | |
|     -- http://www.lua.org/manual/5.3/manual.html#6.4.1 | |
|     local magic = "^$().[]*+-?" | |
|     for i = 1, #magic do | |
|         local char = magic:sub(i, i) | |
|         string = string:gsub("%" .. char, "%%" .. char) | |
|     end | |
| 
 | |
|     return string | |
| end | |
| 
 | |
| function make_regex(filename, version) | |
|     --[[-- | |
|     --  Converts a string into regex, by escaping all special (magic) characters. | |
|     --  Returns two regexes, meant to be used in a loop. (See code using this function to know what I mean) | |
|     --]]-- | |
| 
 | |
|     local regex = escape_regex(filename:gsub(escape_regex(version), "{{version}}"):gsub("%%", "%%%%")) | |
|     return regex:gsub("{{version}}", "(.-") .. ")", regex:gsub(".*{{version}}", "(.-)") | |
| end | |
| 
 | |
| function get_available_versions(satellite) | |
|     --[[-- | |
|     --  Returns a set table containing all available versions on update_url | |
|     --]]-- | |
| 
 | |
|     local version = astrohelp(satellite, "variable version") | |
|     local update_url = astrohelp(satellite, "variable update_url") | |
| 
 | |
|     if not version or not update_url then | |
|         return | |
|     end | |
| 
 | |
|     io.write("\x1B[1K\r" .. satellite .. ": Downloading update file...") | |
|     local update_file = download(update_url) | |
|     if not update_file then | |
|         print("\x1B[1K\rWARNING: " .. satellite .. ": Failed to download " .. update_url) | |
|         return | |
|     end | |
| 
 | |
|     io.write("\x1B[1K\r" .. satellite .. ": Getting available versions...") | |
|     -- Try getting variable update_names, get downloads otherwise. | |
|     local update_names = astrohelp(satellite, "variable update_names") | |
|     if not update_names then | |
|         local tmp_update_names = astrohelp(satellite, "downloads") | |
|         assert(tmp_update_names, "Could not get update names for " ..  satellite) | |
|         update_names = "" | |
|         -- Take the basename of every download url | |
|         for name in tmp_update_names:gmatch("[^\n]+") do | |
|             update_names = update_names .. name:match("[^/]+$") .. "," | |
|         end | |
|     end | |
| 
 | |
|     local versions = {} | |
|     local count = 0 | |
|     for update_name in update_names:gmatch("[^,]+") do | |
|         local loop_regex, end_regex = make_regex(update_name, version) | |
| 
 | |
|         for x in update_file:gmatch(loop_regex) do | |
|             -- Sometimes, the match starts way too soon, and we get a very long "version" number. | |
|             -- Here we make sure we really get the shortest possible match. | |
|             local version | |
|             repeat | |
|                 version = x | |
|                 x = x:match(loop_regex) | |
|             until not x | |
|             version = version:match(end_regex) | |
| 
 | |
|             versions[version] = true | |
|             count = count + 1 | |
|         end | |
|     end | |
| 
 | |
|     if count < 1 then | |
|         print("\x1B[1K\rWARNING: " .. satellite .. ": Couldn't retrieve any versions") | |
|         return | |
|     elseif not versions[version] then | |
|         print("\x1B[1K\rWARNING: " .. satellite .. ": Current version isn't available") | |
|     end | |
| 
 | |
|     return versions, update_url | |
| end | |
| 
 | |
| function check_new_versions(satellite, version_file_path) | |
|     --[[-- | |
|     --  Check if new versions are available for a satellite. | |
|     --  Logs new versions to log_file, which should be a file descriptor. | |
|     --  Uses version_file_path to know where to store all known versions. | |
|     --]]-- | |
| 
 | |
|     local versions, update_url = get_available_versions(satellite) | |
|     if not versions then | |
|         return | |
|     end | |
| 
 | |
|     local version_file = io.open(version_file_path, "r+") | |
| 
 | |
|     local old_versions = nil | |
|     if version_file then | |
|         old_versions = {} | |
|         for version in version_file:lines() do | |
|             old_versions[version] = true | |
|         end | |
|     else | |
|         print("\x1B[1K\r" .. satellite .. ": First check") | |
|         version_file = io.open(version_file_path, "w") | |
|         assert(version_file, "Failed to create " .. version_file_path) | |
|     end | |
| 
 | |
|     local new_versions = {} | |
|     if old_versions then | |
|         for version, _ in spairs(versions) do | |
|             if not old_versions[version] then | |
|                 table.insert(new_versions, version) | |
|             end | |
|         end | |
|     else | |
|         for version, _ in spairs(versions) do | |
|             table.insert(new_versions, version) | |
|         end | |
|     end | |
| 
 | |
|     if #new_versions > 0 then | |
|         print("\x1B[1K\r" .. satellite .. ": From '" .. update_url .. "'") | |
| 
 | |
|         for _, version in ipairs(new_versions) do | |
|             version_file:write(version .. "\n") | |
|             print("\x1B[1K\r" .. satellite .. ": " .. version) | |
|         end | |
|     end | |
| 
 | |
|     version_file:close() | |
| end | |
| 
 | |
| if #arg < 3 then | |
|     show_help() | |
|     os.exit(1) | |
| end | |
| 
 | |
| if arg[1] == "sat" then | |
|     check_new_versions(arg[2], arg[3]) | |
| elseif arg[1] == "dir" then | |
|     satellite_dir = arg[2] | |
|     local version_dir = arg[3] | |
|     assert(os.execute("mkdir -p " .. version_dir), "Failed to create " .. version_dir) | |
| 
 | |
|     local find = call("find " .. satellite_dir .. " -type f -name '*.sat' -printf '%P\n'") | |
|     assert(find, "Failed to run find") | |
| 
 | |
|     local total = select(2, find:gsub("\n", "\n")) | |
|     local cols = call("tput cols") | |
|     local count = 1 | |
| 
 | |
|     for satellite in find:gmatch("(.-)\n") do | |
|         if cols then | |
|             cols = tonumber(cols) | |
|             local countstr = tostring(count) .. "/" .. tostring(total) | |
|             io.write("\r") | |
|             for i = 1, cols - countstr:len() - 1 do | |
|                 io.write(" ") | |
|             end | |
|             io.write(countstr .. "\r") | |
|         end | |
| 
 | |
|         local version_file = version_dir .. "/" .. satellite | |
|         assert(os.execute("mkdir -p " .. version_file:match("^.+/")), "Failed to create dir for " .. satellite) | |
|         check_new_versions(satellite, version_file) | |
| 
 | |
|         count = count + 1 | |
|     end | |
| else | |
|     show_help() | |
|     os.exit(1) | |
| end
 | |
| 
 |