Devshell API

From FedoraProject

Jump to: navigation, search

The following document explains the key components in Fedora Devshell, and how to extend it for your own nefarious purposes. The Modules section addresses the kinds of actions Fedora Devshell can do, and how they are implemented. The Utility functions highlights some of the key components used as building blocks. The Coding Guidelines are critically important, as they must be followed to in order to submit patches. The Submission Guidelines explain how to get your patches in.

Contents

Modules, Interfaces and Base Classes

Directory

Directory is a Base Class for pretty much any class needing persistence on the filesystem. It manages storing metadata attributes in a simple INI-style file under .devshell in each directory. It establishes the link between some directory on the file system and the operations available from the command line, inside the source code, and from any IDE. The initializer takes one optional parameter, a path to the directory on the file system, and it loads up the Directory from there. If not given, Directory uses the current working directory.

It exposes these methods:

And properties:

MetaDirectory

This metaclass registers all directory objects with DirFactory

DirFactory

A subclass of Directory that will return the correct subclass of Directory for a given directory on the filesystem, rather than the base class.

Package

Package is an overarching manager for packages that will eventually become RPMs. There should be a one-to-one correspondence with Package and a source RPM. There will also theoretically be a one-to-one correspondence between Package and entries in the Fedora CVS repository. It manages a spec file, a list of sources, patches for the actively chosen PackageSources and other administrative details.

It exposes the following methods:

The following properties:

Possible Package Types

Packages can be managed in all sorts of ways. Fedora currently uses CVS to manage the workflow. Other people might want to use git. In the future, we will need modules to manage these different workflows

BuildSystem

BuildSystem is a Python class of type MetaBuildSystem. MetaBuildSystems are registerd with a BuildSystemFactory, which can load any BuildSystem loaded in the run time space. It's initializer takes one argument, a PackageSource either on the file system or a Python object. BuildSystem is an interface on top of common build systems such as autotools, cmake, and cabal.

It exposes five methods.

Cabal

Cabal is an implementation of a BuildSystem. It works on top of The Haskell Cabal, which is the build tool used for building Haskell packages. It uses the program cabal2spec provided in Fedora for generating the spec file.

Possible BuildSystem Types

Currently we only support Cabal. Plugging in other build systems should be easily feasible, possible options include Autotools , Ant, Python's setuptools, Ruby Gems, CMake, and many other build systems. We may want to look into handling multiple build targets for cross compiling.

PackageSource

PackageSource is a Python class of type MetaDirectory. MetaDirectorys are registered with a DirFactory, which can load any directory from the filesystem as the properly subclassed Directory in Fedora Devshell. PackageSource is a single source, be it a tarball or revision control that will go into an RPM Package.

It handles the management of patches between the original upstream source and the downstream sourcetree, generating tarballs and patches, Each implementation manages the storage and generation of these details.

It exposes these methods.

It exposes these properties

SourceBall

A SourceBall is an implementation of PackageSource. It maintains both an actively edited work tree, and a copy of the original source tree, along with the original sourcetarball for comparison. It can only generate a single stack of patches, on top its one branch, 'orig'.

RevisionControl

Subclasses PackageSource for all implementations that use RevisionControl. This is a very boring class.

Darcs

The only implementation of RevisionControl. It wraps around the Darcs Distributed Version Control System. It maintains multiple branches based on parameters passed directly to darcs. It does not yet do patch management.

Examples

new foo branch bar - forks bar as foo
new foo --tag 0.8 - forks tag 0.8 as foo
--tag 0.8 - switches to tag 0.8
--to-match 'hash 4593894085394890' - switches to some patch identified by some hash

Possible PackageSource Types

Currently, Darcs and SourceBall are the only supported types. Darcs does branching fundamentally different from Git, Bazaar, and Mercurial. Work will need to go into having the paradigms sit together nicely. Note that we aren't creating an all in one solution, but just using the important bits of each VCS to generate patches to go into RPMs. Ultimately, RPMs must be packaged with Tarballs, the use of RevisionControl is only to ease and aid the process.

Fetcher

Provides an upstream source for multiple packages. Exposes:

Hackage

An implementation of Fetcher for downloading packages from HackageDB - The Haskell Package Repository

Possible Fetcher Types

There are many sources for packages, including Sourceforge, Launchpad, Fedora Hosted, CPan, Python Cheese Shop, and many many others. Implementing Fetchers is easy, so lets see some more.

Port

A Port is analogous to a BSD or Gentoo Port. It combines the above components into a single Module that has an intellegent overview of the whole situation. It can be used to download, setup, configure, install, and package any type of package, so long there is a port to handle it.

It currently exposes:

NOTE: This will very likely turn into a utility function later on.

HaskellPort

This will download any package that is hosted on HackageDB or at darcs.haskell.org, test build it, install it, and generate spec files for it. It combines Hackage, Cabal, Darcs, and SourceBall.

Possible Port Types

Theoretically, there could be one port for every package that is being managed. Many do have in fact their own idiosyncronacies that do need to be managed. Despite that, many components in packages are standardized out of other common systems. One goal of ports is to be able to use as much generic code as possible. For example, a KDE port might use a KDEFetcher, CMakeBuilder, SVNSource, and SourceBall. We may want to look into other ways to declaratively define Ports, and even include them as a repository somewhere.

Build

A wrapper for rpmbuild. It subclasses Directory, and takes an rpmdev-tree (such as ~/rpmbuild, or /usr/src/redhat) as the directory. It can then perform common rpmbuild operations on Packages.

It exposes:

Mock

Mock is a simple subclass of a Module, it is merely a worker module with no state of its own. It uses a Profile for all the stateful bits. It does one thing simplemindedly, it builds a source RPM in mock given some profile and rpmdev-tree for doing temporary work. The initializer takes a Profile and Build

It exposes:

Possible Mock Types

Mock is a bit specific purpose. We may want to define a better clean room type builder. There are many technologies for distributing and cleanly building packages, including Mock, Koji, and many other frameworks. We may want to create a generic RPMBuilder, that Mock is an implementation of. For example, via a single switch, we could send a package to Mock on a local system, do a scratch build in Koji, or inject it into a VM that can be sent across a grid using Condor.

Profile

Profile is a profile to be used in Mock. It manages seperate repos of packages built in mock before to be used as a base, version information, vis-a-vis which version of Fedora to use, and other important information about the build profile. It uses its own directory store mock configurations and results from mock.

It exposes the methods:

And properties:

Utility Functions

Coding Guidelines

The following basic rules must be applied. Exceptions can be granted for any reason, provided there's a good reason.

@property
def spec_file(self):
    '''returns the name of the spec file as it should be accordingto
    fedora guidelines, good for double checking'''
    return self.pkg_name + '.spec'

@property
def pkg_name(self):
    '''canonical name of the package in a source repository'''
    return self.cfg['pkg_name']

Submission Guidelines

All patches are welcome. The best way to submit patches initially is via email or mailing lists, or sending a pull request from another git repo. In order to get write access to the public repo, there is a one drink minimum. To demonstrate understanding of the Coding Guidelines, the submitter must have at least one other patch approved before gaining write access. This will ensure that the coder has had ample time to learn the simple guidelines.