2019-07-24 23:51:29 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
require 'open3'
|
2023-03-17 21:38:47 +00:00
|
|
|
|
2019-07-24 23:51:29 +00:00
|
|
|
# Este modelo implementa los distintos tipos de alojamiento que provee
|
|
|
|
# Sutty.
|
|
|
|
#
|
|
|
|
# Los datos se guardan en la tabla `deploys`. Para guardar los
|
|
|
|
# atributos, cada modelo tiene que definir su propio `store
|
|
|
|
# :attributes`.
|
|
|
|
class Deploy < ApplicationRecord
|
|
|
|
belongs_to :site
|
2020-11-26 17:40:03 +00:00
|
|
|
has_many :build_stats, dependent: :destroy
|
2019-07-24 23:51:29 +00:00
|
|
|
|
2023-03-17 21:38:47 +00:00
|
|
|
DEPENDENCIES = []
|
2023-03-27 17:44:22 +00:00
|
|
|
SOFT_DEPENDENCIES = []
|
2023-03-17 21:38:47 +00:00
|
|
|
|
2022-03-16 21:19:04 +00:00
|
|
|
def deploy(**)
|
2019-07-24 23:51:29 +00:00
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
2022-04-06 23:07:14 +00:00
|
|
|
def url
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
2023-08-31 17:52:49 +00:00
|
|
|
# @return [Array]
|
|
|
|
def urls
|
|
|
|
[url].compact
|
|
|
|
end
|
|
|
|
|
2019-07-24 23:51:29 +00:00
|
|
|
def limit
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
2019-07-26 00:07:53 +00:00
|
|
|
def size
|
|
|
|
raise NotImplementedError
|
|
|
|
end
|
|
|
|
|
2022-04-15 13:39:44 +00:00
|
|
|
# Realizar tareas de limpieza.
|
|
|
|
def cleanup!; end
|
|
|
|
|
2019-07-26 00:07:53 +00:00
|
|
|
def time_start
|
|
|
|
@start = Time.now
|
|
|
|
end
|
|
|
|
|
|
|
|
def time_stop
|
|
|
|
@stop = Time.now
|
|
|
|
end
|
|
|
|
|
|
|
|
def time_spent_in_seconds
|
|
|
|
(@stop - @start).round(3)
|
|
|
|
end
|
|
|
|
|
2019-09-19 13:20:27 +00:00
|
|
|
def home_dir
|
|
|
|
site.path
|
|
|
|
end
|
|
|
|
|
2023-08-31 17:44:43 +00:00
|
|
|
# Un entorno que solo tiene lo que necesitamos
|
|
|
|
#
|
|
|
|
# @return [Hash]
|
|
|
|
def env
|
|
|
|
# XXX: This doesn't support Windows paths :B
|
|
|
|
paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin']
|
|
|
|
|
|
|
|
# Las variables de entorno extra no pueden superponerse al local.
|
|
|
|
extra_env.merge({
|
|
|
|
'HOME' => home_dir,
|
|
|
|
'PATH' => paths.join(':'),
|
|
|
|
'JEKYLL_ENV' => Rails.env,
|
|
|
|
'LANG' => ENV['LANG'],
|
|
|
|
})
|
2019-09-19 13:20:27 +00:00
|
|
|
end
|
|
|
|
|
2023-08-30 18:33:48 +00:00
|
|
|
# Un entorno que solo tiene lo que necesitamos
|
|
|
|
#
|
|
|
|
# @return [Hash]
|
|
|
|
def env
|
|
|
|
# XXX: This doesn't support Windows paths :B
|
|
|
|
paths = [File.dirname(`which bundle`), '/usr/local/bin', '/usr/bin', '/bin']
|
|
|
|
|
|
|
|
# Las variables de entorno extra no pueden superponerse al local.
|
|
|
|
extra_env.merge({
|
|
|
|
'HOME' => home_dir,
|
|
|
|
'PATH' => paths.join(':'),
|
|
|
|
'JEKYLL_ENV' => Rails.env,
|
|
|
|
'LANG' => ENV['LANG'],
|
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2021-04-14 16:09:03 +00:00
|
|
|
# Corre un comando, lo registra en la base de datos y devuelve el
|
|
|
|
# estado.
|
|
|
|
#
|
|
|
|
# @param [String]
|
|
|
|
# @return [Boolean]
|
2022-03-14 16:39:54 +00:00
|
|
|
def run(cmd, output: false)
|
2019-07-26 00:07:53 +00:00
|
|
|
r = nil
|
2021-04-14 16:09:03 +00:00
|
|
|
lines = []
|
2019-07-24 23:51:29 +00:00
|
|
|
|
2019-07-26 00:07:53 +00:00
|
|
|
time_start
|
2023-06-15 21:28:34 +00:00
|
|
|
Open3.popen2e(env, cmd, unsetenv_others: true, chdir: site.path) do |_, o, t|
|
|
|
|
# TODO: Enviar a un websocket para ver el proceso en vivo?
|
|
|
|
Thread.new do
|
|
|
|
o.each do |line|
|
|
|
|
lines << line
|
2022-04-18 20:27:43 +00:00
|
|
|
|
2023-06-15 21:28:34 +00:00
|
|
|
puts line if output
|
|
|
|
end
|
|
|
|
rescue IOError => e
|
|
|
|
lines << e.message
|
|
|
|
puts e.message if output
|
2019-07-24 23:51:29 +00:00
|
|
|
end
|
2023-06-15 21:28:34 +00:00
|
|
|
|
|
|
|
r = t.value
|
2019-07-24 23:51:29 +00:00
|
|
|
end
|
2019-07-26 00:07:53 +00:00
|
|
|
time_stop
|
|
|
|
|
2021-04-14 16:09:03 +00:00
|
|
|
build_stats.create action: readable_cmd(cmd),
|
|
|
|
log: lines.join,
|
|
|
|
seconds: time_spent_in_seconds,
|
|
|
|
bytes: size,
|
|
|
|
status: r&.success?
|
2019-07-24 23:51:29 +00:00
|
|
|
|
2020-10-04 00:32:32 +00:00
|
|
|
r&.success?
|
2019-07-24 23:51:29 +00:00
|
|
|
end
|
2021-04-14 16:09:03 +00:00
|
|
|
|
2022-10-05 21:44:23 +00:00
|
|
|
# Variables de entorno
|
|
|
|
#
|
|
|
|
# @return [Hash]
|
|
|
|
def local_env
|
|
|
|
@local_env ||= {}
|
|
|
|
end
|
|
|
|
|
2023-08-30 13:58:52 +00:00
|
|
|
# Devuelve opciones para jekyll build
|
|
|
|
#
|
|
|
|
# @return [String,nil]
|
|
|
|
def flags_for_build(**args); end
|
|
|
|
|
2023-03-27 17:52:37 +00:00
|
|
|
# Trae todas las dependencias
|
|
|
|
#
|
|
|
|
# @return [Array]
|
|
|
|
def self.all_dependencies
|
|
|
|
self::DEPENDENCIES | self::SOFT_DEPENDENCIES
|
|
|
|
end
|
|
|
|
|
2021-04-14 16:09:03 +00:00
|
|
|
private
|
|
|
|
|
2023-08-29 21:26:03 +00:00
|
|
|
# Escribe el contenido en un archivo temporal y ejecuta el bloque
|
|
|
|
# provisto con el archivo como parámetro
|
|
|
|
#
|
|
|
|
# @param :content [String]
|
|
|
|
def with_tempfile(content, &block)
|
|
|
|
Tempfile.create(SecureRandom.hex) do |file|
|
|
|
|
file.write content.to_s
|
|
|
|
file.rewind
|
|
|
|
file.close
|
|
|
|
|
|
|
|
# @yieldparam :file [File]
|
|
|
|
yield file
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-04-14 16:09:03 +00:00
|
|
|
# @param [String]
|
|
|
|
# @return [String]
|
|
|
|
def readable_cmd(cmd)
|
|
|
|
cmd.split(' -', 2).first.tr(' ', '_')
|
|
|
|
end
|
2022-10-05 21:44:23 +00:00
|
|
|
|
|
|
|
def deploy_local
|
|
|
|
@deploy_local ||= site.deploys.find_by(type: 'DeployLocal')
|
|
|
|
end
|
|
|
|
|
2023-08-30 18:33:48 +00:00
|
|
|
# Consigue todas las variables de entorno configuradas por otros
|
|
|
|
# deploys.
|
|
|
|
#
|
|
|
|
# @return [Hash]
|
|
|
|
def extra_env
|
|
|
|
@extra_env ||=
|
2023-08-30 19:40:33 +00:00
|
|
|
site.deployment_list.reduce({}) do |extra, deploy|
|
|
|
|
extra.merge deploy.local_env
|
2023-08-30 18:33:48 +00:00
|
|
|
end
|
|
|
|
end
|
2019-07-24 23:51:29 +00:00
|
|
|
end
|