"Withdraw a specified release from the current project."
pass
+focus_values = (
+ "Initial freshmeat announcement",
+ "Documentation",
+ "Code cleanup",
+ "Minor feature enhancements",
+ "Major feature enhancements"
+ "Minor bugfixes",
+ "Major bugfixes",
+ "Minor security fixes",
+ "Major security fixes",
+)
+
+# Note: Release Focus is no longer a real Freshmeat field; we'll remap it later.
freshmeat_field_map = (
- ("Project", "p", "project_name"),
+ ("Project", "p", "name"),
("Version", "v", "version"),
("Changes", "c", "changelog"),
("Hide", "x", "hide_from_frontpage"),
- ("License", "l", "license"),
- ("Home-Page-URL", "H", "url_homepage"),
- ("Gzipped-Tar-URL", "G", "url_tgz"),
- ("Bzipped-Tar-URL", "B", "url_bz2"),
- ("Zipped-Tar-URL", "Z", "url_zip"),
- ("Changelog-URL", "C", "url_changelog"),
- ("RPM-URL", "R", "url_rpm"),
- ("Debian-URL", "D", "url_deb"),
- ("OSX-URL", "O", "url_osx"),
- ("BSD-Port-URL", "P", "url_bsdport"),
- ("Purchase-URL", "U", "url_purchase"),
- ("CVS-URL", "S", "url_cvs"),
- ("Mailing-List-URL", "L", "url_list"),
- ("Mirror-Site-URL", "M", "url_mirror"),
- ("Demo-URL", "E", "url_demo"),
+ ("Release-Focus", "r", "release_focus"),
+ ("Tag-List", "t", "tag_list"),
+ ("License-List", "l", "license_list"),
)
def get_rpm_field(fld, rpm):
raise ValueError
return output
-def crack_rpm(rpm, dict):
+def crack_rpm(rpm, meta, urls):
"Extract freshmeat metadata from an RPM."
try:
# Some fields can be copied literally if present.
- if not "project_name" in dict:
- dict["project_name"] = get_rpm_field("name", rpm)
- if not "version" in dict:
- dict["version"] = get_rpm_field("version", rpm)
+ if not "name" in meta:
+ meta["name"] = get_rpm_field("name", rpm)
+ if not "version" in meta:
+ meta["version"] = get_rpm_field("version", rpm)
# This doesn't work. The values don't map over.
- #if not "license" in dict:
- # dict["license"] = get_rpm_field("license", rpm)
- if not "url_homepage" in dict:
- dict["url_homepage"] = get_rpm_field("url", rpm)
- if not "changes" in dict:
+ #if not "license" in meta:
+ # meta["license"] = get_rpm_field("license", rpm)
+ if not "url_homepage" in meta:
+ meta["url_homepage"] = get_rpm_field("url", rpm)
+ if not "changes" in meta:
# Querying gets you the first entry, apparently
# blank-line-delimited.
changes = get_rpm_field("changelogtext", rpm)
# Canonicalize, stripping leading spaces.
changes = map(lambda x: x.strip(), changes.split('\n'))
changes = "\n".join(changes) + "\n"
- dict["changes"] = changes
+ meta["changelog"] = changes
# RPMs have a source field; figure out which Freshmeat field it maps to
source = get_rpm_field("source", rpm)
if source.endswith(".tar.gz") or source.endswith(".tgz"):
- if "url_tgz" not in dict:
- dict["url_tgz"] = source
+ if "Tar/GZ" not in urls:
+ urls["Tar/GZ"] = source
if source.endswith(".tar.bz2"):
- if "url_bz2" not in dict:
- dict["url_bz2"] = source
+ if "Tar/BZ" not in urls:
+ urls["Tar/BZ"] = source
except ValueError:
pass
raise FreshmeatSessionException("Illegal field name %s" % hdr)
def getMetadata(self, stream):
- "Make a Metadata object."
+ "Make a JSON-like Python object describing an update."
data = {}
+ urls = {}
(options, args) = self.argument_parser.parse_args()
- # First stuff from rpms if present.
+ # First stuff from RPMs if present.
for file in args:
if file.endswith(".rpm"):
- crack_rpm(file, data)
- # Second. stuff fropm stdin if present
+ crack_rpm(file, data, urls)
+ # Second. stuff from stdin if present
if options.read:
message = self.message_parser.parse(stream)
for (key, value) in message.items():
- data.update({self.header_to_field(key) : value})
+ if key.endswith("-URL"):
+ urls.update({key[:-4] : value})
+ else:
+ data.update({self.header_to_field(key) : value})
if not 'changes' in data:
data['changes'] = message.get_payload()
# Merge in options from the command line;
for (key, value) in options.__dict__.items():
if key != 'read' and value != None:
data[key] = value
- # Release-Focus field may have to be validated later.
+ # Release-Focus field special handling
if "release_focus" in data:
- val = data["release_focus"].lower()
- if val in '123456789':
- data["release_focus"] = int(val)
+ if data["release_focus"] in '123456789':
+ data["release_focus"] = focus_values[int(data["release_focus"])-1]
+ if data["release_focus"] not in focus_values:
+ raise FreshmeatSessionException("Invalid release focus")
+ data["tag_list"] = data["release_focus" ]
+ del data["release_focus"]
+ # Now merge in the URLs
+ data['approved_urls'] = map(lambda (k, v): {"label": k, "url": v}, urls.items())
return data
if __name__ == "__main__":
noemit = data['noemit']; del data['noemit']
# Maybe we just want to sanity-check the send
if noemit or verbose:
- for (field, shortopt, key) in freshmeat_field_map:
- if key in data and key != 'changes':
- print "%s: %s" % (field, data[key])
- if 'changes' in data:
- sys.stdout.write("\n" + data['changes'])
+ print data
# Time to ship the update.
if not noemit:
# Establish session
</listitem>
</orderedlist>
-<para>Here is a table of the fields and their
+<para>Here is a table of metadata fields and their
corresponding command-line switches:</para>
<informaltable>
<entry>License:</entry> <entry>-</entry>
<entry>-l</entry><entry>--license</entry>
<entry>
-<para>Specify the license under which the release is issued. Note
-that this is not copied from the RPM License field, because the
-values don't map.</para>
+<para>Specify the licenses under which the release is issued. This
+may be a comma-reparated list. Note that this is not copied from the
+RPM License field, because the values don't map.</para>
</entry>
</row>
<row>
-<entry>Home-Page-URL:</entry> <entry>URL</entry>
+<entry>Website-URL:</entry> <entry>URL</entry>
<entry>-H</entry><entry>--home-page-url</entry><entry>
<para>Specify the project home page.</para>
</entry>
</row>
<row>
-<entry>Gzipped-Tar-URL:</entry> <entry>SOURCE</entry>
+<entry>Tar/GZ-URL:</entry> <entry>SOURCE</entry>
<entry>-G</entry><entry>--gzipped-tar-url</entry>
<entry>
<para>Specify the URL where a gzipped tarball of source can be found.</para>
</entry>
</row>
-<row>
-<entry>Bzipped-Tar-URL:</entry> <entry>SOURCE</entry>
-<entry>-B</entry><entry>--bzipped-tar-url</entry>
-<entry>
-<para>Specify the URL where a bzipped tarball of source can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>Zipped-Tar-URL:</entry> <entry>-</entry>
-<entry>-Z</entry><entry>--zipped-tar-url</entry>
-<entry>
-<para>Specify the URL where a zipped tarball of source can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>Changelog-URL:</entry> <entry>-</entry>
-<entry>-C</entry><entry>--changelog-url</entry>
-<entry>
-<para>Specify the URL where the project changelog can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>RPM-URL:</entry> <entry>-</entry>
-<entry>-R</entry><entry>--rpm-url</entry>
-<entry>
-<para>Specify the URL where an installable binary RPM can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>Debian-URL:</entry> <entry>-</entry>
-<entry>-D</entry><entry>--debian-url</entry>
-<entry>
-<para>Specify the URL where an installable Debian package can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>OSX-URL:</entry> <entry>-</entry>
-<entry>-O</entry><entry>--osx-url</entry>
-<entry>
-<para>Specify the URL where an OS/X binary can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>BSD-Port-URL:</entry> <entry>-</entry>
-<entry>-P</entry><entry>--bsdport-url</entry>
-<entry>
-<para>Specify the URL where a BSD Ports package can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>Purchase-URL:</entry> <entry>-</entry>
-<entry>-U</entry><entry>--purchase-url</entry>
-<entry>
-<para>Specify the URL where the software can be purchased.</para>
-</entry>
-</row>
-
-<row>
-<entry>CVS-URL:</entry> <entry>-</entry>
-<entry>-S</entry><entry>--cvs-url</entry>
-<entry>
-<para>Specify the URL of the CVS for this package.</para>
-</entry>
-</row>
-
-<row>
-<entry>Mailing-List-URL:</entry> <entry>-</entry>
-<entry>-L</entry><entry>--mailing-list-url</entry>
-<entry>
-<para>Specify the URL where you can sign up for project mailing lists.</para>
-</entry>
-</row>
-
-<row>
-<entry>Mirror-Site-URL:</entry> <entry>-</entry>
-<entry>-M</entry><entry>--mirror-site-url</entry>
-<entry>
-<para>Specify the URL where an official mirror site for the project
-can be found.</para>
-</entry>
-</row>
-
-<row>
-<entry>Demo-URL:</entry> <entry>-</entry>
-<entry>-E</entry><entry>url-demo</entry>
-<entry>
-<para>Specify the URL where a demonstration site for the package
-can be found.</para>
-</entry>
-</row>
-
</tbody>
</tgroup>
</informaltable>
-<para>The license and all URL fields, when specified, actually change
-the branch record for the project. Only the Changes, Version,
+<para>The License-List and all URL fields, when specified, actually change
+the record for the project. Only the Changes, Version,
Release-Focus, and Hide fields are actually stored for each
version.</para>
Version: 1.1
Release-Focus: Major feature enhancements
Hide: N
-Home-Page-URL: http://www.catb.org/~esr/doclifter/
-Gzipped-Tar-URL: http://www.catb.org/~esr/doclifter/doclifter-1.1.tar.gz
-RPM-URL: http://www.catb.org/~esr/doclifter/doclifter-1.1-1.i386.rpm
+Website-URL: http://www.catb.org/~esr/doclifter/
+Tar/GZ-URL: http://www.catb.org/~esr/doclifter/doclifter-1.1.tar.gz
Fixed a bug in conditional evaluation that twadmin(8) tickled. Better
detection of pure inclusions. Better blank-section elimination.
installation with Fedora updates to *validated* XML-DocBook.
</programlisting>
-<para>More typically, you will run this program in a directory where
-you have already made an RPM, giving it the RPM as a file argument.
-In that case, all you will normally need to supply is the Release-Focus
-field; the other required fields (including, most notably, the Changes
-field) will be mined out of the RPM.</para>
+<para>You may run this program in a directory where you have already
+made an RPM, giving it the RPM as a file argument. In that case, all
+you will normally need to supply is the Release-Focus field; the other
+required fields (including, most notably, the Changes field) will be
+mined out of the RPM.</para>
</refsect1>
<refsect1><title>WARNING</title>
compatibility, the data model has changed in significant ways.</para>
<para>There is no longer a Branch attribute.</para>
+
+<para>The old Release-Focus field is gone. As a special case, this
+pragram will validate it and use it to fill in the tags list.</para>
+
+<para>The old License field is now License-List and can take a
+comma-separated list of licenses.</para>
+
+<para>The old Home-Page-URL is noe Website-URL to match the convention
+used by the new API.</para>
+
+<para>The old Gzipped-Tar-URL is now Tar/GZ-URL to match the convention
+used by the new API.</para>
+
+<para>All the other special-case URL fields are gone. They're replaced by
+the general mechanism for pairing URLs with labels.</para>
</refsect1>
<refsect1><title>FILES</title>
<term><filename>~/.netrc</filename></term>
<listitem>
<para><application>freshmeat-submit</application> expects to find your
-Freshmeat credentials here. The correct form for an entry looks like
+Freshmeat authorization tag here. The correct form for an entry looks like
this:</para>
<screen>
machine freshmeat
- login <your_freshmeat_login>
- password <your_freshmeat_password>
+ account <your_api_auth_code>
</screen>
<para>For security, make sure your <filename>~/.netrc</filename> file
<refsect1><title>RETURN VALUES</title>
<para>0 on success, 1 on failure. In case of failure, any error message
-passed back by the XML-RPC interface is issued to standard error.</para>
+passed back by the Freshmeat API is issued to standard error.</para>
</refsect1>
<refsect1 id='author'><title>AUTHORS</title>