#!/usr/bin/env ruby

# SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
# SPDX-FileCopyrightText: 2026 Harald Sitter <sitter@kde.org>

# https://wiki.archlinux.org/title/DeveloperWiki:NewMirrors

require 'fileutils'
require 'json'
require 'open-uri'
require 'time'
require 'tty/command'

STDOUT.sync = true
BTRFS = ENV.fetch('MIRROR_ON_BTRFS', '1') == '1'

@cmd = TTY::Command.new

def subvolume_create(name)
  if BTRFS
    @cmd.run('btrfs', 'subvolume', 'create', name)
  else
    FileUtils.mkdir(name)
  end
end

def subvolume_snapshot(source, target)
  if BTRFS
    @cmd.run('btrfs', 'subvolume', 'snapshot', source, target)
  else
    FileUtils.cp_r(source, target)
  end
end

subvolume_create('mirror') unless File.exist?('mirror')

# rsync -rlptH --safe-links --delete-delay --delay-updates
loop do
  out, _err = @cmd.run('rsync',
    '--recursive',
    '--links',
    '--perms',
    '--times',
    '--hard-links',
    '--safe-links',
    '--delete-delay',
    '--delay-updates',
    '--exclude', '*-unstable',
    '--exclude', '*-testing',
    '--exclude', '*-staging',
    '--exclude', 'iso',
    '--exclude', 'images',
    '--exclude', 'wsl',
    '--exclude', '.~tmp~',
    '--itemize-changes',
    'rsync://ftp.halifax.rwth-aachen.de/archlinux/',
    'mirror')
  lines = out.split("\n").collect do |line|
    line = line.strip
    next nil if line.empty? # skip
    next nil if line.end_with?(' lastsync') # skip marker file
    # >f..t...... lastsync\n
    next nil unless line.start_with?('>f') # skip non-file changes

    line
  end
  break if lines.compact.empty?

  # ...Otherwise repeat until there are no changes anymore. Serves as a poor mans check to ensure the repo is consistent.
  puts "Changes detected, repeating sync..."
  sleep 30
end

# TODO: can we perform some simple checks on the repo?

# Don't make the snapshot readonly. It'd prevent moving it!
new_snapshot = "snapshot-#{Time.now.utc.iso8601}"
subvolume_snapshot('mirror', new_snapshot)
File.write('latest.txt', new_snapshot)

# Keep the currently used repo. This prevents us from discarding the repo if the packages
# pipeline fails for a couple of days.
never_delete = ['snapshot-2026-07-19T00:02:21Z', 'snapshot-2026-07-15T03:13:16Z', 'snapshot-2026-06-22T03:21:01Z', 'snapshot-2026-04-26T03:43:07Z', 'snapshot-2026-06-28T00:16:33Z', 'snapshot-2026-06-28T00:16:33Z', 'snapshot-2026-06-24T09:32:04Z'] # this version is currently used by the base VM, pending a fix
URI.open('https://storage.kde.org/kde-linux-packages/testing/repo/build_repo.txt') do |f|
  build_repo = f.read.strip
  never_delete << build_repo.split('/').last
end

snapshots = Dir.glob('snapshot-*').select { |f| File.directory?(f) }
snapshots = snapshots.sort.reverse
to_keep = snapshots[..4] || raise # should always have at least one!
to_delete = snapshots[5..] || []
File.write('snapshots.json', JSON.pretty_generate(to_keep))

Dir.mkdir('trash') unless File.exist?('trash')
to_delete.each do |snapshot|
  next if never_delete.include?(snapshot)

  FileUtils.mv(snapshot, "trash/#{snapshot}")
end

