source: users/jberry/mpwa/app/controllers/ports_controller.rb @ 23696

Last change on this file since 23696 was 23696, checked in by jberry@…, 13 years ago

A bit of cleanup to once again sync up the mpwa submit with the design doc.

File size: 6.5 KB
Line 
1require "fileutils"
2
3class PortsController < ApplicationController
4 
5    def makeTempDir()
6        tmpdir = Dir::tmpdir
7        basename = "macports"
8        n = 1
9        begin
10            tmpname = File.join(tmpdir, sprintf('%s.%d.%d', basename, $$, n))
11            n += 1
12            next if File.exist?(tmpname)
13            begin
14                Dir.mkdir(tmpname)
15            rescue SystemCallError
16                next
17            end
18        end while !File.exist?(tmpname)
19        return tmpname
20    end
21
22    def subversionCommand(args)
23        puts "subversion: #{svn} #{args}"
24        `#{svn} #{args}`
25    end
26
27    def ensureRepositoryPath(root, path)
28        # Make sure the root director exists
29        assert { File.directory?(root) }
30       
31        # Step through path, building each component that doesn't exist
32        Pathname.new(path).descend do |p|
33            full = Pathname.new(root) + p
34            if !full.directory?
35                full.mkdir
36                subversionCommand("add #{full}")
37                subversionCommand("commit -m 'Make repository path segment' #{full}")
38             end
39        end
40    end
41   
42    def buildPortPkgDirPrefixPath(pkgId)
43        # Two Level Cache
44        # First level is low 6 bits of pkgId
45        # Second level is next 6 bits of pkgId
46 
47        lev1 = pkgId & 0x3f
48        lev2 = pkgId >> 6 & 0x3f
49        path = format('%02x/%02x', lev1, lev2)
50    end
51
52    def buildPortPkgDirPath(pkgId)
53        prefix = buildPortPkgDirPrefixPath(pkgId)
54        path = format('%s/%016x', prefix, pkgId)
55    end
56
57    def submit
58        # TODO:
59        # => Move some of this into the model
60        # => And/or break up into more methods
61       
62        # Get and validate parameters
63        @portName = params[:portname]
64        @portpkg = params[:portpkg]
65       
66        # Validate parameters (we're probably making this too hard)
67        raise "bad portName" if @portName.nil?
68        raise "bad package" if @portpkg.nil?
69       
70        tempDir = makeTempDir
71        portpkg = "#{tempDir}/portpkg.xar"
72        pkgdir = "#{tempDir}/portpkg"
73        common = "#{tempDir}/common"
74        target = "#{tempDir}/target"
75
76        # Form partial path to the common directory for the portname
77        firstChar = @portName[0,1].downcase
78        commonPartial = "common/#{firstChar}/#{@portName}"
79       
80        # Look for, and create if not found, the common directory for the port
81        ensureRepositoryPath(repo_portpkgs, commonPartial)
82       
83        # Unpack the submitted portdir into a temporary directory
84        File.open(portpkg, "w") { |f| f.write(@portpkg.read) }
85       
86        # Note: a bug in xar presently prevents us from limiting the extraction to the portpkg directory,
87        # => which we'd like to do for the sake of cleanliness. Hopefully this will become fixed soon.
88        system("cd #{tempDir}; #{xar} -xf #{portpkg}")
89       
90        # Check out a private temporary copy of the common directory
91        # so that we don't get into concurrency issues by multi-modifying the directory
92        subversionCommand("co #{repo_portpkgs_url}/#{commonPartial} #{common}")
93       
94        # Sync the submission into the common directory by parsing the results of mtree
95        changeCnt = 0
96        treeOut = `#{mtree} -c -k type,cksum -p #{pkgdir} | #{mtree} -p #{common}`
97        treeOut.each_line do |line|
98            puts "Line #{line}"
99           
100            case line
101            when /^\w+/
102                puts "Whitespace line #$1"
103               
104            when /^(.*) changed$/
105                srcFile = File.join(pkgdir, $1)
106                dstFile = File.join(common, $1)
107                puts "Changed file #{srcFile} != #{dstFile}"
108                FileUtils.cp(srcFile, dstFile)
109                changeCnt += 1
110               
111            when /^(.*) extra$/
112                dstFile = File.join(common, $1)
113                if /^\./ =~ File.basename(dstFile)
114                    puts "Skipping invisible extra entry #{dstFile}"
115                else
116                    puts "Extra entry #{dstFile}"
117                    subversionCommand("rm #{dstFile}")
118                    changeCnt += 1
119               end
120               
121            when /^(.*) missing$/
122                srcFile = File.join(pkgdir, $1)
123                dstFile = File.join(common, $1)
124
125                if /^\./ =~ File.basename(dstFile)
126                    puts "Skipping invisible new entry #{dstFile}"
127                else
128                    puts "New entry #{srcFile} ==> #{dstFile}"
129 
130                    if File.directory?(srcFile)
131                        subversionCommand("mkdir #{dstFile}")
132                    else
133                        FileUtils.cp(srcFile, dstFile)
134                        subversionCommand("add #{dstFile}")
135                    end
136                   
137                    changeCnt += 1
138                end
139
140            end
141        end
142       
143        if changeCnt == 0
144            puts "No changes detected, so don't create a new submission"
145        else
146            puts "Creating new submission from #{common}"
147
148            # Commit changes to the common directory
149            commitOutput = subversionCommand("commit -m 'New portpkg of #{@portName}' #{common}")
150            commitRevision = /^Committed revision (\d+)./.match(commitOutput)[1]
151           
152            # Form the portid from the committed revision number
153            pkgId = commitRevision.to_i
154            portPkgDirPrefix = buildPortPkgDirPrefixPath(pkgId)
155            portPkgDir = buildPortPkgDirPath(pkgId);
156           
157            puts "Creating new portpkg #{pkgId} at #{repo_portpkgs}/#{portPkgDir}"
158   
159            # Make sure there's a path to the repository location for the portPkg
160            ensureRepositoryPath(repo_portpkgs, portPkgDirPrefix)
161           
162            # Make the portPkg directory
163            FileUtils.mkdir("#{repo_portpkgs}/#{portPkgDir}")
164            subversionCommand("add #{repo_portpkgs}/#{portPkgDir}")
165     
166            # Add original package and meta directory
167            FileUtils.cp(portpkg, "#{repo_portpkgs}/#{portPkgDir}/portpkg.xar")
168            FileUtils.mkdir("#{repo_portpkgs}/#{portPkgDir}/meta")
169            subversionCommand("add #{repo_portpkgs}/#{portPkgDir}/portpkg.xar #{repo_portpkgs}/#{portPkgDir}/meta")
170   
171            # Copy the common directory into unpacked
172            subversionCommand("cp #{common} #{repo_portpkgs}/#{portPkgDir}/unpacked")
173   
174            # Commit the portpkg directory
175            subversionCommand("commit -m 'Complete portpkg #{pkgId} of port #{@portName}' #{repo_portpkgs}/#{portPkgDir}")
176        end
177    end
178 
179end
Note: See TracBrowser for help on using the repository browser.