2024-11-24 - 03:50

Dates and Events:

OSADL Articles:

2024-10-02 12:00

Linux is now an RTOS!

PREEMPT_RT is mainline - What's next?


2023-11-12 12:00

Open Source License Obligations Checklists even better now

Import the checklists to other tools, create context diffs and merged lists


2023-03-01 12:00

Embedded Linux distributions

Results of the online "wish list"


2022-01-13 12:00

Phase #3 of OSADL project on OPC UA PubSub over TSN successfully completed

Another important milestone on the way to interoperable Open Source real-time Ethernet has been reached


2021-02-09 12:00

Open Source OPC UA PubSub over TSN project phase #3 launched

Letter of Intent with call for participation is now available



Open Source License Checklists - Access to license compliance raw data - Example code

1. PHP script to populate an interactive compatibility checker using sequentially indexed JSON array

Without explanations - With explanations

Widget in action
     

Code to generate the above widget (to be placed on Web server)
 
<?php
/* SPDX-License-Identifier: CC0-1.0 */
/* Copyright (c) 2022 Open Source Automation Development Lab (OSADL) eG <info@osadl.org>, author Carsten Emde */
 
$json = file_get_contents('http://www.osadl.org/fileadmin/checklists/matrixseqexpl.json');
 
echo '
<!DOCTYPE html>
<html>
 
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>OSADL Compatibility Matrix of FOSS Licenses</title>
</head>
 
<body>
<select id="selectleadinglicense" style="display: inline;" onchange="showcompatibility();">
<option selected="selected">Choose a leading license</option>
</select>
&nbsp;&nbsp;
<select id="selectsubordinatelicense" style="display: inline;" onchange="showcompatibility();">
<option selected="selected">Choose a subordinate license</option>
</select>
&nbsp;&nbsp;
<span id="result"></span>
<span id="help"></span>
 
<script type="text/javascript" language="javascript">
 
var jsobject;
 
var selectleading = document.getElementById("selectleadinglicense");
var selectsubordinate = document.getElementById("selectsubordinatelicense");
 
function showcompatibility()
{
  var result = document.getElementById("result");
  var help = document.getElementById("help");
  var compatibility;
 
  if (selectleading.selectedIndex == 0 || selectsubordinate.selectedIndex == 0) {
    result.innerHTML = "";
    help.innerHTML = "";
    return;
  }
  compatibility = jsobject.licenses[selectleading.selectedIndex-1].compatibilities[selectsubordinate.selectedIndex-1].compatibility;
  explanation = jsobject.licenses[selectleading.selectedIndex-1].compatibilities[selectsubordinate.selectedIndex-1].explanation;
  result.style.fontWeight = "bold";
  if (compatibility == "Yes")
    result.style.color = "green";
  else if (compatibility == "No")
    result.style.color = "red";
  else if (compatibility == "Check dependency")
    result.style.color = "rgb(172, 172, 0)";
  else {
    result.style.color = "black";
    result.style.fontWeight = "normal";
  }
  if (compatibility == "Same") {
    result.innerHTML = "";
    help.innerHTML = "";
  } else {
    result.innerHTML = "<b>Compatibility:</b> " + compatibility;
    help.innerHTML = "<br /><br /><b>Reference:</b><br />" + explanation;
  }
}
 
var json = `' . $json . '`;
jsobject = JSON.parse(json);
for (i = 0; i < jsobject.licenses.length; i++) {
  var license = jsobject.licenses[i].name;
  var eleleading = document.createElement("option");
  var elesubordinate = document.createElement("option");
 
  eleleading.textContent = elesubordinate.textContent = license;
  selectleading.appendChild(eleleading);
  selectsubordinate.appendChild(elesubordinate);
}
</script>
</body>
</html>';
 
?>

 

2. Same as above, but maintaining a local copy of the data file and using static HTML code for "client-only" operation

