001/*
002 * Copyright 2012-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.boot.info;
018
019import java.text.ParseException;
020import java.text.SimpleDateFormat;
021import java.time.Instant;
022import java.util.Properties;
023
024/**
025 * Provide git-related information such as commit id and time.
026 *
027 * @author Stephane Nicoll
028 * @since 1.4.0
029 */
030public class GitProperties extends InfoProperties {
031
032        public GitProperties(Properties entries) {
033                super(processEntries(entries));
034        }
035
036        /**
037         * Return the name of the branch or {@code null}.
038         * @return the branch
039         */
040        public String getBranch() {
041                return get("branch");
042        }
043
044        /**
045         * Return the full id of the commit or {@code null}.
046         * @return the full commit id
047         */
048        public String getCommitId() {
049                return get("commit.id");
050        }
051
052        /**
053         * Return the abbreviated id of the commit or {@code null}.
054         * @return the short commit id
055         */
056        public String getShortCommitId() {
057                String shortId = get("commit.id.abbrev");
058                if (shortId != null) {
059                        return shortId;
060                }
061                String id = getCommitId();
062                if (id == null) {
063                        return null;
064                }
065                return (id.length() > 7) ? id.substring(0, 7) : id;
066        }
067
068        /**
069         * Return the timestamp of the commit or {@code null}.
070         * <p>
071         * If the original value could not be parsed properly, it is still available with the
072         * {@code commit.time} key.
073         * @return the commit time
074         * @see #get(String)
075         */
076        public Instant getCommitTime() {
077                return getInstant("commit.time");
078        }
079
080        private static Properties processEntries(Properties properties) {
081                coercePropertyToEpoch(properties, "commit.time");
082                coercePropertyToEpoch(properties, "build.time");
083                Object commitId = properties.get("commit.id");
084                if (commitId != null) {
085                        // Can get converted into a map, so we copy the entry as a nested key
086                        properties.put("commit.id.full", commitId);
087                }
088                return properties;
089        }
090
091        private static void coercePropertyToEpoch(Properties properties, String key) {
092                String value = properties.getProperty(key);
093                if (value != null) {
094                        properties.setProperty(key, coerceToEpoch(value));
095                }
096        }
097
098        /**
099         * Attempt to convert the specified value to epoch time. Git properties information
100         * are known to be specified either as epoch time in seconds or using a specific date
101         * format.
102         * @param s the value to coerce to
103         * @return the epoch time in milliseconds or the original value if it couldn't be
104         * converted
105         */
106        private static String coerceToEpoch(String s) {
107                Long epoch = parseEpochSecond(s);
108                if (epoch != null) {
109                        return String.valueOf(epoch);
110                }
111                SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
112                try {
113                        return String.valueOf(format.parse(s).getTime());
114                }
115                catch (ParseException ex) {
116                        return s;
117                }
118        }
119
120        private static Long parseEpochSecond(String s) {
121                try {
122                        return Long.parseLong(s) * 1000;
123                }
124                catch (NumberFormatException ex) {
125                        return null;
126                }
127        }
128
129}