github.com/aleksanderaleksic/tgmigrate@v0.1.7/migration/migration_reverter.go (about)

     1  package migration
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/aleksanderaleksic/tgmigrate/common"
     6  	"github.com/aleksanderaleksic/tgmigrate/config"
     7  	"github.com/aleksanderaleksic/tgmigrate/history"
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/service/s3"
    10  	"os"
    11  	"sort"
    12  )
    13  
    14  type Reverter struct {
    15  	Context          *common.Context
    16  	Config           *config.Config
    17  	S3StateClient    *s3.S3
    18  	HistoryInterface history.History
    19  }
    20  
    21  func (r Reverter) RevertToIncluding(migrationName string) error {
    22  	hist, err := r.HistoryInterface.InitializeHistory()
    23  	if err != nil {
    24  		return err
    25  	}
    26  
    27  	migration := getMigrationWithName(hist.AppliedMigration, migrationName)
    28  	if migration == nil {
    29  		return fmt.Errorf("could not find a applied migration with the name: %s", migrationName)
    30  	}
    31  
    32  	migrationsToRevert := migrationsToRevert(hist.AppliedMigration, *migration)
    33  
    34  	defer r.HistoryInterface.WriteToStorage()
    35  
    36  	for _, migration := range migrationsToRevert {
    37  		err := r.revert(migration)
    38  		if err != nil {
    39  			return err
    40  		}
    41  		r.HistoryInterface.RemoveAppliedMigration(migration.Name)
    42  	}
    43  
    44  	return nil
    45  }
    46  
    47  func getMigrationWithName(slice []history.AppliedStorageHistoryObject, migrationName string) *history.AppliedStorageHistoryObject {
    48  	for _, migration := range slice {
    49  		if migration.Name == migrationName {
    50  			return &migration
    51  		}
    52  	}
    53  	return nil
    54  }
    55  
    56  func migrationsToRevert(all []history.AppliedStorageHistoryObject, inclusive history.AppliedStorageHistoryObject) []history.AppliedStorageHistoryObject {
    57  	migrationsToRevert := []history.AppliedStorageHistoryObject{inclusive}
    58  
    59  	for _, migration := range all {
    60  		if migration.Applied.Time().After(inclusive.Applied.Time()) {
    61  			migrationsToRevert = append(migrationsToRevert, migration)
    62  		}
    63  	}
    64  
    65  	sort.Slice(migrationsToRevert, func(i, j int) bool {
    66  		return migrationsToRevert[i].Applied.Time().After(migrationsToRevert[j].Applied.Time())
    67  	})
    68  
    69  	return migrationsToRevert
    70  }
    71  
    72  func (r Reverter) revert(migration history.AppliedStorageHistoryObject) error {
    73  	s3Config := r.Config.State.Config.(*config.S3StateConfig)
    74  
    75  	fmt.Printf("The following object version will be deleted:\n")
    76  	objectIdentifiersToDelete := make([]*s3.ObjectIdentifier, 0)
    77  	for _, obj := range migration.Metadata.S3Metadata.ChangedObjects {
    78  		objectIdentifiersToDelete = append(objectIdentifiersToDelete, &s3.ObjectIdentifier{
    79  			Key:       aws.String(obj.Key),
    80  			VersionId: aws.String(obj.ToVersionId),
    81  		})
    82  		fmt.Printf("\t- key: %s, version: %s\n", obj.Key, obj.ToVersionId)
    83  	}
    84  	fmt.Printf("Are you sure you would like to continue?\n")
    85  	if !common.AskUserToConfirm() {
    86  		fmt.Printf("Cancelled by user, will not delete objects.\n")
    87  		os.Exit(0)
    88  	}
    89  
    90  	_, err := r.S3StateClient.DeleteObjects(&s3.DeleteObjectsInput{
    91  		Bucket: aws.String(s3Config.Bucket),
    92  		Delete: &s3.Delete{
    93  			Objects: objectIdentifiersToDelete,
    94  			Quiet:   aws.Bool(false),
    95  		},
    96  	})
    97  	if err != nil {
    98  		return err
    99  	}
   100  	fmt.Printf("Successfully deleted object versions\n")
   101  
   102  	return nil
   103  }