[25803] users/jberry/mpwa

source_changes at macosforge.org source_changes at macosforge.org
Sat Jun 2 13:00:40 PDT 2007


Revision: 25803
          http://trac.macosforge.org/projects/macports/changeset/25803
Author:   jberry at macports.org
Date:     2007-06-02 13:00:40 -0700 (Sat, 02 Jun 2007)

Log Message:
-----------
mpwa: new changes to schema, of note:

 * files are now referenced by file_ref, which provides a new level
   of indirection and allows single instance, multiple reference storage
   of files, providing more compact storage, especially across minor
   changes to port submissions.
 * also allows file blobs to be linked into other objects besides
   port pkgs, in the future, which might allow, for instance, pictures
   to be connected to users.
   

Modified Paths:
--------------
    users/jberry/mpwa/app/models/file_blob.rb
    users/jberry/mpwa/app/models/port_pkg.rb
    users/jberry/mpwa/app/views/port_pkg/show.rhtml
    users/jberry/mpwa/doc/schema.sql
    users/jberry/mpwa/lib/mpwa-conf.rb

Added Paths:
-----------
    users/jberry/mpwa/app/controllers/file_info_controller.rb
    users/jberry/mpwa/app/controllers/file_ref_controller.rb
    users/jberry/mpwa/app/helpers/file_infos_helper.rb
    users/jberry/mpwa/app/helpers/file_refs_helper.rb
    users/jberry/mpwa/app/models/file_info.rb
    users/jberry/mpwa/app/models/file_ref.rb
    users/jberry/mpwa/app/views/file_info/
    users/jberry/mpwa/app/views/file_info/_form.rhtml
    users/jberry/mpwa/app/views/file_info/edit.rhtml
    users/jberry/mpwa/app/views/file_info/list.rhtml
    users/jberry/mpwa/app/views/file_info/new.rhtml
    users/jberry/mpwa/app/views/file_info/show.rhtml
    users/jberry/mpwa/app/views/file_ref/
    users/jberry/mpwa/app/views/file_ref/_form.rhtml
    users/jberry/mpwa/app/views/file_ref/edit.rhtml
    users/jberry/mpwa/app/views/file_ref/list.rhtml
    users/jberry/mpwa/app/views/file_ref/new.rhtml
    users/jberry/mpwa/app/views/file_ref/show.rhtml
    users/jberry/mpwa/test/fixtures/file_infos.yml
    users/jberry/mpwa/test/fixtures/file_refs.yml
    users/jberry/mpwa/test/functional/file_infos_controller_test.rb
    users/jberry/mpwa/test/functional/file_refs_controller_test.rb
    users/jberry/mpwa/test/unit/file_info_test.rb
    users/jberry/mpwa/test/unit/file_ref_test.rb

Added: users/jberry/mpwa/app/controllers/file_info_controller.rb
===================================================================
--- users/jberry/mpwa/app/controllers/file_info_controller.rb	                        (rev 0)
+++ users/jberry/mpwa/app/controllers/file_info_controller.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,54 @@
+class FileInfoController < ApplicationController
+  def index
+    list
+    render :action => 'list'
+  end
+
+  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
+  verify :method => :post, :only => [ :destroy, :create, :update ],
+         :redirect_to => { :action => :list }
+
+  def list
+    @file_info_pages, @file_infos = paginate :file_infos, :per_page => 10
+  end
+
+  def show
+    @file_info = FileInfo.find(params[:id])
+  end
+
+  def new
+    @file_info = FileInfo.new
+  end
+
+  def create
+    @file_info = FileInfo.new(params[:file_info])
+    if @file_info.save
+      flash[:notice] = 'FileInfo was successfully created.'
+      redirect_to :action => 'list'
+    else
+      render :action => 'new'
+    end
+  end
+
+  def edit
+    @file_info = FileInfo.find(params[:id])
+  end
+
+  def update
+    @file_info = FileInfo.find(params[:id])
+    if @file_info.update_attributes(params[:file_info])
+      flash[:notice] = 'FileInfo was successfully updated.'
+      redirect_to :action => 'show', :id => @file_info
+    else
+      render :action => 'edit'
+    end
+  end
+
+  def destroy
+    FileInfo.find(params[:id]).destroy
+    redirect_to :action => 'list'
+  end
+    
+  private :create, :edit, :update, :destroy
+
+end

