Skip to content

Commit e76aea2

Browse files
committed
Overhaul the import as we know it
1 parent 51447ca commit e76aea2

10 files changed

+219
-116
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Gemfile.lock

Gemfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
source "https://rubygems.org"
2+
3+
gemspec

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2014 FullStack
2+
3+
MIT License
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+19-8
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,22 @@ Chef Legacy is a rake task that aids in the data migration from the old [Opscode
44
to the new [Supermarket](https://github.com/opscode/supermarket) community site. Chef Legacy is intended to be run from
55
within Supermarket but has been broken out into its own project as it has little use beyond the initial data migration.
66

7-
## How To Use
8-
9-
1. Clone Chef Legacy into Supermarket within the `lib/tasks` directory.
10-
1. Collect the necessary CSV files from the Opscode Community Site database and place them in `chef-legacy/data`.
11-
For the most part this is just a matter of dumping the pertinent tables to CSV. Ensure that they are escaped
12-
with `"` and not `\`. In order to associate cookbooks to categories you must also ensure that there is a
13-
`category_name` column in the `cookbooks.csv` that can be derived by joining the cookbooks and categories table.
14-
1. Run `bundle exec rake legacy:import`
7+
## Installation
8+
9+
In your Gemfile:
10+
11+
```ruby
12+
gem 'chef-legacy', github: 'gofullstack/chef-legacy'
13+
```
14+
15+
## Configuration
16+
17+
The data import connects to the old MySQL database. The default configuration should be suitable for an out-of-the-box MySQL server running locally, which has had an `opscode_community_site_production` database created, and filled with an SQL dump of the production database.
18+
19+
* `ENV['LEGACY_DB_HOST']` defaults to `localhost`
20+
* `ENV['LEGACY_DB_USERNAME']` defaults to `root`
21+
* `ENV['LEGACY_DB_DATABASE']` defaults to `opscode_community_site_production`
22+
23+
## Usage
24+
25+
`bundle exec rake chef_legacy:import`

chef-legacy.gemspec

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Gem::Specification.new do |s|
2+
s.name = "chef-legacy"
3+
s.homepage = "https://github.com/gofullstack/chef-legacy"
4+
s.version = "0.0.1"
5+
s.summary = "Legacy Opscode Community Data"
6+
s.description = "Rake tasks to import legacy Opscode Community Site data"
7+
s.authors = ["Tristan O'Neil", "Brian Cobb"]
8+
s.email = ["tristan@gofullstack.com", "brian@gofullstack.com"]
9+
s.files = Dir["lib/**/*"] + ["LICENSE", "README.md"]
10+
s.test_files = []
11+
s.require_paths = ["lib"]
12+
s.license = 'MIT'
13+
14+
s.add_runtime_dependency "mysql2"
15+
s.add_runtime_dependency "ruby-progressbar"
16+
end

data/.gitkeep

Whitespace-only changes.

import.rake

-108
This file was deleted.

lib/chef-legacy.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module ChefLegacy
2+
require 'chef-legacy/railtie'
3+
end

lib/chef-legacy/railtie.rb

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
require 'rails'
2+
3+
module ChefLegacy
4+
class Railtie < Rails::Railtie
5+
railtie_name :chef_data_import
6+
7+
rake_tasks do
8+
load "tasks/import.rake"
9+
end
10+
end
11+
end

lib/tasks/import.rake

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
require 'mysql2'
2+
require 'ruby-progressbar'
3+
4+
DB = Mysql2::Client.new(
5+
host: ENV['LEGACY_DB_HOST'] || 'localhost',
6+
username: ENV['LEGACY_DB_USERNAME'] || 'root',
7+
database: ENV['LEGACY_DB_DATABASE'] || 'opscode_community_site_production'
8+
)
9+
10+
namespace :chef_legacy do
11+
desc 'Import legacy community site data from CSV files.'
12+
task :import => :environment do
13+
progress_bar = ProgressBar.create(total: cookbooks.count)
14+
15+
import_cookbooks_with_versions_and_platforms(progress_bar)
16+
end
17+
end
18+
19+
#
20+
# Parses cookbooks.csv, cookbook_versions.csv and
21+
# platform_versions.csv Then the cookbooks and their dependencies
22+
# (Category and CookbookVersion) are associated/created. The cookbook
23+
# Category is found by using a column in each cookbook row named category_name
24+
# derived from joining the categories and cookbooks table from the original
25+
# legacy database. For each cookbook row the corresponding cookbook version
26+
# rows are found by selecting rows from cookbook_versions.csv
27+
# where the column cookbook_id matches the current cookbook row id.
28+
# Each instance of CookbookVersion is created with a hard coded
29+
# tarball_content_type of application/x-gzip because of inconsistencies
30+
# in the legacy database application/x-gzip is the desired content type
31+
# as all of the legacy tarballs are tgz files. For each CookbookVersion
32+
# the supported platforms are created and associated by finding the corresponding
33+
# platform version rows by matching the current cookbook version row id with the
34+
# platform version row id.
35+
#
36+
def import_cookbooks_with_versions_and_platforms(progress_bar)
37+
cookbooks.each do |row|
38+
progress_bar.increment
39+
40+
next if Cookbook.with_name(row['name']).first
41+
42+
category_name = categories.find do |category|
43+
category['id'] == row['category_id']
44+
end.fetch('name')
45+
46+
category = Category.with_name(category_name).first_or_initialize
47+
48+
if row['external_url'].to_s.strip.size > 0
49+
external_url = URI(row['external_url'])
50+
51+
unless external_url.is_a?(URI::HTTP) || external_url.is_a?(URI::HTTPS)
52+
external_url = URI('http://' + row['external_url'])
53+
end
54+
else
55+
external_url = nil
56+
end
57+
58+
cookbook = Cookbook.new(
59+
name: row['name'],
60+
maintainer: 'john@example.com',
61+
description: row['description'],
62+
category: category,
63+
source_url: external_url.to_s,
64+
download_count: row['download_count'],
65+
deprecated: row['deprecated'],
66+
)
67+
68+
build_cookbook_versions(row['id']).each do |cookbook_version|
69+
cookbook_version.cookbook = cookbook
70+
cookbook.cookbook_versions << cookbook_version
71+
end
72+
73+
cookbook.save!
74+
end
75+
end
76+
77+
def build_cookbook_versions(cookbook_id)
78+
cookbook_versions.
79+
select { |v| v['cookbook_id'] == cookbook_id }.
80+
map do |version|
81+
82+
CookbookVersion.new(
83+
version: version['version'],
84+
license: version['license'],
85+
tarball_file_name: version['tarball_file_name'],
86+
tarball_content_type: 'application/x-gzip',
87+
tarball_file_size: version['tarball_file_size'],
88+
tarball_updated_at: version['tarball_updated_at'],
89+
download_count: version['download_count'],
90+
).tap do |cookbook_version|
91+
build_supported_platforms(version['id']).each do |supported_platform|
92+
supported_platform.cookbook_version = cookbook_version
93+
cookbook_version.supported_platforms << supported_platform
94+
end
95+
end
96+
end
97+
end
98+
99+
def build_supported_platforms(cookbook_version_id)
100+
platform_versions.
101+
select { |p| p['cookbook_version_id'] == cookbook_version_id }.
102+
map do |platform|
103+
104+
version_constraint = platform['version'] || '>= 0.0.0'
105+
106+
if version_constraint != '>=0.0.0'
107+
numeric_part = version_constraint.split(' ').last
108+
109+
if numeric_part.size == 1
110+
version_constraint << '.0' # Corrects, e.g., '~> 5' to '~> 5.0'
111+
end
112+
else
113+
version_constraint = '>= 0.0.0'
114+
end
115+
116+
SupportedPlatform.new(
117+
name: platform['platform'],
118+
version_constraint: version_constraint
119+
)
120+
end
121+
end
122+
123+
def categories
124+
@categories ||= DB.query('select * from categories').to_a
125+
end
126+
127+
def cookbooks
128+
@cookbooks ||= DB.query('select * from cookbooks').to_a
129+
end
130+
131+
def cookbook_versions
132+
@cookbook_versions ||= DB.query('select * from cookbook_versions').to_a
133+
end
134+
135+
def platform_versions
136+
@platform_versions ||= DB.query('select * from platform_versions').to_a
137+
end
138+
139+
#
140+
# Parses a given CSV file found in the data directory.
141+
#
142+
def parse_csv(filename)
143+
CSV.parse(File.read(File.join(File.dirname(__FILE__), "data/#{filename}")), headers: true)
144+
end

0 commit comments

Comments
 (0)