#!/usr/bin/env ruby require 'siteleaf' require 'fileutils' require 'open-uri' require 'tempfile' require 'yaml' def help %Q( Usage: siteleaf [COMMAND] [OPTIONS] Commands: auth Login in with your credentials c, config DOMAIN Configure an existing directory n, new DOMAIN Creates new site on siteleaf.net pull Pulls files for configured site from Siteleaf push Pushes all files in dir to configured site publish Publish website to hosting provider help Prints this help document version Prints the siteleaf gem version Options: -h, --help Prints this help document -v, --version Prints the siteleaf gem version -q, --quiet Suppress publish status See https://github.com/siteleaf/siteleaf-gem for additional documentation. ) end def auth(re_auth = false) Siteleaf.load_settings if !re_auth && !Siteleaf.api_key if re_auth or !Siteleaf.api_key print 'Enter your Siteleaf email: ' email = $stdin.gets.chomp print 'Enter your Siteleaf password: ' system 'stty -echo' password = $stdin.gets.chomp system 'stty echo' puts "\nAuthorizing..." if (auth = Siteleaf::Client.auth(email, password)) && (auth.is_a?(Hash)) && (auth.has_key?('api_key')) Siteleaf.save_settings({api_key: auth['api_key'], api_secret: auth['api_secret']}) puts "=> Gem authorized." if re_auth return true else puts auth['error'] || "Could not authorize, check your email or password." return false end end rescue Exception => e print "Error: #{e.message}\n" end def pull(site_id) print "Reading site...\n" # get all the things site = Siteleaf::Site.find(site_id) site_files = site.source_files('.', recursive: true) updated_count = 0 # download unmatched files site_files.each do |file| sha = ::File.exist?(file.name) && Siteleaf::GitHash.file(file.name) if file.sha != sha print "Downloading #{file.name}..." FileUtils.mkdir_p(::File.dirname(file.name)) ::File.open(file.name, 'w') { |f| f.write(file.to_file) } updated_count += 1 print "complete.\n" end end # check for old files local_files = read_dir missing_files = [] local_files.each do |path| missing_files << path if !site_files.find{|a| a.name.casecmp(path) == 0 } end if missing_files.empty? puts "=> #{updated_count} file(s) downloaded.\n" else print "=> #{updated_count} file(s) downloaded. Delete the following #{missing_files.size} unmatched local file(s)?\n" missing_files.each do |path| puts path end print '(y/n)? ' if $stdin.gets.chomp == 'y' missing_files.each do |path| print "Deleting #{path}..." ::File.delete(path) print "complete.\n" end puts "=> #{missing_files.size} file(s) deleted.\n" end end rescue Exception => e print "Error: #{e.message}\n" end def push(site_id) print "Reading site...\n" # get all the things site = Siteleaf::Site.find(site_id) site_files = site.source_files('.', recursive: true) local_files = read_dir updated_count = 0 # find changed files changed_files = local_files.reject do |path| file = site_files.find{|a| a.name.casecmp(path) == 0 } file && Siteleaf::GitHash.file(path) == file.sha end changed_files.unshift('_config.yml') if changed_files.delete('_config.yml') # upload changed files changed_files.each do |path| print "Uploading #{path}..." response = Siteleaf::SourceFile.create(site_id: site_id, name: path, file: ::File.new(path)) if error = !response || response.error || response.message print (error) ? "error: #{error}\n" : "error.\n" return else updated_count += 1 print "complete.\n" end end # check for old files missing_assets = [] site_files.each do |asset| missing_assets << asset if !local_files.find{|p| p.casecmp(asset.name) == 0 } end if missing_assets.empty? puts "=> #{updated_count} file(s) uploaded.\n" else print "=> #{updated_count} file(s) uploaded. Delete the following #{missing_assets.size} unmatched remote file(s)?\n" missing_assets.each do |asset| puts asset.name end print '(y/n)? ' if $stdin.gets.chomp == 'y' missing_assets.each do |asset| print "Deleting #{asset.name}..." asset.delete print "complete.\n" end puts "=> #{missing_assets.size} file(s) deleted.\n" end end rescue Exception => e print "Error: #{e.message}\n" end def import(file, quiet = true) job = Siteleaf::Site.import(file: ::File.new(file)) if quiet puts "=> Import queued.\n" else last_msg = nil job.stream do |s| if (msg = s["message"]) && (msg != last_msg) puts msg last_msg = msg end end puts "=> Import completed.\n" end rescue Exception => e print "Error: #{e.message}\n" end def publish(site_id, quiet = true) site = Siteleaf::Site.new(id: site_id) job = site.publish if quiet puts "=> Publish queued.\n" else last_msg = nil job.stream do |s| if (msg = s["message"]) && (msg != last_msg) puts msg last_msg = msg end end puts "=> Publish completed.\n" end rescue Exception => e print "Error: #{e.message}\n" end def config(site) Siteleaf.save_settings({site_id: site.id}, '.siteleaf.yml') puts "=> Site configured." end def get_site_id # check env vars [:api_key, :api_secret, :api_base, :api_version].each do |key| if value = ENV['SITELEAF_'+key.to_s.upcase] Siteleaf.send "#{key}=", value end end ENV['SITELEAF_SITE_ID'] || if settings = Siteleaf.load_settings('.siteleaf.yml') settings[:site_id] end end def read_dir jekyll_config = ::File.exist?('_config.yml') ? YAML::load(::File.read('_config.yml')) : {} ignore_paths = ['config.ru', '.*', '_site/*', 'Gemfile', 'Gemfile.lock'] ignore_paths += ::File.read('.siteleafignore').split(/\r?\n/) if ::File.exists?('.siteleafignore') ignore_paths += jekyll_config['exclude'] if jekyll_config['exclude'].is_a? Array Dir.glob("**/*").reject do |path| ::File.directory?(path) || ignore_paths.any? {|i| ::File.fnmatch?(i, path, File::FNM_CASEFOLD) || ::File.fnmatch?(i, ::File.basename(path), File::FNM_CASEFOLD) } end end case ARGV[0] when '-v', '--version', 'version' puts Siteleaf::VERSION when '-h', '--help', 'help' puts help when 'auth' auth true when 'c', 'config', 'setup' if auth != false if site = Siteleaf::Site.find_by_domain(ARGV[1]) config site else puts "No site found for `#{ARGV[1]}`, run `siteleaf new #{ARGV[1]}` to create it.\n" end end when 'n', 'new' if auth != false if (site = Siteleaf::Site.create(:title => ARGV[1], :domain => ARGV[1])) && (!site.error) dir = ARGV.size >= 3 ? ARGV[2] : ARGV[1] Dir.mkdir(dir) unless ::File.directory?(dir) Dir.chdir(dir) config site else puts "Could not create site `#{ARGV[1]}`.\n" end end when 'pull' if ARGV.size == 1 site_id = get_site_id if auth != false if site_id pull(site_id) else puts "Site not configured, run `siteleaf config yoursite.com`.\n" end end else puts "`#{ARGV.join(' ')}` command not found.\n" end when 'push' if ARGV.size == 1 site_id = get_site_id if auth != false if site_id push(site_id) else puts "Site not configured, run `siteleaf config yoursite.com`.\n" end end else puts "`#{ARGV.join(' ')}` command not found.\n" end when 'publish' site_id = get_site_id if auth != false quiet = %w[-q --quiet].include?(ARGV[1]) && ARGV[1] if site_id publish(site_id, quiet) else puts "Site not configured, run `siteleaf config yoursite.com`.\n" end end when 'import' site_id = get_site_id if auth != false file = ARGV[1] if File.extname(file) != '.zip' puts "Import file must be ZIP format.\n" elsif !File.exist?(file) puts "Import file not found.\n" else quiet = %w[-q --quiet].include?(ARGV[2]) && ARGV[2] import(file, quiet) end end else puts "`#{ARGV[0]}` command not found.\n" puts help end