Added: users/jberry/mpwa/app/controllers/file_ref_controller.rb
===================================================================
--- users/jberry/mpwa/app/controllers/file_ref_controller.rb	                        (rev 0)
+++ users/jberry/mpwa/app/controllers/file_ref_controller.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,66 @@
+class FileRefController < ApplicationController
+  def index
+    list
+    render :action => 'list'
+  end
+
+  # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
+  verify :method => :post, :only => [ :destroy, :create, :update ],
+         :redirect_to => { :action => :list }
+
+  def list
+    @file_ref_pages, @file_refs = paginate :file_refs, :per_page => 10
+  end
+
+  def show
+    @file_ref = FileRef.find(params[:id])
+  end
+
+  def new
+    @file_ref = FileRef.new
+  end
+
+  def create
+    @file_ref = FileRef.new(params[:file_ref])
+    if @file_ref.save
+      flash[:notice] = 'FileRef was successfully created.'
+      redirect_to :action => 'list'
+    else
+      render :action => 'new'
+    end
+  end
+
+  def edit
+    @file_ref = FileRef.find(params[:id])
+  end
+
+  def update
+    @file_ref = FileRef.find(params[:id])
+    if @file_ref.update_attributes(params[:file_ref])
+      flash[:notice] = 'FileRef was successfully updated.'
+      redirect_to :action => 'show', :id => @file_ref
+    else
+      render :action => 'edit'
+    end
+  end
+
+  def destroy
+    FileRef.find(params[:id]).destroy
+    redirect_to :action => 'list'
+  end
+  
+  def emit
+    ref = FileRef.find(params[:id])
+    send_data ref.file_info.data,
+      :filename => ref.file_info.file_path,
+      :type => ref.file_info.mime_type,
+      :disposition => 'inline'
+
+    # Bump download counts for the ref, and for the portpkg too if the file is a portpkg.
+    FileRef.increment_counter('download_count', ref)
+    PortPkg.increment_counter('download_count', ref.port_pkg) if ref.is_port_pkg
+  end
+  
+  private :create, :edit, :update, :destroy
+  
+end

Added: users/jberry/mpwa/app/helpers/file_infos_helper.rb
===================================================================
--- users/jberry/mpwa/app/helpers/file_infos_helper.rb	                        (rev 0)
+++ users/jberry/mpwa/app/helpers/file_infos_helper.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,2 @@
+module FileInfosHelper
+end

Added: users/jberry/mpwa/app/helpers/file_refs_helper.rb
===================================================================
--- users/jberry/mpwa/app/helpers/file_refs_helper.rb	                        (rev 0)
+++ users/jberry/mpwa/app/helpers/file_refs_helper.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,2 @@
+module FileRefsHelper
+end

Modified: users/jberry/mpwa/app/models/file_blob.rb
===================================================================
--- users/jberry/mpwa/app/models/file_blob.rb	2007-06-02 19:31:25 UTC (rev 25802)
+++ users/jberry/mpwa/app/models/file_blob.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -1,5 +1,7 @@
+require 'file_info'
+
 class FileBlob < ActiveRecord::Base
-    belongs_to :port_pkg_file
+    belongs_to :file_info
     
     def read(file)
         self.data = file.read

