From 7fc3d33dfbbdadb8fc6257e3c838f224a085a03f Mon Sep 17 00:00:00 2001 From: ellemenno Date: Sat, 3 Jan 2015 12:23:28 -0500 Subject: [PATCH] v1.0.0 release candidate --- LICENSE | 3 +- README.md | 130 +++++++++++++++++++- Rakefile | 102 ++++++++++++++++ lib/tasks/loomlib.rake | 271 +++++++++++++++++++++++++++++++++++++++++ loom.config | 3 + 5 files changed, 506 insertions(+), 3 deletions(-) create mode 100644 Rakefile create mode 100644 lib/tasks/loomlib.rake create mode 100644 loom.config diff --git a/LICENSE b/LICENSE index d2fce97..f431584 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ The MIT License (MIT) -Copyright (c) 2014 pixeldroid +Copyright (c) pixeldroid +https://github.com/pixeldroid/loomtasks Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 9d4e707..1cb8b3e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,130 @@ -loomtasks -========= +loom tasks +========== Rake tasks for working with loomlibs + + +## overview + +If you use [Rake][rake] and follow a consistent file layout across projects, these tasks can provide help for building, testing, releasing and installing loom libraries (`*.loomlib`). + +The tasks install into your `.loom` directory, and can be loaded from there into the Rakefiles of your projects. +They are no substitute for something like Gem or Bundler for Ruby, but they're a first step in that direction. + +loom tasks do not interfere with the [loomcli][loomcli]; the two can be used safely together. + + +## conventions + +The loomlib rake tasks make the following assumptions about the layout of a project: + +### directory structure + + foo-loomlib $ + ├─lib/ + ├─Rakefile + └─test/ + +* library source will go under `lib/` +* the project will use a `Rakefile` for building, testing, and preparing releases +* library test source will go under `test/`; the test app will consume the library and exercise it + +#### lib + + ├─lib + │ ├─assets + │ ├─bin + │ ├─build + │ │ └─Foo.loomlib + │ ├─loom.config + │ └─src + │ ├─Foo.build + │ └─com + │ └─bar + │ └─Foo.ls + +* the loomlib wil be built into `lib/build/` +* the library has its own loom config file at `lib/loom.config` +* the library has its own loom build file at `lib/src/Foo.build` +* library source code is under `lib/src/` + +##### version + +Some file under `lib/` must contain the following line (where `1.2.3` is the version of your library): + + public static const version:String = '1.2.3'; + +This is used to name the loomlib that gets compiled (and anticipates a corresponding [GitHub release][gh-releases]). + +#### test + + └─test + ├─assets + ├─bin + │ └─FooTest.loom + ├─loom.config + └─src + ├─app + │ └─FooTest.ls + ├─spec + │ └─FooSpec.ls + └─FooTest.build + +* the test application wil be built into `test/bin/` +* the tests have their own loom config file at `test/loom.config` +* the tests have their own loom build file at `test/src/Foo.build` +* the test application source code is under `test/src/app/` +* the specification source code is under `test/src/spec/` + + +## installation + +Clone this repo. + +0. Run `rake install` to: + * create a `tasks` folder in your Loom SDK home directory (`~/.loom`) + * put the `.rake` files from this project into it. +0. Run `rake uninstall` to: + * delete the `tasks` folder. + * _**Note:** this deletes the whole folder! So be careful if you decide to put your own tasks in there._ + + +## usage + +In your project's `Rakefile`, declare the name of your library and path to the file containing version info. + + LIB_NAME = 'Foo' + LIB_VERSION_FILE = File.join('lib', 'src', 'com', 'bar', 'Foo.ls') + +Then load the tasks: + + load(File.join(ENV['HOME'], '.loom', 'tasks', 'loomlib.rake')) + +> Note: your whole Rakefile may be just those three lines if there isn't anything else you need to do + +Now run `rake` to execute the default task, which will print the list of available tasks and some useful info: + + Foo v1.2.3 Rakefile running on Ruby 2.1.1 (lib=sprint33, test=sprint33) + rake clean # Remove any temporary products + rake clobber # Remove any generated file + rake lib:build # builds Foo.loomlib for the SDK specified in lib/loom.config + rake lib:install # installs Foo.loomlib into the SDK specified in lib/loom.config + rake lib:release # prepares sdk-specific Foo.loomlib for release + rake lib:show # lists libs installed for the SDK specified in lib/loom.config + rake lib:uninstall # removes Foo.loomlib from the SDK specified in lib/loom.config + rake set[sdk] # sets the provided SDK version into lib/loom.config and test/loom.config + rake test:build # builds FooTest.loom with the SDK specified in test/loom.config + rake test:ci # runs FooTest.loom for CI + rake test:run # runs FooTest.loom + +The Rake tasks are defined with dependencies and modification triggers, so you can just run `rake test:run` every time you edit a source file, and the library and test app will be rebuilt as needed automatically. + + +## contributing + +Pull requests are welcome! + + +[rake]: https://rubygems.org/gems/rake "Rake (Ruby make)" +[loomcli]: https://loomsdk.com/#see "See the Loom CLI demo" +[gh-releases]: https://help.github.com/articles/about-releases/ "about GitHub releases" diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..3942da5 --- /dev/null +++ b/Rakefile @@ -0,0 +1,102 @@ +# encoding: utf-8 + +require 'etc' +require 'fileutils' +require 'json' + +@loom_config = nil + + +task :default => :list_targets + +task :list_targets do |t, args| + a = "#{File.basename(File.dirname(__FILE__))} Rakefile" + b = "running on Ruby #{RUBY_VERSION}" + puts "#{a} #{b}" + system("rake -T") + puts '' +end + +desc "installs rake tasks for Loom" +task :install do |t, args| + Dir.mkdir(installed_tasks_dir) unless Dir.exists?(installed_tasks_dir) + + cmd = "cp lib/tasks/*.rake #{installed_tasks_dir}" + try(cmd, "failed to install tasks") + + puts "[#{t.name}] task completed, tasks installed to #{installed_tasks_dir}" + puts '' +end + +namespace :list do + + desc "lists tasks available to install" + task :available do |t, args| + if Dir.exists?(available_tasks_dir) + cmd = "ls -1 #{available_tasks_dir}/" + try(cmd, "failed to list contents of #{available_tasks_dir} directory") + else + puts "[#{t.name}] no tasks are installed at #{available_tasks_dir}" + end + + puts '' + end + + desc "lists currently installed tasks" + task :installed do |t, args| + if Dir.exists?(installed_tasks_dir) + cmd = "ls -1 #{installed_tasks_dir}/" + try(cmd, "failed to list contents of #{installed_tasks_dir} directory") + else + puts "[#{t.name}] no tasks are installed at #{installed_tasks_dir}" + end + + puts '' + end + +end + +desc "removes the tasks folder from the Loom SDK" +task :uninstall do |t, args| + FileUtils.rm_r(installed_tasks_dir) if Dir.exists?(installed_tasks_dir) + + puts "[#{t.name}] task completed, #{installed_tasks_dir} was removed" + puts '' +end + + +def config() + @loom_config || (@loom_config = JSON.parse(File.read(loom_config_file))) +end + +def exec_with_echo(cmd) + puts(cmd) + stdout = %x[#{cmd}] + puts(stdout) unless stdout.empty? + $?.exitstatus +end + +def fail(message) + abort("◈ #{message}") +end + +def loom_config_file() + 'loom.config' +end + +def available_tasks_dir() + File.join(File.dirname(__FILE__), 'lib', 'tasks') +end + +def installed_tasks_dir() + File.join(Dir.home, '.loom', 'tasks') +end + +def try(cmd, failure_message) + fail(failure_message) if (exec_with_echo(cmd) != 0) +end + +def write_loom_config(config) + File.open(loom_config_file, 'w') { |f| f.write(JSON.pretty_generate(config)) } +end + diff --git a/lib/tasks/loomlib.rake b/lib/tasks/loomlib.rake new file mode 100644 index 0000000..3fca034 --- /dev/null +++ b/lib/tasks/loomlib.rake @@ -0,0 +1,271 @@ +# encoding: utf-8 + +# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +# loomlib.rake - common Rake tasks for loomlib projects +# +# usage +# add the following to your project's Rakefile: +# +# load(File.join(ENV['HOME'], '.loom', 'tasks', 'loomlib.rake')) + +LOOMLIB_VERSION = '1.0.0' + +require 'etc' +require 'fileutils' +require 'json' +require 'rake/clean' + +@lib_loom_config = nil +@test_loom_config = nil + +CLEAN.include ['lib/build/**', 'test/bin/**'] +CLOBBER.include ['lib/build', 'test/bin', 'releases'] +Rake::Task[:clobber].enhance ['lib:uninstall'] + + +task :default => :list_targets + +task :list_targets do |t, args| + a = "#{LIB_NAME} v#{lib_version} Rakefile" + b = "running on Ruby #{RUBY_VERSION}" + c = "lib=#{lib_config['sdk_version']}" + d = "test=#{test_config['sdk_version']}" + puts "#{a} #{b} (#{c}, #{d})" + system("rake -T") + puts "(using #{File.basename(__FILE__)} v#{LOOMLIB_VERSION})" + puts '' +end + + +LIBRARY = "lib/build/#{LIB_NAME}.loomlib" + +FileList['lib/src/**/*.ls'].each do |src| + file LIBRARY => src +end + +file LIBRARY do |t, args| + puts "[file] creating #{t.name}..." + + sdk_version = lib_config['sdk_version'] + + Dir.chdir('lib') do + Dir.mkdir('build') unless Dir.exists?('build') + cmd = "#{sdk_root}/#{sdk_version}/tools/lsc #{LIB_NAME}.build" + try(cmd, "failed to compile .loomlib") + end + + puts '' +end + + +APP = "test/bin/#{LIB_NAME}Test.loom" + +FileList['test/src/**/*.ls'].each do |src| + file APP => src +end + +file APP => LIBRARY do |t, args| + puts "[file] creating #{t.name}..." + + sdk_version = test_config['sdk_version'] + file_installed = "#{sdk_root}/#{sdk_version}/libs/#{LIB_NAME}.loomlib" + + Rake::Task['lib:install'].invoke unless FileUtils.uptodate?(file_installed, [LIBRARY]) + + Dir.chdir('test') do + Dir.mkdir('bin') unless Dir.exists?('bin') + cmd = "#{sdk_root}/#{sdk_version}/tools/lsc #{LIB_NAME}Test.build" + try(cmd, "failed to compile .loom") + end + + puts '' +end + + +desc "sets the provided SDK version into lib/loom.config and test/loom.config" +task :set, [:sdk] => 'lib:uninstall' do |t, args| + args.with_defaults(:sdk => 'sprint33') + sdk_version = args.sdk + + lib_config['sdk_version'] = sdk_version + test_config['sdk_version'] = sdk_version + + write_lib_config(lib_config) + write_test_config(test_config) + + puts "[#{t.name}] task completed, sdk updated to #{sdk_version}" + puts '' +end + +namespace :lib do + + desc "builds #{LIB_NAME}.loomlib for the SDK specified in lib/loom.config" + task :build => LIBRARY do |t, args| + puts "[#{t.name}] task completed, find .loomlib in lib/build/" + puts '' + end + + desc "prepares sdk-specific #{LIB_NAME}.loomlib for release" + task :release => LIBRARY do |t, args| + lib = "lib/build/#{LIB_NAME}.loomlib" + sdk = lib_config['sdk_version'] + ext = '.loomlib' + release_dir = 'releases' + + update_readme_version() + + Dir.mkdir(release_dir) unless Dir.exists?(release_dir) + + lib_release = %Q[#{File.basename(lib, ext)}-#{sdk}#{ext}] + FileUtils.copy(lib, "#{release_dir}/#{lib_release}") + + puts "[#{t.name}] task completed, find #{lib_release} in #{release_dir}/" + puts '' + end + + desc "installs #{LIB_NAME}.loomlib into the SDK specified in lib/loom.config" + task :install => LIBRARY do |t, args| + lib = "lib/build/#{LIB_NAME}.loomlib" + sdk_version = lib_config['sdk_version'] + libs_path = "#{sdk_root}/#{sdk_version}/libs" + + cmd = "cp #{lib} #{libs_path}" + try(cmd, "failed to install lib") + + puts "[#{t.name}] task completed, #{LIB_NAME}.loomlib installed for #{sdk_version}" + puts '' + end + + desc "removes #{LIB_NAME}.loomlib from the SDK specified in lib/loom.config" + task :uninstall do |t, args| + sdk_version = lib_config['sdk_version'] + lib = "#{sdk_root}/#{sdk_version}/libs/#{LIB_NAME}.loomlib" + + if (File.exists?(lib)) + cmd = "rm -f #{lib}" + try(cmd, "failed to remove lib") + puts "[#{t.name}] task completed, #{LIB_NAME}.loomlib removed from #{sdk_version}" + else + puts "[#{t.name}] nothing to do; no #{LIB_NAME}.loomlib found in #{sdk_version} sdk" + end + puts '' + end + + desc "lists libs installed for the SDK specified in lib/loom.config" + task :show do |t, args| + sdk_version = lib_config['sdk_version'] + + cmd = "ls -1 #{sdk_root}/#{sdk_version}/libs" + try(cmd, "failed to list contents of #{sdk_version} libs directory") + + puts '' + end + +end + +namespace :test do + + desc "builds #{LIB_NAME}Test.loom with the SDK specified in test/loom.config" + task :build => APP do |t, args| + puts "[#{t.name}] task completed, find .loom in test/bin/" + puts '' + end + + desc "runs #{LIB_NAME}Test.loom" + task :run => APP do |t, args| + puts "[#{t.name}] running #{t.prerequisites[0]}..." + + sdk_version = test_config['sdk_version'] + cmd = "#{sdk_root}/#{sdk_version}/tools/loomexec test/bin/#{LIB_NAME}Test.loom --format ansi" + try(cmd, "failed to run .loom") + + puts '' + end + + desc "runs #{LIB_NAME}Test.loom for CI" + task :ci => APP do |t, args| + puts "[#{t.name}] running #{t.prerequisites[0]}..." + + sdk_version = test_config['sdk_version'] + cmd = "#{sdk_root}/#{sdk_version}/tools/loomexec test/bin/#{LIB_NAME}Test.loom --format junit --format console" + try(cmd, "failed to run .loom") + + puts '' + end + +end + + +def readme_file() + File.join('README.md') +end + +def lib_config_file() + File.join('lib', 'loom.config') +end + +def lib_version_file() + LIB_VERSION_FILE +end + +def test_config_file() + File.join('test', 'loom.config') +end + +def lib_config() + @lib_loom_config || (@lib_loom_config = JSON.parse(File.read(lib_config_file))) +end + +def test_config() + @test_loom_config || (@test_loom_config = JSON.parse(File.read(test_config_file))) +end + +def readme_version_regex() + Regexp.new(%q/download\/v(\d\.\d\.\d)/) +end + +def readme_version_literal() + "download/v#{lib_version}" +end + +def update_readme_version() + IO.write( + readme_file, + File.open(readme_file, 'r') { |f| f.read.gsub!(readme_version_regex, readme_version_literal) } + ) +end + +def lib_version_regex() + Regexp.new(%q/^\s*public static const version:String = '(\d\.\d\.\d)';/) +end + +def lib_version() + File.open(lib_version_file, 'r') { |f| f.read.scan(lib_version_regex).first[0] } +end + +def write_lib_config(config) + File.open(lib_config_file, 'w') { |f| f.write(JSON.pretty_generate(config)) } +end + +def write_test_config(config) + File.open(test_config_file, 'w') { |f| f.write(JSON.pretty_generate(config)) } +end + +def sdk_root() + File.join(Dir.home, '.loom', 'sdks') +end + +def fail(message) + abort("◈ #{message}") +end + +def try(cmd, failure_message) + fail(failure_message) if (exec_with_echo(cmd) != 0) +end + +def exec_with_echo(cmd) + puts(cmd) + stdout = %x[#{cmd}] + puts(stdout) unless stdout.empty? + $?.exitstatus +end diff --git a/loom.config b/loom.config new file mode 100644 index 0000000..12977d9 --- /dev/null +++ b/loom.config @@ -0,0 +1,3 @@ +{ + "sdk_version": "sprint33" +} \ No newline at end of file