source: trunk/base/portmgr/jobs/port_binary_distributable.tcl @ 80411

Last change on this file since 80411 was 80411, checked in by jmr@…, 6 years ago

update license conflicts

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 9.1 KB
Line 
1#!/usr/bin/tclsh
2# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4
3#
4# $Id: port_binary_distributable.tcl 80411 2011-07-12 13:07:49Z jmr@macports.org $
5#
6# Check that binaries of a port are distributable by looking at its license
7# and the licenses of its dependencies.
8#
9# Expected format: A {B C} means the license is A plus either B or C.
10#
11# Exit status:
12# 0: distributable
13# 1: non-distributable
14# 2: error
15
16
17set MY_VERSION 0.1
18
19array set portsSeen {}
20
21set check_deptypes {depends_build depends_lib}
22
23
24# Notes:
25# 'Restrictive/Distributable' means a non-free license that nonetheless allows
26# distributing binaries.
27# 'Restrictive' means a non-free license that does not allow distributing
28# binaries, and is thus not in the list.
29set good_licenses {agpl apache apsl artistic boost bsd cecill cpl curl
30                   fontconfig freebsd freetype gfdl gpl ibmpl ijg jasper
31                   lgpl libpng mit mpl openssl php psf qpl public-domain
32                   restrictive/distributable ruby sleepycat ssleay x11 zlib
33                   zpl}
34foreach lic $good_licenses {
35    set license_good($lic) 1
36}
37# keep these values sorted
38array set license_conflicts \
39    {agpl {cecill gpl-2 gpl-1 restrictive/distributable}
40    apache {cecill gpl}
41    apsl {cecill gpl}
42    cpl {cecill gpl}
43    cecill {agpl apache apsl cpl ibmpl mpl openssl php qpl restrictive/distributable ssleay zpl-1}
44    freetype {gpl-2}
45    gpl {agpl apache apsl cpl ibmpl mpl openssl php qpl restrictive/distributable ssleay zpl-1}
46    gpl-1 {gpl-3 gpl-3+ lgpl-3 lgpl-3+}
47    gpl-2 {freetype gpl-3 gpl-3+ lgpl-3 lgpl-3+}
48    gpl-3 {gpl-1 gpl-2}
49    gpl-3+ {gpl-1 gpl-2}
50    ibmpl {cecill gpl}
51    lgpl-3 {gpl-1 gpl-2}
52    lgpl-3+ {gpl-1 gpl-2}
53    mpl {cecill gpl}
54    openssl {cecill gpl}
55    php {cecill gpl}
56    qpl {cecill gpl}
57    restrictive/distributable {agpl cecill gpl}
58    ssleay {cecill gpl}
59    zpl-1 {cecill gpl}}
60
61proc printUsage {} {
62    puts "Usage: $::argv0 \[-hvV\] \[-t macports-tcl-path\] port-name \[variants...\]"
63    puts "  -h    This help"
64    puts "  -t    Give a different location for the base MacPorts Tcl"
65    puts "        file (defaults to /Library/Tcl)"
66    puts "  -v    verbose output"
67    puts "  -V    show version and MacPorts version being used"
68    puts ""
69    puts "port-name is the name of a port to check"
70    puts "variants is the list of variants to enable/disable: +one -two..."
71}
72
73
74# return deps and license for given port
75proc infoForPort {portName variantInfo} {
76    global check_deptypes
77    set dependencyList {}
78    set portSearchResult [mportlookup $portName]
79    if {[llength $portSearchResult] < 1} {
80        puts "Warning: port \"$portName\" not found"
81        return {}
82    }
83    array set portInfo [lindex $portSearchResult 1]
84    set mport [mportopen $portInfo(porturl) [list subport $portName] $variantInfo]
85    array unset portInfo
86    array set portInfo [mportinfo $mport]
87    mportclose $mport
88
89    foreach dependencyType $check_deptypes {
90        if {[info exists portInfo($dependencyType)] && [string length $portInfo($dependencyType)] > 0} {
91            foreach dependency $portInfo($dependencyType) {
92                set afterColon [expr {[string last ":" $dependency] + 1}]
93                lappend dependencyList [string range $dependency $afterColon end]
94            }
95        }
96    }
97
98    set ret [list $dependencyList $portInfo(license)]
99    if {[info exists portInfo(installs_libs)]} {
100        lappend ret $portInfo(installs_libs)
101    } else {
102        # when in doubt, assume code from the dep is incorporated
103        lappend ret yes
104    }
105    return $ret
106}
107
108# return license with any trailing dash followed by a number and/or plus sign removed
109proc remove_version {license} {
110    set dash [string last - $license]
111    if {$dash != -1 && [regexp {[0-9.+]+} [string range $license [expr $dash + 1] end]]} {
112        return [string range $license 0 [expr $dash - 1]]
113    } else {
114        return $license
115    }
116}
117
118proc check_licenses {portName variantInfo verbose} {
119    global license_good license_conflicts
120    array set portSeen {}
121    set top_info [infoForPort $portName $variantInfo]
122    set top_license [lindex $top_info 1]
123    set top_license_names {}
124    # check that top-level port's license(s) are good
125    foreach sublist $top_license {
126        # each element may be a list of alternatives (i.e. only one need apply)
127        set any_good 0
128        set sub_names {}
129        foreach full_lic $sublist {
130            # chop off any trailing version number
131            set lic [remove_version [string tolower $full_lic]]
132            # add name to the list for later
133            lappend sub_names $lic
134            if {[info exists license_good($lic)]} {
135                set any_good 1
136            }
137        }
138        lappend top_license_names $sub_names
139        if {!$any_good} {
140            if {$verbose} {
141                puts "'$portName' has license '$lic' which is not known to be distributable"
142            }
143            return 1
144        }
145    }
146
147    # start with deps of top-level port
148    set portList [lindex $top_info 0]
149    while {[llength $portList] > 0} {
150        set aPort [lindex $portList 0]
151        # mark as seen and remove from the list
152        set portSeen($aPort) 1
153        set portList [lreplace $portList 0 0]
154
155        set aPortInfo [infoForPort $aPort $variantInfo]
156        set aPortLicense [lindex $aPortInfo 1]
157        set installs_libs [lindex $aPortInfo 2]
158        if {!$installs_libs} {
159            continue
160        }
161        foreach sublist $aPortLicense {
162            set any_good 0
163            set any_compatible 0
164            # check that this dependency's license(s) are good
165            foreach full_lic $sublist {
166                set lic [remove_version [string tolower $full_lic]]
167                if {[info exists license_good($lic)]} {
168                    set any_good 1
169                } else {
170                    # no good being compatible with other licenses if it's not distributable itself
171                    continue
172                }
173
174                # ... and that they don't conflict with the top-level port's
175                set any_conflict 0
176                foreach top_sublist [concat $top_license $top_license_names] {
177                    set any_sub_compatible 0
178                    foreach top_lic $top_sublist {
179                        if {![info exists license_conflicts([string tolower $top_lic])]
180                            || ([lsearch -sorted $license_conflicts([string tolower $top_lic]) $lic] == -1
181                            && [lsearch -sorted $license_conflicts([string tolower $top_lic]) [string tolower $full_lic]] == -1)} {
182                            set any_sub_compatible 1
183                            break
184                        }
185                    }
186                    if {!$any_sub_compatible} {
187                        set any_conflict 1
188                        break
189                    }
190                }
191                if {!$any_conflict} {
192                    set any_compatible 1
193                    break
194                }
195            }
196
197            if {!$any_good} {
198                if {$verbose} {
199                    puts "dependency '$aPort' has license '$lic' which is not known to be distributable"
200                }
201                return 1
202            }
203            if {!$any_compatible} {
204                if {$verbose} {
205                    puts "dependency '$aPort' has license '$full_lic' which conflicts with license '$top_lic' from '$portName'"
206                }
207                return 1
208            }
209        }
210
211        # add its deps to the list
212        foreach possiblyNewPort [lindex $aPortInfo 0] {
213            if {![info exists portSeen($possiblyNewPort)]} {
214                lappend portList $possiblyNewPort
215            }
216        }
217    }
218
219    if {$verbose} {
220        puts "$portName is distributable"
221    }
222    return 0
223}
224
225
226# Begin
227
228set macportsTclPath /Library/Tcl
229set verbose 0
230set showVersion 0
231
232while {[string index [lindex $::argv 0] 0] == "-" } {
233    switch [string range [lindex $::argv 0] 1 end] {
234        h {
235            printUsage
236            exit 0
237        }
238        t {
239            if {[llength $::argv] < 2} {
240                puts "-t needs a path"
241                printUsage
242                exit 2
243            }
244            set macportsTclPath [lindex $::argv 1]
245            set ::argv [lrange $::argv 1 end]
246        }
247        v {
248             set verbose 1
249        }
250        V {
251            set showVersion 1
252        }
253        default {
254            puts "Unknown option [lindex $::argv 0]"
255            printUsage
256            exit 2
257        }
258    }
259    set ::argv [lrange $::argv 1 end]
260}
261
262source ${macportsTclPath}/macports1.0/macports_fastload.tcl
263package require macports
264mportinit
265
266if {$showVersion} {
267    puts "Version $MY_VERSION"
268    puts "MacPorts version [macports::version]"
269    exit 0
270}
271
272if {[llength $::argv] == 0} {
273    puts "Error: missing port-name"
274    printUsage
275    exit 2
276}
277set portName [lindex $::argv 0]
278set ::argv [lrange $::argv 1 end]
279
280array set variantInfo {}
281foreach variantSetting $::argv {
282    set flag [string index $variantSetting 0]
283    set variantName [string range $variantSetting 1 end]
284    set variantInfo($variantName) $flag
285}
286
287exit [check_licenses $portName [array get variantInfo] $verbose]
Note: See TracBrowser for help on using the repository browser.