Added: users/jberry/mpwa/app/models/file_info.rb
===================================================================
--- users/jberry/mpwa/app/models/file_info.rb	                        (rev 0)
+++ users/jberry/mpwa/app/models/file_info.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,98 @@
+require 'stringio'
+
+require 'file_blob'
+require 'file_ref'
+require 'mpwa-conf'
+
+class FileInfoException < RuntimeError
+end
+
+class FileInfo < ActiveRecord::Base
+  has_many :file_refs
+  #has_many :file_blobs -- we don't use this association to avoid keeping many blobs in memory
+  before_destroy { |f| FileBlob.delete_all "file_info_id = #{f.id}" }
+  
+  def FileInfo.mimetype_from_path(path)
+      mimetype = /^([^;]+)(;\w*(.*))?/.match(`#{MPWA::FILETOOL} --mime --brief #{path}`)[1]
+  end
+
+  def read_from_path(path, path_root = nil, options = {})
+      mimetype = options[:mimetype] || FileInfo.mimetype_from_path(path)
+      reported_path = options[:filename] || path_root.nil? ?
+          path.to_s : Pathname.new(path).relative_path_from(path_root).to_s
+          
+      File.open(path, "r") { |f| read_from_file(f, :path => reported_path, :mimetype => mimetype) }
+      return self
+  end
+  
+  def read_from_file(file, options = {})
+      # Save file meta information
+      self.file_path = options[:path]
+      self.length = 0
+      self.mime_type = options[:mimetype] || 'application/octet-stream'
+      
+      # Save so that we get a primary id for the blob associations
+      self.save
+      
+      # Create digesters for our digests
+      md5 = Digest::MD5.new
+      sha256 = Digest::SHA256.new
+      
+      # Read the file, creating blobs of data as we go
+      buf = ''
+      length = 0
+      seq = 0
+      while (file.read(MPWA::MAX_BLOB_SIZE, buf))
+          # Update the digests
+          md5.update buf
+          sha256.update buf
+          
+          # Create a new bob
+          blob = FileBlob.create(:file_info => self, :data => buf, :sequence => seq)
+
+          length += buf.length
+          seq += 1
+      end
+      
+      # Finish up
+      self.md5 = md5.hexdigest
+      self.sha256 = sha256.hexdigest
+      self.length = length
+  
+      self.save
+      return self  
+  end
+  
+  def write_to_file(file)
+      # Create a digester so that we can verify the digest
+      digest = Digest::MD5.new
+
+      # Page in the blobs, writing to file as we go
+      length = 0
+      seq = 0
+      while (length < self.length)
+          blob = FileBlob.find(:first, :conditions => "file_info_id=#{self.id} and sequence=#{seq}")
+          raise FileInfoException, "file_info missing segment" if !blob
+          
+          buf = blob.data
+          digest.update buf
+          
+          file.write(buf)
+          length += buf.length
+          
+          seq += 1
+      end
+      
+      # Verify the digest
+      raise FileInfoException, "digest mismatch while reading file_info #{self.id}" if digest.hexdigest != self.md5
+  end
+  
+  def data()
+      StringIO.open("rw") do |f|
+          write_to_file(f)
+          f.string
+      end
+  end
+  
+  
+end

Added: users/jberry/mpwa/app/models/file_ref.rb
===================================================================
--- users/jberry/mpwa/app/models/file_ref.rb	                        (rev 0)
+++ users/jberry/mpwa/app/models/file_ref.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,39 @@
+require 'file_info'
+require 'port_pkg'
+
+class FileRef < ActiveRecord::Base
+  belongs_to :file_info
+  belongs_to :port_pkg
+  
+  def FileRef.create_from_path(path, path_root, options = {})
+    ref = FileRef.new()
+    
+    # Create a new FileInfo object from specfied path
+    new_info = FileInfo.new()
+    new_info.read_from_path(path, path_root, options)
+    
+    # If we already had a FileInfo matching the specifics
+    # (path and digests) then use that one, deleting the new
+    existing_info = FileInfo.find_by_md5_and_sha256_and_file_path(
+                      new_info.md5, new_info.sha256,
+                      new_info.file_path,
+                      :conditions => "id != #{new_info.id}")
+    if (existing_info)
+      ref.file_info = existing_info
+      FileInfo.destroy(new_info)
+    else
+      ref.file_info = new_info
+    end
+    
+    return ref
+  end
+  
+  def <=>(other)
+    if (self.file_info.file_path == other.file_info.file_path)
+      return self.id <=> other.id
+    else
+      return self.file_info.file_path <=> other.file_info.file_path
+    end
+  end
+  
+end

Modified: users/jberry/mpwa/app/models/port_pkg.rb
===================================================================
--- users/jberry/mpwa/app/models/port_pkg.rb	2007-06-02 19:31:25 UTC (rev 25802)
+++ users/jberry/mpwa/app/models/port_pkg.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -20,7 +20,8 @@
 class PortPkg < ActiveRecord::Base
     belongs_to :port
     belongs_to :submitter, :class_name => 'Person', :foreign_key => 'submitter_id'
-    has_many :files, :class_name => 'PortPkgFile', :dependent => :destroy
+    has_many :file_refs, :dependent => :destroy
+    has_many :file_infos, :through => :file_refs
     has_many :variants, :dependent => :destroy
     has_and_belongs_to_many :tags
     
@@ -110,11 +111,14 @@
         meta.categories.each { |c| self.add_tag(c) }
         
         # Save unpacked data into a file
-        self.files << PortPkgFile.from_path(self, pkgPath, tempDirPath, :mimetype => 'application/vnd.macports.portpkg')
+        portpkg_ref = FileRef.create_from_path(pkgPath, tempDirPath,
+                            :mimetype => 'application/vnd.macports.portpkg')
+        portpkg_ref.is_port_pkg = true
+        self.file_refs << portpkg_ref
         
         # Save files from the expanded package
         expandedPkgPath.find do |p|
