Skip to content

Instantly share code, notes, and snippets.

@pbhogan
Last active March 9, 2018 16:51
Show Gist options
  • Save pbhogan/0834e861d5c3f0dee404053d92265537 to your computer and use it in GitHub Desktop.
Save pbhogan/0834e861d5c3f0dee404053d92265537 to your computer and use it in GitHub Desktop.
Factorio Helper Script
#!/usr/bin/ruby
require "thor"
require "httparty"
require "logger"
require "fileutils"
class FactorioTools < Thor
SOURCE_LINK = "https://www.factorio.com/get-download/latest/headless/linux64"
TARGET_FILE = "factorio.tar.xz"
BINARY_PATH = "/opt/factorio/bin/x64/factorio"
class_option :quiet, type: :boolean, aliases: "-q"
class_option :log, type: :string, aliases: "-l"
class Factorio
class << self
def setup_logger(options = {})
$logger = ::Logger.new(options[:log] ? options[:log] : STDOUT)
$logger.level = options[:quiet] ? ::Logger::WARN : ::Logger::INFO
$logger.datetime_format = "%Y-%m-%d %H:%M:%S"
$logger.formatter = proc do |severity, datetime, program_name, message|
"#{datetime.strftime($logger.datetime_format)} #{severity}: #{message}\n"
end
$logger
end
def get_installed_version(options = {})
version_command = "#{BINARY_PATH} --version"
if File.exist? BINARY_PATH
version = `#{version_command}`[/Version: ([\d\.]+)/, 1]
if version.empty?
$logger.fatal "Could not parse version from command output: #{version_command}"
exit
end
version
else
unless options[:silent]
$logger.fatal "Could not find factorio binary at: #{BINARY_PATH}"
exit
end
end
rescue Exception => e
$logger.fatal e.message
exit
end
def get_target_time
File.mtime(TARGET_FILE).to_time.to_i
rescue
0
end
def get_remote_info(version = "latest")
source_link = SOURCE_LINK.gsub "latest", "#{version.downcase}"
begin
response = HTTParty.head SOURCE_LINK
source_link = response.request.last_uri.to_s
if response["last-modified"].nil? || response["last-modified"].empty?
$logger.fatal "Could not find Last-Modified HTTP header: #{response}"
exit
end
begin
last_modified_at = DateTime.strptime(response["last-modified"], "%a, %d %b %Y %H:%M:%S %Z").to_time.to_i
rescue Exception => e
$logger.fatal "Could not parse version from Last-Modified HTTP header: #{response["last-modified"]}"
$logger.fatal e.message
exit
end
version = source_link[/factorio_headless_x64_([\d\.]+)\.tar/, 1]
if version.empty?
$logger.fatal "Could not parse version from URL: #{source_link}"
exit
end
return OpenStruct.new(
url: source_link,
last_modified_at: last_modified_at,
version: version,
)
rescue Exception => e
$logger.fatal "Could not access remote URL: #{source_link}"
$logger.fatal e.message
exit
end
end
def download_package(remote_info)
$logger.info "Downloading package #{remote_info.url}"
File.open(TARGET_FILE, "w") do |file|
response = HTTParty.get(remote_info.url, stream_body: true) do |part|
file.write part
end
end
$logger.info "Updating package mtime"
FileUtils.touch TARGET_FILE, mtime: remote_info.last_modified_at
end
def install_package
$logger.info "Extracting package"
`tar -Jxf #{TARGET_FILE}`
$logger.info "Changing ownership to user 'factorio'"
FileUtils.chown_R "factorio", "factorio", "./factorio"
$logger.info "Restarting service"
`systemctl restart factorio`
end
end
end
desc "version", "Detect the currently installed version of Factorio"
def version
Factorio.setup_logger options
if version = Factorio.get_installed_version
puts version
end
end
desc "latest", "Detect the latest version of Factorio available"
def latest
Factorio.setup_logger options
if remote_info = Factorio.get_remote_info
puts remote_info.version
end
end
desc "install [VERSION]", "Install Factorio version (default: latest)"
option :force, type: :boolean
def install(version = "latest")
Factorio.setup_logger options
if installed_version = Factorio.get_installed_version(silent: true)
$logger.fatal "Factorio is already installed. Use 'upgrade' to install a different version."
exit
end
remote_info = Factorio.get_remote_info version
if options[:force] || Factorio.get_target_time != remote_info.last_modified_at
Factorio.download_package remote_info
end
Factorio.install_package
end
desc "upgrade [VERSION]", "Upgrade to Factorio version (default: latest)"
option :force, type: :boolean
def upgrade(version = "latest")
Factorio.setup_logger options
remote_info = Factorio.get_remote_info version
if options[:force] || remote_info.version != Factorio.get_installed_version(silent: true)
if options[:force] || Factorio.get_target_time != remote_info.last_modified_at
Factorio.download_package remote_info
end
Factorio.install_package
$logger.info "Factorio #{remote_info.version} has been installed."
else
$logger.info "Factorio #{remote_info.version} is already up to date."
end
end
desc "download [VERSION]", "Download Factorio package for version (default: latest)"
option :force, type: :boolean
def download(version = "latest")
Factorio.setup_logger options
remote_info = Factorio.get_remote_info version
if options[:force] || Factorio.get_target_time != remote_info.last_modified_at
Factorio.download_package remote_info
$logger.info "#{TARGET_FILE} has been downloaded."
else
$logger.info "#{TARGET_FILE} is already present and up to date."
end
end
desc "backup", "Backup current installation to the archives folder"
def backup
Factorio.setup_logger options
backup_path = "archived/games"
version = Factorio.get_installed_version
FileUtils.mkdir_p backup_path
FileUtils.cp_r "factorio", "#{backup_path}/factorio-#{version}", remove_destination: true
$logger.info "Archived current Factorio installation to '#{backup_path}'"
end
end
FactorioTools.start ARGV
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment