Class: Aidp::Database::StorageMigrator

Inherits:
Object
  • Object
show all
Defined in:
lib/aidp/database/storage_migrator.rb

Overview

Migrates file-based storage to SQLite database

Handles migration of all .aidp directory files to the new SQLite storage. Supports dry-run mode, backup creation, and rollback.

Usage:

migrator = StorageMigrator.new(project_dir: Dir.pwd)
migrator.migrate!

Defined Under Namespace

Classes: MigrationError

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_dir: Dir.pwd, dry_run: false) ⇒ StorageMigrator

Returns a new instance of StorageMigrator.



25
26
27
28
29
30
# File 'lib/aidp/database/storage_migrator.rb', line 25

def initialize(project_dir: Dir.pwd, dry_run: false)
  @project_dir = project_dir
  @dry_run = dry_run
  @stats = Hash.new(0)
  @errors = []
end

Instance Attribute Details

#errorsObject (readonly)

Returns the value of attribute errors.



23
24
25
# File 'lib/aidp/database/storage_migrator.rb', line 23

def errors
  @errors
end

#project_dirObject (readonly)

Returns the value of attribute project_dir.



23
24
25
# File 'lib/aidp/database/storage_migrator.rb', line 23

def project_dir
  @project_dir
end

#statsObject (readonly)

Returns the value of attribute stats.



23
24
25
# File 'lib/aidp/database/storage_migrator.rb', line 23

def stats
  @stats
end

Instance Method Details

#already_migrated?Boolean

Check if database already has data

Returns:

  • (Boolean)

    True if database has migrated data



42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/aidp/database/storage_migrator.rb', line 42

def already_migrated?
  return false unless File.exist?(ConfigPaths.database_file(project_dir))

  Database::Migrations.run!(project_dir)
  # Check if any tables have data
  db = Database.connection(project_dir)
  tables = %w[checkpoints tasks progress harness_state workstreams watch_state]
  tables.any? do |table|
    count = db.get_first_value("SELECT COUNT(*) FROM #{table}")
    count.to_i > 0
  end
rescue
  false
end

#cleanup_old_storage!(keep_config: true) ⇒ Object

Clean up old file-based storage after successful migration

Parameters:

  • keep_config (Boolean) (defaults to: true)

    Keep aidp.yml config file



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/aidp/database/storage_migrator.rb', line 119

def cleanup_old_storage!(keep_config: true)
  return if @dry_run

  Aidp.log_info("storage_migrator", "cleaning_up_old_storage")

  files_to_remove = migrated_files
  files_to_remove << ConfigPaths.config_file(project_dir) unless keep_config

  files_to_remove.each do |file|
    next unless File.exist?(file)

    FileUtils.rm_rf(file)
    @stats[:files_removed] += 1
  end

  # Remove empty directories
  cleanup_empty_directories
end

#create_backupString

Create backup of .aidp directory

Returns:

  • (String)

    Backup directory path



105
106
107
108
109
110
111
112
113
114
# File 'lib/aidp/database/storage_migrator.rb', line 105

def create_backup
  timestamp = Time.now.strftime("%Y%m%d_%H%M%S")
  backup_dir = File.join(project_dir, ".aidp_backup_#{timestamp}")

  Aidp.log_info("storage_migrator", "creating_backup", backup_dir: backup_dir)

  FileUtils.cp_r(ConfigPaths.aidp_dir(project_dir), backup_dir)
  @stats[:backup_created] = 1
  backup_dir
end

#migrate!(backup: true) ⇒ Hash

Run the migration

Parameters:

  • backup (Boolean) (defaults to: true)

    Create backup before migration

Returns:

  • (Hash)

    Migration results



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/aidp/database/storage_migrator.rb', line 61

def migrate!(backup: true)
  Aidp.log_info("storage_migrator", "starting_migration",
    project_dir: project_dir, dry_run: @dry_run)

  unless migration_needed?
    Aidp.log_info("storage_migrator", "no_migration_needed")
    return {status: :skipped, reason: "No file-based storage found"}
  end

  create_backup if backup && !@dry_run
  Database::Migrations.run!(project_dir) unless @dry_run

  migrate_checkpoints
  migrate_tasks
  migrate_progress
  migrate_harness_state
  migrate_workstreams
  migrate_watch_state
  migrate_worktrees
  migrate_evaluations
  migrate_provider_info
  migrate_model_cache
  migrate_deprecated_models
  migrate_secrets
  migrate_prompt_archive
  migrate_jobs
  migrate_provider_metrics

  result = {
    status: @errors.empty? ? :success : :partial,
    stats: @stats.dup,
    errors: @errors.dup,
    dry_run: @dry_run
  }

  Aidp.log_info("storage_migrator", "migration_complete",
    status: result[:status], stats: @stats)

  result
end

#migration_needed?Boolean

Check if migration is needed

Returns:

  • (Boolean)

    True if file-based storage exists



35
36
37
# File 'lib/aidp/database/storage_migrator.rb', line 35

def migration_needed?
  file_storage_exists?
end