-            self.files << PortPkgFile.from_path(self, p, tempDirPath) if p.file?
+            self.file_refs << FileRef.create_from_path(p, tempDirPath) if p.file?
         end
         
         # Save the pkg (maybe we shouldn't?)
@@ -132,10 +136,16 @@
         return candidates.first
     end
     
-    def portpkg_file()
-        file_by_path("portpkg.portpkg")
+    def portpkg_file_ref()
+        candidates = self.file_refs.select { |r| r.is_port_pkg }
+        return candidates.first
     end
     
+    def data_file_refs()
+        refs = self.file_refs.select { |r| !r.is_port_pkg }
+        return refs
+    end
+    
     def has_tag(name)
         !self.tags.select { |t| t.name == name }.empty?
     end

Added: users/jberry/mpwa/app/views/file_info/_form.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_info/_form.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_info/_form.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,19 @@
+<%= error_messages_for 'file_info' %>
+
+<!--[form:file_info]-->
+<p><label for="file_info_file_path">File path</label><br/>
+<%= text_field 'file_info', 'file_path'  %></p>
+
+<p><label for="file_info_length">Length</label><br/>
+<%= text_field 'file_info', 'length'  %></p>
+
+<p><label for="file_info_mime_type">Mime type</label><br/>
+<%= text_field 'file_info', 'mime_type'  %></p>
+
+<p><label for="file_info_md5">Md5</label><br/>
+<%= text_field 'file_info', 'md5'  %></p>
+
+<p><label for="file_info_sha256">Sha256</label><br/>
+<%= text_field 'file_info', 'sha256'  %></p>
+<!--[eoform:file_info]-->
+

Added: users/jberry/mpwa/app/views/file_info/edit.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_info/edit.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_info/edit.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,9 @@
+<h1>Editing file_info</h1>
+
+<% form_tag :action => 'update', :id => @file_info do %>
+  <%= render :partial => 'form' %>
+  <%= submit_tag 'Edit' %>
+<% end %>
+
+<%= link_to 'Show', :action => 'show', :id => @file_info %> |
+<%= link_to 'Back', :action => 'list' %>

Added: users/jberry/mpwa/app/views/file_info/list.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_info/list.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_info/list.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,23 @@
+<h1>Listing file_infos</h1>
+
+<table>
+  <tr>
+  <% for column in FileInfo.content_columns %>
+    <th><%= column.human_name %></th>
+  <% end %>
+  </tr>
+  
+<% for file_info in @file_infos %>
+  <tr>
+  <% for column in FileInfo.content_columns %>
+    <td><%=h file_info.send(column.name) %></td>
+  <% end %>
+    <td><%= link_to 'Show', :action => 'show', :id => file_info %></td>
+    <td><%= link_to 'Edit', :action => 'edit', :id => file_info %></td>
+    <td><%= link_to 'Destroy', { :action => 'destroy', :id => file_info }, :confirm => 'Are you sure?', :method => :post %></td>
+  </tr>
+<% end %>
+</table>
+
+<%= link_to 'Previous page', { :page => @file_info_pages.current.previous } if @file_info_pages.current.previous %>
+<%= link_to 'Next page', { :page => @file_info_pages.current.next } if @file_info_pages.current.next %> 

Added: users/jberry/mpwa/app/views/file_info/new.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_info/new.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_info/new.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,8 @@
+<h1>New file_info</h1>
+
+<% form_tag :action => 'create' do %>
+  <%= render :partial => 'form' %>
+  <%= submit_tag "Create" %>
+<% end %>
+
+<%= link_to 'Back', :action => 'list' %>

Added: users/jberry/mpwa/app/views/file_info/show.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_info/show.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_info/show.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,5 @@
+<% for column in FileInfo.content_columns %>
+<p>
+  <b><%= column.human_name %>:</b> <%=h @file_info.send(column.name) %>
+</p>
+<% end %>

Added: users/jberry/mpwa/app/views/file_ref/_form.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_ref/_form.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_ref/_form.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,7 @@
+<%= error_messages_for 'file_ref' %>
+
+<!--[form:file_ref]-->
+<p><label for="file_ref_is_port_pkg">Is port pkg</label><br/>
+<select id="file_ref_is_port_pkg" name="file_ref[is_port_pkg]"><option value="false">False</option><option value="true">True</option></select></p>
+<!--[eoform:file_ref]-->
+

