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
							 | 
						|
								
							 |