openc3/tasks/gemfile_stats.rake
# encoding: ascii-8bit
# Copyright 2022 Ball Aerospace & Technologies Corp.
# All Rights Reserved.
#
# This program is free software; you can modify and/or redistribute it
# under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation; version 3 with
# attribution addendums as found in the LICENSE.txt
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# Modified by OpenC3, Inc.
# All changes Copyright 2022, OpenC3, Inc.
# All Rights Reserved
#
# This file may also be used under the terms of a commercial license
# if purchased from OpenC3, Inc.
desc 'Create a picture of gemfile downloads'
task :gemfile_stats do
require 'gems'
require 'win32ole'
def get_latest_gem_data
gem_data = []
# This is the only API call to Rubygems
versions = Gems.versions 'openc3'
versions.each do |version|
version_no = version['number']
next if version_no.split('.')[0] < '3' # anything before 3 is another gem
month = version['built_at'].split('-')[0..1].join('-')
downloads = version['downloads_count'].to_i
if gem_data.length > 0 && gem_data[-1][1] == version_no
gem_data[-1][2] += downloads
else
gem_data << [month, version_no, downloads]
end
end
gem_data
end
# This is useful for testing to prevent server round trips
# Simply comment out this line when working on the formatting below (after first running once)
File.open("gemdata.marshall", 'w') { |file| file.write(Marshal.dump(get_latest_gem_data())) }
gem_data = Marshal.load(File.read("gemdata.marshall"))
# Convert all the date text into Ruby Dates
gem_data.map! { |x| [Date.strptime(x[0], "%Y-%m"), x[1], x[2]] }
# Sort first by date and then version number
gem_data.sort_by! { |x| [x[0], x[1]] }
excel = WIN32OLE.new('excel.application')
excel.visible = true
book = excel.Workbooks.Add
sheet = book.Worksheets(1)
# Build up date labels
labels = {} # Must be hash with integer keys and label value
index = 0
start_date = gem_data[0][0]
end_date = gem_data[-1][0]
while start_date <= end_date
labels[index] = start_date.strftime("%m/%y")
index += 1
start_date = start_date >> 1
end
# Create an array of 0s the size of the labels which will hold the D/L counts
counts = Array.new(labels.length, 0)
dataset = {}
gem_data.each do |full_date, full_version, count|
# Build up just the major minor version: 1.0
version = full_version.split('.')[0..1].join('.')
date = full_date.strftime("%m/%y")
# Find the location in the count array to start adding counts
index = labels.key(date)
dataset[version] ||= counts.clone
# We fill in the count array starting at the first location
# and going until the end because this is a stacked area graph
# and all the counts are additive over time
(index...counts.length).each do |i|
dataset[version][i] += count
end
end
# Put dates in rows as there are more dates than there are releases
# Force the date column to be text
sheet.Columns(1).NumberFormat = "\@"
labels.values.each_with_index do |val, x|
sheet.Cells((x + 2), 1).Value = val
end
col = 2
dataset.each do |version, data|
# Set the version (e.g. 3.0) in the top row
sheet.Cells(1, col).Value = version
# The download values by date appear below the version in the same column
data.each_with_index do |val, x|
sheet.Cells((x + 2), col).Value = val
end
col += 1
end
# Excel column name lookup, 4 sets of alphabets gives us 104 versions to work with
letters = ('A'..'Z').to_a.concat(('AA'..'AZ').to_a).concat(('BA'..'BZ').to_a).concat(('CA'..'CZ').to_a)
chart = book.Charts.Add
chart.Name = "OpenC3 Downloads"
chart.SetSourceData(sheet.Range("A1:#{letters[dataset.length]}#{labels.length + 1}"))
chart.HasTitle = true
chart.ChartTitle.Characters.Text = "OpenC3 Downloads"
chart.ChartType = 76 # AreaStacked
end