Added: users/jberry/mpwa/app/views/file_ref/edit.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_ref/edit.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_ref/edit.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,9 @@
+<h1>Editing file_ref</h1>
+
+<% form_tag :action => 'update', :id => @file_ref do %>
+  <%= render :partial => 'form' %>
+  <%= submit_tag 'Edit' %>
+<% end %>
+
+<%= link_to 'Show', :action => 'show', :id => @file_ref %> |
+<%= link_to 'Back', :action => 'list' %>

Added: users/jberry/mpwa/app/views/file_ref/list.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_ref/list.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_ref/list.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,23 @@
+<h1>Listing file_refs</h1>
+
+<table>
+  <tr>
+  <% for column in FileRef.content_columns %>
+    <th><%= column.human_name %></th>
+  <% end %>
+  </tr>
+  
+<% for file_ref in @file_refs %>
+  <tr>
+  <% for column in FileRef.content_columns %>
+    <td><%=h file_ref.send(column.name) %></td>
+  <% end %>
+    <td><%= link_to 'Show', :action => 'show', :id => file_ref %></td>
+    <td><%= link_to 'Edit', :action => 'edit', :id => file_ref %></td>
+    <td><%= link_to 'Destroy', { :action => 'destroy', :id => file_ref }, :confirm => 'Are you sure?', :method => :post %></td>
+  </tr>
+<% end %>
+</table>
+
+<%= link_to 'Previous page', { :page => @file_ref_pages.current.previous } if @file_ref_pages.current.previous %>
+<%= link_to 'Next page', { :page => @file_ref_pages.current.next } if @file_ref_pages.current.next %> 

Added: users/jberry/mpwa/app/views/file_ref/new.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_ref/new.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_ref/new.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,8 @@
+<h1>New file_ref</h1>
+
+<% form_tag :action => 'create' do %>
+  <%= render :partial => 'form' %>
+  <%= submit_tag "Create" %>
+<% end %>
+
+<%= link_to 'Back', :action => 'list' %>

Added: users/jberry/mpwa/app/views/file_ref/show.rhtml
===================================================================
--- users/jberry/mpwa/app/views/file_ref/show.rhtml	                        (rev 0)
+++ users/jberry/mpwa/app/views/file_ref/show.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,5 @@
+<% for column in FileRef.content_columns %>
+<p>
+  <b><%= column.human_name %>:</b> <%=h @file_ref.send(column.name) %>
+</p>
+<% end %>

Modified: users/jberry/mpwa/app/views/port_pkg/show.rhtml
===================================================================
--- users/jberry/mpwa/app/views/port_pkg/show.rhtml	2007-06-02 19:31:25 UTC (rev 25802)
+++ users/jberry/mpwa/app/views/port_pkg/show.rhtml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -51,15 +51,17 @@
   <tr>
     <th>Path</th>
     <th>Length</th>
-    <th>mime-type</th>
+    <th>MIME-type</th>
     <th>Download</th>
+    <th>Download Count</th>
   </tr>
-	<% for file in @port_pkg.files %>
+	<% for ref in @port_pkg.file_refs %>
 		<tr>
-		<td><%= link_to file.file_path, :controller => 'port_pkg_file', :action => 'show', :id => file %></td>
-		<td><%=h file.length %></td>
-		<td><%=h file.mime_type %></td>
-		<td><%= link_to 'download', :controller => 'port_pkg_file', :action => 'emit', :id => file %></td>
+		<td><%= link_to ref.file_info.file_path, :controller => 'file_info', :action => 'show', :id => ref.file_info %></td>
+		<td><%=h ref.file_info.length %></td>
+		<td><%=h ref.file_info.mime_type %></td>
+		<td><%= link_to 'download', :controller => 'file_ref', :action => 'emit', :id => ref %></td>
+		<td><%= ref.download_count %></td>
 		</tr>
 	<% end %>
 </table>

Modified: users/jberry/mpwa/doc/schema.sql
===================================================================
--- users/jberry/mpwa/doc/schema.sql	2007-06-02 19:31:25 UTC (rev 25802)
+++ users/jberry/mpwa/doc/schema.sql	2007-06-02 20:00:40 UTC (rev 25803)
@@ -7,34 +7,41 @@
     user_name         varchar(63),
     first_name        varchar(63),
     last_name         varchar(63),
-    email             varchar(63)
+    email             varchar(63),
     
-    -- auth_method
-    -- auth_token
-    -- pub key
+    auth_method       varchar(31),
+    auth_token        varchar(255),
+    
+    public_key        text
 );
