From 155d8574dfe4715cdf1e62afcc95cf8b871bf0e7 Mon Sep 17 00:00:00 2001
From: Jeremy Stanley <fungi@yuggoth.org>
Date: Sun, 26 Mar 2006 17:08:52 +0000
Subject: [PATCH] Imported from archive.

* Initial release 1.0.
---
 INSTALL     |  39 ++++++++++++++
 LICENSE     |  22 ++++++++
 weather     |  31 +++++++++++
 weather.1   |  87 +++++++++++++++++++++++++++++++
 weather.py  | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 weatherrc   |  15 ++++++
 weatherrc.5 |  72 +++++++++++++++++++++++++
 7 files changed, 436 insertions(+)
 create mode 100644 INSTALL
 create mode 100644 LICENSE
 create mode 100755 weather
 create mode 100644 weather.1
 create mode 100644 weather.py
 create mode 100644 weatherrc
 create mode 100644 weatherrc.5

diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..9180903
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,39 @@
+BASIC UNIX INSTALLATION INSTRUCTIONS FOR THE WEATHER UTILITY
+
+
+PREREQUISITES
+
+You need the Python interpreter installed somewhere in your path
+(most modern UNIX derivatives come with one already). The weather
+executable assumes your Python interpreter is /usr/bin/python so you
+may need to edit the #! line if that is not the case. If you need
+Python for some reason, it can be obtained from
+http://www.python.org/ (but chances are your operating system at
+least provides some sort of native package for it, which you should
+probably install in whatever means is recommended by your OS
+vendor/distributor).
+
+
+INSTALLING THE UTILITY
+
+The file named weather should be made executable and put somewhere
+in your path (/usr/local/bin/ or ~/bin/ for example). Similarly,
+weather.py needs to be somewhere in Python's include path. You can
+see your Python interpreter's default include path by running:
+
+   python -c "import sys ; print sys.path"
+
+
+CONFIGURATION
+
+The weatherrc file should go in /etc/ or you can save it in your
+home directory as a dotfile (~/.weatherrc) to support user-specific
+alias configuration and overrides of the global /etc/weatherrc file.
+
+
+MANUALS
+
+Optionally, the weather.1 and weatherrc.5 files can be placed in
+sane locations for TROFF/NROFF manual files on your system (for
+example, /usr/local/share/man/ or ~/man/).
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1f63def
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+   - Redistributions of source code must retain the above copyright notice,
+     this list of conditions and the following disclaimer.
+   - Redistributions in binary form must reproduce the above copyright notice,
+     this list of conditions and the following disclaimer in the documentation
+     and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/weather b/weather
new file mode 100755
index 0000000..ffaf2a5
--- /dev/null
+++ b/weather
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+# Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
+# Licensed per terms in the LICENSE file distributed with this software.
+
+import weather
+
+# initialize options and configs
+selections = weather.Selections()
+get = selections.get
+get_boolean = selections.get_boolean
+
+# this mode just lists the aliases defined in the config
+if get_boolean("list"): print weather.list_aliases(selections.config)
+
+# normal operation
+else:
+	for argument in selections.arguments:
+		if get_boolean("conditions", argument):
+			print weather.get_metar(
+				get("id", argument),
+				get_boolean("verbose", argument)
+				)
+		if not get_boolean("conditions", argument) \
+			or get_boolean("forecast", argument):
+			print weather.get_forecast(
+				get("city", argument),
+				get("st", argument),
+				get_boolean("verbose", argument)
+				)
+
diff --git a/weather.1 b/weather.1
new file mode 100644
index 0000000..05aa865
--- /dev/null
+++ b/weather.1
@@ -0,0 +1,87 @@
+.TH WEATHER 1 "March 26, 2006"
+.SH NAME
+weather \- command\-line tool to obtain weather conditions and forecasts
+.SH SYNOPSIS
+.B weather [ options ] [ alias [ alias [...] ] ]
+.SH DESCRIPTION
+This utility is intended to provide quick access to current weather
+conditions and forecasts. Presently, it is capable of providing data for
+localities throughout the United States of America by retrieving and
+processing METAR data from the National Oceanic and Atmospheric
+Administration and forecasts from the National Weather Service. Behavior
+can be determined by command\-line options and specification of zero or
+more aliases. Aliases are defined in weatherrc files, as a convenient
+means of grouping option combinations together using a short name.
+Specifying multiple aliases on the command line causes the utility to
+output data for each, as if it had been invoked multiple times. If no
+alias is specified, then an alias of "default" is used (assuming it has
+been defined) or the built\-in default values are chosen (if it has not).
+.SH OPTIONS
+A summary of options is included below.
+.TP
+.B \-\-version
+show program's version number and exit
+.TP
+.B \-h, \-\-help
+show a help message and exit
+.TP
+.B \-cCITY, \-\-city=CITY
+the city name (ex: "Raleigh Durham")
+.TP
+.B \-f, \-\-forecast
+include a local forecast
+.TP
+.B \-iID, \-\-id=ID
+the METAR station ID (ex: KRDU)
+.TP
+.B \-l, \-\-list
+print a list of configured aliases
+.TP
+.B \-n, \-\-no\-conditions
+disable output of current conditions (implies \-\-forecast)
+.TP
+.B \-sST, \-\-st=ST
+the state abbreviation (ex: NC)
+.TP
+.B \-v, \-\-verbose
+show full decoded feeds
+.SH FILES
+.B weather
+may additionally obtain configuration data from a system\-wide
+configuration file, a per\-user configuration file, and a local
+directory configuration file. The file format and configuration options
+are described in
+.BR weatherrc (5) .
+They are aggregated in the following order:
+.TP
+.B /etc/weatherrc
+the system\-wide configuration
+.TP
+.B ~/.weatherrc
+the per\-user configuration (can be used to override the above)
+.TP
+.B ./.weatherrc
+the local directory configuration (can be used to override the above)
+.SH EXAMPLES
+.TP
+.B weather
+View output for the defined default alias, or the built-in default values
+if there is no default alias defined in the configuration files.
+.TP
+.B weather -i kavl
+Display current conditions at the KAVL METAR station.
+.TP
+.B weather -n -c asheville -s nc
+See a forecast for the Asheville, NC area.
+.TP
+.B weather -fv gso
+Get the full decoded METAR for the station associated with the gso alias,
+and the forecast data for the City/State associated with the gso alias,
+without filtering or fancy formatting.
+.TP
+.B weather home work
+Show current conditions for both the home and work aliases in that order.
+.SH SEE ALSO
+.BR weatherrc (5)
+.SH AUTHOR
+Utility and manual written by Jeremy Stanley <fungi@yuggoth.org>.
diff --git a/weather.py b/weather.py
new file mode 100644
index 0000000..6073a5c
--- /dev/null
+++ b/weather.py
@@ -0,0 +1,170 @@
+# Copyright (c) 2006 Jeremy Stanley <fungi@yuggoth.org>, all rights reserved.
+# Licensed per terms in the LICENSE file distributed with this software.
+
+version = "1.0"
+
+class Selections:
+	"""An object to contain selection data."""
+	def __init__(self):
+		"""Store the config, options and arguments."""
+		self.config = get_config()
+		self.options, self.arguments = get_options()
+		if self.arguments:
+			self.arguments = [(x.lower()) for x in self.arguments]
+		else: self.arguments = [ None ]
+	def get(self, option, argument=None):
+		"""Retrieve data from the config or options."""
+		if not argument: argument = "default"
+		if self.config.has_option(argument, option):
+			return self.config.get(argument, option)
+		else: return self.options.__dict__[option]
+	def get_boolean(self, option, argument=None):
+		"""Get data and coerce to a boolean if necessary."""
+		data = self.get(option, argument)
+		if type(data) is str:
+			if eval(data): return True
+			else: return False
+		else:
+			if data: return True
+			else: return False
+
+def quote(words):
+	"""Wrap a string in quotes if it contains spaces."""
+	if words.find(" ") != -1: words = "\"" + words + "\""
+	return words
+
+def sorted(data):
+	"""Return a sorted copy of a list."""
+	new_copy = data[:]
+	new_copy.sort()
+	return new_copy
+
+def get_url(url):
+	"""Return a string containing the results of a URL GET."""
+	import urllib
+	return urllib.urlopen(url).read()
+
+def get_metar(id, verbose=False):
+	"""Return a summarized METAR for the specified station."""
+	metar = get_url(
+		"http://weather.noaa.gov/pub/data/observations/metar/decoded/" \
+			+ id.upper() + ".TXT")
+	if verbose: return metar
+	else:
+		lines = metar.split("\n")
+		headings = [
+			"Relative Humidity",
+			"Precipitation last hour",
+			"Sky conditions",
+			"Temperature",
+			"Weather",
+			"Wind" 
+			]
+		output = []
+		output.append("Current conditions at " \
+			+ lines[0].split(", ")[1] + " (" \
+			+ id.upper() +")")
+		output.append("Last updated " + lines[1])
+		for line in lines:
+			for heading in headings:
+				if line.startswith(heading + ":"):
+					output.append("   " + line)
+		return "\n".join(output)
+
+def get_forecast(city, st, verbose=False):
+	"""Return the forecast for a specified city/st combination."""
+	forecast = get_url("http://weather.noaa.gov/pub/data/forecasts/city/" \
+		+ st.lower() + "/" + city.lower().replace(" ", "_") \
+		+ ".txt")
+	if verbose: return forecast
+	else:
+		lines = forecast.split("\n")
+		output = []
+		output.append(lines[2])
+		output.append(lines[3])
+		for line in lines:
+			if line.startswith("."):
+				output.append(line.replace(".", "   ", 1))
+		return "\n".join(output)
+
+def get_options():
+	"""Parse the options passed on the command line."""
+	import optparse
+	usage = "usage: %prog [ options ] [ alias [ alias [...] ] ]"
+	verstring = "%prog " + version
+	option_parser = optparse.OptionParser(usage=usage, version=verstring)
+	option_parser.add_option("-c", "--city",
+		dest="city",
+		default="Raleigh Durham",
+		help="the city name (ex: \"Raleigh Durham\")")
+	option_parser.add_option("-f", "--forecast",
+		dest="forecast",
+		action="store_true",
+		default=False,
+		help="include forecast (needs -c and -s)")
+	option_parser.add_option("-i", "--id",
+		dest="id",
+		default="KRDU",
+		help="the METAR station ID (ex: KRDU)")
+	option_parser.add_option("-l", "--list",
+		dest="list",
+		action="store_true",
+		default=False,
+		help="print a list of configured aliases")
+	option_parser.add_option("-n", "--no-conditions",
+		dest="conditions",
+		action="store_false",
+		default=True,
+		help="disable output of current conditions (implies --forecast)")
+	option_parser.add_option("-s", "--st",
+		dest="st",
+		default="NC",
+		help="the state abbreviation (ex: NC)")
+	option_parser.add_option("-v", "--verbose",
+		dest="verbose",
+		action="store_true",
+		default=False,
+		help="show full decoded feeds")
+	options, arguments = option_parser.parse_args()
+	return options, arguments
+
+def get_config():
+	"""Parse the aliases and configuration."""
+	import ConfigParser
+	config = ConfigParser.ConfigParser()
+	import os.path
+	rcfiles = [
+		".weatherrc",
+		os.path.expanduser("~/.weatherrc"),
+		"/etc/weatherrc"
+		]
+	import os
+	for rcfile in rcfiles:
+		if os.access(rcfile, os.R_OK): config.read(rcfile)
+	for section in config.sections():
+		if section != section.lower():
+			if config.has_section(section.lower()):
+				config.remove_section(section.lower())
+			config.add_section(section.lower())
+			for option,value in config.items(section):
+				config.set(section.lower(), option, value)
+	return config
+
+def list_aliases(config):
+	"""Return a formatted list of aliases defined in the config."""
+	sections = []
+	for section in config.sections():
+		if section.lower() not in sections and section != "default":
+			sections.append(section.lower())
+	output = "configured aliases..."
+	for section in sorted(sections):
+		output += "\n   " \
+			+ section \
+			+ ": --id=" \
+			+ quote(config.get(section, "id")) \
+			+ " --city=" \
+			+ quote(config.get(section, "city")) \
+			+ " --st=" \
+			+ quote(config.get(section, "st"))
+	return output
+
diff --git a/weatherrc b/weatherrc
new file mode 100644
index 0000000..ae09d8e
--- /dev/null
+++ b/weatherrc
@@ -0,0 +1,15 @@
+[AVL]
+City = Asheville
+ID = KAVL
+St = NC
+
+[GSO]
+City = Greensboro
+ID = KGSO
+St = NC
+
+[RDU]
+City = Raleigh Durham
+ID = KRDU
+St = NC
+
diff --git a/weatherrc.5 b/weatherrc.5
new file mode 100644
index 0000000..0d6b999
--- /dev/null
+++ b/weatherrc.5
@@ -0,0 +1,72 @@
+.TH WEATHERRC 5 "March 26, 2006"
+.SH NAME
+weatherrc \- configuration file format for the
+.BR weather (1)
+utility
+.SH DESCRIPTION
+The weatherrc file format is intended to specify a set of macros
+by which to group a METAR station ID for current conditions data with a
+city/state combination for a forecast, but many of the other
+command\-line options/flags for the weather utility can be specified as
+well. The file is organized as an INI-format config, with the alias name
+in [] brackets and the associated parameter/value pairs on following
+lines. Parameters and their values as separated by = or : characters.
+Multi-word values do not need quoting.
+.SH PARAMETERS
+These parameters are supported...
+.TP
+.B city
+the city name (ex: Raleigh Durham)
+.TP
+.B forecast
+include a local forecast (possible values are False and True or 0 and 1)
+.TP
+.B id
+the METAR station ID (ex: KRDU)
+.TP
+.B conditions
+output current conditions (possible values are False and True or 0 and 1)
+.TP
+.B st
+the state abbreviation (ex: NC)
+.TP
+.B verbose
+show full decoded feeds (possible values are False and True or 0 and 1)
+.SH EXAMPLES
+Following is an example
+.B ~/.weatherrc
+defining the default settings to be used when running the utility with no
+aliases specified, and a couple definitions for aliases named home and
+work...
+.P
+.RS
+[default]
+.br
+City = Asheville
+.br
+Forecast = True
+.br
+ID = KAVL
+.br
+St = NC
+.P
+[home]
+.br
+City = Raleigh Durham
+.br
+ID = KRDU
+.br
+St = NC
+.P
+[work]
+.br
+City = Greensboro
+.br
+ID = KGSO
+.br
+St = NC
+.RE
+.SH SEE ALSO
+.BR weather (1)
+.SH AUTHOR
+Specification and manual written by Jeremy Stanley <fungi@yuggoth.org>.
-- 
2.11.0