Skip to content
This repository has been archived by the owner on Apr 27, 2021. It is now read-only.

Commit

Permalink
Initial commit. Can upload and download all theme files, also have si…
Browse files Browse the repository at this point in the history
…mple 'watch' functionality
  • Loading branch information
John Duff committed Jun 20, 2011
0 parents commit 4eedeb7
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
*.gem
.bundle
Gemfile.lock
pkg/*
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source "http://rubygems.org"

# Specify your gem's dependencies in shopify_theme.gemspec
gemspec
2 changes: 2 additions & 0 deletions Rakefile
@@ -0,0 +1,2 @@
require 'bundler'
Bundler::GemHelper.install_tasks
4 changes: 4 additions & 0 deletions bin/theme
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require File.expand_path('../../lib/shopify_theme',__FILE__)
require File.expand_path('../../lib/shopify_theme/cli',__FILE__)
ShopifyTheme::Cli.start(ARGV)
3 changes: 3 additions & 0 deletions lib/shopify_theme.rb
@@ -0,0 +1,3 @@
module ShopifyTheme
# Your code goes here...
end
124 changes: 124 additions & 0 deletions lib/shopify_theme/cli.rb
@@ -0,0 +1,124 @@
require 'rubygems'
require 'thor'
require 'yaml'
require 'abbrev'
require 'httparty'
require 'base64'
require 'ftools'
require 'json'

module ShopifyTheme
class Cli < Thor
include Thor::Actions

BINARY_EXTENSIONS = %w(png gif jpg jpeg eot svg ttf woff swf)
IGNORE = %w(config.yml)

tasks.keys.abbrev.each do |shortcut, command|
map shortcut => command.to_sym
end

desc "configure API_KEY PASSWORD STORE", "generate a config file for the store to connect to"
def generate(api_key=nil, password=nil, store=nil)
config = {:api_key => api_key, :password => password, :store => store}
create_file('config.yml', config.to_yaml)
end

desc "download", "download the shops current theme"
def download
setup
asset_list.each do |a|
asset = get_asset(a)

if asset['value']
content = asset['value'].gsub("\r", "")
elsif asset['attachment']
content = Base64.decode64(asset['attachment'])
end

File.makedirs(File.dirname(a))
File.open(a, "w") {|f| f.write content} if content
print "."
$stdout.flush
end
puts "\nDone."
end

desc "upload", "upload all theme files to shop"
def upload
setup

local_assets_list.each do |a|
send_asset(a)
end
puts "Done."
end

desc "watch", "upload individual files as they change"
method_option :quiet, :type => :boolean, :default => false
def watch
setup

loop do
modified_files.each do |a|
send_asset(a, options['quiet'])
end
sleep(1)
end
rescue Interrupt
puts ""
end

private
def setup
@config = YAML.load(File.read('config.yml'))
@default_options = {:basic_auth => {:username => @config[:api_key], :password => @config[:password]}}
@base_uri = "http://#{@config[:store]}"
end

def asset_list
response = HTTParty.get("#{@base_uri}/admin/assets.json", @default_options)
assets = JSON.parse(response.body)["assets"].collect {|a| a['key'] }
# Remove any .css files if a .css.liquid file exists
assets.reject{|a| assets.include?("#{a}.liquid") }
end

def get_asset(asset)
response = HTTParty.get("#{@base_uri}/admin/assets.json", @default_options.merge(:query =>{:asset => {:key => asset}}))
# HTTParty json parsing is broken?
JSON.parse(response.body)["asset"]
end

def local_assets_list
Dir.glob(File.join("**", "*")).reject{ |p| File.directory?(p) || IGNORE.include?(p)}
end

def send_asset(asset, quiet=false)
data = {:key => asset}
if (content = File.read(asset)).is_binary_data? || BINARY_EXTENSIONS.include?(File.extname(asset).gsub('.',''))
data.merge!(:attachment => Base64.encode64(content))
else
data.merge!(:value => content)
end

response = HTTParty.put("#{@base_uri}/admin/assets.json", @default_options.merge(:body =>{:asset => data}))

if response.success?
puts "Uploaded: #{asset}" unless quiet
else
puts "Error: Could not upload #{asset} to #{@config['store']}"
end
end

def modified_files
@reference_time ||= Time.now
checked = Time.now

files = local_assets_list.select do |asset|
File.mtime(asset) > @reference_time
end
@reference_time = checked unless files.empty?
files
end
end
end
3 changes: 3 additions & 0 deletions lib/shopify_theme/version.rb
@@ -0,0 +1,3 @@
module ShopifyTheme
VERSION = "0.0.1"
end
24 changes: 24 additions & 0 deletions shopify_theme.gemspec
@@ -0,0 +1,24 @@
# -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "shopify_theme/version"

Gem::Specification.new do |s|
s.name = "shopify_theme"
s.version = ShopifyTheme::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["John Duff"]
s.email = ["john.duff@shopify.com"]
s.homepage = ""
s.summary = %q{Command line tool for developing themes}
s.description = %q{Command line tool to help with developing Shopify themes. Provides simple commands to download and upload a theme, as well as watch a directory and upload files as they change.}

s.rubyforge_project = "shopify_theme"
s.add_dependency("thor", [">= 0.14.4"])
s.add_dependency("httparty")
s.add_dependency("json")

s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
s.require_paths = ["lib"]
end

0 comments on commit 4eedeb7

Please sign in to comment.