-    
+
+
 -- Ports represents a port: a piece of software
 drop table if exists ports;
 create table ports (
     id                bigint not null primary key auto_increment,
     
+    -- these fields are duplicated in port_pkgs
     name              varchar(63),
     short_desc        text,
     long_desc         text,
-    home_page         varchar(255)
+    home_page         varchar(255),
     
+    index name_index(name)
+    
     -- many-many association for tags through ports_tags
     -- many-many association for maintainers through ports_maintainers
 );
-    
+
+
 -- ports_maintainers: many-many association between Maintainers and Ports
 drop table if exists maintainers_ports;
 create table maintainers_ports (
     person_id         bigint not null,
     port_id           bigint not null
 );
-    
+
+
 -- A PortPkg is an instance of build/install rules for a port.
 -- There may be many PortPkg for each Port
 drop table if exists port_pkgs;
@@ -43,6 +50,11 @@
 
     port_id           bigint not null,
     
+    name              varchar(63),
+    short_desc        text,
+    long_desc         text,
+    home_page         varchar(255),
+    
     submitted_at      datetime not null,
     submitter_id      bigint not null, -- one-one: Person
     submitter_notes   text,
@@ -53,66 +65,87 @@
     
     votes_for         int not null default 0,
     votes_against     int not null default 0,
-    download_count    int not null default 0
-                                    
-    -- one-many association for variants
-    -- many-many association for tags through PkgTagAssoc
-    -- many-many association for dependencies through PkgDependencyAssoc
+    download_count    int not null default 0,
     
-    -- (note that both pkgs and variants, have dependency relations)
+    index submitted_at_index(submitted_at),
+    index submitter_index(submitter_id),
+    index port_index(port_id)
 );
