1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.timezone.location.common;
18 
19 import java.io.BufferedReader;
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.FileReader;
23 import java.io.IOException;
24 import java.nio.file.Files;
25 import java.util.Arrays;
26 import java.util.Objects;
27 
28 /** Utilities to help with LICENSE files and associated headers. */
29 public class LicenseSupport {
30 
31     /**
32      * The standard header to be put in files generated from OpenStreetMap data obtained from
33      * https://opendatacommons.org/licenses/odbl/ on 2020-08-04.
34      */
35     private static final String TEXT_PROTO_ODBL_LICENSE_HEADER = ""
36             + "# This time zone geo data is made available under the Open Database License:\n"
37             + "# http://opendatacommons.org/licenses/odbl/1.0/.\n"
38             + "# Any rights in individual contents of the database are licensed under the Database"
39             + " Contents License:\n"
40             + "# http://opendatacommons.org/licenses/dbcl/1.0/\n"
41             + "\n";
42     private static final String ODBL_LICENSE_SNIPPET = "Open Database License (ODbL) v1.0";
43 
44     public static final String LICENSE_FILE_NAME = "LICENSE";
45 
46     /** Individual licenses. */
47     public enum License {
48         ODBL(ODBL_LICENSE_SNIPPET, TEXT_PROTO_ODBL_LICENSE_HEADER);
49 
50         private final String mTextProtoHeader;
51 
52         private final String mLicenseFileSnippet;
53 
License(String licenseFileSnippet, String textProtoHeader)54         License(String licenseFileSnippet, String textProtoHeader) {
55             this.mLicenseFileSnippet = Objects.requireNonNull(licenseFileSnippet);
56             this.mTextProtoHeader = Objects.requireNonNull(textProtoHeader);
57         }
58 
59         /** Returns the text proto file header for this license type. */
getTextProtoHeader()60         public String getTextProtoHeader() {
61             return mTextProtoHeader;
62         }
63 
64         /**
65          * Confirms a LICENSE file is present and contains a snippet of the expected license, or
66          * throws an exception.
67          */
checkLicensePresentInDir(File dir)68         public void checkLicensePresentInDir(File dir) throws IOException {
69             checkIsDir(dir);
70             File licenseFile = new File(dir, LICENSE_FILE_NAME);
71             checkIsFile(licenseFile);
72             checkFileContains(licenseFile, mLicenseFileSnippet);
73         }
74     }
75 
LicenseSupport()76     private LicenseSupport() {
77     }
78 
79     /**
80      * Copies the LICENSE file from {@code inputDir} to {@code outputDir} as needed. If the file
81      * already exists in the {@code outputDir}, it is checked to see if it is the same.
82      */
copyLicenseFile(File inputDir, File outputDir)83     public static void copyLicenseFile(File inputDir, File outputDir) throws IOException {
84         checkIsDir(inputDir);
85         checkIsDir(outputDir);
86 
87         File licenseFileInput = new File(inputDir, LICENSE_FILE_NAME);
88         if (!licenseFileInput.exists()) {
89             throw new IllegalArgumentException(licenseFileInput + " does not exist");
90         }
91         File licenseOutputFile = new File(outputDir, LICENSE_FILE_NAME);
92         if (licenseOutputFile.exists()) {
93             System.out.println(licenseOutputFile + " already exists: checking content");
94             // Just do a basic check for equality.
95             checkFilesIdentical(licenseFileInput, licenseOutputFile);
96         } else {
97             System.out.println(
98                     "Copying LICENSE from " + licenseFileInput + " to " + licenseOutputFile);
99             Files.copy(licenseFileInput.toPath(), licenseOutputFile.toPath());
100         }
101     }
102 
checkFilesIdentical(File one, File two)103     private static void checkFilesIdentical(File one, File two) throws IOException {
104         try (FileInputStream oneInput = new FileInputStream(one);
105                 FileInputStream twoInput = new FileInputStream(two)) {
106 
107             byte[] oneBytes = oneInput.readAllBytes();
108             byte[] twoBytes = twoInput.readAllBytes();
109             if (!Arrays.equals(oneBytes, twoBytes)) {
110                 throw new IllegalArgumentException("File " + one + " is not the same as " + two);
111             }
112         }
113     }
114 
checkFileContains(File file, String snippet)115     private static void checkFileContains(File file, String snippet) throws IOException {
116         try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
117             String line;
118             while ((line = reader.readLine()) != null) {
119                 if (line.contains(snippet)) {
120                     return;
121                 }
122             }
123         }
124         throw new IllegalArgumentException(file + " does not contain " + snippet);
125     }
126 
checkIsFile(File file)127     private static void checkIsFile(File file) {
128         if (!file.isFile()) {
129             throw new IllegalArgumentException(file + " is not a file.");
130         }
131     }
132 
checkIsDir(File dir)133     private static void checkIsDir(File dir) {
134         if (!dir.isDirectory()) {
135             throw new IllegalArgumentException(dir + " is not a directory.");
136         }
137     }
138 }
139