├── install.sh ├── systemd └── pods-compose.service ├── pods-compose.ini ├── README.md ├── pods-compose.py └── LICENSE /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | service="pods-compose.service" 4 | 5 | cp -v systemd/${service} /etc/systemd/system/ 6 | cp -v pods-compose.ini /usr/local/bin/ 7 | cp -v pods-compose.py /usr/local/bin/pods-compose 8 | -------------------------------------------------------------------------------- /systemd/pods-compose.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Deploy all my pods 3 | After=var.mount var-cache.mount usr.mount usr-share.mount 4 | 5 | [Service] 6 | Type=oneshot 7 | RemainAfterExit=yes 8 | ExecStart=/usr/bin/python3 /usr/local/bin/pods-compose --start 9 | ExecStop=/usr/bin/python3 /usr/local/bin/pods-compose --stop 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /pods-compose.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | kubedir = /var/lib/pods-compose/kube 3 | basedir = /path/to/parent/of/build/contexts 4 | default_tag = prod 5 | networks = podman 6 | 7 | [builds] 8 | #image_php = example/php74-fpm-debian:%(default_tag)s,%(basedir)s/containerfiles/php74-fpm/php-upstream-debian 9 | #image_sql = example/php74-sql-debian:%(default_tag)s,%(basedir)s/containerfiles/sql/sql-upstream-debian 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pods-compose 2 | 3 | **[Update 02-22-2022] This project is not maintained anymore. If you are looking for an alternative, have a look at [podman-compose](https://github.com/containers/podman-compose) or use [Ansible with ansible-podman-collections](https://github.com/containers/ansible-podman-collections).** 4 | 5 | A wrapper around [Podman](https://github.com/containers/libpod) CLI to provide similar experince for PODs as docker-compose gives to services. 6 | 7 | It has a [configuration file](#configuration-of-pods-compose) to store image build descriptions and other settings. 8 | 9 | # Synopsis 10 | 11 | Usage: **pods-compose** [*options*] [pod] 12 | 13 | # Options: 14 | A wrapper around Podman's cli API to mimic basic behavior of docker-compose 15 | ``` 16 | optional arguments: 17 | -h, --help show this help message and exit 18 | --build Build container images defined in pods-compose.ini 19 | --down [DOWN] Destroy existing pod(s) and container(s) 20 | --generate [GENERATE] 21 | Generate Kubernetes Pod YAMLs 22 | --ps Show status of pods and containers 23 | --restart [RESTART] Restart running pod(s) 24 | --start [START] Start existing pod(s) 25 | --stop [STOP] Stop existing pod(s) 26 | --up [UP] Create pods and containers from Kubernetes Pod YAMLs 27 | ``` 28 | 29 | # Comparison with docker-compose 30 | 31 | This script tries to mimic some of docker-compose's features to minimize the learning curve of new users. 32 | 33 | It is not a replacement for docker-compose. If you are looking for a replacement for docker-compose then check out [podman-compose](https://github.com/containers/podman-compose). 34 | 35 | Here are the similarities and differences between **docker-compose** and **pods-compose**. 36 | 37 | | | pods-compose | docker-compose | 38 | | --- | --- | --- | 39 | | Deploy pod(s) | --up [POD] | up [SERVICE] | 40 | | Tear down pod(s) | --down [POD] | down [SERVICE] | 41 | | Start pod(s) | --start [POD] | start [SERVICE] | 42 | | Stop pod(s) | --stop [POD] | stop [SERVICE] | 43 | | Restart pod(s) | --restart [POD] | restart [SERVICE] | 44 | | Build all container images | --build | build | 45 | | Status of pods and containers | --ps | ps | 46 | | Generate Kubernetes Pod YAML(s) | --generate [POD] | | 47 | 48 | ## Install 49 | 50 | tl;dr: Adjust *kubedir* in **pods-compose.ini** then execute [install.sh](install.sh). This directory should be writable by the running user. 51 | 52 | ### Configuration of pods-compose 53 | The tool itself has a configuration file to set a couple of settings. 54 | 55 | - *kubedir* - A permanent directory where the generated YAMLs will be placed. 56 | - *basedir* - The parent directory of image build contexts. 57 | - *default_tag* - Simplifies maintaining generated YAMLs. Do not set it to "latest". Defaults to 'prod'. 58 | 59 | The configuration file is placed next to the executable and called **pods-compose.ini**. 60 | 61 | #### Define which images should be built 62 | 63 | In [pods-compose.ini](pods-compose.ini) you can add image build descriptions according to the commented examples. 64 | 65 | You just need to make sure that all has the prefix of **"image_"**. The value will be separated by a single comma to TAG and CONTEXT. CONTEXT is expected to be a directory and must contain either a Dockerfile or a Containerfile. 66 | 67 | #### Autostart of pods and containers upon system reboot 68 | As Podman is daemonless, there is no system daemon which should start pods and containers upon reboot. 69 | To achieve that one can create a systemd service unit to start the deployment automatically. An example of [pods-compose.service](systemd/pods-compose.service) is included in the repo. 70 | 71 | The provided [install.sh](install.sh) script will install it for you. In order to systemd recognize it, you have to run these commands. 72 | ``` 73 | # systemctl daemon-reload 74 | # systemctl enable pods-compose.service 75 | ``` 76 | 77 | ##### Overriding mounts 78 | Should your deployment depends on other mount points (like NFS, 9p) to be available, then add them to an systemd unit override. 79 | 80 | You can do it like this: 81 | ``` 82 | # systemctl edit pods-compose.service 83 | 84 | [Unit] 85 | After= srv.mount 86 | ``` 87 | 88 | ## Deploying pods and containers 89 | 90 | **docker-compose** uses a YAML file for describing and managing services. Normally you have create one manually. 91 | 92 | **pods-compose** also relies on YAML files for describing pods and containers, however you do not have to create them manually. 93 | 94 | 1. You need to [create pods and containers](#1-describe-pods-and-containers) using the command line interface of Podman. The CLI is well documented and mostly behaves the same way as [docker CLI](https://podman.io/whatis.html) does. 95 | 2. Then use pod-compose to generate [Kubernetes Pod YAML](https://github.com/containers/libpod/blob/master/docs/source/markdown/podman-generate-kube.1.md) files for each pod. 96 | 3. The YAMLs will be used to deploy your pods and containers with '**--up**'. 97 | 98 | ### 1. Describe pods and containers 99 | 100 | Although you can do this manually, the following scripts will show an example of deploying two pods containing Nextcloud (and its dependencies) and a reverse proxy. Notice how similar the CLI arguments are compared to Docker's CLI arguments. 101 | 102 | ```bash 103 | #!/bin/bash 104 | 105 | podname="nextcloud" 106 | publish_ip="10.88.0.1" 107 | 108 | podman pod rm -f ${podname} 109 | podman pod create --name ${podname} --hostname ${podname} -p ${publish_ip}:8080:80 110 | 111 | podman run -d --name nextcloud-php --hostname nextcloud-php --expose 9000 --pod ${podname} \ 112 | -v /srv/www/nextcloud:/var/www \ 113 | localhost/example/php74-fpm-debian:prod 114 | 115 | podman run -d --name nextcloud-www --hostname nextcloud-www --expose 80 --pod ${podname} \ 116 | -v /var/containers/config/nginx/backend_nextcloud/conf.d/nextcloud.conf:/etc/nginx/conf.d/default.conf:ro \ 117 | -v /var/containers/config/nginx/backend_nextcloud/nginx.conf:/etc/nginx/nginx.conf:ro \ 118 | -v /srv/www/nextcloud:/var/www \ 119 | nginx:1.16 120 | 121 | podman run -d --name nextcloud-redis --hostname nextcloud-redis --expose 6379 --pod ${podname} \ 122 | -v /var/containers/volumes/redis:/data \ 123 | redis:5 124 | ``` 125 | And another pod with a single Nginx container as a reverse proxy. 126 | 127 | ```bash 128 | #!/bin/bash 129 | 130 | podname="reverse_proxy" 131 | publish_ip="1.2.3.4" 132 | 133 | podman pod rm -f ${podname} 134 | podman pod create --name ${podname} --hostname ${podname} -p ${publish_ip}:80:80 -p ${publish_ip}:443:443 135 | 136 | podman run -d --name proxy --hostname proxy --expose 80 --expose 443 --pod ${podname} \ 137 | -v /var/containers/config/nginx/proxy/conf.d/reverse_proxy.conf:/etc/nginx/conf.d/default.conf:ro \ 138 | nginx:1.16 139 | ``` 140 | 141 | You can read more about **publish IPs** is the following blog: [Convert docker-compose services to pods with Podman](https://balagetech.com/convert-docker-compose-services-to-pods/) 142 | ### 2. Generate Kubernetes Pod YAML definitions 143 | 144 | Once you have your pods defined, let's create a snapshot of their description in YAMLs. 145 | 146 | ```bash 147 | # pods-compose --generate 148 | Generating YAML file for pod 'nextcloud' 149 | Generating YAML file for pod 'reverse_proxy' 150 | ``` 151 | 152 | ### 3. Deploy and destroy 153 | 154 | You may want to throw away your local pods to avoid any issues and simply rely on the generated YAMLs. 155 | 156 | ```bash 157 | # pods-compose --down 158 | Tear down pods 'nextcloud reverse_proxy' 159 | ``` 160 | 161 | ```bash 162 | # pods-compose --up 163 | Replay Kubernetes YAML for pod 'nextcloud' 164 | Replay Kubernetes YAML for pod 'reverse_proxy' 165 | ``` 166 | 167 | -------------------------------------------------------------------------------- /pods-compose.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # Make sure your only locally existing images do not have :latest tag as it will try to alway pull and fail 4 | # during --up 5 | # https://github.com/containers/libpod/blob/1be61789151c80d46c0c4b75a02fb23a6937df7b/pkg/adapter/pods.go#L709 6 | 7 | from subprocess import Popen, PIPE 8 | import sys 9 | import argparse 10 | import os 11 | import os.path 12 | import configparser 13 | 14 | INIFILE = 'pods-compose.ini' 15 | DOTFILE = '.'+ INIFILE 16 | HOME = os.path.expandvars("$HOME") 17 | ETC = "/etc/pods-compose" 18 | SCRIPT_LOC = os.path.dirname(os.path.abspath(__file__)) 19 | for location in HOME, ETC, SCRIPT_LOC: 20 | CONFIGFILE = os.path.join(location, INIFILE) 21 | if os.path.exists(CONFIGFILE): break 22 | if location == HOME: 23 | CONFIGFILE = os.path.join(location, DOTFILE) 24 | if os.path.exists(CONFIGFILE): break 25 | 26 | config = configparser.ConfigParser() 27 | config.read(CONFIGFILE) 28 | 29 | if __name__ == "__main__": 30 | 31 | parser = argparse.ArgumentParser( 32 | description="A wrapper around podman's cli API to mimic basic behavior of docker-compose") 33 | 34 | parser.add_argument( 35 | "--build", help="Build container images defined in pods-compose.ini", action="store_true") 36 | parser.add_argument("--down", nargs="?", const="all", 37 | help="Destroy existing pod(s) and container(s)") 38 | parser.add_argument("--generate", nargs="?", const="all", 39 | help="Generate Kubernetes Pod YAMLs") 40 | parser.add_argument( 41 | "--ps", help="Show status of pods and containers", action="store_true") 42 | parser.add_argument("--restart", nargs="?", const="all", 43 | help="Restart running pod(s)") 44 | parser.add_argument("--start", nargs="?", const="all", 45 | help="Start existing pod(s)") 46 | parser.add_argument("--stop", nargs="?", const="all", 47 | help="Stop existing pod(s)") 48 | parser.add_argument("--up", nargs="?", const="all", 49 | help="Create pods and containers from Kubernetes Pod YAMLs") 50 | #parser.add_argument("--update", nargs="?", const="all", help="update container images") 51 | 52 | args = parser.parse_args() 53 | 54 | ####### skip ####### 55 | 56 | def get_containerimage_configs(): 57 | import re 58 | images = [] 59 | p = re.compile('^image_.+$') 60 | # 'builds' should contain config items starting with "image_" 61 | # they represent a list, first item is a tag, second is the directory of the image description (Containerfile) 62 | for key in config['builds']: 63 | if p.match(key): 64 | images.append(config['builds'][key]) 65 | 66 | return images 67 | 68 | def runcmd(text, cmd, echo): 69 | # https://stackoverflow.com/questions/2715847/read-streaming-input-from-subprocess-communicate 70 | if echo in ['Y', 'Yes', 'yes']: 71 | print(text) 72 | stdout = [] 73 | with Popen([cmd], 74 | shell=True, 75 | stdout=PIPE, 76 | bufsize=1, 77 | universal_newlines=True 78 | ) as process: 79 | 80 | for line in process.stdout: 81 | if echo in ['Y', 'Yes', 'yes']: 82 | print(line, end='') 83 | 84 | line = line.rstrip() 85 | stdout.append(line) 86 | 87 | return stdout 88 | 89 | def get_pods_by_name(): 90 | pods = runcmd("Existing pods:", 91 | '/usr/bin/podman pod ls --format "{{.Name}}"', "no") 92 | return pods 93 | 94 | def find_yamls_in_dir(directory): 95 | iterator = os.scandir(path=directory) 96 | yamls = [] 97 | for DirEntry in iterator: 98 | filename, extension = os.path.splitext(DirEntry.name) 99 | if extension == ".yml": 100 | yamls.append(DirEntry.name) 101 | 102 | return yamls 103 | 104 | ####### return to argparse ####### 105 | 106 | if (args.ps): 107 | runcmd("Status of running pods:", '/usr/bin/podman pod ls', "yes") 108 | runcmd("Status of running containers:", 109 | "/usr/bin/podman ps -p --format 'table {{.ID}} {{.Names}} {{.PodName}} {{.Status}}'", "yes") 110 | 111 | elif (args.start): 112 | pods = ' '.join(get_pods_by_name() 113 | ) if args.start == "all" else args.start 114 | runcmd("Starting pods '" + pods + "'", 115 | "/usr/bin/podman pod start " + pods, "yes") 116 | 117 | elif (args.stop): 118 | pods = ' '.join(get_pods_by_name() 119 | ) if args.stop == "all" else args.stop 120 | runcmd("Stopping pods '" + pods + "'", 121 | "/usr/bin/podman pod stop " + pods, "yes") 122 | 123 | elif (args.restart): 124 | pods = ' '.join(get_pods_by_name() 125 | ) if args.restart == "all" else args.restart 126 | runcmd("Restarting pods '" + pods + "'", 127 | "/usr/bin/podman pod restart " + pods, "yes") 128 | 129 | elif (args.down): 130 | pods = ' '.join(get_pods_by_name() 131 | ) if args.down == "all" else args.down 132 | runcmd("Tear down pods '" + pods + "'", 133 | "/usr/bin/podman pod rm -f " + pods, "yes") 134 | 135 | elif (args.build): 136 | images = get_containerimage_configs() 137 | for image in images: 138 | tag, context = image.split(',') 139 | # FIXME input validation on tag is missing 140 | if os.path.exists(context): 141 | runcmd("Building image '" + tag + "' from context " + context, 142 | "/usr/bin/podman build -t " + tag + " " + context, "yes") 143 | else: 144 | print("Context does not exist: {}".format(context)) 145 | sys.exit(1) 146 | 147 | elif (args.up): 148 | from pathlib import Path 149 | kubedir = Path(config['DEFAULT']['kubedir']) 150 | kubes = find_yamls_in_dir(kubedir) 151 | if not kubes: 152 | print("No Kubernetes YAMLs found in directory: {}".format(kubedir)) 153 | 154 | # TODO if replay fails then delete the pod anyway 155 | 156 | def _up_kube(kube): 157 | kubeyml = kubedir / kube 158 | networks = config['DEFAULT']['networks'] 159 | netcmd = str() 160 | if networks: 161 | netcmd = " --network " + networks 162 | if kubeyml.exists(): 163 | rc = runcmd("Replay Kubernetes YAML for pod '" + kube + 164 | "'", "/usr/bin/podman play kube " + str(kubeyml) + netcmd, "yes") 165 | return rc 166 | 167 | # podman play kube only accepts a single yaml file, so we have to iterate 168 | if args.up == "all": 169 | for kube in kubes: 170 | _up_kube(kube) 171 | else: 172 | # just provide the pod's name and I will add the extension 173 | kube = args.up + ".yml" 174 | _up_kube(kube) 175 | 176 | elif (args.generate): 177 | from pathlib import Path 178 | kubedir = Path(config['DEFAULT']['kubedir']) 179 | # Check post for limitations: https://developers.redhat.com/blog/2019/01/29/podman-kubernetes-yaml/ 180 | 181 | if not kubedir.is_dir(): 182 | kubedir.mkdir(mode=0o755, parents=True) 183 | 184 | def _generate_kube(pod): 185 | podyml = pod + ".yml" 186 | kubename = kubedir / podyml 187 | if kubename.exists(): 188 | kubename.unlink() 189 | rc = runcmd("Generating YAML file for pod '" + pod + "'", 190 | "/usr/bin/podman generate kube -f " + str(kubename) + " " + str(pod), "yes") 191 | return rc 192 | 193 | # podman generate kube only accepts a single pod or container, so we have to iterate 194 | if args.generate == "all": 195 | pods = get_pods_by_name() 196 | for pod in pods: 197 | _generate_kube(pod) 198 | else: 199 | pod = args.generate 200 | _generate_kube(pod) 201 | else: 202 | print(args) 203 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 7 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA 8 | 9 | Everyone is permitted to copy and distribute verbatim copies of this license 10 | document, but changing it is not allowed. 11 | 12 | Preamble 13 | 14 | The licenses for most software are designed to take away your freedom to share 15 | and change it. By contrast, the GNU General Public License is intended to 16 | guarantee your freedom to share and change free software--to make sure the 17 | software is free for all its users. This General Public License applies to 18 | most of the Free Software Foundation's software and to any other program whose 19 | authors commit to using it. (Some other Free Software Foundation software 20 | is covered by the GNU Lesser General Public License instead.) You can apply 21 | it to your programs, too. 22 | 23 | When we speak of free software, we are referring to freedom, not price. Our 24 | General Public Licenses are designed to make sure that you have the freedom 25 | to distribute copies of free software (and charge for this service if you 26 | wish), that you receive source code or can get it if you want it, that you 27 | can change the software or use pieces of it in new free programs; and that 28 | you know you can do these things. 29 | 30 | To protect your rights, we need to make restrictions that forbid anyone to 31 | deny you these rights or to ask you to surrender the rights. These restrictions 32 | translate to certain responsibilities for you if you distribute copies of 33 | the software, or if you modify it. 34 | 35 | For example, if you distribute copies of such a program, whether gratis or 36 | for a fee, you must give the recipients all the rights that you have. You 37 | must make sure that they, too, receive or can get the source code. And you 38 | must show them these terms so they know their rights. 39 | 40 | We protect your rights with two steps: (1) copyright the software, and (2) 41 | offer you this license which gives you legal permission to copy, distribute 42 | and/or modify the software. 43 | 44 | Also, for each author's protection and ours, we want to make certain that 45 | everyone understands that there is no warranty for this free software. If 46 | the software is modified by someone else and passed on, we want its recipients 47 | to know that what they have is not the original, so that any problems introduced 48 | by others will not reflect on the original authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software patents. We 51 | wish to avoid the danger that redistributors of a free program will individually 52 | obtain patent licenses, in effect making the program proprietary. To prevent 53 | this, we have made it clear that any patent must be licensed for everyone's 54 | free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and modification 57 | follow. 58 | 59 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 60 | 61 | 0. This License applies to any program or other work which contains a notice 62 | placed by the copyright holder saying it may be distributed under the terms 63 | of this General Public License. The "Program", below, refers to any such program 64 | or work, and a "work based on the Program" means either the Program or any 65 | derivative work under copyright law: that is to say, a work containing the 66 | Program or a portion of it, either verbatim or with modifications and/or translated 67 | into another language. (Hereinafter, translation is included without limitation 68 | in the term "modification".) Each licensee is addressed as "you". 69 | 70 | Activities other than copying, distribution and modification are not covered 71 | by this License; they are outside its scope. The act of running the Program 72 | is not restricted, and the output from the Program is covered only if its 73 | contents constitute a work based on the Program (independent of having been 74 | made by running the Program). Whether that is true depends on what the Program 75 | does. 76 | 77 | 1. You may copy and distribute verbatim copies of the Program's source code 78 | as you receive it, in any medium, provided that you conspicuously and appropriately 79 | publish on each copy an appropriate copyright notice and disclaimer of warranty; 80 | keep intact all the notices that refer to this License and to the absence 81 | of any warranty; and give any other recipients of the Program a copy of this 82 | License along with the Program. 83 | 84 | You may charge a fee for the physical act of transferring a copy, and you 85 | may at your option offer warranty protection in exchange for a fee. 86 | 87 | 2. You may modify your copy or copies of the Program or any portion of it, 88 | thus forming a work based on the Program, and copy and distribute such modifications 89 | or work under the terms of Section 1 above, provided that you also meet all 90 | of these conditions: 91 | 92 | a) You must cause the modified files to carry prominent notices stating that 93 | you changed the files and the date of any change. 94 | 95 | b) You must cause any work that you distribute or publish, that in whole or 96 | in part contains or is derived from the Program or any part thereof, to be 97 | licensed as a whole at no charge to all third parties under the terms of this 98 | License. 99 | 100 | c) If the modified program normally reads commands interactively when run, 101 | you must cause it, when started running for such interactive use in the most 102 | ordinary way, to print or display an announcement including an appropriate 103 | copyright notice and a notice that there is no warranty (or else, saying that 104 | you provide a warranty) and that users may redistribute the program under 105 | these conditions, and telling the user how to view a copy of this License. 106 | (Exception: if the Program itself is interactive but does not normally print 107 | such an announcement, your work based on the Program is not required to print 108 | an announcement.) 109 | 110 | These requirements apply to the modified work as a whole. If identifiable 111 | sections of that work are not derived from the Program, and can be reasonably 112 | considered independent and separate works in themselves, then this License, 113 | and its terms, do not apply to those sections when you distribute them as 114 | separate works. But when you distribute the same sections as part of a whole 115 | which is a work based on the Program, the distribution of the whole must be 116 | on the terms of this License, whose permissions for other licensees extend 117 | to the entire whole, and thus to each and every part regardless of who wrote 118 | it. 119 | 120 | Thus, it is not the intent of this section to claim rights or contest your 121 | rights to work written entirely by you; rather, the intent is to exercise 122 | the right to control the distribution of derivative or collective works based 123 | on the Program. 124 | 125 | In addition, mere aggregation of another work not based on the Program with 126 | the Program (or with a work based on the Program) on a volume of a storage 127 | or distribution medium does not bring the other work under the scope of this 128 | License. 129 | 130 | 3. You may copy and distribute the Program (or a work based on it, under Section 131 | 2) in object code or executable form under the terms of Sections 1 and 2 above 132 | provided that you also do one of the following: 133 | 134 | a) Accompany it with the complete corresponding machine-readable source code, 135 | which must be distributed under the terms of Sections 1 and 2 above on a medium 136 | customarily used for software interchange; or, 137 | 138 | b) Accompany it with a written offer, valid for at least three years, to give 139 | any third party, for a charge no more than your cost of physically performing 140 | source distribution, a complete machine-readable copy of the corresponding 141 | source code, to be distributed under the terms of Sections 1 and 2 above on 142 | a medium customarily used for software interchange; or, 143 | 144 | c) Accompany it with the information you received as to the offer to distribute 145 | corresponding source code. (This alternative is allowed only for noncommercial 146 | distribution and only if you received the program in object code or executable 147 | form with such an offer, in accord with Subsection b above.) 148 | 149 | The source code for a work means the preferred form of the work for making 150 | modifications to it. For an executable work, complete source code means all 151 | the source code for all modules it contains, plus any associated interface 152 | definition files, plus the scripts used to control compilation and installation 153 | of the executable. However, as a special exception, the source code distributed 154 | need not include anything that is normally distributed (in either source or 155 | binary form) with the major components (compiler, kernel, and so on) of the 156 | operating system on which the executable runs, unless that component itself 157 | accompanies the executable. 158 | 159 | If distribution of executable or object code is made by offering access to 160 | copy from a designated place, then offering equivalent access to copy the 161 | source code from the same place counts as distribution of the source code, 162 | even though third parties are not compelled to copy the source along with 163 | the object code. 164 | 165 | 4. You may not copy, modify, sublicense, or distribute the Program except 166 | as expressly provided under this License. Any attempt otherwise to copy, modify, 167 | sublicense or distribute the Program is void, and will automatically terminate 168 | your rights under this License. However, parties who have received copies, 169 | or rights, from you under this License will not have their licenses terminated 170 | so long as such parties remain in full compliance. 171 | 172 | 5. You are not required to accept this License, since you have not signed 173 | it. However, nothing else grants you permission to modify or distribute the 174 | Program or its derivative works. These actions are prohibited by law if you 175 | do not accept this License. Therefore, by modifying or distributing the Program 176 | (or any work based on the Program), you indicate your acceptance of this License 177 | to do so, and all its terms and conditions for copying, distributing or modifying 178 | the Program or works based on it. 179 | 180 | 6. Each time you redistribute the Program (or any work based on the Program), 181 | the recipient automatically receives a license from the original licensor 182 | to copy, distribute or modify the Program subject to these terms and conditions. 183 | You may not impose any further restrictions on the recipients' exercise of 184 | the rights granted herein. You are not responsible for enforcing compliance 185 | by third parties to this License. 186 | 187 | 7. If, as a consequence of a court judgment or allegation of patent infringement 188 | or for any other reason (not limited to patent issues), conditions are imposed 189 | on you (whether by court order, agreement or otherwise) that contradict the 190 | conditions of this License, they do not excuse you from the conditions of 191 | this License. If you cannot distribute so as to satisfy simultaneously your 192 | obligations under this License and any other pertinent obligations, then as 193 | a consequence you may not distribute the Program at all. For example, if a 194 | patent license would not permit royalty-free redistribution of the Program 195 | by all those who receive copies directly or indirectly through you, then the 196 | only way you could satisfy both it and this License would be to refrain entirely 197 | from distribution of the Program. 198 | 199 | If any portion of this section is held invalid or unenforceable under any 200 | particular circumstance, the balance of the section is intended to apply and 201 | the section as a whole is intended to apply in other circumstances. 202 | 203 | It is not the purpose of this section to induce you to infringe any patents 204 | or other property right claims or to contest validity of any such claims; 205 | this section has the sole purpose of protecting the integrity of the free 206 | software distribution system, which is implemented by public license practices. 207 | Many people have made generous contributions to the wide range of software 208 | distributed through that system in reliance on consistent application of that 209 | system; it is up to the author/donor to decide if he or she is willing to 210 | distribute software through any other system and a licensee cannot impose 211 | that choice. 212 | 213 | This section is intended to make thoroughly clear what is believed to be a 214 | consequence of the rest of this License. 215 | 216 | 8. If the distribution and/or use of the Program is restricted in certain 217 | countries either by patents or by copyrighted interfaces, the original copyright 218 | holder who places the Program under this License may add an explicit geographical 219 | distribution limitation excluding those countries, so that distribution is 220 | permitted only in or among countries not thus excluded. In such case, this 221 | License incorporates the limitation as if written in the body of this License. 222 | 223 | 9. The Free Software Foundation may publish revised and/or new versions of 224 | the General Public License from time to time. Such new versions will be similar 225 | in spirit to the present version, but may differ in detail to address new 226 | problems or concerns. 227 | 228 | Each version is given a distinguishing version number. If the Program specifies 229 | a version number of this License which applies to it and "any later version", 230 | you have the option of following the terms and conditions either of that version 231 | or of any later version published by the Free Software Foundation. If the 232 | Program does not specify a version number of this License, you may choose 233 | any version ever published by the Free Software Foundation. 234 | 235 | 10. If you wish to incorporate parts of the Program into other free programs 236 | whose distribution conditions are different, write to the author to ask for 237 | permission. For software which is copyrighted by the Free Software Foundation, 238 | write to the Free Software Foundation; we sometimes make exceptions for this. 239 | Our decision will be guided by the two goals of preserving the free status 240 | of all derivatives of our free software and of promoting the sharing and reuse 241 | of software generally. 242 | 243 | NO WARRANTY 244 | 245 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR 246 | THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE 247 | STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM 248 | "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, 249 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 250 | FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE 251 | OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME 252 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 253 | 254 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 255 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 256 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 257 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE 258 | OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA 259 | OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES 260 | OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH 261 | HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 262 | END OF TERMS AND CONDITIONS 263 | 264 | How to Apply These Terms to Your New Programs 265 | 266 | If you develop a new program, and you want it to be of the greatest possible 267 | use to the public, the best way to achieve this is to make it free software 268 | which everyone can redistribute and change under these terms. 269 | 270 | To do so, attach the following notices to the program. It is safest to attach 271 | them to the start of each source file to most effectively convey the exclusion 272 | of warranty; and each file should have at least the "copyright" line and a 273 | pointer to where the full notice is found. 274 | 275 | 276 | 277 | Copyright (C) 278 | 279 | This program is free software; you can redistribute it and/or modify it under 280 | the terms of the GNU General Public License as published by the Free Software 281 | Foundation; either version 2 of the License, or (at your option) any later 282 | version. 283 | 284 | This program is distributed in the hope that it will be useful, but WITHOUT 285 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 286 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 287 | 288 | You should have received a copy of the GNU General Public License along with 289 | this program; if not, write to the Free Software Foundation, Inc., 51 Franklin 290 | Street, Fifth Floor, Boston, MA 02110-1301 , USA. 291 | 292 | Also add information on how to contact you by electronic and paper mail. 293 | 294 | If the program is interactive, make it output a short notice like this when 295 | it starts in an interactive mode: 296 | 297 | Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 298 | with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, 299 | and you are welcome to redistribute it under certain conditions; type `show 300 | c' for details. 301 | 302 | The hypothetical commands `show w' and `show c' should show the appropriate 303 | parts of the General Public License. Of course, the commands you use may be 304 | called something other than `show w' and `show c'; they could even be mouse-clicks 305 | or menu items--whatever suits your program. 306 | 307 | You should also get your employer (if you work as a programmer) or your school, 308 | if any, to sign a "copyright disclaimer" for the program, if necessary. Here 309 | is a sample; alter the names: 310 | 311 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' 312 | (which makes passes at compilers) written by James Hacker. 313 | 314 | < signature of Ty Coon > , 1 April 1989 Ty Coon, President of Vice This General 315 | Public License does not permit incorporating your program into proprietary 316 | programs. If your program is a subroutine library, you may consider it more 317 | useful to permit linking proprietary applications with the library. If this 318 | is what you want to do, use the GNU Lesser General Public License instead 319 | of this License. 320 | --------------------------------------------------------------------------------