Only redump the files when something has actually changed
[dbsrgits/DBIx-Class-Schema-Loader.git] / lib / DBIx / Class / Schema / Loader / Base.pm
index 35ccc20..fab01f5 100644 (file)
@@ -2,10 +2,9 @@ package DBIx::Class::Schema::Loader::Base;
 
 use strict;
 use warnings;
-use base qw/Class::Accessor::Fast/;
+use base qw/Class::Accessor::Fast Class::C3::Componentised/;
 use Class::C3;
 use Carp::Clan qw/^DBIx::Class/;
-use UNIVERSAL::require;
 use DBIx::Class::Schema::Loader::RelBuilder;
 use Data::Dump qw/ dump /;
 use POSIX qw//;
@@ -17,7 +16,7 @@ use File::Temp qw//;
 use Class::Unload;
 require DBIx::Class;
 
-our $VERSION = '0.04999_06';
+our $VERSION = '0.04999_08';
 
 __PACKAGE__->mk_ro_accessors(qw/
                                 schema
@@ -266,13 +265,15 @@ sub new {
             if $self->{dump_overwrite};
 
     $self->{dynamic} = ! $self->{dump_directory};
-    $self->{dump_directory} ||= File::Temp::tempdir( 'dbicXXXX',
+    $self->{temp_directory} ||= File::Temp::tempdir( 'dbicXXXX',
                                                      TMPDIR  => 1,
                                                      CLEANUP => 1,
                                                    );
 
+    $self->{dump_directory} ||= $self->{temp_directory};
+
     $self->{relbuilder} = DBIx::Class::Schema::Loader::RelBuilder->new(
-        $self->schema_class, $self->inflect_plural, $self->inflect_singular
+        $self->schema, $self->inflect_plural, $self->inflect_singular
     ) if !$self->{skip_relationships};
 
     $self;
@@ -361,6 +362,7 @@ sub rescan {
     my ($self, $schema) = @_;
 
     $self->{schema} = $schema;
+    $self->{relbuilder}{schema} = $schema;
 
     my @created;
     my @current = $self->_tables_list;
@@ -398,9 +400,13 @@ sub _load_tables {
     if(!$self->skip_relationships) {
         # The relationship loader needs a working schema
         $self->{quiet} = 1;
+        local $self->{dump_directory} = $self->{temp_directory};
         $self->_reload_classes(@tables);
         $self->_load_relationships($_) for @tables;
         $self->{quiet} = 0;
+
+        # Remove that temp dir from INC so it doesn't get reloaded
+        @INC = grep { $_ ne $self->{dump_directory} } @INC;
     }
 
     $self->_load_external($_)
@@ -421,6 +427,10 @@ sub _reload_classes {
 
     unshift @INC, $self->dump_directory;
     
+    my @to_register;
+    my %have_source = map { $_ => $self->schema->source($_) }
+        $self->schema->sources;
+
     for my $table (@tables) {
         my $moniker = $self->monikers->{$table};
         my $class = $self->classes->{$table};
@@ -430,17 +440,25 @@ sub _reload_classes {
             local *Class::C3::reinitialize = sub {};
             use warnings;
 
-            if ( Class::Unload->unload( $class ) ) {
-                my $resultset_class = ref $self->schema->resultset($moniker);
-                Class::Unload->unload( $resultset_class )
-                      if $resultset_class ne 'DBIx::Class::ResultSet';
+            Class::Unload->unload($class);
+            my ($source, $resultset_class);
+            if (
+                ($source = $have_source{$moniker})
+                && ($resultset_class = $source->resultset_class)
+                && ($resultset_class ne 'DBIx::Class::ResultSet')
+            ) {
+                my $has_file = Class::Inspector->loaded_filename($resultset_class);
+                Class::Unload->unload($resultset_class);
+                $self->ensure_class_loaded($resultset_class) if $has_file;
             }
-            $class->require or die "Can't load $class: $@";
+            $self->ensure_class_loaded($class);
         }
+        push @to_register, [$moniker, $class];
+    }
 
-        $self->schema_class->register_class($moniker, $class);
-        $self->schema->register_class($moniker, $class)
-            if $self->schema ne $self->schema_class;
+    Class::C3->reinitialize;
+    for (@to_register) {
+        $self->schema->register_class(@$_);
     }
 }
 
@@ -517,6 +535,14 @@ sub _dump_to_dir {
 
 }
 
+sub _sig_comment {
+    my ($self, $version, $ts) = @_;
+    return qq|\n\n# Created by DBIx::Class::Schema::Loader|
+         . qq| v| . $version
+         . q| @ | . $ts 
+         . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
+}
+
 sub _write_classfile {
     my ($self, $class, $text) = @_;
 
@@ -529,13 +555,27 @@ sub _write_classfile {
         unlink($filename);
     }    
 
+    my ($custom_content, $old_md5, $old_ver, $old_ts) = $self->_get_custom_content($class, $filename);
+
     $text .= qq|$_\n|
         for @{$self->{_dump_storage}->{$class} || []};
 
-    $text .= qq|\n\n# Created by DBIx::Class::Schema::Loader|
-        . qq| v| . $DBIx::Class::Schema::Loader::VERSION
-        . q| @ | . POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
-        . qq|\n# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:|;
+    # Check and see if the dump is infact differnt
+
+    my $compare_to;
+    if ($old_md5) {
+      $compare_to = $text . $self->_sig_comment($old_ver, $old_ts);
+      
+
+      if (Digest::MD5::md5_base64($compare_to) eq $old_md5) {
+        return;
+      }
+    }
+
+    $text .= $self->_sig_comment(
+      $DBIx::Class::Schema::Loader::VERSION, 
+      POSIX::strftime('%Y-%m-%d %H:%M:%S', localtime)
+    );
 
     open(my $fh, '>', $filename)
         or croak "Cannot open '$filename' for writing: $!";
@@ -548,36 +588,42 @@ sub _write_classfile {
         for @{$self->{_ext_storage}->{$class} || []};
 
     # Write out any custom content the user has added
-    my $custom_content = $self->_get_custom_content($class, $filename);
-
-    $custom_content ||= qq|\n\n# You can replace this text with custom|
-        . qq| content, and it will be preserved on regeneration|
-        . qq|\n1;\n|;
-
     print $fh $custom_content;
 
     close($fh)
         or croak "Error closing '$filename': $!";
 }
 
+sub _default_custom_content {
+    return qq|\n\n# You can replace this text with custom|
+         . qq| content, and it will be preserved on regeneration|
+         . qq|\n1;\n|;
+}
+
 sub _get_custom_content {
     my ($self, $class, $filename) = @_;
 
-    return if ! -f $filename;
+    return ($self->_default_custom_content) if ! -f $filename;
+
     open(my $fh, '<', $filename)
         or croak "Cannot open '$filename' for reading: $!";
 
     my $mark_re = 
         qr{^(# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:)([A-Za-z0-9/+]{22})\n};
 
-    my $found = 0;
     my $buffer = '';
+    my ($md5, $ts, $ver);
     while(<$fh>) {
-        if(!$found && /$mark_re/) {
-            $found = 1;
-            $buffer .= $1;
+        if(!$md5 && /$mark_re/) {
+            $md5 = $2;
+            my $line = $1;
+
+            # Pull out the previous version and timestamp
+            ($ver, $ts) = $buffer =~ m/# Created by DBIx::Class::Schema::Loader v(.*?) @ (.*?)$/s;
+
+            $buffer .= $line;
             croak "Checksum mismatch in '$filename'"
-                if Digest::MD5::md5_base64($buffer) ne $2;
+                if Digest::MD5::md5_base64($buffer) ne $md5;
 
             $buffer = '';
         }
@@ -588,9 +634,12 @@ sub _get_custom_content {
 
     croak "Cannot not overwrite '$filename' without 'really_erase_my_files',"
         . " it does not appear to have been generated by Loader"
-            if !$found;
+            if !$md5;
 
-    return $buffer;
+    # Default custom content:
+    $buffer ||= $self->_default_custom_content;
+
+    return ($buffer, $md5, $ver, $ts);
 }
 
 sub _use {
@@ -661,7 +710,14 @@ sub _setup_src_meta {
     my $table_class = $self->classes->{$table};
     my $table_moniker = $self->monikers->{$table};
 
-    $self->_dbic_stmt($table_class,'table',$table);
+    my $table_name = $table;
+    my $name_sep   = $self->schema->storage->sql_maker->name_sep;
+
+    if ($name_sep && $table_name =~ /\Q$name_sep\E/) {
+        $table_name = \ $self->_quote_table_name($table_name);
+    }
+
+    $self->_dbic_stmt($table_class,'table',$table_name);
 
     my $cols = $self->_table_columns($table);
     my $col_info;
@@ -670,17 +726,26 @@ sub _setup_src_meta {
         $self->_dbic_stmt($table_class,'add_columns',@$cols);
     }
     else {
-        my %col_info_lc = map { lc($_), $col_info->{$_} } keys %$col_info;
+        if ($self->_is_case_sensitive) {
+            for my $col (keys %$col_info) {
+                $col_info->{$col}{accessor} = lc $col
+                    if $col ne lc($col);
+            }
+        } else {
+            $col_info = { map { lc($_), $col_info->{$_} } keys %$col_info };
+        }
+
         my $fks = $self->_table_fk_info($table);
+
         for my $fkdef (@$fks) {
             for my $col (@{ $fkdef->{local_columns} }) {
-                $col_info_lc{$col}->{is_foreign_key} = 1;
+                $col_info->{$col}{is_foreign_key} = 1;
             }
         }
         $self->_dbic_stmt(
             $table_class,
             'add_columns',
-            map { $_, ($col_info_lc{$_}||{}) } @$cols
+            map { $_, ($col_info->{$_}||{}) } @$cols
         );
     }
 
@@ -714,6 +779,13 @@ sub tables {
 }
 
 # Make a moniker from a table
+sub _default_table2moniker {
+    my ($self, $table) = @_;
+
+    return join '', map ucfirst, split /[\W_]+/,
+        Lingua::EN::Inflect::Number::to_S(lc $table);
+}
+
 sub _table2moniker {
     my ( $self, $table ) = @_;
 
@@ -726,8 +798,7 @@ sub _table2moniker {
         $moniker = $self->moniker_map->($table);
     }
 
-    $moniker ||= join '', map ucfirst, split /[\W_]+/,
-        Lingua::EN::Inflect::Number::to_S(lc $table);
+    $moniker ||= $self->_default_table2moniker($table);
 
     return $moniker;
 }
@@ -798,6 +869,22 @@ sub _ext_stmt {
     push(@{$self->{_ext_storage}->{$class}}, $stmt);
 }
 
+sub _quote_table_name {
+    my ($self, $table) = @_;
+
+    my $qt = $self->schema->storage->sql_maker->quote_char;
+
+    return $table unless $qt;
+
+    if (ref $qt) {
+        return $qt->[0] . $table . $qt->[1];
+    }
+
+    return $qt . $table . $qt;
+}
+
+sub _is_case_sensitive { 0 }
+
 =head2 monikers
 
 Returns a hashref of loaded table to moniker mappings.  There will