File indexing completed on 2024-10-13 13:02:02

0001 require 'json'
0002 require 'tmpdir'
0003 require 'yaml'
0004 
0005 class Source
0006   attr_reader :upstream_name
0007   attr_reader :upstream_version
0008 
0009   def initialize(upstream_name)
0010     @upstream_name = upstream_name
0011   end
0012 
0013   def all_qml_depends
0014     @all_qml_depends ||= controls.collect do |control|
0015       control.binaries.collect do |binary|
0016         next nil unless runtime_binaries.include?(binary['package'])
0017         deps = binary.fetch('depends', []) + binary.fetch('recommends', [])
0018         deps.collect do |dep|
0019           dep = [dep[0]] if dep.size > 1
0020           next nil unless dep[0].name.start_with?('qml-module')
0021           dep = dep.each { |y| y.architectures = nil; y.version = nil; y.operator = nil }
0022           # puts "---> #{dep} ---> #{dep[0].substvar?}"
0023           dep = dep.reject(&:substvar?)
0024           dep.collect(&:to_s)
0025         end.compact
0026       end.flatten
0027     end.flatten
0028   end
0029 
0030   def dev_binaries
0031     dev_only(all_packages)
0032   end
0033 
0034   def runtime_binaries
0035     runtime_only(all_packages)
0036   end
0037 
0038   def all_build_depends
0039     @all_build_depends ||= controls.collect do |control|
0040       bdeps = control.source.fetch('build-depends', []) +
0041               control.source.fetch('build-depends-indep', [])
0042       bdeps.collect do |x|
0043         # TODO: this makes a bunch of assumptions as we have no proper
0044         #   resolver for dependencies. in alternates the first always wins
0045         #   architecture restrictions are entirely ignored
0046         x = [x[0]] if x.size > 1
0047         x = x.each { |y| y.architectures = nil; y.version = nil; y.operator = nil }
0048         x.collect(&:to_s)
0049       end.compact
0050     end.flatten
0051   end
0052 
0053   private
0054 
0055   def read_upstream_version(dir)
0056     version = `dpkg-parsechangelog -S version -l #{dir}/debian/changelog`.strip
0057     unless $?.success?
0058       warn 'Got error during dpkg-parsechangelog!'
0059       warn version
0060       return nil
0061     end
0062     version = version.split(':', 2)[-1] # ditch epoch
0063     version.split('-', 2)[0] # ditch rev
0064   end
0065 
0066   def parse_control(src)
0067     system("apt-get --download-only source #{src}") || raise
0068     FileUtils.mkpath('source/')
0069     files = 'debian/control debian/changelog'
0070     system("tar -xvf *debian.tar.* -C source #{files}") || raise
0071     @upstream_version = read_upstream_version('source')
0072     require_relative 'debian/control'
0073     control = Debian::Control.new('source')
0074     control.parse!
0075     control
0076   end
0077 
0078   def controls
0079     @controls ||= sources.collect do |src|
0080       Dir.mktmpdir do |tmpdir|
0081         Dir.chdir(tmpdir) do
0082           parse_control(src)
0083         end
0084       end
0085     end
0086   end
0087 
0088 
0089   def all_packages
0090     @all_packages ||= controls.collect do |control|
0091       control.binaries.collect { |x| x.fetch('package') }
0092     end.flatten
0093   end
0094 
0095   def dev_only(packages)
0096     packages.select do |pkg|
0097       pkg.include?('-dev') && !(pkg == 'qt5-qmake-arm-linux-gnueabihf')
0098     end
0099   end
0100 
0101   def runtime_only(packages)
0102     packages.delete_if do |pkg|
0103       pkg.include?('-dev') || pkg.include?('-doc') || pkg.include?('-dbg') ||
0104         pkg.include?('-examples') || pkg == 'qt5-qmake-arm-linux-gnueabihf'
0105     end
0106   end
0107 
0108   MAP = {
0109     'qt5' => %w(qtbase-opensource-src
0110                 qtscript-opensource-src
0111                 qtdeclarative-opensource-src
0112                 qttools-opensource-src
0113                 qtsvg-opensource-src
0114                 qtx11extras-opensource-src),
0115     'kwallet' => %w(kwallet-kf5),
0116     'kdnssd' => [],
0117     'baloo' => %w(baloo-kf5),
0118     'kdoctools' => %w(kdoctools5),
0119     'kfilemetadata' => %w(kfilemetadata-kf5),
0120     'attica' => %w(attica-kf5),
0121     'kactivities' => %w(kactivities-kf5)
0122   }.freeze
0123 
0124   def sources
0125     MAP.fetch(@upstream_name, [@upstream_name])
0126   end
0127 end
0128 
0129 class SnapcraftConfig
0130   module AttrRecorder
0131     def attr_accessor(*args)
0132       record_readable(*args)
0133       super
0134     end
0135 
0136     def attr_reader(*args)
0137       record_readable(*args)
0138       super
0139     end
0140 
0141     def record_readable(*args)
0142       @readable_attrs ||= []
0143       @readable_attrs += args
0144     end
0145 
0146     def readable_attrs
0147       @readable_attrs
0148     end
0149   end
0150 
0151   module YamlAttributer
0152     def encode_with(c)
0153       c.tag = nil # Unset the tag to prevent clutter
0154       self.class.readable_attrs.each do |readable_attrs|
0155         next unless data = method(readable_attrs).call
0156         c[readable_attrs.to_s.tr('_', '-')] = data
0157       end
0158       super(c) if defined?(super)
0159     end
0160   end
0161 
0162   class Part
0163     extend AttrRecorder
0164     prepend YamlAttributer
0165 
0166     # Array<String>
0167     attr_accessor :after
0168     # String
0169     attr_accessor :plugin
0170     # Array<String>
0171     attr_accessor :build_packages
0172     # Array<String>
0173     attr_accessor :stage_packages
0174     # Hash
0175     attr_accessor :filesets
0176     # Array<String>
0177     attr_accessor :snap
0178     # Array<String>
0179     attr_accessor :stage
0180     # Hash<String, String>
0181     attr_accessor :organize
0182 
0183     attr_writer :source
0184     attr_writer :configflags
0185 
0186     def initialize
0187       @after = []
0188       @plugin = 'nil'
0189       @build_packages = []
0190       @stage_packages = []
0191       @filesets = {
0192         'exclusion' => %w(
0193           -usr/lib/*/cmake/*
0194           -usr/lib/*/qt5/bin/moc
0195           -usr/lib/*/qt5/bin/qmake
0196           -usr/lib/*/qt5/bin/rcc
0197           -usr/lib/*/qt5/bin/*cpp*
0198           -usr/lib/qt5/bin/assistant
0199           -usr/lib/qt5/bin/designer
0200           -usr/lib/qt5/bin/lconvert
0201           -usr/lib/qt5/bin/linguist
0202           -usr/lib/qt5/bin/lupdate
0203           -usr/lib/qt5/bin/lrelease
0204           -usr/lib/qt5/bin/moc
0205           -usr/lib/qt5/bin/pixeltool
0206           -usr/lib/qt5/bin/qcollectiongenerator
0207           -usr/lib/qt5/bin/qdbuscpp2xml
0208           -usr/lib/qt5/bin/qdbusxml2cpp
0209           -usr/lib/qt5/bin/qdoc
0210           -usr/lib/qt5/bin/qhelpconverter
0211           -usr/lib/qt5/bin/qlalr
0212           -usr/lib/qt5/bin/qmake
0213           -usr/lib/qt5/bin/rcc
0214           -usr/lib/qt5/bin/syncqt.pl
0215           -usr/lib/vlc/plugins/gui/libqt4_plugin.so
0216           -usr/include/*
0217           -usr/share/ECM/*
0218           -usr/share/xml/docbook/*
0219           -usr/share/doc/*
0220           -usr/share/locale/*/LC_MESSAGES/vlc.mo
0221           -usr/share/man/*
0222           -usr/share/icons/breeze/*.rcc
0223           -usr/share/icons/breeze-dark/*.rcc
0224           -usr/share/wallpapers/*
0225           -usr/share/fonts/*
0226           -usr/share/pkgconfig
0227           -usr/lib/*/pkgconfig
0228           -usr/share/QtCurve
0229           -usr/share/kde4
0230           -usr/share/bug
0231           -usr/share/debhelper
0232           -usr/share/lintian
0233           -usr/share/menu
0234           -usr/bin/*vlc
0235           -usr/bin/dh_*
0236           -usr/lib/*/*.a
0237           -usr/lib/*/*.pri
0238         )
0239       }
0240       @stage = %w[
0241         -usr/share/doc/*
0242         -usr/share/man/*
0243         -usr/share/icons/breeze/*.rcc
0244         -usr/share/wallpapers/*
0245         -usr/share/fonts/*
0246       ]
0247       @snap = %w($exclusion)
0248       # @organize = {
0249       #   'etc/*' => 'slash/etc/',
0250       #   'usr/*' => 'slash/usr/'
0251       # }
0252     end
0253 
0254     def encode_with(c)
0255       if @plugin != 'nil'
0256         c['configflags'] = @configflags
0257         c['source'] = @source
0258       end
0259       super if defined?(super)
0260     end
0261   end
0262 
0263   class Slot
0264     extend AttrRecorder
0265     prepend YamlAttributer
0266 
0267     attr_accessor :content
0268     attr_accessor :interface
0269     attr_accessor :read
0270   end
0271 
0272   extend AttrRecorder
0273   prepend YamlAttributer
0274 
0275   attr_accessor :name
0276   attr_accessor :version
0277   attr_accessor :summary
0278   attr_accessor :description
0279   attr_accessor :confinement
0280   attr_accessor :grade
0281   attr_accessor :slots
0282   attr_accessor :parts
0283 
0284   def initialize
0285     @parts = {}
0286     @slots = {}
0287   end
0288 end
0289 
0290 config = SnapcraftConfig.new
0291 config.name = 'kde-frameworks-5'
0292 config.version = 'unknown'
0293 config.summary = 'KDE Frameworks 5'
0294 config.description = 'KDE Frameworks are addons and useful extensions to Qt'
0295 config.confinement = 'strict'
0296 config.grade = 'stable'
0297 
0298 slot = SnapcraftConfig::Slot.new
0299 slot.content = 'kde-frameworks-5-all'
0300 slot.interface = 'content'
0301 slot.read = %w[.]
0302 config.slots['kde-frameworks-5-slot'] = slot
0303 
0304 # These are only old versions! The new version is created later after we know
0305 # the current versions of the content.
0306 content_versions = JSON.parse(File.read('versions.json')).uniq
0307 content_versions.each do |content_version|
0308   slot = SnapcraftConfig::Slot.new
0309   slot.content = content_version
0310   slot.interface = 'content'
0311   slot.read = %w[.]
0312   config.slots[content_version] = slot
0313 end
0314 
0315 # This list is generated by resolving and sorting the dep tree from
0316 # kde-build-metadata. Commented out bits we don't presently want to build.
0317 parts = %w(extra-cmake-modules kcoreaddons) + # kdesupport/polkit-qt-1
0318         %w(kauth kconfig kwidgetsaddons kcompletion
0319            kwindowsystem kcrash karchive ki18n kfilemetadata
0320            kjobwidgets kpty kunitconversion kcodecs) + # kdesupport/phonon/phonon
0321         %w(knotifications kpackage kguiaddons kconfigwidgets kitemviews
0322            kiconthemes attica kdbusaddons kservice kglobalaccel sonnet
0323            ktextwidgets breeze-icons kxmlgui kbookmarks solid kwallet kio
0324            kdeclarative kcmutils kplotting kparts kdewebkit
0325            kemoticons knewstuff kinit knotifyconfig kded
0326            kdesu ktexteditor kactivities kactivities-stats
0327            kdnssd kidletime kitemmodels threadweaver
0328            plasma-framework kxmlrpcclient kpeople frameworkintegration
0329            kdoctools
0330            kdesignerplugin
0331            krunner kwayland baloo)
0332            # plasma-integration) # extra integration pulls in breeze pulls in kde4/qt4
0333 parts += %w(qtwebkit qtbase qtdeclarative qtgraphicaleffects qtlocation
0334 qtmultimedia qtquickcontrols qtquickcontrols2 qtscript qtsensors qtserialport
0335 qtsvg qttools qttranslations qtvirtualkeyboard qtwayland qtwebchannel
0336 qtwebengine qtwebsockets qtx11extras qtxmlpatterns).collect { |x| x += '-opensource-src' }
0337 #
0338 # oxygen-icons5 only one icon set
0339 # Not Runtime Relevant! FIXME: need to seperate these out to only end up in -dev but not content!
0340 #   extra-cmake-modules
0341 #   kdesignerplugin
0342 #   kdoctools
0343 # No Porting Aids!
0344 #   kdelibs4support
0345 #   khtml
0346 #   kjs
0347 #   kjsembed
0348 #   kmediaplayer
0349 #   kross
0350 
0351 # padding
0352 parts = [nil] + parts
0353 # parts += [nil]
0354 
0355 devs = []
0356 # mesa-utils-extra - es2_info useful to debug GL problems.
0357 runs = %w[mesa-utils-extra]
0358 # GStreamer plugins
0359 runs += %w[gstreamer1.0-fluendo-mp3 gstreamer1.0-x gstreamer1.0-plugins-base
0360            gstreamer1.0-pulseaudio gstreamer1.0-plugins-good]
0361 # For on-demand locale generation we need the raw data to generate locales from.
0362 runs += %w[locales libc-bin]
0363 
0364 kf5_version = nil
0365 qt5_version = nil
0366 
0367 parts.each_cons(2) do |first_name, second_name|
0368   # puts "#{second_name} AFTER #{first_name}"
0369   next unless second_name # first item is nil
0370   source = Source.new(second_name)
0371   devs += source.dev_binaries
0372   runs += source.runtime_binaries
0373   if source.upstream_name == 'extra-cmake-modules' && config.version
0374     kf5_version = source.upstream_version
0375     config.version = source.upstream_version
0376   end
0377   if source.upstream_name == 'qtbase-opensource-src'
0378     qt5_version = source.upstream_version
0379   end
0380 end
0381 
0382 # Construct a new interface name with up to date versions.
0383 # This is the only way we can version a content snap.
0384 kf5_version = 'kde-frameworks-' + kf5_version.split('.')[0..1].join('-')
0385 qt5_version = 'qt-' + qt5_version.split('.')[0..1].join('-')
0386 platform_version = 'ubuntu-1604'
0387 
0388 latest_version = [kf5_version, qt5_version, platform_version].join('-')
0389 # Dump the latest interface. The application builds will pick this up and
0390 # set it as their content provider, this way we should be able to prevent
0391 # Qt version mismatches.
0392 File.write('content.json',
0393            JSON.generate(latest_version))
0394 unless config.slots.include?(latest_version)
0395   slot = SnapcraftConfig::Slot.new
0396   slot.content = latest_version
0397   slot.interface = 'content'
0398   slot.read = %w[.]
0399   config.slots[latest_version] = slot
0400 
0401   content_versions << latest_version
0402   File.write('versions.json', JSON.generate(content_versions.uniq))
0403 end
0404 
0405 # Do not pull in the GTK stack.
0406 runs.delete('qt5-gtk-platformtheme')
0407 devs.delete('qt5-gtk-platformtheme')
0408 
0409 part = SnapcraftConfig::Part.new
0410 part.stage_packages = runs.flatten
0411 config.parts['kf5'] = part
0412 
0413 dev = SnapcraftConfig::Part.new
0414 dev.stage_packages = devs.flatten
0415 dev.stage = (dev.stage + %w[
0416   -usr/share/emoticons
0417   -usr/share/icons/*
0418   -usr/share/locale/*/LC_*/*
0419   -usr/share/qt5/translations/*
0420   -usr/lib/*/dri/*
0421 ]).uniq
0422 dev.snap = ['-*']
0423 dev.after = %w(kf5)
0424 config.parts['kf5-dev'] = dev
0425 
0426 breeze = SnapcraftConfig::Part.new
0427 breeze.after = %w(kf5-dev)
0428 breeze.build_packages = %w(
0429   pkg-config
0430   libx11-dev
0431   extra-cmake-modules
0432   qtbase5-dev
0433   libkf5config-dev
0434   libkf5configwidgets-dev
0435   libkf5windowsystem-dev
0436   libkf5i18n-dev
0437   libkf5coreaddons-dev
0438   libkf5guiaddons-dev
0439   libqt5x11extras5-dev
0440   libkf5style-dev
0441   libkf5kcmutils-dev
0442   kwayland-dev
0443   libkf5package-dev
0444 )
0445 breeze.configflags = %w(
0446   -DKDE_INSTALL_USE_QT_SYS_PATHS=ON
0447   -DCMAKE_INSTALL_PREFIX=/usr
0448   -DCMAKE_BUILD_TYPE=Release
0449   -DENABLE_TESTING=OFF
0450   -DBUILD_TESTING=OFF
0451   -DKDE_SKIP_TEST_SETTINGS=ON
0452   -DWITH_DECORATIONS=OFF
0453 )
0454 breeze.plugin = 'cmake'
0455 breeze.source = 'http://download.kde.org/stable/plasma/5.10.5/breeze-5.10.5.tar.xz'
0456 config.parts['breeze'] = breeze
0457 
0458 integration = SnapcraftConfig::Part.new
0459 integration.after = %w(kf5-dev breeze)
0460 integration.build_packages = %w(
0461                extra-cmake-modules
0462                kio-dev
0463                kwayland-dev
0464                libkf5config-dev
0465                libkf5configwidgets-dev
0466                libkf5i18n-dev
0467                libkf5iconthemes-dev
0468                libkf5notifications-dev
0469                libkf5widgetsaddons-dev
0470                libqt5x11extras5-dev
0471                libxcursor-dev
0472                qtbase5-dev
0473                qtbase5-private-dev
0474 )
0475 integration.configflags = %w(
0476   -DKDE_INSTALL_USE_QT_SYS_PATHS=ON
0477   -DCMAKE_INSTALL_PREFIX=/usr
0478   -DCMAKE_BUILD_TYPE=Release
0479   -DENABLE_TESTING=OFF
0480   -DBUILD_TESTING=OFF
0481   -DKDE_SKIP_TEST_SETTINGS=ON
0482 )
0483 integration.plugin = 'cmake'
0484 integration.source = 'http://download.kde.org/stable/plasma/5.10.5/plasma-integration-5.10.5.tar.xz'
0485 config.parts['plasma-integration'] = integration
0486 
0487 puts File.write('snapcraft.yaml', YAML.dump(config, indentation: 4))
0488 puts File.write('stage-content.json', JSON.generate(runs))
0489 puts File.write('stage-dev.json', JSON.generate(runs + devs))