# talk to previous contributors about the logic in source_files # # the docs recommend to just ‘packagecloud push src target` packagecloud.io/docs#travis
module Dpl
module Providers class Packagecloud < Provider register :packagecloud status :alpha description sq(<<-str) tbd str gem 'packagecloud-ruby', '~> 1.0.8', require: 'packagecloud' env :packagecloud opt '--username USER', 'The packagecloud.io username.', required: true opt '--token TOKEN', 'The packagecloud.io api token.', required: true, secret: true opt '--repository REPO', 'The repository to push to.', required: true opt '--local_dir DIR', 'The sub-directory of the built assets for deployment.', default: '.' opt '--dist DIST', 'Required for debian, rpm, and node.js packages (use "node" for node.js packages). The complete list of supported strings can be found on the packagecloud.io docs.' opt '--force', 'Whether package has to be (re)uploaded / deleted before upload' opt '--connect_timeout SEC', type: :integer, default: 60 opt '--read_timeout SEC', type: :integer, default: 60 opt '--write_timeout SEC', type: :integer, default: 180 opt '--package_glob GLOB', type: :array, default: ['**/*'] # previous implementation checks against all of these in dist_required? but # then the error message only lists rmp, deb, python, and dsc. i think the # error message might be out of date? so is the option description in the # readme (and thus above). NEED_DIST = %w(rpm deb dsc whl egg egg-info gz zip tar bz2 z tgz) msgs authenticate: 'Logging in to https://packagecloud.io with %{username}:%{token}', timeouts: 'Timeouts: %{timeout_info}', unauthenticated: 'Could not authenticate to https://packagecloud.io, please check the credentials', supported_packages: 'Supported packages: %s', source_packages: 'Source packages: %s', delete_package: 'Deleting package: %s on %s', push_package: 'Pushing package: %s to %s/%s', source_fragment: 'Found source fragment: %s for %s', missing_packages: 'No supported packages found', missing_dist: 'Distribution needed for rpm, deb, python, and dsc packages (e.g. dist: ubuntu/breezy)', unknown_dist: 'Failed to find distribution %{dist}', error: 'Error: %s' def install @cwd = Dir.pwd Dir.chdir(local_dir) end def login info :authenticate info :timeouts client rescue ::Packagecloud::UnauthenticatedException error :unauthenticated end def timeout_info to_pairs(timeouts) end def validate error :missing_packages if paths.empty? error :missing_dist if missing_dist? info :supported_packages, paths.join(', ') info :source_packages, source_paths.join(', ') if source_paths.any? end def deploy packages.each do |package| delete(package) if force? push(package) end end def finish Dir.chdir(@cwd) end private def delete(package) info :delete_package, package.filename, dist result = client.delete_package(repository, *dist.split('/'), package.filename) error "Error #{result.response}" unless result.succeeded end def push(package) info :push_package, package.filename, username, repository args = [repository, package] args << distro if dist_required?(package.filename) result = client.put_package(*args) error :error, result.response unless result.succeeded end def packages paths.map { |path| package(path) } end def package(path) opts = { file: path } opts[:source_files] = source_files(path) if source?(path) ::Packagecloud::Package.new(opts) end def paths @paths ||= glob(package_glob).select { |path| supported?(path) } end def source_paths paths.select { |path| source?(path) } end # I believe this resembles the logic in the previous version, but it seems # very odd to me. Files are considered source files only if they are already # part of the package (it looks up the package from the client, and extracts # the file names), and if they are not located in sub directories (it uses # File.basename to filter). Not sure that's how it's supposed to work? def source_files(path) files = contents(path) paths = glob('**/*').select { |path| files.include?(path) } paths = paths.map { |path| [File.basename(path), path] } paths.each { |name, _| info(:source_fragement, name, path) } paths.map { |name, path| [name, open(path)] }.to_h end def contents(path) package = ::Packagecloud::Package.new(file: path) result = client.package_contents(repository, package, distro) error :error, result.response unless result.succeeded result.response['files'].map { |file| file['filename'] } end def distro @distro ||= client.find_distribution_id(dist) || error(:unknown_dist) rescue ArgumentError => e error :error, e.message end def supported?(path) ::Packagecloud::SUPPORTED_EXTENSIONS.include?(ext(path)) end def source?(path) ext(path) == 'dsc' end def dist_required?(path) NEED_DIST.include?(ext(path)) end def package_glob "{#{super.join(',')}}" end def timeouts only(opts, :connect_timeout, :read_timeout, :write_timeout) end def ext(path) File.extname(path).to_s.gsub('.','').downcase end def glob(glob) Dir.glob(glob).reject { |path| File.directory?(path) } end def missing_dist? !dist? && paths.any? { |path| dist_required?(path) } end def client @client ||= ::Packagecloud::Client.new(credentials, "travis-ci dpl #{Dpl::VERSION}", connection) end def credentials ::Packagecloud::Credentials.new(username, token) end def connection ::Packagecloud::Connection.new('https', 'packagecloud.io', '443', timeouts) end def to_pairs(hash) hash.map { |pair| pair.join('=') }.join(' ') end end end
end