(Please note that with this approach, it is the user's responsibility to ensure that the local copy of the data file is up to date.)

Web page in action

Code to generate the above Web page (to be loaded into browser)
 
<!--
SPDX-License-Identifier: CC0-1.0
Copyright (c) 2022 Open Source Automation Development Lab (OSADL) eG <info@osadl.org>, author Carsten Emde
Copyright (c) 2022 Pilz GmbH & Co. KG, author Thorsten Godau <t.godau@pilz.de>
"Client-only" version based on:
https://www.osadl.org/Example-code-for-license-compliance-raw.procedural-raw-compliance-import.0.html
The OSADL license compatibility matrix is licensed under the Creative Commons Attribution 4.0 International license (CC-BY-4.0), https://creativecommons.org/licenses/by/4.0/.
-->
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>OSADL Compatibility Matrix of FOSS Licenses ("Client-only" version)</title>
  </head>
  <body>
    <p>
    Instructions:
    <ul>
      <li>Download the <a href="https://www.osadl.org/fileadmin/checklists/matrixseqexpl.json">OSADL license compatibility matrix with explanations</a> JSON file (by right click and "Save link as...").</li>
      <li>Choose the downloaded JSON file with the file picker.</li>
      <li>Use the compatibility checker by selecting a leading and a subordinate license.</li>
    </ul>
    <p>
    <input type="file" id="jsonFilePicker" accept=".json"></input>
    <p>
    <select id="selectleadinglicense" style="display: inline;" onchange="showcompatibility();">
      <option selected="selected">Choose a leading license</option>
    </select>
    &nbsp;&nbsp;
    <select id="selectsubordinatelicense" style="display: inline;" onchange="showcompatibility();">
      <option selected="selected">Choose a subordinate license</option>
    </select>
    &nbsp;&nbsp;
    <span id="result"></span>
    <span id="help"></span>
    <script type="text/javascript" language="javascript">
 
    var jsonObject;
    var selectleading = document.getElementById("selectleadinglicense");
    var selectsubordinate = document.getElementById("selectsubordinatelicense");
    document.getElementById("jsonFilePicker").addEventListener("change", function() {
      var fileHandle = document.getElementById("jsonFilePicker").files[0];
      var fileRead = new FileReader();
      fileRead.onload = function(e) {
        jsonObject = JSON.parse(e.target.result);
        for (i = 0; i < jsonObject.licenses.length; i++) {
          var license = jsonObject.licenses[i].name;
          var eleleading = document.createElement("option");
          var elesubordinate = document.createElement("option");
          eleleading.textContent = elesubordinate.textContent = license;
          selectleading.appendChild(eleleading);
          selectsubordinate.appendChild(elesubordinate);
        }
      };
      fileRead.readAsText(fileHandle);
    });
    function showcompatibility()
    {
      var leadingselectbox = document.getElementById("selectleadinglicense");
      var subordinateselectbox = document.getElementById("selectsubordinatelicense");
      var result = document.getElementById("result");
      var help = document.getElementById("help");
      var compatibility;
      if (leadingselectbox.selectedIndex == 0 || subordinateselectbox.selectedIndex == 0) {
        result.innerHTML = "";
        help.innerHTML = "";
        return;
      }
      compatibility = jsonObject.licenses[leadingselectbox.selectedIndex-1].compatibilities[subordinateselectbox.selectedIndex-1].compatibility;
      explanation = jsonObject.licenses[leadingselectbox.selectedIndex-1].compatibilities[subordinateselectbox.selectedIndex-1].explanation;
      result.style.fontWeight = "bold";
      if (compatibility == "Yes")
        result.style.color = "green";
      else if (compatibility == "No")
        result.style.color = "red";
      else if (compatibility == "Check dependency")
        result.style.color = "rgb(172, 172, 0)";
      else {
        result.style.color = "black";
        result.style.fontWeight = "normal";
      }
      if (compatibility == "Same") {
        result.innerHTML = "";
        help.innerHTML = "";
      } else {
        result.innerHTML = "<b>Compatibility:</b> " + compatibility;
        help.innerHTML = "<br /><br /><b>Reference:</b><br />" + explanation;
      }
    }
 
 </script>
  </body>
</html>

 

3. PHP script to generate a list of compatible and incompatible licenses of a given leading license

Without explanations - With explanations

Widget in action
     

Code to generate the above widget (to be placed on Web server)
 
<?php
/* SPDX-License-Identifier: CC0-1.0 */
/* Copyright (c) 2023 Open Source Automation Development Lab (OSADL) eG <info@osadl.org>, author Carsten Emde */
 
$json = file_get_contents('http://www.osadl.org/fileadmin/checklists/matrixseqexpl.json');
 
echo '
<!DOCTYPE html>
<html>
 
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>OSADL Generated Compatibility List of a Given License with Explanations</title>
</head>
 
<body>
<select id="selectgivenlicense" style="display: inline;" onchange="showlicenses();">
<option selected="selected">Choose a given license</option>
</select>
&nbsp;&nbsp;
<select id="selectfilter" style="display: inline;" onchange="showlicenses();">
<option selected="selected">Choose a compatibility filter</option>
</select>
&nbsp;&nbsp;
<span id="list"></span>
 
<script type="text/javascript" language="javascript">
 
var jsobject;
 
var givenlicenseselectbox = document.getElementById("selectgivenlicense");
var filterselectbox = document.getElementById("selectfilter");
 
function showlicenses()
{
  var list = document.getElementById("list");
  var compatibility;
 
  list.innerHTML = "";
 
  if (givenlicenseselectbox.selectedIndex == 0)
    return;
  for (license in jsobject.licenses) {
    compatibility = jsobject.licenses[givenlicenseselectbox.selectedIndex-1].compatibilities[license].compatibility;
    explanation = jsobject.licenses[givenlicenseselectbox.selectedIndex-1].compatibilities[license].explanation;
    endspan = "</span></b>";
    if (compatibility == "Yes")
      startspan = "<br /><b><span style=\"color: green;\">";
    else if (compatibility == "No")
      startspan = "<br /><b><span style=\"color: red;\">";
    else if (compatibility == "Check dependency")
      startspan = "<br /><b><span style=\"color: rgb(172, 172, 0);\">";
    else {
      startspan = "<br /><span style=\"color: black;\">";
      endspan ="</span>";
    }
    if (compatibility != "Same") {
      if (filterselectbox.selectedIndex != 0 && compatibility != filter[filterselectbox.selectedIndex - 1])
        continue;
      list.innerHTML += startspan + jsobject.licenses[license].name + endspan + " ";
      list.innerHTML += "(<i>" + explanation + "</i>)<br />&nbsp;";
    }
  }
}
 
var json = `' . $json . '`;
jsobject = JSON.parse(json);
for (i = 0; i < jsobject.licenses.length; i++) {
  var license = jsobject.licenses[i].name;
  var eleotherlicense = document.createElement("option");
 
  eleotherlicense.textContent = license;
  givenlicenseselectbox.appendChild(eleotherlicense);
}
var filter = ["Yes", "No", "Check dependency", "Unknown"];
for (i = 0; i < filter.length; i++) {
  var elefilter = document.createElement("option");
 
  elefilter.textContent = filter[i];
  filterselectbox.appendChild(elefilter);
}
</script>
</body>
</html>';
 
?>

 

4. Python command line application to display individual license compatibility using 2-way associative JSON array

Console output
Can I use BSD-2-Clause under GPL-2.0-only? Yes
Can I use GPL-2.0-only under BSD-2-Clause? No

Code to produce the above output (to be executed by Python interpreter)
 
from urllib.request import urlopen
import json
 
url = 'https://www.osadl.org/fileadmin/checklists/matrix.json'
response = urlopen(url)
licenses = json.loads(response.read())
 
gpl2 = 'GPL-2.0-only'
bsd2 = 'BSD-2-Clause'
print("Can I use %s under %s? %s" % (bsd2, gpl2, licenses[gpl2][bsd2]))
print("Can I use %s under %s? %s" % (gpl2, bsd2, licenses[bsd2][gpl2]))
 

5. Same as above except using locally cached matrix data

Console output
Can I use BSD-2-Clause under GPL-2.0-only? Yes
Can I use GPL-2.0-only under BSD-2-Clause? No

Code to produce the above output (to be executed by Python interpreter)
 
import time
import datetime
import requests
from os.path import expanduser
import os.path
from urllib.request import urlopen
import json
 
timestamp_url = 'https://www.osadl.org/fileadmin/checklists/timestamp'
timestamp_format_url = 'https://www.osadl.org/fileadmin/checklists/timeformat'
matrix_url = 'https://www.osadl.org/fileadmin/checklists/matrix.json'
cache = os.path.join(expanduser("~"), 'osadl-matrix.json')
cachemtime = 0
timestamptime = 0
 
def webcheck(url):
    try:
        ret = requests.head(url).status_code
        if ret < 400:
            return True
        else:
            return False
    except:
        return False
 
if webcheck(matrix_url):
    timestamp = urlopen(timestamp_url).read().decode("utf-8")
    timestampformat = urlopen(timestamp_format_url).read().decode("utf-8")
    timestamptime = time.mktime(datetime.datetime.strptime(timestamp, timestampformat).timetuple())
 
if os.path.isfile(cache):
    cachemtime = os.path.getmtime(cache)
 
if timestamptime == 0 and cachemtime == 0:
    print('No Web access and no local cache: Cannot continue')
    exit()
 
if cachemtime == 0 or timestamptime > cachemtime:
    matrix = urlopen(matrix_url).read().decode("utf-8")
    cachefile = open(cache, 'w')
    cachefile.write(matrix)
    cachefile.close()
else:
    cachefile = open(cache, 'r')
    matrix = cachefile.read()
    cachefile.close()
 
licenses = json.loads(matrix)
 
gpl2 = 'GPL-2.0-only'
bsd2 = 'BSD-2-Clause'
print("Can I use %s under %s? %s" % (bsd2, gpl2, licenses[gpl2][bsd2]))
print("Can I use %s under %s? %s" % (gpl2, bsd2, licenses[bsd2][gpl2]))