本文整理汇总了Golang中github.com/docker/swarmkit/manager/state/store.GetService函数的典型用法代码示例。如果您正苦于以下问题:Golang GetService函数的具体用法?Golang GetService怎么用?Golang GetService使用的例子?那么恭喜您, 这里精选的函数代码示例或许可以为您提供帮助。
在下文中一共展示了GetService函数的20个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于我们的系统推荐出更棒的Golang代码示例。
示例1: UpdateService
// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
if request.ServiceID == "" || request.ServiceVersion == nil {
return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
}
if err := validateServiceSpec(request.Spec); err != nil {
return nil, err
}
var service *api.Service
s.store.View(func(tx store.ReadTx) {
service = store.GetService(tx, request.ServiceID)
})
if service == nil {
return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
}
if request.Spec.Endpoint != nil && !reflect.DeepEqual(request.Spec.Endpoint, service.Spec.Endpoint) {
if err := s.checkPortConflicts(request.Spec, request.ServiceID); err != nil {
return nil, err
}
}
err := s.store.Update(func(tx store.Tx) error {
service = store.GetService(tx, request.ServiceID)
if service == nil {
return nil
}
// temporary disable network update
if request.Spec != nil && !reflect.DeepEqual(request.Spec.Networks, service.Spec.Networks) {
return errNetworkUpdateNotSupported
}
// orchestrator is designed to be stateless, so it should not deal
// with service mode change (comparing current config with previous config).
// proper way to change service mode is to delete and re-add.
if request.Spec != nil && reflect.TypeOf(service.Spec.Mode) != reflect.TypeOf(request.Spec.Mode) {
return errModeChangeNotAllowed
}
service.Meta.Version = *request.ServiceVersion
service.Spec = *request.Spec.Copy()
// Reset update status
service.UpdateStatus = nil
return store.UpdateService(tx, service)
})
if err != nil {
return nil, err
}
if service == nil {
return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
}
return &api.UpdateServiceResponse{
Service: service,
}, nil
}
开发者ID:maxim28,项目名称:docker,代码行数:61,代码来源:service.go
示例2: completeUpdate
func (u *Updater) completeUpdate(ctx context.Context, serviceID string) {
log.G(ctx).Debugf("update of service %s complete", serviceID)
err := u.store.Update(func(tx store.Tx) error {
service := store.GetService(tx, serviceID)
if service == nil {
return nil
}
if service.UpdateStatus == nil {
// The service was changed since we started this update
return nil
}
if service.UpdateStatus.State == api.UpdateStatus_ROLLBACK_STARTED {
service.UpdateStatus.State = api.UpdateStatus_ROLLBACK_COMPLETED
service.UpdateStatus.Message = "rollback completed"
} else {
service.UpdateStatus.State = api.UpdateStatus_COMPLETED
service.UpdateStatus.Message = "update completed"
}
service.UpdateStatus.CompletedAt = ptypes.MustTimestampProto(time.Now())
return store.UpdateService(tx, service)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to mark update of service %s complete", serviceID)
}
}
开发者ID:CWSpear,项目名称:docker,代码行数:28,代码来源:updater.go
示例3: UpdateService
// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
if request.ServiceID == "" || request.ServiceVersion == nil {
return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
}
if err := validateServiceSpec(request.Spec); err != nil {
return nil, err
}
var service *api.Service
err := s.store.Update(func(tx store.Tx) error {
service = store.GetService(tx, request.ServiceID)
if service == nil {
return nil
}
service.Meta.Version = *request.ServiceVersion
service.Spec = *request.Spec.Copy()
return store.UpdateService(tx, service)
})
if err != nil {
return nil, err
}
if service == nil {
return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
}
return &api.UpdateServiceResponse{
Service: service,
}, nil
}
开发者ID:amitshukla,项目名称:docker,代码行数:33,代码来源:service.go
示例4: handleTaskChange
func (r *Orchestrator) handleTaskChange(ctx context.Context, t *api.Task) {
// If we already set the desired state past TaskStateRunning, there is no
// further action necessary.
if t.DesiredState > api.TaskStateRunning {
return
}
var (
n *api.Node
service *api.Service
)
r.store.View(func(tx store.ReadTx) {
if t.NodeID != "" {
n = store.GetNode(tx, t.NodeID)
}
if t.ServiceID != "" {
service = store.GetService(tx, t.ServiceID)
}
})
if !orchestrator.IsReplicatedService(service) {
return
}
if t.Status.State > api.TaskStateRunning ||
(t.NodeID != "" && invalidNode(n)) {
r.restartTasks[t.ID] = struct{}{}
}
}
开发者ID:yongtang,项目名称:swarmkit,代码行数:29,代码来源:tasks.go
示例5: waitRestart
func (r *Supervisor) waitRestart(ctx context.Context, oldDelay *delayedStart, cluster *api.Cluster, taskID string) {
// Wait for the last restart delay to elapse.
select {
case <-oldDelay.doneCh:
case <-ctx.Done():
return
}
// Start the next restart
err := r.store.Update(func(tx store.Tx) error {
t := store.GetTask(tx, taskID)
if t == nil {
return nil
}
if t.DesiredState > api.TaskStateRunning {
return nil
}
service := store.GetService(tx, t.ServiceID)
if service == nil {
return nil
}
return r.Restart(ctx, tx, cluster, service, *t)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to restart task after waiting for previous restart")
}
}
开发者ID:Mic92,项目名称:docker,代码行数:28,代码来源:restart.go
示例6: pauseUpdate
func (u *Updater) pauseUpdate(ctx context.Context, serviceID, message string) {
log.G(ctx).Debugf("pausing update of service %s", serviceID)
err := u.store.Update(func(tx store.Tx) error {
service := store.GetService(tx, serviceID)
if service == nil {
return nil
}
if service.UpdateStatus == nil {
// The service was updated since we started this update
return nil
}
if service.UpdateStatus.State == api.UpdateStatus_ROLLBACK_STARTED {
service.UpdateStatus.State = api.UpdateStatus_ROLLBACK_PAUSED
} else {
service.UpdateStatus.State = api.UpdateStatus_PAUSED
}
service.UpdateStatus.Message = message
return store.UpdateService(tx, service)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to pause update of service %s", serviceID)
}
}
开发者ID:CWSpear,项目名称:docker,代码行数:27,代码来源:updater.go
示例7: UpdateService
// UpdateService updates a Service referenced by ServiceID with the given ServiceSpec.
// - Returns `NotFound` if the Service is not found.
// - Returns `InvalidArgument` if the ServiceSpec is malformed.
// - Returns `Unimplemented` if the ServiceSpec references unimplemented features.
// - Returns an error if the update fails.
func (s *Server) UpdateService(ctx context.Context, request *api.UpdateServiceRequest) (*api.UpdateServiceResponse, error) {
if request.ServiceID == "" || request.ServiceVersion == nil {
return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
}
if err := validateServiceSpec(request.Spec); err != nil {
return nil, err
}
var service *api.Service
err := s.store.Update(func(tx store.Tx) error {
service = store.GetService(tx, request.ServiceID)
if service == nil {
return nil
}
// temporary disable network update
if request.Spec != nil && !reflect.DeepEqual(request.Spec.Networks, service.Spec.Networks) {
return errNetworkUpdateNotSupported
}
service.Meta.Version = *request.ServiceVersion
service.Spec = *request.Spec.Copy()
return store.UpdateService(tx, service)
})
if err != nil {
return nil, err
}
if service == nil {
return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
}
return &api.UpdateServiceResponse{
Service: service,
}, nil
}
开发者ID:CheggEng,项目名称:docker,代码行数:38,代码来源:service.go
示例8: allocateService
func (a *Allocator) allocateService(ctx context.Context, nc *networkContext, s *api.Service) error {
if s.Spec.Endpoint != nil {
if s.Endpoint == nil {
s.Endpoint = &api.Endpoint{
Spec: s.Spec.Endpoint.Copy(),
}
}
// The service is trying to expose ports to the external
// world. Automatically attach the service to the ingress
// network only if it is not already done.
if len(s.Spec.Endpoint.Ports) != 0 {
var found bool
for _, vip := range s.Endpoint.VirtualIPs {
if vip.NetworkID == ingressNetwork.ID {
found = true
break
}
}
if !found {
s.Endpoint.VirtualIPs = append(s.Endpoint.VirtualIPs,
&api.Endpoint_VirtualIP{NetworkID: ingressNetwork.ID})
}
}
}
if err := nc.nwkAllocator.ServiceAllocate(s); err != nil {
nc.unallocatedServices[s.ID] = s
return err
}
if err := a.store.Update(func(tx store.Tx) error {
for {
err := store.UpdateService(tx, s)
if err != nil && err != store.ErrSequenceConflict {
return fmt.Errorf("failed updating state in store transaction for service %s: %v", s.ID, err)
}
if err == store.ErrSequenceConflict {
storeService := store.GetService(tx, s.ID)
storeService.Endpoint = s.Endpoint
s = storeService
continue
}
break
}
return nil
}); err != nil {
if err := nc.nwkAllocator.ServiceDeallocate(s); err != nil {
log.G(ctx).WithError(err).Errorf("failed rolling back allocation of service %s: %v", s.ID, err)
}
return err
}
return nil
}
开发者ID:CadeLaRen,项目名称:docker-3,代码行数:60,代码来源:network.go
示例9: rollbackUpdate
func (u *Updater) rollbackUpdate(ctx context.Context, serviceID, message string) {
log.G(ctx).Debugf("starting rollback of service %s", serviceID)
var service *api.Service
err := u.store.Update(func(tx store.Tx) error {
service = store.GetService(tx, serviceID)
if service == nil {
return nil
}
if service.UpdateStatus == nil {
// The service was updated since we started this update
return nil
}
service.UpdateStatus.State = api.UpdateStatus_ROLLBACK_STARTED
service.UpdateStatus.Message = message
if service.PreviousSpec == nil {
return errors.New("cannot roll back service because no previous spec is available")
}
service.Spec = *service.PreviousSpec
service.PreviousSpec = nil
return store.UpdateService(tx, service)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to start rollback of service %s", serviceID)
return
}
}
开发者ID:CWSpear,项目名称:docker,代码行数:31,代码来源:updater.go
示例10: resolveService
func (r *ReplicatedOrchestrator) resolveService(ctx context.Context, task *api.Task) *api.Service {
if task.ServiceID == "" {
return nil
}
var service *api.Service
r.store.View(func(tx store.ReadTx) {
service = store.GetService(tx, task.ServiceID)
})
return service
}
开发者ID:JMesser81,项目名称:docker,代码行数:10,代码来源:services.go
示例11: addTask
func (g *Orchestrator) addTask(ctx context.Context, batch *store.Batch, service *api.Service, nodeID string) {
task := orchestrator.NewTask(g.cluster, service, 0, nodeID)
err := batch.Update(func(tx store.Tx) error {
if store.GetService(tx, service.ID) == nil {
return nil
}
return store.CreateTask(tx, task)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("global orchestrator: failed to create task")
}
}
开发者ID:msabansal,项目名称:docker,代码行数:13,代码来源:global.go
示例12: restartTask
// restartTask calls the restart supervisor's Restart function, which
// sets a task's desired state to dead and restarts it if the restart
// policy calls for it to be restarted.
func (g *GlobalOrchestrator) restartTask(ctx context.Context, taskID string, serviceID string) {
err := g.store.Update(func(tx store.Tx) error {
t := store.GetTask(tx, taskID)
if t == nil || t.DesiredState > api.TaskStateRunning {
return nil
}
service := store.GetService(tx, serviceID)
if service == nil {
return nil
}
return g.restarts.Restart(ctx, tx, service, *t)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("global orchestrator: restartTask transaction failed")
}
}
开发者ID:CadeLaRen,项目名称:docker-3,代码行数:19,代码来源:global.go
示例13: GetService
// GetService returns a Service given a ServiceID.
// - Returns `InvalidArgument` if ServiceID is not provided.
// - Returns `NotFound` if the Service is not found.
func (s *Server) GetService(ctx context.Context, request *api.GetServiceRequest) (*api.GetServiceResponse, error) {
if request.ServiceID == "" {
return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
}
var service *api.Service
s.store.View(func(tx store.ReadTx) {
service = store.GetService(tx, request.ServiceID)
})
if service == nil {
return nil, grpc.Errorf(codes.NotFound, "service %s not found", request.ServiceID)
}
return &api.GetServiceResponse{
Service: service,
}, nil
}
开发者ID:ChristianKniep,项目名称:swarmkit,代码行数:20,代码来源:service.go
示例14: commitAllocatedService
func (a *Allocator) commitAllocatedService(ctx context.Context, batch *store.Batch, s *api.Service) error {
if err := batch.Update(func(tx store.Tx) error {
err := store.UpdateService(tx, s)
if err == store.ErrSequenceConflict {
storeService := store.GetService(tx, s.ID)
storeService.Endpoint = s.Endpoint
err = store.UpdateService(tx, storeService)
}
return errors.Wrapf(err, "failed updating state in store transaction for service %s", s.ID)
}); err != nil {
if err := a.netCtx.nwkAllocator.ServiceDeallocate(s); err != nil {
log.G(ctx).WithError(err).Errorf("failed rolling back allocation of service %s", s.ID)
}
return err
}
return nil
}
开发者ID:Mic92,项目名称:docker,代码行数:21,代码来源:network.go
示例15: tickTasks
func (r *Orchestrator) tickTasks(ctx context.Context) {
if len(r.restartTasks) > 0 {
_, err := r.store.Batch(func(batch *store.Batch) error {
for taskID := range r.restartTasks {
err := batch.Update(func(tx store.Tx) error {
// TODO(aaronl): optimistic update?
t := store.GetTask(tx, taskID)
if t != nil {
if t.DesiredState > api.TaskStateRunning {
return nil
}
service := store.GetService(tx, t.ServiceID)
if !orchestrator.IsReplicatedService(service) {
return nil
}
// Restart task if applicable
if err := r.restarts.Restart(ctx, tx, r.cluster, service, *t); err != nil {
return err
}
}
return nil
})
if err != nil {
log.G(ctx).WithError(err).Errorf("Orchestrator task reaping transaction failed")
}
}
return nil
})
if err != nil {
log.G(ctx).WithError(err).Errorf("orchestrator task removal batch failed")
}
r.restartTasks = make(map[string]struct{})
}
}
开发者ID:yongtang,项目名称:swarmkit,代码行数:38,代码来源:tasks.go
示例16: startUpdate
func (u *Updater) startUpdate(ctx context.Context, serviceID string) {
err := u.store.Update(func(tx store.Tx) error {
service := store.GetService(tx, serviceID)
if service == nil {
return nil
}
if service.UpdateStatus != nil {
return nil
}
service.UpdateStatus = &api.UpdateStatus{
State: api.UpdateStatus_UPDATING,
Message: "update in progress",
StartedAt: ptypes.MustTimestampProto(time.Now()),
}
return store.UpdateService(tx, service)
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to mark update of service %s in progress", serviceID)
}
}
开发者ID:CWSpear,项目名称:docker,代码行数:23,代码来源:updater.go
示例17: restartTasksByNodeID
func (r *Orchestrator) restartTasksByNodeID(ctx context.Context, nodeID string) {
var err error
r.store.View(func(tx store.ReadTx) {
var tasks []*api.Task
tasks, err = store.FindTasks(tx, store.ByNodeID(nodeID))
if err != nil {
return
}
for _, t := range tasks {
if t.DesiredState > api.TaskStateRunning {
continue
}
service := store.GetService(tx, t.ServiceID)
if orchestrator.IsReplicatedService(service) {
r.restartTasks[t.ID] = struct{}{}
}
}
})
if err != nil {
log.G(ctx).WithError(err).Errorf("failed to list tasks to remove")
}
}
开发者ID:yongtang,项目名称:swarmkit,代码行数:23,代码来源:tasks.go
示例18: updateTask
func (u *Updater) updateTask(ctx context.Context, slot orchestrator.Slot, updated *api.Task) error {
// Kick off the watch before even creating the updated task. This is in order to avoid missing any event.
taskUpdates, cancel := state.Watch(u.watchQueue, state.EventUpdateTask{
Task: &api.Task{ID: updated.ID},
Checks: []state.TaskCheckFunc{state.TaskCheckID},
})
defer cancel()
// Create an empty entry for this task, so the updater knows a failure
// should count towards the failure count. The timestamp is added
// if/when the task reaches RUNNING.
u.updatedTasksMu.Lock()
u.updatedTasks[updated.ID] = time.Time{}
u.updatedTasksMu.Unlock()
var delayStartCh <-chan struct{}
// Atomically create the updated task and bring down the old one.
_, err := u.store.Batch(func(batch *store.Batch) error {
oldTask, err := u.removeOldTasks(ctx, batch, slot)
if err != nil {
return err
}
err = batch.Update(func(tx store.Tx) error {
if store.GetService(tx, updated.ServiceID) == nil {
return errors.New("service was deleted")
}
if err := store.CreateTask(tx, updated); err != nil {
return err
}
return nil
})
if err != nil {
return err
}
delayStartCh = u.restarts.DelayStart(ctx, nil, oldTask, updated.ID, 0, true)
return nil
})
if err != nil {
return err
}
if delayStartCh != nil {
select {
case <-delayStartCh:
case <-u.stopChan:
return nil
}
}
// Wait for the new task to come up.
// TODO(aluzzardi): Consider adding a timeout here.
for {
select {
case e := <-taskUpdates:
updated = e.(state.EventUpdateTask).Task
if updated.Status.State >= api.TaskStateRunning {
u.updatedTasksMu.Lock()
u.updatedTasks[updated.ID] = time.Now()
u.updatedTasksMu.Unlock()
return nil
}
case <-u.stopChan:
return nil
}
}
}
开发者ID:yongtang,项目名称:swarmkit,代码行数:71,代码来源:updater.go
示例19: allocateTask
func (a *Allocator) allocateTask(ctx context.Context, t *api.Task) (err error) {
taskUpdated := false
nc := a.netCtx
// We might be here even if a task allocation has already
// happened but wasn't successfully committed to store. In such
// cases skip allocation and go straight ahead to updating the
// store.
if !nc.nwkAllocator.IsTaskAllocated(t) {
a.store.View(func(tx store.ReadTx) {
if t.ServiceID != "" {
s := store.GetService(tx, t.ServiceID)
if s == nil {
err = fmt.Errorf("could not find service %s", t.ServiceID)
return
}
if !nc.nwkAllocator.IsServiceAllocated(s) {
err = fmt.Errorf("service %s to which this task %s belongs has pending allocations", s.ID, t.ID)
return
}
if s.Endpoint != nil {
taskUpdateEndpoint(t, s.Endpoint)
taskUpdated = true
}
}
for _, na := range t.Networks {
n := store.GetNetwork(tx, na.Network.ID)
if n == nil {
err = fmt.Errorf("failed to retrieve network %s while allocating task %s", na.Network.ID, t.ID)
return
}
if !nc.nwkAllocator.IsAllocated(n) {
err = fmt.Errorf("network %s attached to task %s not allocated yet", n.ID, t.ID)
return
}
na.Network = n
}
if err = nc.nwkAllocator.AllocateTask(t); err != nil {
err = errors.Wrapf(err, "failed during networktask allocation for task %s", t.ID)
return
}
if nc.nwkAllocator.IsTaskAllocated(t) {
taskUpdated = true
}
})
if err != nil {
return err
}
}
// Update the network allocations and moving to
// PENDING state on top of the latest store state.
if a.taskAllocateVote(networkVoter, t.ID) {
if t.Status.State < api.TaskStatePending {
updateTaskStatus(t, api.TaskStatePending, allocatedStatusMessage)
taskUpdated = true
}
}
if !taskUpdated {
return errNoChanges
}
return nil
}
开发者ID:Mic92,项目名称:docker,代码行数:72,代码来源:network.go
示例20: doNetworkInit
//.........这里部分代码省略.........
// Allocate services in the store so far before we process watched events.
var services []*api.Service
a.store.View(func(tx store.ReadTx) {
services, err = store.FindServices(tx, store.All)
})
if err != nil {
return errors.Wrap(err, "error listing all services in store while trying to allocate during init")
}
var allocatedServices []*api.Service
for _, s := range services {
if nc.nwkAllocator.IsServiceAllocated(s) {
continue
}
if err := a.allocateService(ctx, s); err != nil {
log.G(ctx).WithError(err).Errorf("failed allocating service %s during init", s.ID)
continue
}
allocatedServices = append(allocatedServices, s)
}
if _, err := a.store.Batch(func(batch *store.Batch) error {
for _, s := range allocatedServices {
if err := a.commitAllocatedService(ctx, batch, s); err != nil {
log.G(ctx).WithError(err).Errorf("failed committing allocation of service %s during init", s.ID)
}
}
return nil
}); err != nil {
log.G(ctx).WithError(err).Error("failed committing allocation of services during init")
}
// Allocate tasks in the store so far before we started watching.
var (
tasks []*api.Task
allocatedTasks []*api.Task
)
a.store.View(func(tx store.ReadTx) {
tasks, err = store.FindTasks(tx, store.All)
})
if err != nil {
return errors.Wrap(err, "error listing all tasks in store while trying to allocate during init")
}
for _, t := range tasks {
if taskDead(t) {
continue
}
var s *api.Service
if t.ServiceID != "" {
a.store.View(func(tx store.ReadTx) {
s = store.GetService(tx, t.ServiceID)
})
}
// Populate network attachments in the task
// based on service spec.
a.taskCreateNetworkAttachments(t, s)
if taskReadyForNetworkVote(t, s, nc) {
if t.Status.State >= api.TaskStatePending {
continue
}
if a.taskAllocateVote(networkVoter, t.ID) {
// If the task is not attached to any network, network
// allocators job is done. Immediately cast a vote so
// that the task can be moved to ALLOCATED state as
// soon as possible.
allocatedTasks = append(allocatedTasks, t)
}
continue
}
err := a.allocateTask(ctx, t)
if err == nil {
allocatedTasks = append(allocatedTasks, t)
} else if err != errNoChanges {
log.G(ctx).WithError(err).Errorf("failed allocating task %s during init", t.ID)
nc.unallocatedTasks[t.ID] = t
}
}
if _, err := a.store.Batch(func(batch *store.Batch) error {
for _, t := range allocatedTasks {
if err := a.commitAllocatedTask(ctx, batch, t); err != nil {
log.G(ctx).WithError(err).Errorf("failed committing allocation of task %s during init", t.ID)
}
}
return nil
}); err != nil {
log.G(ctx).WithError(err).Error("failed committing allocation of tasks during init")
}
return nil
}
开发者ID:Mic92,项目名称:docker,代码行数:101,代码来源:network.go
注:本文中的github.com/docker/swarmkit/manager/state/store.GetService函数示例整理自Github/MSDocs等源码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。 |
请发表评论