-create index pkg_submit_date on port_pkgs(submitted_at);
-create index pkg_submitter on port_pkgs(submitter_id);
-create index pkg_port_id on port_pkgs(port_id);
 
 
-drop table if exists port_pkg_files;
-create table port_pkg_files (
+-- Reference to a file
+-- Currently only supports references from port_pkg, but could
+-- be extended to support references from people (pictures?), etc.
+drop table if exists file_refs;
+create table file_refs (
     id                  bigint not null primary key auto_increment,
-    port_pkg_id         bigint not null,
+    file_info_id        bigint not null,
+    port_pkg_id         bigint,     -- owned by port_pkg
+    is_port_pkg         tinyint(1) not null default 0,
+    download_count      int not null default 0,
+    
+    index file_index(file_info_id),
+    index port_pkg_index(port_pkg_id)
+);
+
+  
+-- FileInfo: main representation of a file, referenced
+-- by other tables through FileRef, with data stored
+-- in one or more FileBlob.
+drop table if exists file_infos;
+create table file_infos (
+    id                  bigint not null primary key auto_increment,
     file_path           varchar(2047),
     length              bigint not null,
     mime_type           varchar(63),
     md5                 varchar(32),
     sha256              varchar(64),
-    
-    download_count      int not null default 0
+
+    index info_index(file_path(64), md5, sha256)
 );
-create index portpkgfile_pkgid on port_pkg_files(port_pkg_id);
 
 
 drop table if exists file_blobs;
 create table file_blobs (
     id                  bigint not null primary key auto_increment,
-    port_pkg_file_id    bigint not null,
+    file_info_id        bigint not null,
     sequence            int not null,
-    data                blob
+    data                blob,
+    
+    index file_index(file_info_id, sequence)
 );
-create index fileblog_index on file_blobs(port_pkg_file_id, sequence);
 
 
 -- A tag which may be attached to various items through Ports_Tags, Port_Pkgs_Tags
 drop table if exists tags;
 create table tags (
     id                  bigint not null primary key auto_increment,
-    name                varchar(31)
+    name                varchar(31),
+    
+    index name_index(name)
 );
-create unique index tag_names on tags(name);
+
        
 -- many-many relationship between PortPkg and Tag
-drop table if exists Port_Pkgs_Tags;
-create table Port_Pkgs_Tags (
+drop table if exists port_pkgs_tags;
+create table port_pkgs_tags (
     port_pkg_id         bigint not null,
-    tag_id              bigint not null
+    tag_id              bigint not null,
+    
+    primary key (port_pkg_id, tag_id)
 );
 
+
 -- many-many relationship between Port and Tag
 drop table if exists ports_tags;
 create table ports_tags (
     port_id             bigint not null,
-    tag_id              bigint not null
+    tag_id              bigint not null,
+    
+    primary key (port_id, tag_id)
 );
 
+
 -- Variant available to a PortPkg
 drop table if exists variants;
 create table variants (
@@ -120,13 +153,14 @@
     port_pkg_id         bigint not null,
     
     name                varchar(63),
-    description         text
+    description         text,
     
-    -- many-many association for dependencies through Dependencies_Variants
+    index port_pkg_index(port_pkg_id)
     
     -- conflicts expr?
 );
 
+
 -- A dependency onto another port (not complete)
 drop table if exists dependencies;
 create table dependencies (
@@ -138,18 +172,23 @@
     -- maybe we have nullable fields for port, portpkg, porturl, version, revision, etc...
 );
 
+
 -- many-one relationship from Dependency to PortPkg
 drop table if exists dependencies_port_pkgs;
 create table dependencies_port_pkgs (
     package_id          bigint not null,
-    dependency_id       bigint not null
+    dependency_id       bigint not null,
+    
+    primary key (package_id, dependency_id)
 );
 
 -- many-one relationship from Variant to Dependency
 drop table if exists dependencies_variants;
 create table dependencies_variants (
     variant_id          bigint not null,
-    dependency_id       bigint not null
+    dependency_id       bigint not null,
+    
+    primary key (variant_id, dependency_id)
 );
 
 
@@ -167,7 +206,9 @@
 drop table if exists comments_ports;
 create table comments_ports (
     comment_id          bigint not null,
-    port_id             bigint not null
+    port_id             bigint not null,
+    
+    primary key (comment_id, port_id)
 );
 
 
@@ -175,7 +216,9 @@
 drop table if exists comments_port_pkgs;
 create table comments_port_pkgs (
     comment_id          bigint not null,
-    port_pkg_id         bigint not null
+    port_pkg_id         bigint not null,
+    
+    primary key (comment_id, port_pkg_id)
 );
 
 
@@ -195,7 +238,9 @@
 drop table if exists status_reports_port_pkgs;
 create table status_reports_port_pkgs (
     status_report_id    bigint not null,
-    port_pkg_id         bigint not null
+    port_pkg_id         bigint not null,
+    
+    primary key (status_report_id, port_pkg_id)
 );
 
 

Modified: users/jberry/mpwa/lib/mpwa-conf.rb
===================================================================
--- users/jberry/mpwa/lib/mpwa-conf.rb	2007-06-02 19:31:25 UTC (rev 25802)
+++ users/jberry/mpwa/lib/mpwa-conf.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -1,6 +1,6 @@
 class MPWA
 	FILETOOL = "/usr/bin/file"
-	XARTOOL = "/opt/local/bin/xar"
+	XARTOOL = "/usr/local/bin/xar"
 	PORTTOOL = "/opt/local/bin/port"
 	
 	MAX_BLOB_SIZE = 1024*64

Added: users/jberry/mpwa/test/fixtures/file_infos.yml
===================================================================
--- users/jberry/mpwa/test/fixtures/file_infos.yml	                        (rev 0)
+++ users/jberry/mpwa/test/fixtures/file_infos.yml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,5 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+  id: 1
+two:
+  id: 2

Added: users/jberry/mpwa/test/fixtures/file_refs.yml
===================================================================
--- users/jberry/mpwa/test/fixtures/file_refs.yml	                        (rev 0)
+++ users/jberry/mpwa/test/fixtures/file_refs.yml	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,5 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+one:
+  id: 1
+two:
+  id: 2

Added: users/jberry/mpwa/test/functional/file_infos_controller_test.rb
===================================================================
--- users/jberry/mpwa/test/functional/file_infos_controller_test.rb	                        (rev 0)
+++ users/jberry/mpwa/test/functional/file_infos_controller_test.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,92 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'file_infos_controller'
+
+# Re-raise errors caught by the controller.
+class FileInfosController; def rescue_action(e) raise e end; end
+
+class FileInfosControllerTest < Test::Unit::TestCase
+  fixtures :file_infos
+
+  def setup
+    @controller = FileInfosController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+
+    @first_id = file_infos(:first).id
+  end
+
+  def test_index
+    get :index
+    assert_response :success
+    assert_template 'list'
+  end
+
+  def test_list
+    get :list
+
+    assert_response :success
+    assert_template 'list'
+
+    assert_not_nil assigns(:file_infos)
+  end
+
+  def test_show
+    get :show, :id => @first_id
+
+    assert_response :success
+    assert_template 'show'
+
+    assert_not_nil assigns(:file_info)
+    assert assigns(:file_info).valid?
+  end
+
+  def test_new
+    get :new
+
+    assert_response :success
+    assert_template 'new'
+
+    assert_not_nil assigns(:file_info)
+  end
+
+  def test_create
+    num_file_infos = FileInfo.count
+
+    post :create, :file_info => {}
+
+    assert_response :redirect
+    assert_redirected_to :action => 'list'
+
+    assert_equal num_file_infos + 1, FileInfo.count
+  end
+
+  def test_edit
+    get :edit, :id => @first_id
+
+    assert_response :success
+    assert_template 'edit'
+
+    assert_not_nil assigns(:file_info)
+    assert assigns(:file_info).valid?
+  end
+
+  def test_update
+    post :update, :id => @first_id
+    assert_response :redirect
+    assert_redirected_to :action => 'show', :id => @first_id
+  end
+
+  def test_destroy
+    assert_nothing_raised {
+      FileInfo.find(@first_id)
+    }
+
+    post :destroy, :id => @first_id
+    assert_response :redirect
+    assert_redirected_to :action => 'list'
+
+    assert_raise(ActiveRecord::RecordNotFound) {
+      FileInfo.find(@first_id)
+    }
+  end
+end

Added: users/jberry/mpwa/test/functional/file_refs_controller_test.rb
===================================================================
--- users/jberry/mpwa/test/functional/file_refs_controller_test.rb	                        (rev 0)
+++ users/jberry/mpwa/test/functional/file_refs_controller_test.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,92 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'file_refs_controller'
+
+# Re-raise errors caught by the controller.
+class FileRefsController; def rescue_action(e) raise e end; end
+
+class FileRefsControllerTest < Test::Unit::TestCase
+  fixtures :file_refs
+
+  def setup
+    @controller = FileRefsController.new
+    @request    = ActionController::TestRequest.new
+    @response   = ActionController::TestResponse.new
+
+    @first_id = file_refs(:first).id
+  end
+
+  def test_index
+    get :index
+    assert_response :success
+    assert_template 'list'
+  end
+
+  def test_list
+    get :list
+
+    assert_response :success
+    assert_template 'list'
+
+    assert_not_nil assigns(:file_refs)
+  end
+
+  def test_show
+    get :show, :id => @first_id
+
+    assert_response :success
+    assert_template 'show'
+
+    assert_not_nil assigns(:file_ref)
+    assert assigns(:file_ref).valid?
+  end
+
+  def test_new
+    get :new
+
+    assert_response :success
+    assert_template 'new'
+
+    assert_not_nil assigns(:file_ref)
+  end
+
+  def test_create
+    num_file_refs = FileRef.count
+
+    post :create, :file_ref => {}
+
+    assert_response :redirect
+    assert_redirected_to :action => 'list'
+
+    assert_equal num_file_refs + 1, FileRef.count
+  end
+
+  def test_edit
+    get :edit, :id => @first_id
+
+    assert_response :success
+    assert_template 'edit'
+
+    assert_not_nil assigns(:file_ref)
+    assert assigns(:file_ref).valid?
+  end
+
+  def test_update
+    post :update, :id => @first_id
+    assert_response :redirect
+    assert_redirected_to :action => 'show', :id => @first_id
+  end
+
+  def test_destroy
+    assert_nothing_raised {
+      FileRef.find(@first_id)
+    }
+
+    post :destroy, :id => @first_id
+    assert_response :redirect
+    assert_redirected_to :action => 'list'
+
+    assert_raise(ActiveRecord::RecordNotFound) {
+      FileRef.find(@first_id)
+    }
+  end
+end

Added: users/jberry/mpwa/test/unit/file_info_test.rb
===================================================================
--- users/jberry/mpwa/test/unit/file_info_test.rb	                        (rev 0)
+++ users/jberry/mpwa/test/unit/file_info_test.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,10 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class FileInfoTest < Test::Unit::TestCase
+  fixtures :file_infos
+
+  # Replace this with your real tests.
+  def test_truth
+    assert true
+  end
+end

Added: users/jberry/mpwa/test/unit/file_ref_test.rb
===================================================================
--- users/jberry/mpwa/test/unit/file_ref_test.rb	                        (rev 0)
+++ users/jberry/mpwa/test/unit/file_ref_test.rb	2007-06-02 20:00:40 UTC (rev 25803)
@@ -0,0 +1,10 @@
+require File.dirname(__FILE__) + '/../test_helper'
+
+class FileRefTest < Test::Unit::TestCase
+  fixtures :file_refs
+
+  # Replace this with your real tests.
+  def test_truth
+    assert true
+  end
+end

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macports-changes/attachments/20070602/9f40bc56/attachment.html


More information about the macports-changes mailing list